For one of our projects we had to retrieve data from an external source and store them in a database. One of the requests from the client was to see the retrieved data in a graph. Furthermore, he wanted to see a live update every second of the retrieved data in that graph.
After some searching I found the OxyPlot library. This library can be used in WPF, Silverlight, Windows Forms and even in Windows Store apps. The are now working on a alpha release for Mono.
Although the package is already downloaded more then 10 000 times there are not so many blog posts to find about implementing the library.
Using Nuget
The easiest way to include OxyPlot in you application is by using the Nuget package manager in Visual Studio.
Open op Visual Studio and start with creating a new WPF project. Choose a name and a location and hit ‘OK’.
After the project is created open up the Package Manager Console and type following commands at the prompt and hit enter (after every command):
- Install-Package Oxyplot.Core
- Install-Package Oxyplot.Wpf
You can of course use the Package Manager UI by right clicking References and choose Manage Nuget Packages and them that way.
Create the ViewModel
We’ll use the MVVM model (partial) to render the Graph on the screen. First step is to create the ViewModel for our MainWindow.xaml. Right click on the project and add a folder ViewModels. Right click the folder and add a class MainWindowModel.cs.
To use the MVVM model we need to make the class public and inherit the INotifyPropertyChanged interface.
NOTE: The OxyPlot WPF package doesn’t completely support the MVVM model. You can’t use only the OnPropertyChanged method to update the graph. You’ll still need the manually refresh the graph from the code behind class of the XAML page. I saw a post in the discussions on codeplex that they are looking to add complete MVVM model but are short of time at the moment. Maybe the next version will support it. To be complete I add the necessary steps to implement the MVVM model in this post.
After inheriting the interface we have to implement the PropertyChangedEventHandler event as shown below.
Now we can add some public properties that we’ll bind to in the XAML page. First create a PlotModel that’s part of the OxyPlot library. In the constructor we’ll initiate the PlotModel parameter. The setter will call the OnPropertyChanged method that will notify the view there is a change on the object that may have to be rendered.
Adding the graph to the page
We can now add the graph to the MainWindow.xaml page. Before we can add the graph we’ll need to add the namespace for the OxyPlot library (line 4). We’ll bind the PlotModel parameter to the PlotModel we’ve created in the view model.
Binding the model to the view
Last part for our setup is to bind the view model to the view. Because we don’t use any MVVM frameworks we’ll have to manually bind the model in the code behind of the MainWindow.xaml page.
Add a private property of our view model and initiate this property in the constructor. Point the DataContext to this property and we’re done.
If we hit F5 to run the application we’ll see an empty window opening. We have of course add some data to the PlotModel before the graph will be rendered.
Set up the Graph – PlotModel
Back to our view model to set up our view model. First start will be adding the axes for the graph so OxyPlot knows where to plot the points.
Create a new method SetUpModel in our view model class. In here we’ll define the legend of the graph (position, border, sire, …) and add 2 axis. A DateTimeAxis for our X-axis (we want to plot points in a line of time) and a ValuaAxis for our Y-axis.
The set up for the legend of the graph is self explanatory. At line 10 you’ll see the creation of the DateTimeAxis. We’ll choose the position of the axis, give it a name (Date) and a string format pattern how the date has to be displayed. Next to that we’ll add some parameters to show major and minor gridlines and the interval size. After creation we’ll add the axis to the PlotModel.
The ValueAxis is similar initiated, only did we position the axis on the left side and tell the Axis to start at the value 0.
If we add a call to this method in the constructor of our view model and hit F5 again we’ll now see window opening that contains an empty graph.
The data
Now we have our graph and are ready to add some graph lines to the PlotModel. In this post we’ll add four different lines that will be plot.
To avoid complexity I added a class Data.cs where the data is hardcoded. In a real life application you’ll be implementing a database call or a service invocation or a web API request, …
The data I’ll receive will be a List<T> of a new simple class I’ve created: Measurement. This class has 3 public parameters: a DetectorId (long), a Value (int) and a DateTime (DateTime). I’ve added 4 different detectors that each have 10 measurements of a random value between 1 and 30.
Add the data to the PlotModel
In the view model we’ll create a new method LoadData where we’ll get the data and add some code to plot all point on the graph.
After fetching the data I’ll use the LINQ GroupBy expression to create a IEnumerable with as key the DetectorId and a collection of Value and Datetime as values. (line 5)
This will allow us to loop over the result and then add a LineSerie per Detector. In the setup of the LineSerie we’ll set some properties like colors and line thickness and the title. (line 9 till 18).
After we’ve created the LineSerie we can add the points to the LineSerie. We make use of the DateTimeAxis builtin funtion to convert a date to a double and add the value (line 20).
After we added the points to the LineSerie we’ll still have to add the LineSerie to the PlotModel. (line 21).
And that’s it. Hit F5 and you’ll see that are graph will be rendered and that per detector a line will appear plotting the random values between 1 and 30.
Updating the graph real-time
For the second question of our client we had to add real-time updates. For this demo I’ll add an new measurement to the graph every second. The OxyPlot library will make sure our graph will move along every time we’ll add a new measurement.
I’ve added a static method in the Data.cs class that will return a random value a second after the DateTime parameter that will be send along. In the view model I’ve created a private parameter DateTime parameter (lasUpdate) that will hold the moment we last updated the graph.
Update the view model
We’ll add a new method to the view model UpdateModel. This time we’ll make it public so it can be called from the view as shown in the next chapter.
In the UpdateModel method we’ll fetch the data from out Data.cs class and perform the same grouping action as in the LoadData method.
This will allow us to fetch the data per detector. After retrieving the correct LineSerie we can add the points like we did in the LoadData method.
Update from the view
We don’t want the update of the model to initiate before the previous is completely rendered to avoid an exception that we are modifying a list while rendering the graph. Therefor we make use of a CompositionTarget.Rendering event. This event will be fired every time the view is done rendering.
In the constructor of the MainWindow.xaml.cs class we’ll attach an eventhandler on the Rendering event.
In the event handler we’ll call the update method from the view model. After that call we’ll have to tell the PlotModel that there was an update and that he has to refresh the graph (line 14). (This is where OxyPlot drifts away from the MVVM model).
Avoid to many updates
The rendering event is ideal to avoid exceptions but you’ll see to many updates per second to keep the graph readable. We can solve this to add a StopWatch in the code behind and only trigger the update when the last update is at least a second ago.
After adding the StopWatch we’ll see that every (for this demo 5 seconds) a new point is added to the graph.
Source code
As you can see, with OxyPlot you don’t need to write to many code to create real time updating charts.
OxyPlot has many more options and graph styles, they have provided a demo page where a variety of graphs are rendered in Silverlight. You can copy the source code with the keyboard combination Ctrl+Alt+C. If you want to copy the properties use Ctrl+Alt+R.
The source code of this post can you find on Github. Feel free to fork, download, …
Thanx got working after a bit of thinking but wouldn’t have been able to without the demo
Hi, do you know how to plot smoothed lines (i.e. is there built in capability to do this).
var lineSerie = new LineSeries
{
…
…
Smooth = True,
};
Thanks! It worked!
Are there any additional documentation of this product
Thomas, you’ll find some more documentation on http://oxyplot.codeplex.com/. I learned the most from diggin around in the Silverlight example browser (http://www.oxyplot.org/examplebrowser/)
TIP: use Ctrl+Alt+C to copy the code from the plot your looking at in the example browser. Use Ctrl+Alt+R to copy the properties.
Just started looking at OxyPlot for some scientific data plots. This is a great intro to it’s usage. I tried just building up the app based on the code shown here – of course that doesn’t work because some bits aren’t shown in the blog. So do get the code from GitHub – even if just for further reference.
A further point – the “using OxyPlotDemo.Annotations;” threw me because R#8 does not automatically create this. Not needed though if you omit [NotifyPropertyChangedInvocator] from above
“protected virtual void OnPropertyChanged(string propertyName)”
Thanks Bart – a really good learning article, especially as OxyPlot has little on-line documentation.
How do i make the oxyplot a pop up with a single click on the graph?
In MainWindow.xaml.cs : Plot1.RefreshPlot(true);
I get an error : “‘OxyPlot.Wpf.Plot’ does not contain a definition for ‘RefreshPlot’….”
I’m using OxyPlot version : “2014.1.267.1” How do I solve this?
In current version of oxyplot You need to change:
Plot1.RefreshPlot(true);
to:
Plot1.InvalidatePlot(true);
Nope.
That does not work either.
There is a lot of useless advice on the forums about this.
And examples are often obsolete.
As is the OxyPlot doc.
Hey there, great post! Any idea how I could mark areas in the plot? I thought of plotting one ultra-fat horizontal lines.
I want to implement a “only-export-selected-data” function.
Thanks in advance!
OXY plot is a nice charting library, but will it be able to compete in features with the Nevron NOV Chart – a porting of their great .NET charting component to their portable framework:
Nevron Chart for .NET
One thing I know is that NOV Chart will not have 3D features initially – does OXY plot support 3D?
thanks that’s great.
how to add zoom operations on these wave form display?
eg: zoom in and zoom out etec, and mark in i.e.., plotting between two or more point(s).
Need detailed documentation to embed with C#. does it need WPF knowledge ?
Hi Bart,
Great post.
I am doing the exact implementation in my project. But I came to a situation where i need to get the default Maximum time from the Plotmodel. I tried both these methods below. But somehow, they are not the Plotmodel that is in the View .
PlotModel.DefaultXAxis is NULL.
PlotModel.Axes[1] this doesn’t represent the Plotmodel in view.
Do you think any workaround with which we can take the DefaultAxis in viewmodel from Oxyplot object in view?
Regards,
Toms
Anno 2015 this graph project doesn’t exist?
I have tried the PMC commands listed but the package is nowhere to be found?
How do I install the lastest stable version of OxyPlot for Visual Studio Community 2015?
I need it for a WPF project 😀
Cheers,
Daniel
Just thought I’d share a tweak I made of your solution (which is awesome btw). The following allows graph to actually move (or pan) left or right depending on pan value (negative moves to left, positive moves to right):
public void RefreshModel()
{
List measurements = this.GetUpdateData(lastUpdate);
var dataPerDetector = measurements.GroupBy(m => m.DetectorId).OrderBy(m => m.Key).ToList();
foreach (var Data in dataPerDetector)
{
var LineSeries = PlotModel.Series[Data.Key] as LineSeries;
if (LineSeries == null) continue;
Data.ToList().ForEach(d => LineSeries.Points.Add(new DataPoint(DateTimeAxis.ToDouble(d.DateTime), d.Value)));
}
lastUpdate = DateTime.Now;
PlotModel.DefaultXAxis.Pan(-1);
}
And then I removed the panning statements from your SetupModel method. Hope this helps someone else (:
i just started the c# and oxyplot. for me it is confusing. i am using visual studio 2015 nothing is working to me.
number of solution and queries are limited and has not good explanation and solution
Hi! May I know what’s in the GetData() method?
Hello,
I have problem with – xmlns:oxy=”http://oxyplot.codeplex.com” – namespace. If I insert this into XAML code, visual studio will write a warning, that oxy:Plot type not found. I followed this tutorial.
Thank you for your help
Hey dude,
the problem is that the demo in this blog uses a version of oxyplot named: 2013.1.38.1
If you install oxyplot over nuget, you will install version: v1.0.0
solution: download the example in this blog and copy the packages folder to your new project folder and add the references manually to your new project.
Then the xmlns:oxy=”http://oxyplot.codeplex.com” – namespace will work again!
Cheers,
Davo
Is it possible to have grid lines around the month title on DateTimeAxis?
Meaning, the grid lines are at the beginning and at the end of each month but the month title is between them?
The issue below has a picture of “what I’m trying to build”.
https://github.com/oxyplot/oxyplot/issues/1186