C#中的堆栈列图表 [英] Stacked Column Chart in C#

查看:946
本文介绍了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值


  • 您控制要显示的点的范围和图表的其他方面,所有x值应为数字




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



请注意,该示例使用以代码编写的DataSource中的数据。从数据库读取它没有真正的区别,因为你在做。



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



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



要解决这个问题,您可以将您的查询更改为填充空白的某些 join 帮助你。



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



让我们来看看一个有趣的帮助函数 Chart.DataManipulator.InsertEmptyPoints



此函数有几个重载;我们将使用一个包含所有要对齐的系列名称的字符串。这不仅会添加缺失的点,而是实际上将它们插入到他们缺失的地方,所以我们现在应该通过规则#1& 2!



在进入更多细节之前(是的,更多的细节,叹息,但只是有一点是正确的。)让我们看看规则#3:



这适用于所有图表类型,也是图表控件的一个规则用户最常见的情况,通常甚至没有注意到: p>

所有X值都应为数字!



字符串将填充到轴标签中,否则会被丢弃。最值得注意的是,结果数据点的x值都是 0



这是确定只要你不需要他们,但一旦你做了一个讨厌的惊喜。因为他们走了,你不能使用它们来计算任何东西,或者格式化标签,或者显示工具提示等,或者使用它们来设置显示范围。



注意,即使x值都为0,数据点仍然沿x轴扩展;你只是不再控制任何更多..



所以你需要决定一些计划将你的x值转换成数字!



一个是设置一个数据结构,其中列出了所有的值:

  List< string> ; catLookup = new List< string>(){ARTEFACT,et..cetc ..}; 

然后,您可以按如下方式查找每个值:

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

这将工作,但如果你的应用程序是真的,它应该能够与数据增长;因此您应该从数据库中读取所有可能的值。如果它是正确的设计,已经有一个查找表使用,并使用它的键是最自然的选择。



如果不是你仍然可以读入值与一个简单的查询:

 通过reject_category从tblReject_test顺序中选择不同的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]));
}

你会注意到,我不仅插入了帮助变量使调试更容易,而且第二次查找,您需要创建系列并将点添加到各自的系列中。



我将留给您创建;如果某个类别或部门不是发现..


I am trying to set up my program so that the user can display a stacked column chart that displays the number of reject categories that appear in each department (for example, 5 appear in department 1, 3 in department 2, etc). I've had a look around online and taken a crack at it myself but I cannot seem to get it working. If anyone would be able to help that would be fantastic.

What the chart currently does when the user presses a button to switch to a stacked column chart:

Code:

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;
    }

解决方案

Creating a stacked chart is easy. That is if you have the proper data.

Creating a stacked chart is hard. That is if you don't have the proper data.

There is one rule to follow: The data in all your series need to be aligned for the stacking to work!

This sounds simple but in fact is a lot trickier than one may expect.

Before we start with a few examples here are the details the simple rule breaks down to:

  • Rule #1 You need to have a datapoint in **each series for each x-value you have in any series.**

  • Rule #2 Your points need to be in the right order, that is with ascending x-values

  • Rule #3 To let you control the range of points to display and other aspects of your chart, all x-values should be numeric

For a working example of a stacked chart do have a look at this post! There the question was 'How to avoid the gaps?' but it really boiled down to 'How to make the stacking work properly?'.

Note that the example uses data from a DataSource that was written in code. There is no real difference to reading it from a DataBase as you are doing.

The solution was to add dummy points to fill in the gaps.

This will be one of your problems as you can't expect the data from your query to be complete.

To solve this problem you can either change your query to some join that fills the gaps or ask the chart to help you along.

I won't go into the SQL option although it would seem to be the most natural one. Note however that in order to follow rules #2 you will need to add an order clause to the query to sort the records by the x-values in any case, i.e. by your rejection-categories.

Let's instead have a look at an interesting helper function called Chart.DataManipulator.InsertEmptyPoints :

This function has several overloads; we'll use the one with the string that holds all series names that we want to align. This will not just add the missing points but actually insert them at the spots where they are missing, so we should now be ok by rules #1 & 2!

Before going into more details (yes, even more details, sigh, but there simply is quite a bit to get right..) let's have a look at rule #3:

This is one that applies to all chart types and also the one rule users of the chart control break most often, usually without even noticing..:

All X-Values should be numeric!

If instead you add strings, those string will be stuffed into the axis labels and otherwise are thrown away. Most notably the x-values of the resulting data points all are 0!

Which is ok as long as you don't need them, but once you do you are in for a nasty surprise. Since they are gone you cannot use them to calculate anything from them, or to format the labels, or to show tooltips etc, or use them to set a range to display.

Note that even though the x-values are all 0 the datapoints are still spread along the x-axis; you just don't control that any more..

So you need to decide on some scheme to turn your x-values into numbers!

One is to set up a data structure where all your values are listed:

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

You can then find each value like this:

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

This will work but if your application is real it should be able to grow with the data; so you should read all possible values from the database. If it is desigend properly there is already a lookup table to use and using its key owuld be the most naturaly choice.

If it isn't you still can read in the values with a simple query:

Select distinct reject_category from tblReject_test order by reject_category;

Now let's do the call, that aligns all series we have:

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

Now back to your original code and what you need to do there:

For one thing all your values are strings. So you should change you loop to something like this:

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"]));
}

You will notice that I not only have inserted helper variable that make debugging so much easier, but also a second lookup to hold the departments you need to create the series and add the points to their respective series..

I leave creating this to you; also adding the necessary checks if a category or department is not found..

这篇关于C#中的堆栈列图表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