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.
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.