Allow users to set chart colors

bones

Well-known member
Joined
Aug 23, 2014
Messages
143
Programming Experience
Beginner
datavisualization charting 4.0
I'd like to build in an option for the end user to be able to select line colors of their choice. Is there something out there regarding that?

I did find this Manipulating the Chart Appearance

Visual Basic 2010 doesn't like this code. I looked in references for dlgChart in case that was the issue. Didn't find it or anything like it. I suspect the problem is my chart is a datavisualization chart and this references MSChart. I did fiddle with the code a bit but no luck.

VB.NET:
Private Sub MSChart1_SeriesActivated(ByVal Series As _
   Integer, ByVal MouseFlags As Integer, ByVal Cancel As Integer)
        ' The CommonDialog control is named dlgChart.
        Dim red, green, blue As Integer
        With dlgChart ' CommonDialog object
            .ShowColor()
            red = RedFromRGB(.Color)
            green = GreenFromRGB(.Color)
            blue = BlueFromRGB(.Color)
        End With


        ' NOTE: Only the 2D and 3D line charts use the
        ' Pen object. All other types use the Brush.


        If MSChart1.chartType <> VtChChartType2dLine Or _
        MSChart1.chartType <> VtChChartType3dLine Then
            MSChart1.Plot.SeriesCollection(Series). _
               DataPoints(-1).Brush.FillColor. _
               Set(red, green, blue)
        Else
            MSChart1.Plot.SeriesCollection(Series).Pen. _
               VtColor.Set(red, green, blue)
        End If
    End Sub
 
I'd suggest adding a user setting to hold and retain the selected color. In project settings add it in Settings tab (give it a name and select type Color).
To use dialog to select and store value:
        Using dialog As New ColorDialog
            If dialog.ShowDialog = Windows.Forms.DialogResult.OK Then
                My.Settings.SeriesColor = dialog.Color
            End If
        End Using

To assign Series.Color from setting:
Chart1.Series(0).Color = My.Settings.SeriesColor


Two quick comments about your ChartType code, (1) don't use strings and (2) don't repeat code :) Check into your "SeriesChartType" thread here again if you're uncertain what this means.


I had the color pallets all setup and pointed the properties grid to chart1 in it's properties but no changes would take place....
With the example you supplied, Would that last bit of code need to be applied to a command button on the form for the change to be completed?
 
ChartColorPalette is an enumeration, underlying value is a simple integer value, so yes, whenever you change a ChartColorPalette setting you would have to reflect that change by assigning the new value to Chart.Palette.

Actually, for Chart.Palette there is also another option. Unlike the Series objects (that are items in a charts Series collection) Chart is a control object, so it has a DataBindings property that allow you to bind a control property to a datasource property. The datasource can be My.Settings object. So if you have a "ChartPalette" user setting of type ChartColorPalette you can bind it like this:
Me.Chart1.DataBindings.Add(New Binding("Palette", My.Settings, "ChartPalette"))

Now when setting is changed the Chart.Palette property is automatically set to new value also.
 
ChartColorPalette is an enumeration, underlying value is a simple integer value, so yes, whenever you change a ChartColorPalette setting you would have to reflect that change by assigning the new value to Chart.Palette.

Actually, for Chart.Palette there is also another option. Unlike the Series objects (that are items in a charts Series collection) Chart is a control object, so it has a DataBindings property that allow you to bind a control property to a datasource property. The datasource can be My.Settings object. So if you have a "ChartPalette" user setting of type ChartColorPalette you can bind it like this:
Me.Chart1.DataBindings.Add(New Binding("Palette", My.Settings, "ChartPalette"))

Now when setting is changed the Chart.Palette property is automatically set to new value also.

OK... I think I get that :sneakiness: but wouldn't this code limit me to a single pallet choice? I can only select one pallet at a time in the settings grid.

