Chart Control in Visual Studio 2010

image

 

I used the chart control in Visual Studio 2010 (VS2010) last week on a consulting project.  It was a useful means of using my serial communication software to create a visual display of the data being read.  It is relatively easy to bind an array to a chart and display it on a form, so I thought I ‘d share that here.

In this example there are four arrays of data that are filled through serial polling.  In other words, I read the data from a controller every 50ms via a serial communication bus, and put the data into my arrays (the area of code where I read the data is not shown here).  The arrays are circular, so after I store enough data to fill the array I point back to the beginning of the array and start storing data again.  This creates an image like you might see on an oscilloscope.  The line chart scrolls left to right and when 50 samples are taken the 51st sample starts back at 0.  Subsequent data overwrites existing line chart data.  While not high resolution like an oscilloscope, you can see the value of charting data for a customer that might not have electronic design instruments.

To initialize the chart settings I fill the arrays with 0, and then set the size of each axis and define labels.  I should point out that the image of the chart above is the “default” object view.  When the VS2010 program runs the two charts are scaled as defined below.  The top chart will have an Y axis of 0 to 1050 while the bottom chart will range from –1050 to +1050.  The X axis reads from 0 to the length of the data arrays – 1 (49 in this case).  Additionally, the label “Value” shows up left of the X axis and “Sample” below the Y axis.

