When logging datas from sensors it’s important to visualize them with a powerful real-time chart. In automation especially it’s common to analyze processes with the help of charts to predict and regulate the process.
One of the most powerful charts (and for many the best) is Dynamic Data Display, an open source library for WPF. This library is good because of the many features (panning, zooming, saving screenshots etc…) and because it renders fast with huge collections of points.
There are 2 versions, both hosted on codeplex:
- the official and oldest one, remember get the latest source code.
- The newest one
I’ll show an example on how to realize a real time chart with a “customized observable collection” provided by this control, the RingArray. I will design a variable Sin, one point every 100ms on a datetime axis.
There are three points of interest that you should note:
- Creating the ViewModel for the chart
- Binding the chart to the ViewModel
- Write the Xaml for the chart
ViewModel
The ViewModel, as said before, is a RingArray. in this case i called it Voltage Point Collection
public class VoltagePointCollection : RingArray { private const int TOTAL_POINTS = 300; public VoltagePointCollection() : base(TOTAL_POINTS) // here i set how much values to show { } } public class VoltagePoint { public DateTime Date { get; set; } public double Voltage { get; set; } public VoltagePoint(double voltage, DateTime date) { this.Date = date; this.Voltage = voltage; } }
Binding
The binding of the chart to this RingArray must be done in code behind on the constructor, in this way:
var ds = new EnumerableDataSource(voltagePointCollection); ds.SetXMapping(x => dateAxis.ConvertToDouble(x.Date)); ds.SetYMapping(y => y.Voltage); plotter.AddLineGraph(ds, Colors.Green, 2, "Volts"); // to use this method you need to add manually "using Microsoft.Research.DynamicDataDisplay;"
Xaml
The xaml chart is written in this way:
<d3:ChartPlotter x:Name="plotter" Grid.Row="1" Grid.Column="1"> <d3:ChartPlotter.HorizontalAxis> <d3:HorizontalDateTimeAxis Name="dateAxis"/> </d3:ChartPlotter.HorizontalAxis> <d3:Header FontFamily="Georgia" Content="Voltage chart"/> <d3:VerticalAxisTitle FontFamily="Georgia" Content="Voltage [V]" /> <d3:HorizontalAxisTitle FontFamily="Georgia" Content="Time"/> <d3:HorizontalLine Value="{Binding MaxVoltage}" Stroke="Red" StrokeThickness="2"/> <d3:HorizontalLine Value="{Binding MinVoltage}" Stroke="Red" StrokeThickness="2"/> </d3:ChartPlotter>
Get the sample application and more examples
Get the sample application on GitHub: https://github.com/mesta1/DynamicDataDisplay-example
You can also find more examples here:http://d3future.codeplex.com/SourceControl/list/changesets
Hi,
I am working on Wpf real time application.In this application i have to show thousands of record in a single time using chartplotter.My code works fine without any exception.
Problem :
Here problem is that it take long time to show output.For 30 thousands of record it takes 15 minutes.How i can modify my code so that i reduce the response time.
Thanks in Advance
@Sunny:
I should see the code to help you, anyway i already used big datasets (bigger than 30.000) without any problem.
Let’s suppose that you have a Window that contains a button that pop-up the chart in another window.
Looking at the example provided with this article, you should build your collection when you acquire the data, so if you are reading data from a device, you should process the data and you add them to a RingArray collection.
In the main window you create your collection and update it, in the popup window you bind the collection to chart (like in the example in the “loaded event”).
This chart’s databinding is strange, so you should use an existing collection provided by this chart (like RingArray) and not observable collections or lists.
Just thank you ,the source was very nice and useful.
Hi there… i am very happy to find this article… it’s very helpfully.
how change amplitude range of sine wave
I can’t understand what you mean.
The sin is calculated here:
voltagePointCollection.Add(new VoltagePoint(Math.Sin(i*0.1),DateTime.Now));
So if you multiply the sin for a factor you will obtain a bigger sin.
If you need a different scaling from autoscaling, i think you have to modify the sources to adapt the chart to your needs. Check the discussions on codeplex.
Hi, if we wanna add multiple line what we should do?
You should probably check the samples inside the library.
There are for sure examples with more than 1 line.
Thanks for your article. It’s a diamond among many useless examples.
Is there a way to create scatter plots with just points and no lines?
Its very helpful.
I have a requirement to click a each line plot. Is it possible?
This chart has a lot of examples in the sources, and for sure there is one that contain a clickable chart. You have to dig into the examples and find how to do it.
I checked in examples, but I didn’t find any examples for clickable linegraph controls. if you know it please share to me. Also I want to set the width between x axis plot. for example , if set the width is 5, then marking the x axis scale is 5,10,15 etc?
This is really helpful. Thanks.
But I wanted to clear the screen after some time interval and continue the plotting. Just like a ECG plot for heart. Could you help with that ?
You have to dig into the examples for things like this. The way to go is probably having a collection and clear it when you want to repaint. Once you clear it you have to set the starting point of the X axis on the 1st point of the collection.
could you point me to some link with good examples on the same .
Thanks in advance
The examples are contained inside the source code of the newest version: http://d3future.codeplex.com/SourceControl/list/changesets
Fantastic, really helpful. Thanks a lot
Hi. Very nice work! How can i change the time interval when chart starts scrolling? and how do i set the minimum and maximum value for the chart?
Hi Roy, there are lot of examples on the new sources here: http://d3future.codeplex.com/SourceControl/list/changesets
Probably there are also the features that you are looking for.
Hi mesta,
Can you help me how to drag the graph by clicking with the mouse.Is it possible with the dynamic data display??
I don’t know if it’s possible. I only used this chart to plot real time data.
Hi mesta,
I have the “using Microsoft.Research.DynamicDataDisplay;” in my file but for some reasons I can’t use the function AddLineGraph and keep getting the error “‘Microsoft.Research.DynamicDataDisplay.ChartPlotter’ does not contain a definition for ‘AddLineGraph'”.
Would you have any idea on what I’m missing?
I think you need to add
Check the example at the bottom of the article.
Thanks for the great example!
We have download the example code from this site and notice that the project “DynamicDataDisplay” source code version is 0.3.0.0.
The latest one is DynamicDataDisplay for WPF is 0.4.0.0.
If we install through NuGet, we only get the dlls such as “DynamicDataDisplay.dll”, “DynamicDataDisply.Maps.dll”, “DynamicDataDisplay.Markers.dll”, and “DynamicDataDisplay.Markers2.dll” without source code.
We want to get the source code.
We went to the site: http://d3future.codeplex.com/SourceControl/latest
download the zip file from Source code tab page and notice the dlls are version 0.3.2.0.
Where could we download latest “DynamicDataDisplay” project with source code for WPF with version 0.4.0.0?
thanks!
Try here http://dynamicdatadisplay.codeplex.com/wikipage?title=D3v1
Mesta,
Thanks for providing the link.
we just notice that using Dynamic Data Display library we get the following data binding errors:
System.Windows.Data Error: 4 : Cannot find source for binding with reference ‘RelativeSource FindAncestor, AncestorType=’System.Windows.Controls.ItemsControl’, AncestorLevel=’1”. BindingExpression:Path=HorizontalContentAlignment; DataItem=null; target element is ‘MenuItem’ (Name=”); target property is ‘HorizontalContentAlignment’ (type ‘HorizontalAlignment’)
System.Windows.Data Error: 4 : Cannot find source for binding with reference ‘RelativeSource FindAncestor, AncestorType=’System.Windows.Controls.ItemsControl’, AncestorLevel=’1”. BindingExpression:Path=VerticalContentAlignment; DataItem=null; target element is ‘MenuItem’ (Name=”); target property is ‘VerticalContentAlignment’ (type ‘VerticalAlignment’)
We tried to run your example of application and get the same errors in the Output window.
Have you noticed this data binding errors?
we search “RelativeSource” in the Dynamic Data Display library and only found the following 8 instances of “RelativeSource”.
Find all “RelativeSource”, Subfolders, Find Results 1, Entire Solution, “*.*”
C:\CSharp\DynamicDataDisplaySample\DynamicDataDisplay\Charts\Legend.xaml(9):
Matching lines: 8 Matching files: 3 Total files searched: 253
Do you know how to remove those data binding errors? thx!
Hi Mesta,
We just found the link: http://dynamicdatadisplay.codeplex.com/discussions/73870
In the Dynamic Data Display ChartPlotter constructor, comment out defaultContextMenu will remove the binding errors. However, this means there is no context menu anymore.
Children.AddMany(
horizontalAxis,
verticalAxis,
axisGrid,
mouseNavigation,
keyboardNavigation,
//defaultContextMenu,
horizontalAxisNavigation,
verticalAxisNavigation,
legend
);
If you know the better way to fix this binding error, please share! thx!
He basically means that you need to create your own ContextMenu.
This is a quick and dirty example, hope it gets you started. Go on constructor of chart plotter, above the Children.AddMany, then keep the line commented out and add the part that build the ContextMenu.
Mesta,
Thanks for providing the solution!
very useful article
Thou I sometimes get NullReferenceException at line 2 of your Binding example
full stacktrace: http://pastebin.com/9StCbdFj
here’s my code:
public MainWindow()
{
Loaded += (sender, args) => SetupGraph();
InitializeComponent();
}
private void SetupGraph()
{
Data = new ObservableDataSource(new List {new DataPoint(DataType.Ai0, 0) });
Data.SetYMapping(y => y.Value);
if(dateAxis == null)
Console.WriteLine(“dateAxis”);
Data.SetXMapping(x => dateAxis.ConvertToDouble(x.Date));
plotter.AddLineGraph(Data, Colors.Green, 2, “Volt”);
}
It’s dateAxis.ConvertToDouble(x.Date)) that breaks and aparently it’s x.Date which is Null but that cannot be true because when I look at it with a breakpoint i can clearly see that the first Member of “Data” has a correct DateTime
Would be cool if you could have a look on it
My formattings was nuked so please see here for the formatted code: http://pastebin.com/tHdP4Cf9
You didn’t post DataPoint class, but it seems that you added a point with a value and an integer, instead of a point with a value and a Date. This is why it can’t convert the date to double, so the ConvertToDouble method returns null.
sharp thinking there but my DataPoint contains a valid DateTime. See here for the class: http://pastebin.com/zETkL4iK
I cannot explain the error to me. It’s weird thats why i asked you, who probably knows how things work
I already tried having `DateTime Date` with a default value of 01.01.1970 but this didn’t stop the error
Does that class somehow use the default constructor?
There are two things different from my example, one is that I used EnumerableDataSource and you use ObservableDataSource, and the second one is that you initialize everything in the loaded event and I initialized it in the constructor. My guess is that one of the two is causing the problem, but if not, upload the example somewhere and I’ll take a look.
A thank you. I’ll have a look on both
You really did helped me. Now I no longer get random NullReferenceExceptions. I’m sorry to waste your time again but I’m not happy with my current approach. My Graph only updates when i zoom or pan around in the view. Calling plotter.UpdateLayout(); had no effect.
Could you please have a look on my code again? http://pastebin.com/cza0Vee5
When you scroll down you see my old working code which is the one that crashed every second or third time i started the software but otherwise worked fine
I can create a minimal working examle .sIn for you if you want to but i think the code above is sufficent (doesn’t throw any exceptions but isn’t live)
Plus I don’t know how to append data to an EnumerableDataSource. I looked really close on your example and I don’t know if the approach with the RingArray fit’s my needs
There are several examples that you can look at, not only mine.The documentation on DDD is scarce and the only way is to look through all the examples and read the source code, until you find what you need.
Also there is another chart library that is more up to date and has better documentation, Oxyplot. Maybe you want to check also that.
Great job! Congrats! 🙂
Hello all,
I’m currently using this for displaying spectrum on User interface, it works great but has a huge memory leak (about 1-2MB/cycle). Did any one else experienced this problem? and how would I go about solving it?
Thanks in advance. See my code below
Dim P1Chart As New Microsoft.Research.DynamicDataDisplay.ChartPlotter()
Dim P1ChartDateTime As New Windows.Controls.Label()
…………………….
‘First remove old line graph from chart
ClearSpectrum(iTabIndex)
‘Load arrays with new spectral data
For SpectCtr = 0 To ScanElements
If Spectrum = ScanType.Absorbance Then
x(SpectCtr) = SpectCtr * 0.5 + 800.0 ‘Convert to wavelength if absorbance spectra
Else
x(SpectCtr) = SpectCtr
End If
y(SpectCtr) = sr.ReadLine()
Next
Dim xDataSource = AsXDataSource(x)
Dim yDataSource = AsYDataSource(y)
Dim xyDataSource As New CompositeDataSource(xDataSource, yDataSource)
Select Case StreamNumber
Case 1
P1Chart.AddLineGraph(xyDataSource, Colors.Red, 1, “Probe A”)
P1ChartDateTime.Content = String.Format(“Time: {0}, X-Axis: {1}”, FileSaveTime, xAxisTitle)
Case 2
P2Chart.AddLineGraph(xyDataSource, Colors.Red, 1, “Probe B”)
P2ChartDateTime.Content = String.Format(“Time: {0}, X-Axis: {1}”, FileSaveTime, xAxisTitle)
End Select
………
Private Sub ClearSpectrum(ByVal iTabIndex As Integer)
Dim nIndex As Integer
Select Case iTabIndex
Case 1
For Each child1 As IPlotterElement In P1Chart.Children
If TypeOf child1 Is Microsoft.Research.DynamicDataDisplay.LineGraph Then
RemoveList.Add(child1)
End If
Next
For Each child1 In RemoveList
P1Chart.Children.Remove(child1)
Next
……………..
I used it in binding with a collection in my example. If you have a memory leak you are storing the points or you are recreating the graph every time and not disposing it.
It’s better if you use it in binding with a collection.
Have you ever tried LiveCharts https://lvcharts.net/ ?
I just found it in internet by coincidence and i was wondering if its worth to try.
It’s the first time that I see it. Thanks for linking it, I will try it out the next days.
Hi there!
I just made simple app to test this library and I’m disappointed. It looks really greate but performance is much slower then I expected. There is an option to pay for some kind of additional featres which increase performance but i didn’t tried it. Maybe this way it’s faster but anyway i’m looking for free options.
If you want to save some of Your time here is link to repo. https://github.com/mklimczuk/Charts .
Cheers
Thank you, I checked it today and with a lot of points (3000+) performance are really bad. Maybe you can have a look at OxyPlot for a comparison.
Is there a way to set the colours (current : green and red) in ChartPlotter on a stock chart . . ?
<d3:StockItem Style="{x:Static d3:StockItemStyles.Default}" . . . . . . . .
Many thanks for super info.
When I had to do some customizations, the only way was to modify the sources.
I am not too proficient in WPF/C#; which specific modules need changing ?
Many thanks
mano
San Jose, CA
former technology banker NYC
Mesta,
Thanks for providing the solution!
I am working on this application and i can use it to draw sin curve.
I wonder that if i can add a function that to show the accurate value(X,Y) of any point on the curve when the pointer attach to it.
I got an example of a similar chart:
Could you help with that ?
Thanks man, for taking the time to show us this. What makes internet great is people like you 🙂
Mesta,
After running your excellent example I want to learn more about the capabilities of D3. For the real time chart example I would like to add a)Panning and b)Zooming. Could you please direct me to an example on how to do this. Also is there any documentation describing how to implement the various other features that D3 has for real time charts.
Thanks,
Paul
I would like to know whether dynamic data display dll is open source. if yes then why there is no proper license informations regarding commercial usage.