VB.NET:
Me.Chart1.DataBindings.Add(New[COLOR=#333333][FONT=Consolas] [/FONT][/COLOR]Binding("Palette", My.Settings, "ChartPalette"))

Been looking at this option. I would like a cleaner looking control on my form so a Combobox seems the correct choice here. Another reason is this.

I have a working combobox that allows the user to select the chart type. Here's the code for it. It presents a list of all the chart types and upon selection of a type, the chart is immediately changed to that type.

VB.NET:
 Private Sub CboChartType_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles CboChartType.SelectedIndexChanged


        ' Dim value = DirectCast(Me.CboChartType.SelectedValue, DataVisualization.Charting.SeriesChartType)
        Chart1.Series(0).ChartType = System.Enum.Parse(GetType(System.Windows.Forms.DataVisualization.Charting.SeriesChartType), CboChartType.SelectedItem.ToString)
        Chart1.Series(1).ChartType = System.Enum.Parse(GetType(System.Windows.Forms.DataVisualization.Charting.SeriesChartType), CboChartType.SelectedItem.ToString)
        Chart1.Series(2).ChartType = System.Enum.Parse(GetType(System.Windows.Forms.DataVisualization.Charting.SeriesChartType), CboChartType.SelectedItem.ToString)
        Chart1.Series(3).ChartType = System.Enum.Parse(GetType(System.Windows.Forms.DataVisualization.Charting.SeriesChartType), CboChartType.SelectedItem.ToString)
        Chart1.Series(4).ChartType = System.Enum.Parse(GetType(System.Windows.Forms.DataVisualization.Charting.SeriesChartType), CboChartType.SelectedItem.ToString)
        Chart1.Series(5).ChartType = System.Enum.Parse(GetType(System.Windows.Forms.DataVisualization.Charting.SeriesChartType), CboChartType.SelectedItem.ToString)


    End Sub

So I thought...let's just do that with the pallets. So I added another cbobox and used this code.

VB.NET:
Private Sub CboChartColors_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles CboChartColors.SelectedIndexChanged
        'Chart1.Series(0).ChartType = System.Enum.Parse(GetType(System.Windows.Forms.DataVisualization.Charting.SeriesChartType), CboChartType.SelectedItem.ToString)
        Chart1.Series(0).Palette = System.Enum.Parse(GetType(System.Windows.Forms.DataVisualization.Charting.ChartColorPalette), CboChartType.SelectedItem.my.settings)
        Chart1.Series(1).Palette = System.Enum.Parse(GetType(System.Windows.Forms.DataVisualization.Charting.ChartColorPalette), CboChartType.SelectedItem.my.settings)
        Chart1.Series(2).Palette = System.Enum.Parse(GetType(System.Windows.Forms.DataVisualization.Charting.ChartColorPalette), CboChartType.SelectedItem.my.settings)
        Chart1.Series(3).Palette = System.Enum.Parse(GetType(System.Windows.Forms.DataVisualization.Charting.ChartColorPalette), CboChartType.SelectedItem.my.settings)
        Chart1.Series(4).Palette = System.Enum.Parse(GetType(System.Windows.Forms.DataVisualization.Charting.ChartColorPalette), CboChartType.SelectedItem.my.settings)
        Chart1.Series(5).Palette = System.Enum.Parse(GetType(System.Windows.Forms.DataVisualization.Charting.ChartColorPalette), CboChartType.SelectedItem.my.settings)


    End Sub

On running the app in debug it shows no list of my settings....it's empty. NOTE: I had it initially coded to selectedItem.ToString but that didn't popluate the cbobox either.
I left & commented out a line from the other box so I had a visual when I was tweaking the code...

Any idea why it won't work like the cbobox for chart type does?

The cbo for the chart type has no binding source but it works fine....

Here's a shot of my settings

settings.jpg
 
Last edited:
HOLD THE PHONE.....I found the problem... It was FormLoad

VB.NET:
'Display all the chart types available system wide in combobox cboChartType
        CboChartType.Items.AddRange([Enum].GetNames(GetType(SeriesChartType)))


        'Display chart color pallets
        CboChartType.Items.AddRange([Enum].GetNames(GetType(ChartColorPalette)))

Added second line....Voila.... Now I'll see if it works....
 
You're mixing CboChartType with your combobox for ChartColorPalette, maybe that is named "CboPalette" ? :)

Also, you add enum values to combobox, but when you get selected value you suddenly do all kinds of weird things with strings. Correct is simply:
Dim value = CType(CboPalette.SelectedValue, DataVisualization.Charting.ChartColorPalette)

OK... I think I get that but wouldn't this code limit me to a single pallet choice? I can only select one pallet at a time in the settings grid.
One setting is to hold one value, and that value can be changed any time, just like a variable. If that settings is type ChartColorPalette then that value can be any of the members of that enumeration. If you need to store more than one value then you need more than one setting.
 
Last edited:
Almost got it now... Blow up problem was because I was pointing the thing to the wrong cbobox... duh!

Fixed that.... another issue though.

VB.NET:
'Chart1.Series(0).Palette = System.Enum.Parse(GetType(System.Windows.Forms.DataVisualization.Charting.ChartColorPalette), CboChartColors.SelectedItem.ToString)
        'Chart1.Series(1).Palette = System.Enum.Parse(GetType(System.Windows.Forms.DataVisualization.Charting.ChartColorPalette), CboChartColors.SelectedItem.ToString)
        'Chart1.Series(2).Palette = System.Enum.Parse(GetType(System.Windows.Forms.DataVisualization.Charting.ChartColorPalette), CboChartColors.SelectedItem.ToString)
        'Chart1.Series(3).Palette = System.Enum.Parse(GetType(System.Windows.Forms.DataVisualization.Charting.ChartColorPalette), CboChartColors.SelectedItem.ToString)
        'Chart1.Series(4).Palette = System.Enum.Parse(GetType(System.Windows.Forms.DataVisualization.Charting.ChartColorPalette), CboChartColors.SelectedItem.ToString)
        'Chart1.Series(5).Palette = System.Enum.Parse(GetType(System.Windows.Forms.DataVisualization.Charting.ChartColorPalette), CboChartColors.SelectedItem.ToString)
        Chart1.Palette = System.Enum.Parse(GetType(System.Windows.Forms.DataVisualization.Charting.ChartColorPalette), CboChartColors.SelectedItem.ToString)

Commented out lines apply the pallet BUT only to the series as it's charted and every series line is same color...

Last line does absolutely nothing.... doesn't blow up but the pallet isn't applied to the chart itself or any of the series.

Shouldn't the pallet apply to the chart background color & the series? I thought that's what it would do...BUT to prove or disprove that I manually changed the chart pallet to "fire" in the chart properties in the GUI. I had no effect on the chart at all.

So it would appear that when you pick a pallet color in the chart properties, all it would do is provide you with those particular colors if you were manually assigning the chart series colors via the properties box in the GUI... I don't use that. I setup my chart background color there but the series are all configured in my form load code.

Am I looking at this correctly?
 
Last edited:
Just noticed you added strings in previous code:
[Enum].GetNames(GetType(ChartColorPalette))
Do this instead to add values:
[Enum].GetValues(GetType(ChartColorPalette))
Avoid strings as the plague whenever you can :)
 
Here's where I'm at..


Form Load
VB.NET:
'Display all the chart types available system wide in combobox cboChartType
        CboChartType.Items.AddRange([Enum].GetNames(GetType(SeriesChartType)))


        'Display chart color pallets
        CboChartColors.Items.AddRange([Enum].GetNames(GetType(ChartColorPalette)))

I tried changing .getNames to .getValues in both of those lines of code.
My chart capturing [previously working fine and not mentioned before either] blew up. Don't want to muddy the waters that now.

I changed .getValues back to .getNames and that works again.

You gave me this line but I don't know where it needs to be added. FormLoad sub or in the cboChartColors sub?

VB.NET:
Dimvalue = CType(CboPalette.SelectedValue, DataVisualization.Charting.ChartColorPalette)

cboChartColors The last line does nothing. Uncommenting the other lines yields results but not what I expected. The series line colors will change but it changes every series line....so that's out.

VB.NET:
Private Sub CboChartColors_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles CboChartColors.SelectedIndexChanged
        'Chart1.Series(0).ChartType = System.Enum.Parse(GetType(System.Windows.Forms.DataVisualization.Charting.SeriesChartType), CboChartType.SelectedItem.ToString)
        'Dim value = CType(CboPalette.SelectedValue, DataVisualization.Charting.ChartColorPalette)
        'Chart1.Series(0).Palette = System.Enum.Parse(GetType(System.Windows.Forms.DataVisualization.Charting.ChartColorPalette), CboChartColors.SelectedItem.ToString)
        'Chart1.Series(1).Palette = System.Enum.Parse(GetType(System.Windows.Forms.DataVisualization.Charting.ChartColorPalette), CboChartColors.SelectedItem.ToString)
        'Chart1.Series(2).Palette = System.Enum.Parse(GetType(System.Windows.Forms.DataVisualization.Charting.ChartColorPalette), CboChartColors.SelectedItem.ToString)
        'Chart1.Series(3).Palette = System.Enum.Parse(GetType(System.Windows.Forms.DataVisualization.Charting.ChartColorPalette), CboChartColors.SelectedItem.ToString)
        'Chart1.Series(4).Palette = System.Enum.Parse(GetType(System.Windows.Forms.DataVisualization.Charting.ChartColorPalette), CboChartColors.SelectedItem.ToString)
        'Chart1.Series(5).Palette = System.Enum.Parse(GetType(System.Windows.Forms.DataVisualization.Charting.ChartColorPalette), CboChartColors.SelectedItem.ToString)
        Chart1.Palette = System.Enum.Parse(GetType(System.Windows.Forms.DataVisualization.Charting.ChartColorPalette), CboChartColors.SelectedItem.ToString)


    End Sub

If I could use the settings grid to setup 6 user options of Name: chartseries0, chartseries1, etc and then be able select a range of colors in VALUE, it would be great. However, I can't see a method of doing that in the settings grid. All I can do is select one color at a time for a series..... There must be a way around that...using code.

I'm thinking NOT and that leads me right back to using a properties grid..... arrrrrghhhh:apologetic:

This screen capture show what I'm referring to. Is there a method to have the option be all of the "custom colors" ?colors.jpg
 
Last edited:
From the settings.designer

Where it says
VB.NET:
 Me("chartseries0") = value
is there code to replace the word "value" that will make a range of colors available rather than one color?

Or perhaps this line
VB.NET:
[COLOR=#333333]Global.System.Configuration.DefaultSettingValueAttribute("Maroon")> _
is the magic line.....[/COLOR]

VB.NET:
 <Global.System.Configuration.UserScopedSettingAttribute(), _
         Global.System.Diagnostics.DebuggerNonUserCodeAttribute(), _
         Global.System.Configuration.DefaultSettingValueAttribute("Maroon")> _
        Public Property chartseries0() As Global.System.Drawing.Color
            Get
                Return CType(Me("chartseries0"), Global.System.Drawing.Color)
            End Get
            Set(ByVal value As Global.System.Drawing.Color)
                Me("chartseries0") = value
            End Set
        End Property
    End Class
End Namespace
 
For this combined and complete mess which I can't keep track of anymore, well I just put together sample that shows how it all it's done, see attachment.
 

Attachments

  • vbnet40-ChartSample.zip
    17.3 KB · Views: 46
You'll probably be pleased to know I got it working from your sample. Here's what I learned.

I had to remark out my preset char series colors from my FormLoad code to get the new code to work...don't know why...but it wouldn't work until I did that.

VB.NET:
 'Add the chart series for each port & configure their initial display properties
        Chart1.Series.Add("Port1")
        'Chart1.Series(0).Color = Color.Black
        Chart1.Series(0).BorderWidth = 2
        Chart1.Series(0).IsVisibleInLegend = True
        Chart1.Series(0).ChartType = DataVisualization.Charting.SeriesChartType.Line


        Chart1.Series.Add("Port2")
        'Chart1.Series(1).Color = Color.Blue
        Chart1.Series(1).BorderWidth = 2
        Chart1.Series(1).IsVisibleInLegend = True
        Chart1.Series(1).ChartType = DataVisualization.Charting.SeriesChartType.Line


        Chart1.Series.Add("Port3")
        'Chart1.Series(2).Color = Color.Red
        Chart1.Series(2).BorderWidth = 2
        Chart1.Series(2).IsVisibleInLegend = True
        Chart1.Series(2).ChartType = DataVisualization.Charting.SeriesChartType.Line


        Chart1.Series.Add("Port4")
        'Chart1.Series(3).Color = Color.SteelBlue
        Chart1.Series(3).BorderWidth = 2
        Chart1.Series(3).IsVisibleInLegend = True
        Chart1.Series(3).ChartType = DataVisualization.Charting.SeriesChartType.Line


        Chart1.Series.Add("Port5")
        ' Chart1.Series(4).Color = Color.Orange
        Chart1.Series(4).BorderWidth = 2
        Chart1.Series(4).IsVisibleInLegend = True
        Chart1.Series(4).ChartType = DataVisualization.Charting.SeriesChartType.Line


        Chart1.Series.Add("Port6")
        'Chart1.Series(5).Color = Color.Purple
        Chart1.Series(5).BorderWidth = 2
        Chart1.Series(5).IsVisibleInLegend = True
        Chart1.Series(5).ChartType = DataVisualization.Charting.SeriesChartType.Line


        Me.CboPalette.DataSource = System.Enum.GetValues(GetType(ChartColorPalette))
        Me.CboChartType.DataSource = {SeriesChartType.Line, SeriesChartType.Spline, SeriesChartType.Column, _
                                      SeriesChartType.Bar, SeriesChartType.Area, SeriesChartType.StackedArea, SeriesChartType.StackedColumn}
        'combobox preselect current setting value
        Me.CboPalette.SelectedItem = My.Settings.ChartPalette
        Me.CboChartType.SelectedItem = My.Settings.ChartType


        'Chart1.Palette is bound to My.Settings.ChartPalette in designer
        'set current chart type for each series
        For Each s In Me.Chart1.Series
            s.ChartType = My.Settings.ChartType
        Next


    End Sub

Also, the way settings works in combination with the code is NOT intuitive at all. By that I mean there's now way I would have guessed that you could have only one palette showing in the setting grid ....yet have all of them applied in the code. THAT was a valuable lesson...T.Y. very much. Without your sample...I would not have guess that and it was something I did ask about.

Two things would be nice to tweak and I'm trying to sort that out by reading online and fiddling with the settings grid.

1 - I would like very much to create a custom palette with my original series colors.
2 - In the settings grid, I found a setting for .charting.chartarea but there's no selectable colors in value.


Agaiin..thank you for your patience and assistance.... I know newbies are a pain....
 

Thank you... Now before I go hacking away, a couple of important questions. No sense in wandering into the wilderness without a compass heading :single_eye:

If I create a custom palette from my original colors:

a] will it be found by the system in the list of palette colors that populates my cboChartPaletts combobox? [ that's the ideal setup]

or

b] will it again prevent the custom palette colors from being applied? ...leading me right back to where I was

or

c] will it be a palette that I need to apply to the chart initially and would that still allow cboChartPaletts.combobox to function?
 
Back
Top