Hello all
I want get following chart with it's above datasurce, look at the first pictue I uploaded.
What I can do now please look at following code:
Private Sub UltraChart1_ChartDrawItem(ByVal sender As Object, ByVal e As Infragistics.UltraChart.Shared.Events.ChartDrawItemEventArgs) Handles UltraChart1.ChartDrawItem
If e.Primitive Is Nothing Then Exit Sub
If e.Primitive.Path = "Border.Title.Grid.Chart" Then
'''dv is a datatable from datasource
Select Case dv.Table.Rows(i).Item("color")
Case "blue"
e.Primitive.PE.Fill = Color.Blue
e.Primitive.PE.FillStopColor = Color.Blue
Case "yellow"
e.Primitive.PE.Fill = Color.Yellow
e.Primitive.PE.FillStopColor = Color.Yellow
Case "red"
e.Primitive.PE.Fill = Color.Red
e.Primitive.PE.FillStopColor = Color.Red
Case "green"
e.Primitive.PE.Fill = Color.Green
e.Primitive.PE.FillStopColor = Color.Green
End Select
i += 1
End If
End Sub
it works but it is not right what I want.
my questions is:
1\ is there others better approach to get the purpose what I what?
2\ how to do not show the bar border line so that the line between contiguous bar cannot be seen. this make the contiguous bar looks like one picture
3\ how to show the bar like BackGradientStyle (vertical etc.) with color and color2?
4\ how to add other bar in the same Chart, now I only can show one bar in the chart.
I user Swap Rows and Columns so all of row change to column I think.
but other bars may be come from the rows which some field can distinguish it. just like first picture I uploaded.
thank you in advance
Herry
Hi,
Thank you for contacting Infragistics Developer Support.
In order to use your data source as the source for a stacked bar chart, you will need to modify it. The chart will treat each row as a separate bar using its numeric values as the values for the fragments and its string value for the label. If you use Swap Rows and Columns it will use each numeric column as a bar and the column key as the label. I would suggest in your case to create series based on your data table, by grouping the rows by the value of the chart field and then adding the value of the length column for each row. As for your other requirements I would use the FillSceneGraph event. In it you can get the box primitives for each fragment of the bars, set its color and add a text primitive with the length field (I actually used the difference of the current box value and the previous box value).
I have attached a sample which demonstrates this suggestion. I have created the chart as close as possible to the picture you have uploaded. If you want to have a gradient paint elements you can use the Fill, FillStopColor and FillGradientStyle properties.
Please let me know if you have any additional questions.
Hi Dimitar
Thank you so much for you example and help
this is so good and really gave me a great inspiration for this case.
Hi Herry,
Thank you for your feedback.
Do not hesitate to let us know, if you have any additional questions.
Thank you for using Infragistics Components.
hello Dimitar
I did little modification to your code but the color is wrong when I add some data to the table(I added chart 3\4\5, color and value don't match begin from chart 4)
following is the cold
Imports Infragistics.UltraChart.Resources.AppearanceImports Infragistics.UltraChart.Core.PrimitivesImports Infragistics.UltraChart.Data.Series
Public Class Form1 Private dt As DataTable Private PaintElements As New Dictionary(Of Color, PaintElement)
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load UltraChart1.ChartType = Infragistics.UltraChart.Shared.Styles.ChartType.StackBarChart UltraChart1.SmoothingMode = Drawing2D.SmoothingMode.None
GetBarData()
ConvertDataForChart(dt)
UltraChart1.Axis.Y.Labels.SeriesLabels.Orientation = Infragistics.UltraChart.Shared.Styles.TextOrientation.Horizontal UltraChart1.BarChart.BarSpacing = 1
Private Sub GetBarData() dt = New DataTable()
dt.Columns.Add("Chart", GetType(Integer)) dt.Columns.Add("Current Value", GetType(Integer)) dt.Columns.Add("Color", GetType(String)) dt.Columns.Add("Length", GetType(Integer))
dt.Rows.Add(New Object() {1, 4, "blue", 4}) dt.Rows.Add(New Object() {1, 8, "green", 4}) dt.Rows.Add(New Object() {1, 12, "green", 4}) dt.Rows.Add(New Object() {1, 20, "blue", 8}) dt.Rows.Add(New Object() {1, 28, "red", 8}) dt.Rows.Add(New Object() {1, 32, "red", 4}) dt.Rows.Add(New Object() {1, 40, "red", 8}) dt.Rows.Add(New Object() {1, 56, "green", 16}) dt.Rows.Add(New Object() {1, 60, "blue", 4}) dt.Rows.Add(New Object() {1, 68, "blue", 8}) dt.Rows.Add(New Object() {2, 8, "blue", 8}) dt.Rows.Add(New Object() {2, 16, "green", 8}) dt.Rows.Add(New Object() {2, 20, "green", 4}) dt.Rows.Add(New Object() {2, 24, "blue", 4}) dt.Rows.Add(New Object() {2, 32, "red", 8}) dt.Rows.Add(New Object() {2, 36, "red", 4}) dt.Rows.Add(New Object() {2, 40, "red", 4}) dt.Rows.Add(New Object() {2, 56, "green", 16}) dt.Rows.Add(New Object() {2, 65, "blue", 8}) dt.Rows.Add(New Object() {2, 68, "blue", 4})
'''''after add following data, then the chart doesn't work well.
dt.Rows.Add(New Object() {3, 8, "blue", 8}) dt.Rows.Add(New Object() {3, 16, "green", 8}) dt.Rows.Add(New Object() {3, 20, "green", 4}) dt.Rows.Add(New Object() {3, 24, "blue", 4}) dt.Rows.Add(New Object() {3, 32, "red", 8}) dt.Rows.Add(New Object() {4, 36, "red", 4}) dt.Rows.Add(New Object() {4, 40, "red", 4}) dt.Rows.Add(New Object() {5, 56, "green", 16}) dt.Rows.Add(New Object() {5, 65, "blue", 8}) dt.Rows.Add(New Object() {5, 68, "blue", 4}) End Sub
Private Sub ConvertDataForChart(ByVal dt As DataTable) Dim seriesGroups As IEnumerable(Of IGrouping(Of Int32, DataRow)) = _ dt.Rows.Cast(Of DataRow).GroupBy(Function(r) r.Field(Of Integer)("Chart")) Dim maxLenght As Integer = seriesGroups.Max(Function(g) g.Count()) For Each groupedRows In seriesGroups Dim series As NumericSeries = New NumericSeries Dim key = groupedRows.Key.ToString() series.Label = "Chart " + key
For Each row As DataRow In groupedRows series.Points.Add(New NumericDataPoint(row.Field(Of Integer)("Length"), key, False)) Next
For index = 0 To maxLenght - groupedRows.Count() Step 1 series.Points.Add(New NumericDataPoint(0, key, True)) Next UltraChart1.Series.Add(series) Next UltraChart1.Data.DataBind() End Sub
Private Sub UltraChart1_FillSceneGraph(ByVal sender As System.Object, ByVal e As Infragistics.UltraChart.Shared.Events.FillSceneGraphEventArgs) Handles UltraChart1.FillSceneGraph Dim groupedBoxes As IEnumerable(Of IGrouping(Of ISeries, Box)) = _ e.SceneGraph.OfType(Of Box).Where(Function(b) b.Series IsNot Nothing).GroupBy(Function(b) b.Series)
For Each boxGroup In groupedBoxes For i = 0 To boxGroup.Count() - 1 Dim boxPrim = boxGroup.ElementAt(i)
Dim c As Color = Color.FromName(dt.Rows(i).Item("Color"))
Dim pe As PaintElement = Nothing
'get the paint element from a dictionary with cached paint elements, if it was added before PaintElements.TryGetValue(c, pe) If (pe Is Nothing) Then 'if it was not added, chache it in the dictionary and return it pe = AddPaintElement(c) End If boxPrim.PE = pe
Dim textPrim As New Text
textPrim.bounds = boxPrim.rect textPrim.labelStyle.HorizontalAlign = StringAlignment.Far If (i = 0) Then textPrim.SetTextString(boxPrim.Value.ToString()) Else Dim val = boxPrim.Value - boxGroup.ElementAt(i - 1).Value textPrim.SetTextString(val.ToString()) End If e.SceneGraph.Add(textPrim) Next Next End Sub
Private Function AddPaintElement(ByVal c As Color) As PaintElement Dim pe = New PaintElement() pe.Stroke = Color.Transparent
pe.Fill = c pe.FillStopColor = Color.LightSteelBlue
pe.FillGradientStyle = Infragistics.UltraChart.Shared.Styles.GradientStyle.Vertical pe.ElementType = Infragistics.UltraChart.Shared.Styles.PaintElementType.Gradient PaintElements.Add(c, pe) Return pe End FunctionEnd Class
herry
Hello Dimitar
I modified followed Sub as following, it works well. any high-efficiency approach or any suggest?
thank you in advance.
Private Sub UltraChart1_FillSceneGraph(ByVal sender As System.Object, ByVal e As Infragistics.UltraChart.Shared.Events.FillSceneGraphEventArgs) Handles UltraChart1.FillSceneGraph Try
Dim groupedBoxes As IEnumerable(Of IGrouping(Of ISeries, Box)) = _ e.SceneGraph.OfType(Of Box).Where(Function(b) b.Series IsNot Nothing).GroupBy(Function(b) b.Series)
Dim seriesGroups_Counter As Integer = 0 If groupedBoxes.Count > 0 Then Dim seriesGroups As IEnumerable(Of IGrouping(Of Int32, DataRow)) = _ dt.Rows.Cast(Of DataRow).GroupBy(Function(r) r.Field(Of Integer)("Chart")) For Each boxGroup In groupedBoxes
seriesGroups_Counter += 1 For i = 0 To boxGroup.Count() - 1
Dim boxPrim = boxGroup.ElementAt(i) Dim curr_seriesGroups = seriesGroups(seriesGroups_Counter - 1) If i < curr_seriesGroups.Count Then Dim curr_datarow As DataRow = curr_seriesGroups(i) Dim c As Color = Color.FromName(curr_datarow.Item("Color")) Dim pe As PaintElement = Nothing
'get the paint element from a dictionary with cached paint elements, if it was added before PaintElements.TryGetValue(c, pe) If (pe Is Nothing) Then 'if it was not added, chache it in the dictionary and return it pe = AddPaintElement(c) End If boxPrim.PE = pe End If
textPrim.bounds = boxPrim.rect textPrim.labelStyle.HorizontalAlign = StringAlignment.Far If (i = 0) Then textPrim.SetTextString(boxPrim.Value.ToString()) Else Dim val = boxPrim.Value - boxGroup.ElementAt(i - 1).Value textPrim.SetTextString(val.ToString()) End If e.SceneGraph.Add(textPrim) Next Next
End If Catch ex As Exception MsgBox(ex.Message) End Try End Sub
Thank you for the reply.
Your modifications seem good to me. I simplified your code a bit, but you will still need to get the seriesGroupsCollection:
Try
Dim groupedBoxes As List(Of IGrouping(Of ISeries, Box)) = _
e.SceneGraph.OfType(Of Box).Where(Function(b) b.Series IsNot Nothing).GroupBy(Function(b) b.Series).ToList()
If groupedBoxes.Count > 0 Then
Dim seriesGroups As List(Of IGrouping(Of Int32, DataRow)) = _
dt.Rows.Cast(Of DataRow).GroupBy(Function(r) r.Field(Of Integer)("Chart")).ToList()
For Each boxGroup In groupedBoxes
For i = 0 To boxGroup.Count() - 1
Dim boxPrim = boxGroup.ElementAt(i)
Dim curr_datarow As DataRow = seriesGroups(boxPrim.Row)(boxPrim.Column)
Dim c As Color = Color.FromName(curr_datarow.Item("Color"))
'get the paint element from a dictionary with cached paint elements, if it was added before
PaintElements.TryGetValue(c, pe)
If (pe Is Nothing) Then
'if it was not added, chache it in the dictionary and return it
pe = AddPaintElement(c)
boxPrim.PE = pe
textPrim.bounds = boxPrim.rect
textPrim.labelStyle.HorizontalAlign = StringAlignment.Far
If (i = 0) Then
textPrim.SetTextString(boxPrim.Value.ToString())
Else
Dim val = boxPrim.Value - boxGroup.ElementAt(i - 1).Value
textPrim.SetTextString(val.ToString())
e.SceneGraph.Add(textPrim)
Next
Catch ex As Exception
MsgBox(ex.Message)
End Try