Reputation: 23
I am attempting to dynamically create a bar chart in C# based on the following datatable (which will change, hence the need for dynamic creation).
Here's the datatables that I'm reading from currently: (people of the future: these images contained work stuff and I don't want to get fired, so I've removed them =O )
The top table is where I add the series (s24, s26, s27) data. The second table is where I slim it down and add the "Total" series.
So here are the columns that I'm trying to chart from:
Config - this is where I want to get my individual series: ie: s24, s26, s27, etc. HRC_Count - this is the actual value I'm trying to graph HRC_Description and HRC - these are labels for the Y axis Total_HRC_Count - this is for my "Total" series (black bar on chart)
//get distinct Configs (to be added as Series in chart)
//this creates a dataview to parse for the series in the chart
DataView view = new DataView(dt);
DataTable distinctValues = new DataTable();
distinctValues = view.ToTable(true, "Config");
DataView dv = new DataView(distinctValues);
dv.Sort = "Config ASC";
DataTable dt_temp = new DataTable();
dt_temp = dv.ToTable();
distinctValues = dt_temp;
GraphDataNew(distinctValues);
then I call GraphDataNew and parse the dataview for the series:
private void GraphDataNew(DataTable dt_distinct)
{
chart_new.Series.Clear();
foreach (DataRow row in dt_distinct.Rows)
{
string s = row["Config"].ToString();
chart_new.Series.Add(s);
chart_new.Series[s].ChartType = SeriesChartType.Bar;
chart_new.Series[s].IsValueShownAsLabel = true;
chart_new.Series[s].Sort(PointSortOrder.Ascending, "X");
chart_new.Series[s].XValueType = System.Windows.Forms.DataVisualization.Charting.ChartValueType.String;
chart_new.Series[s].YValueType = System.Windows.Forms.DataVisualization.Charting.ChartValueType.Double;
}
So now I have my Series (Configs) set up, now I add actual data:
DataView dv = new DataView(dt);
dv.Sort = "HRC_Description ASC, Config ASC"; // sort by description first, then config second
string HRC_Description = "";
string Config = "";
double HRC_Count = 0;
DataTable dt_temp = new DataTable();
dt_temp = dv.ToTable();
// add actual data
//loop through dt_temp and add datapoints and custom labels to chart
for (int x = 0; x < dt_temp.Rows.Count; x++)
{
HRC_Description = (dt_temp.Rows[x]["HRC_Description"].ToString().Trim());
Config = dt_temp.Rows[x]["Config"].ToString().Trim();
HRC_Count = Double.Parse(dt_temp.Rows[x]["HRC_Count"].ToString().Trim());
chart_new.Series[Config].Points.AddXY(HRC_Description, HRC_Count);
int y = chart_new.Series[Config].Points.Count;
chart_new.Series[Config].Points[y - 1].AxisLabel = HRC_Description;
}
Then I add the "Total" series bar:
if (1==1) // fake condition for this question
{
chart_new.Series.Add("Total");
chart_new.Series["Total"].ChartType = SeriesChartType.Bar;
chart_new.Series["Total"].Color = Color.Black;
chart_new.Series["Total"].IsValueShownAsLabel = true;
chart_new.Series["Total"].XValueType = System.Windows.Forms.DataVisualization.Charting.ChartValueType.String;
chart_new.Series["Total"].YValueType = System.Windows.Forms.DataVisualization.Charting.ChartValueType.Double;
DataView view1 = new DataView(dt_temp);
DataTable distinctValues1 = view1.ToTable(true, "HRC_Description", "Total_HRC_Count");
dt_temp = distinctValues1;
double Total_HRC_Count = 0;
for (int x = 0; x < dt_temp.Rows.Count; x++)
{
HRC_Description = (dt_temp.Rows[x]["HRC_Description"].ToString().Trim());
Total_HRC_Count = Double.Parse(dt_temp.Rows[x]["Total_HRC_Count"].ToString().Trim());
chart_new.Series["Total"].Points.AddXY(HRC_Description, Total_HRC_Count);
}
}
This is what the chart looks like: [![Example Chart][2]][2]
However, as you can see in the attached chart, my data is all off. There are 10 of the HRC_Description, but only 9 show up, and one is repeated. On top of that, it seems that whenever I have more than 2 series, the data gets mixed up. Does anyone have any tips on what I can do to fix this? It's driving me crazy! Thanks!!
Upvotes: 2
Views: 2030
Reputation: 54463
I can't fully analyze your data but I can give you a hint, which should help in solving your problem:
I see that you add the datapoints with strings as the x-values.
This is ok (sort of; well, no, not really) but the x-values of the datapoints that actually are addded really are not strings but double and they all contain 0
.
The strings only go into the labels, not the x-values! (So the values are lost)
But to be grouped together the points in your various series need some criterion and as the x-values won't work (even though they do look as if they did) the position of the points is used instead. Which dervies from the positions, i.e. from the order and number of points you add.
So only those bars will be grouped together which are added to the same position and since there are no real positions the order in which they are added is all that counts.
So you need to make sure to always use the same order and to never leave a spot empty when you add your points. If a values is missing in a series you need to add an empty dummy points (set its DataPoint.IsEmpty=true
)
Easy to get wrong..!
You can check if this is the cause by checking the number of datapoints in each series. If they are not all the same this is the problem..
Here is an example: Note how the second, yellow and the 3rd, red series both are missing values but how only the yellow one is off; note the last point especially!
private void button17_Click(object sender, EventArgs e)
{
chart3.ChartAreas[0].AxisY.MajorGrid.Enabled = false;
chart3.Series.Clear();
Series s1 = chart3.Series.Add("S1");
Series s2 = chart3.Series.Add("S2");
Series s3 = chart3.Series.Add("S3");
Random R = new Random(42);
s1.ChartType = SeriesChartType.Bar;
s2.ChartType = SeriesChartType.Bar;
s3.ChartType = SeriesChartType.Bar;
for (int i = 0; i < 10; i++)
{
// this series is complete..:
s1.Points.AddXY(i + "", R.Next(100));
int r = R.Next(5);
// this series misses some points..:
if (r==0) s2.Points.AddXY(i + "", R.Next(100));
// this series inserts empty points and so misses no points.:
if (r == 0) s3.Points.AddXY(i + "", R.Next(100));
else { int p = s3.Points.AddXY(i + "", R.Next(100)); s3.Points[p].IsEmpty = true; }
}
// now add a value at "10" for all series..;
s1.Points.AddXY("10", 100);
s2.Points.AddXY("10", 100);
s3.Points.AddXY("10", 100);
}
Upvotes: 1