(Update:  I noticed some VB code with long lines was chopped off by the code insertion tool I use for this blog.  I’ve added “_” to those lines to break them up.  Not sure it will compile that way so if it causes problems just backspace those into single lines.

This code is located in the Form_Load() subroutine.

       For Array_Pointer = 0 To ActualPosition_Data.Length - 1
            ActualPosition_Data(ArrayPointer) = 0
            DesiredPosition_Data(ArrayPointer) = 0
            BatteryVoltage_Data(ArrayPointer) = 0
            PWMOut_Data(ArrayPointer) = 0
        Next

        Chart_FanData.Series(0).ChartType = _
             DataVisualization.Charting.SeriesChartType.FastLine
        Chart_FanData.ChartAreas(0).AxisX.Minimum = 0
        Chart_FanData.ChartAreas(0).AxisX.Maximum = ActualPosition_Data.Length - 1
        Chart_FanData.ChartAreas(0).AxisY.Minimum = 0
        Chart_FanData.ChartAreas(0).AxisY.Maximum = 1050
        Chart_FanData.ChartAreas(0).AxisY.Interval = 500
        Chart_FanData.ChartAreas(0).AxisX.Title = "Sample"
        Chart_FanData.ChartAreas(0).AxisY.Title = "Value"

        Chart_FanData2.Series(0).ChartType = _
             DataVisualization.Charting.SeriesChartType.FastLine
        Chart_FanData2.ChartAreas(0).AxisX.Minimum = 0
        Chart_FanData2.ChartAreas(0).AxisX.Maximum = ActualPosition_Data.Length - 1
        Chart_FanData2.ChartAreas(0).AxisY.Minimum = -1050
        Chart_FanData2.ChartAreas(0).AxisY.Maximum = 1050
        Chart_FanData2.ChartAreas(0).AxisY.Interval = 500
        Chart_FanData2.ChartAreas(0).AxisX.Title = "Sample"
        Chart_FanData2.ChartAreas(0).AxisY.Title = "Value"

        Chart_Update()

Chart_Update() is the routine I call whenever I need to update the chart data, so in my case every 50mS.  The routine is pretty simple.  I update the pointer for the array, and reset it to 0 if needed.  Then the newest data is loaded into the four arrays I use.  Finally, I bind the arrays to the Y axis of the two charts.  This causes the charts to update with the new chart data.

Private Sub Chart_Update()

        ArrayPointer = ArrayPointer + 1
        If ArrayPointer >= ActualPosition_Data.Length Then ArrayPointer = 0

        ActualPosition_Data(ArrayPointer) = ActualPos
        DesiredPosition_Data(ArrayPointer) = DesiredPos
        BatteryVoltage_Data(ArrayPointer) = VbatFiltered
        PWMOut_Data(ArrayPointer) = PWMOut

        Chart_FanData.Series(0).Points.DataBindY(ActualPosition_Data)
        Chart_FanData.Series(1).Points.DataBindY(DesiredPosition_Data)

        Chart_FanData2.Series(0).Points.DataBindY(BatteryVoltage_Data)
        Chart_FanData2.Series(1).Points.DataBindY(PWMOut_Data)

    End Sub

You can also place some user controls to adjust the an axis of the chart.  For example, the top chart X axis ranges from 0-1050.  But if I want to look at a range of 500 to 700 to zoom in on the data I just need to change the values associated with these settings.

        Chart_FanData.ChartAreas(0).AxisY.Minimum = 0
        Chart_FanData.ChartAreas(0).AxisY.Maximum = 1050

I added track bars controls to my form to do this.  They are at the lower right of the first image in this blog.  Once placing the track bar controls and setting their min-max-default values you can double click them to create an event that fires when they are moved.  In the code I also make sure that the min value can’t exceed the max value and vice versa.

Private Sub TrackBar_ChartDataMin_Scroll _
                (ByVal sender As System.Object, ByVal e As System.EventArgs) _
                Handles TrackBar_ChartDataMin.Scroll
        If TrackBar_ChartDataMin.Value > TrackBar_ChartDataMax.Value Then
            TrackBar_ChartDataMin.Value = TrackBar_ChartDataMax.Value
        End If

        Chart_FanData.ChartAreas(0).AxisY.Minimum = TrackBar_ChartDataMin.Value
        Chart_FanData.ChartAreas(0).AxisY.Maximum = TrackBar_ChartDataMax.Value
        Chart_FanData.ChartAreas(0).AxisY.Interval = _
          Format((TrackBar_ChartDataMax.Value - TrackBar_ChartDataMin.Value) / 2, 0)

    End Sub

    Private Sub TrackBar_ChartDataMax_Scroll _
               (ByVal sender As System.Object, ByVal e As System.EventArgs)_ 
               Handles TrackBar_ChartDataMax.Scroll
        If TrackBar_ChartDataMax.Value < TrackBar_ChartDataMin.Value Then
            TrackBar_ChartDataMax.Value = TrackBar_ChartDataMin.Value
        End If

        Chart_FanData.ChartAreas(0).AxisY.Minimum = TrackBar_ChartDataMin.Value
        Chart_FanData.ChartAreas(0).AxisY.Maximum = TrackBar_ChartDataMax.Value
        Chart_FanData.ChartAreas(0).AxisY.Interval = _
         Format((TrackBar_ChartDataMax.Value - TrackBar_ChartDataMin.Value) / 2, 0)

    End Sub

You can configure all of the chart settings via code.  But I also used some of the chart control associated windows to set things like color.  For example, to add and name each chart data series I used the chart properties window and the “Series” collection as shown below.

image

Lastly, since I was charting the data and already had it in array format I went ahead and created a subroutine that would allow me (and our customer) to write it to a text file if it needed to be saved and looked at later.

Private Sub Button_SaveData_Click _ 
             (ByVal sender As System.Object, ByVal e As System.EventArgs)_ 
             Handles Button_SaveData.Click
        ' Configure save file dialog box
        SaveFileDialog1.FileName = "testdata" ' Default file name
        SaveFileDialog1.DefaultExt = ".text" ' Default file extension
        SaveFileDialog1.Filter = "Text documents (.txt)|*.txt" ' Filter files by extension

        Dim i As Integer
        Dim ProgString As String
        Dim Length As Integer

        ProgString = _ 
           "Sample, Actual Position, Desired Position, Battery Voltage, PWM Output" _
           & vbCrLf
        Length = ActualPosition_Data.Length - 1

        For i = 0 To Length
            ProgString = ProgString & i & "," & ActualPosition_Data(i) & "," _
            & DesiredPosition_Data(i) & "," & BatteryVoltage_Data(i) & "," _
            & PWMOut_Data(i) & "," & vbCrLf
        Next

        Dim result? As Boolean = SaveFileDialog1.ShowDialog()

        Try
            Dim j As Integer
            Dim k As Byte

            Using FS As New _
             IO.FileStream(SaveFileDialog1.FileName, IO.FileMode.Create)

                j = Len(ProgString) - 1
                For i = 0 To j
                    k = Asc(ProgString.Chars(i))
                    FS.WriteByte(Asc(ProgString.Chars(i)))
                Next
            End Using
        Catch
            Console.WriteLine("Error saving file")
        End Try
    End Sub

That’s one simple way to use the chart control in Visual Studio 2010 with your electronic designs.

Comments

  1. Hi Lon
    Adding code bellow in the from load makes it even cooler

    Chart_FanData.ChartAreas(0).CursorX.SelectionStart = 5
    Chart_FanData.ChartAreas(0).CursorX.SelectionEnd = 10
    Chart_FanData.ChartAreas(0).CursorX.IsUserEnabled = True
    Chart_FanData.ChartAreas(0).CursorX.AutoScroll = True
    Chart_FanData.ChartAreas(0).CursorX.IsUserSelectionEnabled = True

    Chart_FanData.ChartAreas(0).CursorY.SelectionStart = 5
    Chart_FanData.ChartAreas(0).CursorY.SelectionEnd = 10
    Chart_FanData.ChartAreas(0).CursorY.IsUserEnabled = True
    Chart_FanData.ChartAreas(0).CursorY.AutoScroll = True
    Chart_FanData.ChartAreas(0).CursorY.IsUserSelectionEnabled = True

    br Jan

  2. Hi Jan,

    Nice piece of code there. Two things that would help a newby like me would be what .net did you use to compile that with and the private declarations would also help. I’m stuck on a project that has to be done in .net 3.5

  3. Urgh! I meant that message for Lon

Speak Your Mind

*