C#中的堆积柱形图

我正在尝试设置我的程序,以便用户可以显示堆积的柱形图,其中显示每个部门中显示的拒绝类别的数量(例如,5显示在部门1中,3显示在部门2中,等等)。 我已经在网上浏览了一下并自己解决了这个问题,但我似乎无法让它发挥作用。 如果有人能够帮助那将是太棒了。

用户按下按钮切换到堆积柱形图时图表当前的作用: 堆积柱形图

码:

private void btnStacked_Click(object sender, EventArgs e) { charRejections.Series["RFR"].Enabled = false; charRejections.Series["Department 1"].Points.Clear(); charRejections.Series["Department 1"].Enabled = true; charRejections.Series["Department 2"].Points.Clear(); charRejections.Series["Department 2"].Enabled = true; charRejections.Series["Department 3"].Points.Clear(); charRejections.Series["Department 3"].Enabled = true; { string connectiontring = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=|DataDirectory|\\Database1.mdb"; DataConnection = new OleDbConnection(connectiontring); try { DataConnection.Open(); OleDbCommand command = new OleDbCommand(); command.Connection = DataConnection; string query1 = "SELECT COUNT(reject_category) as reject, reject_category FROM tblReject_test GROUP BY reject_category"; command.CommandText = query1; OleDbDataReader reader = command.ExecuteReader(); while (reader.Read()) { charRejections.Series["Department 1"].Points.AddXY(reader["reject_category"].ToString(), reader["reject"].ToString()); charRejections.Series["Department 2"].Points.AddXY(reader["reject_category"].ToString(), reader["reject"].ToString()); charRejections.Series["Department 3"].Points.AddXY(reader["reject_category"].ToString(), reader["reject"].ToString()); } DataConnection.Close(); } catch (Exception ex) { MessageBox.Show("Error " + ex); } } this.charRejections.Series["Department 1"].ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.StackedColumn; this.charRejections.Series["Department 2"].ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.StackedColumn; this.charRejections.Series["Department 3"].ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.StackedColumn; } 

创建堆积图很容易。 那就是你有合适的数据。

创建堆积图表很难。 那就是你没有合适的数据。

有一条规则要遵循:所有系列中的数据都需要对齐才能使堆叠工作!

这听起来很简单,但实际上比人们想象的要复杂得多。

在我们开始之前的几个例子之前,简单规则的细节分解为:

  • 规则#1对于任何系列中的每个 x值,您需要在每个系列中都有一个数据点 。**

  • 规则#2 您的点需要按正确的顺序排列,即x值递增

  • 规则#3为了让您控制要显示的点的范围和图表的其他方面, 所有x值都应该是数字

有关堆积图表的工作示例,请查看此post ! 那里的问题是“如何避免差距?” 但它真的归结为‘如何使堆叠工作正常?’

请注意,该示例使用来自以代码编写的DataSource的数据。 从正在进行的数据库中读取它没有什么不同。

解决方案是添加虚拟点以填补空白。

这将是您的一个问题,因为您不能指望查询中的数据是完整的。

要解决此问题,您可以将查询更改为填补空白的某个联接或要求图表帮助您。

我不会进入SQL选项,尽管它似乎是最自然的选项。 但请注意,为了遵循规则#2,您需要在查询中添加一个order子句, order在任何情况下按x值对记录进行排序,即通过拒绝类别。

让我们看看一个名为Chart.DataManipulator.InsertEmptyPoints的有趣助手函数:

这个function有几个重载; 我们将使用包含我们想要对齐的所有系列名称的字符串。 这不仅会添加缺失点,而且实际上会将它们插入缺失的位置,因此我们现在应该按照规则#1和2进行操作!

在进入更多细节之前(是的,甚至更多的细节,叹息,但只是有很多东西要做对..)让我们来看看规则#3:

这适用于所有图表类型,并且图表控件的一个规则用户最常打破,通常甚至没有注意到..:

所有X值都应该是数字!

如果您添加字符串,那么这些字符串将被填充到轴标签中,否则将被丢弃 。 最值得注意的是,结果数据点的x值均为0

只要你不需要它们就可以了,但是一旦你做到了,你就会有一个令人讨厌的惊喜。 由于它们已经消失,您无法使用它们来计算任何内容,或格式化标签,或显示工具提示等,或使用它们来设置要​​显示的范围。

请注意,即使x值全为0 ,数据点仍然沿x轴扩展; 你只是不再控制..

所以你需要决定一些方案来把你的x值变成数字!

一种是建立一个数据结构,其中列出了所有值:

  List catLookup = new List() { "ARTEFACT", "et..cetc.."}; 

然后,您可以找到这样的每个值:

  int found = catLookup.FindIndex(x => x == someValueWeSearch); 

这将有效但如果您的应用程序是真实的,它应该能够与数据一起增长; 所以你应该从数据库中读取所有可能的值。 如果它是正确设计的,那么已经有一个查找表可供使用,并且使用它的密钥将是最自然的选择。

如果不是,您仍然可以使用简单查询读取值:

 Select distinct reject_category from tblReject_test order by reject_category; 

现在让我们进行调整,调整我们拥有的所有系列:

  string seriesNames = String.Join(",", seriesLookup.Keys); chart1.DataManipulator.InsertEmptyPoints(1, IntervalType.Number, seriesNames); 

现在回到原始代码以及您需要做的事情:

一方面,你所有的价值观都是字符串。 所以你应该把你的循环变成这样的东西:

 while (reader.Read()) { string seriesName = reader[1].ToString(); int seriesIndex = seriesLookup.FindIndex(x => x == seriesName); string catName = reader[2].ToString(); int catIndex = catLookup.FindIndex(x => x == catName); charRejections.Series[seriesName ].Points.AddXY(catIndex, Convert.ToInt16((reader["reject"])); } 

您会注意到我不仅插入了辅助变量,使调试变得更加容易,而且还有第二次查找以保存创建系列所需的部门并将点添加到各自的系列中。

我留给你创造这个; 如果找不到类别或部门,还会添加必要的检查。