Problems stacking bar charts
Problems stacking bar charts
Im using the latest debug build 2.0.2242.29273
I have created a set of data with the following query. essentially 3 columns TYPE, VALUE and X. NOTE that for type 'A' I have no data for 24th January.
select 'A' as type,
10 as value,
cast('23JAN2006' as datetime)as x
union all
select 'A' as type,
10 as value,
cast('25JAN2006' as datetime)as x
union all
select 'A' as type,
10 as value,
cast('26JAN2006' as datetime)as x
union all
select 'B' as type,
15 as value,
cast('23JAN2006' as datetime)as x
union all
select 'B' as type,
15 as value,
cast('24JAN2006' as datetime)as x
union all
select 'B' as type,
15 as value,
cast('25JAN2006' as datetime) as x
union all
select 'B' as type,
15 as value,
cast('26JAN2006' as datetime) as x
If I create a bar graph where the first bar is for type A and the second bar is for type B, the Xaxis is the datetime value and the bar value is value. I get a graph that is correct, it shows the 4 days where the 23rd, 25th and 26th have two bars side-by-side. If however I stack the series the bar for B from the 24th is left hanging i.e. it looks like it's being stacked on something but there is nothing there. The A data for the 26 is not shown, I think it's all moved up a day.
I think what is happening is that TCHART is doing the stacking based on the simple order of the data not on the date/time groups. There is no A data from the 24th, TCHART tries to stack the B data with the A data from the 25th. If I reverse the order of the series ie plot B first and then A it stacks correctly.
I have created a set of data with the following query. essentially 3 columns TYPE, VALUE and X. NOTE that for type 'A' I have no data for 24th January.
select 'A' as type,
10 as value,
cast('23JAN2006' as datetime)as x
union all
select 'A' as type,
10 as value,
cast('25JAN2006' as datetime)as x
union all
select 'A' as type,
10 as value,
cast('26JAN2006' as datetime)as x
union all
select 'B' as type,
15 as value,
cast('23JAN2006' as datetime)as x
union all
select 'B' as type,
15 as value,
cast('24JAN2006' as datetime)as x
union all
select 'B' as type,
15 as value,
cast('25JAN2006' as datetime) as x
union all
select 'B' as type,
15 as value,
cast('26JAN2006' as datetime) as x
If I create a bar graph where the first bar is for type A and the second bar is for type B, the Xaxis is the datetime value and the bar value is value. I get a graph that is correct, it shows the 4 days where the 23rd, 25th and 26th have two bars side-by-side. If however I stack the series the bar for B from the 24th is left hanging i.e. it looks like it's being stacked on something but there is nothing there. The A data for the 26 is not shown, I think it's all moved up a day.
I think what is happening is that TCHART is doing the stacking based on the simple order of the data not on the date/time groups. There is no A data from the 24th, TCHART tries to stack the B data with the A data from the 25th. If I reverse the order of the series ie plot B first and then A it stacks correctly.
-
- Site Admin
- Posts: 14730
- Joined: Mon Jun 09, 2003 4:00 am
- Location: Banyoles, Catalonia
- Contact:
Hi Adrian,
To stack series, all stacked series need to have the same XValues. If a value is missing then add a null point. The code below has the behaviour you request.
To stack series, all stacked series need to have the same XValues. If a value is missing then add a null point. The code below has the behaviour you request.
Code: Select all
private void Form1_Load(object sender, System.EventArgs e)
{
bar1.Add(1,1);
bar1.Add(2,2);
bar1.Add(3,3);
bar1.Add();
bar1.Add(5,5);
bar1.Add(6,6);
bar1.Add(7,7);
bar2.Add(1,1);
bar2.Add(2,2);
bar2.Add(3,3);
bar2.Add(4,4);
bar2.Add(5,5);
bar2.Add(6,6);
bar2.Add(7,7);
}
Best Regards,
Narcís Calvet / Development & Support Steema Software Avinguda Montilivi 33, 17003 Girona, Catalonia Tel: 34 972 218 797 http://www.steema.com |
Instructions - How to post in this forum |
this is fine when adding points individually however I'm using a datatable and the datasource property. I would have thought that the stack operation should compare XValues for each series and match them up. It's a little impracticle to have to work out if there are any gaps in any series and then adding the points individually don't you think?
-
- Site Admin
- Posts: 14730
- Joined: Mon Jun 09, 2003 4:00 am
- Location: Banyoles, Catalonia
- Contact:
Hi Adrian,
How do you think the series should be painted if they don't have the same X values. For example, if series A has X values for 1, 3 and 4 and series B has values for 1,2,3.9 and 5, the 3.9 and 4 values from series B and A respectively may overlap.
How do you think the series should be painted if they don't have the same X values. For example, if series A has X values for 1, 3 and 4 and series B has values for 1,2,3.9 and 5, the 3.9 and 4 values from series B and A respectively may overlap.
Best Regards,
Narcís Calvet / Development & Support Steema Software Avinguda Montilivi 33, 17003 Girona, Catalonia Tel: 34 972 218 797 http://www.steema.com |
Instructions - How to post in this forum |
I understand that there are issues like the one you point out however, in my examples I have two series. Series one has XValues of 1,2,4 and 5 (no XValue 3). Series two has XValues of 1,2,3,4,5 (includes a XValue for 3). In this case there is no overlap. What we should see here after painting Series one is a bar at XValues 1,2,4 and 5 and a gap at XValue 3. After painting series two we should see additional bars for XValues 1,2,4 and 5 and a single bar at Xvalue 3. After stacking we should see stacked bars for XValues 1,2,4 and 5 and a single bar (the data from series 2) for XValue 3.
This doesn't work though, we end up with the series 2 bar for Xvalue 4 being painted against XValue 3 , sort of hanging above the XValue 3 point.
This doesn't work though, we end up with the series 2 bar for Xvalue 4 being painted against XValue 3 , sort of hanging above the XValue 3 point.
-
- Site Admin
- Posts: 14730
- Joined: Mon Jun 09, 2003 4:00 am
- Location: Banyoles, Catalonia
- Contact:
Hi Adrian,
A solution for that would be controlling how data is added to the database or to the series and add null values where necessary.
Another solution would be using:
That is, the series with most x values should be painted first.
Yes, that's right, but you'll understand that implementing a generic solution for that is really complex.In this case there is no overlap.
A solution for that would be controlling how data is added to the database or to the series and add null values where necessary.
Another solution would be using:
Code: Select all
bar1.MultiBar = Steema.TeeChart.Styles.MultiBars.Stacked;
bar2.MultiBar = Steema.TeeChart.Styles.MultiBars.Stacked;
double[] X1 = new double[] { 1, 2, 4, 5 };
double[] X2 = new double[] { 1, 2, 3, 4, 5 };
double[] Y1 = new double[] { 2, 2, 2, 2 };
double[] Y2 = new double[] { 2, 2, 2, 2, 2 };
bar1.Add(X1, Y1);
bar2.Add(X2, Y2);
if (bar1.Count < bar2.Count)
{
tChart1.Series.Exchange(0, 1);
}
Best Regards,
Narcís Calvet / Development & Support Steema Software Avinguda Montilivi 33, 17003 Girona, Catalonia Tel: 34 972 218 797 http://www.steema.com |
Instructions - How to post in this forum |
-
- Site Admin
- Posts: 14730
- Joined: Mon Jun 09, 2003 4:00 am
- Location: Banyoles, Catalonia
- Contact:
Hi Adrian,
I noticed that 2nd solution I posted is not good enough. I tested yIT using random values instead of a fix Y value. What happened is that, after the series data gap the bars stacked at the top are still positioned as if they where stacked on the previous bar. So a more robust solution is to do post-modify the values:
I noticed that 2nd solution I posted is not good enough. I tested yIT using random values instead of a fix Y value. What happened is that, after the series data gap the bars stacked at the top are still positioned as if they where stacked on the previous bar. So a more robust solution is to do post-modify the values:
Code: Select all
bar1.MultiBar = Steema.TeeChart.Styles.MultiBars.Stacked;
bar2.MultiBar = Steema.TeeChart.Styles.MultiBars.Stacked;
Random rnd = new Random();
double[] X1 = new double[] { 1, 2, 4, 5 };
double[] X2 = new double[] { 1, 2, 3, 4, 5 };
double[] Y1 = new double[] { rnd.NextDouble(), rnd.NextDouble(), rnd.NextDouble(), rnd.NextDouble() };
double[] Y2 = new double[] { rnd.NextDouble(), rnd.NextDouble(), rnd.NextDouble(), rnd.NextDouble(), rnd.NextDouble() };
bar1.Marks.Visible = false;
bar2.Marks.Visible = false;
bar1.Add(X1, Y1);
bar2.Add(X2, Y2);
if (bar1.Count < bar2.Count)
{
for (int i = 0; i < bar2.Count; ++i)
{
double xvalue = bar2.XValues[i];
if (bar1.XValues.IndexOf(xvalue) == -1)
{
bar1.Add(xvalue, 0, Color.Transparent);
}
}
}
Best Regards,
Narcís Calvet / Development & Support Steema Software Avinguda Montilivi 33, 17003 Girona, Catalonia Tel: 34 972 218 797 http://www.steema.com |
Instructions - How to post in this forum |
I still think there is a bug here. I know I can fix it up with code but shouldn't TCHART stack the bars properly. If, when I add multiple series unstacked it can place the bars against the correct XVALUES why can't it stack them correctly. It seems that when we change the chart to be stacked TCHART stops matching the bars against the XVALUES. My application provides a generaic charting facility it would be extreamly difficult for me to cater for the stacking problem through coding, this is one of the reasons I chose TCHART for my charting engine. I'm pretty sure this issue was not around with the ACTIVEX version.
Can it be look at again please.
Can it be look at again please.
-
- Site Admin
- Posts: 14730
- Joined: Mon Jun 09, 2003 4:00 am
- Location: Banyoles, Catalonia
- Contact:
Hi Adrian,
Thanks for suggestion which is already on our wish-list to be considered for future releases.
Thanks for suggestion which is already on our wish-list to be considered for future releases.
I'm afraid this also happens with v6 and v7 ActiveX, try using the code below to check it. You need to uncomment the commented line to have it working.I'm pretty sure this issue was not around with the ACTIVEX version.
Code: Select all
Private Sub Form_Load()
TChart1.AddSeries scBar
TChart1.AddSeries scBar
TChart1.Series(0).asBar.MultiBar = mbStacked
TChart1.Series(0).AddXY 1, 1, "", clTeeColor
TChart1.Series(0).AddXY 2, 2, "", clTeeColor
TChart1.Series(0).AddXY 3, 3, "", clTeeColor
' TChart1.Series(0).AddNullXY 4, 4, ""
TChart1.Series(0).AddXY 5, 5, "", clTeeColor
TChart1.Series(0).AddXY 6, 6, "", clTeeColor
TChart1.Series(0).AddXY 7, 7, "", clTeeColor
TChart1.Series(1).AddXY 1, 1, "", clTeeColor
TChart1.Series(1).AddXY 2, 2, "", clTeeColor
TChart1.Series(1).AddXY 3, 3, "", clTeeColor
TChart1.Series(1).AddXY 4, 4, "", clTeeColor
TChart1.Series(1).AddXY 5, 5, "", clTeeColor
TChart1.Series(1).AddXY 6, 6, "", clTeeColor
TChart1.Series(1).AddXY 7, 7, "", clTeeColor
End Sub
Best Regards,
Narcís Calvet / Development & Support Steema Software Avinguda Montilivi 33, 17003 Girona, Catalonia Tel: 34 972 218 797 http://www.steema.com |
Instructions - How to post in this forum |
Hi Again Narcis,
I'm reviewing my charting code again and this issue is still a problem for me. I think this is the same issue but just to make sure if I have data like
the convertaxisvalues function just changes date types to a type DOUBLE if possible so that the ADD method doesn't fail. Notice that if I get a Y value that is NULL I do not draw the bar.
Using the above code if I create a bar graph without stacking I get the following, this is exactly what I would expect.
Now if I change the stacking from none to stacked (using the chart editor dialog) I end up with which is not what I expect.
On further investigation, after I've changed the stack type and go back to the editor none of the stack radio buttons are set.
My application is a generic reporting tool, I cannot control what the users input to the charting so I need to have a solution that caters for this situation.
Any ideas would be great...
I'm reviewing my charting code again and this issue is still a problem for me. I think this is the same issue but just to make sure if I have data like
- X,Y1,Y2
01/jan/2000,10,5
02/jan/2000,null,5
03/jan/2000,30,5
Code: Select all
Dim row As DataRowView
For i As Integer = 0 To dv.Count - 1
row = dv.Item(i)
ox = ConvertAxisValue(row, xName)
oy = ConvertAxisValue(row, yName)
If Not TypeOf oy Is System.DBNull Then
iPoint = serBar.Add(ox, oy)
If LabelName <> "" Then
serBar.Labels.Item(iPoint) = row(LabelName)
End If
If ColourName <> "" Then
serBar(iPoint).Color = System.Drawing.Color.FromName(row(ColourName))
End If
End If
Next
Using the above code if I create a bar graph without stacking I get the following, this is exactly what I would expect.
Now if I change the stacking from none to stacked (using the chart editor dialog) I end up with which is not what I expect.
On further investigation, after I've changed the stack type and go back to the editor none of the stack radio buttons are set.
My application is a generic reporting tool, I cannot control what the users input to the charting so I need to have a solution that caters for this situation.
Any ideas would be great...
Last edited by Adrian on Sat Nov 11, 2006 4:26 am, edited 3 times in total.
If I try adding a null bar
I end up with
Code: Select all
If Not TypeOf oy Is System.DBNull Then
iPoint = serBar.Add(ox, oy)
If LabelName <> "" Then
serBar.Labels.Item(iPoint) = row(LabelName)
End If
If ColourName <> "" Then
serBar(iPoint).Color = System.Drawing.Color.FromName(row(ColourName))
End If
Else
iPoint = serBar.Add()
End If
Ok...
I've done a bit more work on this and have a workaround for the situation where we have X values and NULL Y values. The following code handles this correctly.
The following chart shows the side by side representation, note the missing blue value at 2nd Jan.
after stacking we get the following which is correct....
So I've worked around the situation where we have same number of data points in both series but some Y values are NULL. However there is still a problem where we have a different number of rows in two series. see below.
I have two series of data where one series has a different number of points to the other. I create a bar graph with stacking set to side by side.
As you can see the green series is missing data for 6th, 7th and 8th but is represented correctly is this graph side by side.
When I change it to stacked however i get the following
Now clearly there is an indexing problem here.... The stacking algorithm is aligning the bars correctly i.e. green series for the 9th stacked up on the 9th however it is using the value of the red series for the 6th to position the green bar starting point.
Without having to manipulate my users data and insert missing null rows for the green series I can't see how I can correct this. In any event while I could do it for this simple case it becomes very difficult when several series are stacked each with hundreds or thousands of points.
Your previous suggestion of drawing the series with the most points first would not work as I could have two series with the same number of points but each could be missing some i.e.
Series 1
X,Y
1,1
2,1
4,1
Series 2
X,Y
1,2
3,2
4,2
In any event forcing a particular series to be painted first is no solution as my users require the various series to be stacked in a particular order.
Can you PLEASE... PLEASE... PLEASE look into this as it is clearly a bug in the stacking routines...
ps. apologies to you for all the posts... it has taken me a while to work through this problem.
Ta.
I've done a bit more work on this and have a workaround for the situation where we have X values and NULL Y values. The following code handles this correctly.
Code: Select all
For i As Integer = 0 To dv.Count - 1
row = dv.Item(i)
ox = ConvertAxisValue(row, xName)
oy = ConvertAxisValue(row, yName)
If Not TypeOf ox Is System.DBNull Then
If Not TypeOf oy Is System.DBNull Then
If TypeOf ox Is System.String Then
iPoint = serBar.Add(oy)
serBar(iPoint).Label = ox
Else
iPoint = serBar.Add(ox, oy)
End If
If LabelName <> "" Then
Try
serBar.Labels.Item(iPoint) = row(LabelName)
Catch ex As Exception
If ex.Message.IndexOf("is neither a DataColumn nor a DataRelation for table") <> -1 Then
m_Control.Log.LogMsg("ColourName " & LabelName & " not found in source data", False, Constants.LOG_MESSAGE_TYPES.Warning, -98, Me.m_iChartID)
Else
Throw ex
End If
End Try
End If
If HonourColourMapping Then
serBar.Color = m_Control.Read_Colour(yName, DefaultColour, serBar.Title)
serBar.ColorEach = False
Else
If ColourName <> "" Then
Try
serBar(iPoint).Color = System.Drawing.Color.FromName(row(ColourName))
serBar.ColorEach = True
Catch ex As Exception
If ex.Message.IndexOf("is neither a DataColumn nor a DataRelation for table") <> -1 Then
m_Control.Log.LogMsg("Column " & ColourName & " not found in source data", False, Constants.LOG_MESSAGE_TYPES.Warning, -98, Me.m_iChartID)
End If
serBar(iPoint).Color = DefaultColour
serBar.ColorEach = False
End Try
Else
serBar(iPoint).Color = DefaultColour
serBar.ColorEach = False
End If
End If
Else
iPoint = serBar.Add(ox, 0, System.Drawing.Color.Transparent)
End If
End If
Next
after stacking we get the following which is correct....
So I've worked around the situation where we have same number of data points in both series but some Y values are NULL. However there is still a problem where we have a different number of rows in two series. see below.
I have two series of data where one series has a different number of points to the other. I create a bar graph with stacking set to side by side.
As you can see the green series is missing data for 6th, 7th and 8th but is represented correctly is this graph side by side.
When I change it to stacked however i get the following
Now clearly there is an indexing problem here.... The stacking algorithm is aligning the bars correctly i.e. green series for the 9th stacked up on the 9th however it is using the value of the red series for the 6th to position the green bar starting point.
Without having to manipulate my users data and insert missing null rows for the green series I can't see how I can correct this. In any event while I could do it for this simple case it becomes very difficult when several series are stacked each with hundreds or thousands of points.
Your previous suggestion of drawing the series with the most points first would not work as I could have two series with the same number of points but each could be missing some i.e.
Series 1
X,Y
1,1
2,1
4,1
Series 2
X,Y
1,2
3,2
4,2
In any event forcing a particular series to be painted first is no solution as my users require the various series to be stacked in a particular order.
Can you PLEASE... PLEASE... PLEASE look into this as it is clearly a bug in the stacking routines...
ps. apologies to you for all the posts... it has taken me a while to work through this problem.
Ta.
A final post on a way around this problem. The following function will "inject" null points into a series if it has less data points than any existing series and it will "inject" null points into any existing series if they do not have the same points as the new series.
While this appears to solve the issue I would really like a fix for it in TCHART as you can imagine this additional code WILL significantly slow down the creation of charts with a large number of series and/or data points.
Cheers...
Code: Select all
Private Sub Check_BAR_series_counts(ByVal tc As Steema.TeeChart.Chart, ByVal serbar As Steema.TeeChart.Styles.Bar)
If tc.Series.Count = 0 Then Exit Sub
' check for points in serbar that are not in any other series.
For i As Integer = 0 To serbar.XValues.Count - 1
For Each s As Steema.TeeChart.Styles.Series In tc.Series
If Not (s Is serbar) Then
If s.XValues.IndexOf(serbar.XValues.Item(i)) = -1 Then
s.Add(serbar.XValues.Item(i), 0, System.Drawing.Color.Transparent)
End If
End If
Next
Next
' now check that there are no missing points in serbar
For Each s As Steema.TeeChart.Styles.Series In tc.Series
If Not (s Is serbar) Then
For i As Integer = 0 To s.XValues.Count - 1
If serbar.XValues.IndexOf(s.XValues.Item(i)) = -1 Then
serbar.Add(s.XValues.Item(i), 0, System.Drawing.Color.Transparent)
End If
Next
End If
Next
End Sub
Cheers...