A few weeks ago I published a blog post which compared the performance of the Visiblox charts and the Silverlight Toolkit charts. The results indicated that the Visblox charts are considerably faster than the Toolkit charts, however Microsoft’s David Anson did point out that the Toolkit charts were not designed with performance in mind, and that a comparison would be more fair if the ‘FastLineSeries’ series that has been on the TODO list for a while were implemented.
I have been asked by a few people to extend the performance test to include a few other Silverlight charts to see how they compare. I have refactored the test code so that different charts can be plugged in more easily. This not only makes it easier to test the performance of other charting components, but has also allowed me to compare the different charting APIs more easily.
This blog post compares the performance of Visiblox, Visifire, Silverlight Toolkit and Dynamic Data Display (D3) charts. I also compared a few other charting components, however the terms of their trial license prohibit me from publishing the results.
A summary of the performance measurement is given below, where each chart is used to plot rapidly changing data, with the framerate being used as a measure of performance.

The test clients running with each of the different charts are shown below:
| Visiblox Chart | Visifire Chart |
|---|---|
| Silverlight Toolkit Chart | D3 Chart |
[cheetah image courtesy of flickrfavorites, snail image courtesy of Per Ola Wiberg, tortoise image courtesy of wwarby, horse image courtesy of Linnéa Gröndalen]
We’ll look at the XAML markup for each chart and the code-behind used to add data to each chart in the following sections:
Visiblox
The XAML markup for the Visiblox charts is reasonably concise, with the X & Y axes configured and styled and the three LineSeries added to the chart:
<UserControl.Resources> <Style TargetType="Line" x:Key="GridLineStyle"> <Setter Property="Stroke" Value="#dddddd" /> <Setter Property="StrokeThickness" Value="1" /> </Style> </UserControl.Resources> <Grid x:Name="LayoutRoot" Background="White"> <chart:Chart x:Name="chart" LegendVisibility="Collapsed" Margin="5,0,5,5"> <chart:Chart.XAxis> <!-- a 'hidden' X axis --> <chart:LinearAxis ShowAxis="False" GridlineStyle="{StaticResource GridLineStyle}"/> </chart:Chart.XAxis> <chart:Chart.YAxis> <!-- A Y axis with labels within the chart area --> <chart:LinearAxis ShowLabels="True" LabelsPosition="Inside" GridlineStyle="{StaticResource GridLineStyle}" ShowMajorTicks="False" ShowMinorTicks="False"/> </chart:Chart.YAxis> <chart:Chart.Series> <!-- the series used to render the RGB components --> <chart:LineSeries LineStroke="#A00"/> <chart:LineSeries LineStroke="#0A0"/> <chart:LineSeries LineStroke="#00A"/> </chart:Chart.Series> </chart:Chart> </Grid> |
The code-behind is also reasonably concise with the list of DataPoint objects returned by the test-harness converted into Visiblox DataSeries via a Linq Select projection.
protected override void RenderDataToChart(List<List<Histogram.DataPoint>> rgbData) { _chart.Chart.Series[0].DataSeries = ListToSeries(rgbData[0]); _chart.Chart.Series[1].DataSeries = ListToSeries(rgbData[1]); _chart.Chart.Series[2].DataSeries = ListToSeries(rgbData[2]); } private DataSeries<double, double> ListToSeries(List<Histogram.DataPoint> data) { return new DataSeries<double, double>(data.Select(pt => new DataPoint<double, double>(pt.Location, pt.Intensity))); } |
Visifire
Visifire also has a reasonably concise XAML markup, however in order to provide maximum performance, there are a number of chart features that need to be disabled. The Visifire charts have a Line series which could be used for this comparison, however they recently released a QuickLine series type which removes certain features to provide better performance.
<Grid x:Name="LayoutRoot" Background="White"> <vc:Chart x:Name="chart" AnimationEnabled="False" ScrollingEnabled="False"> <vc:Chart.Legends> <vc:Legend Enabled="False"/> </vc:Chart.Legends> <!-- the series used to render the RGB components --> <vc:Chart.Series> <vc:DataSeries RenderAs="QuickLine" Color="#A00" LineThickness="1" MarkerEnabled="False" ShadowEnabled="False" /> <vc:DataSeries RenderAs="QuickLine" Color="#0A0" LineThickness="1" MarkerEnabled="False" ShadowEnabled="False" /> <vc:DataSeries RenderAs="QuickLine" Color="#00A" LineThickness="1" MarkerEnabled="False" ShadowEnabled="False" /> </vc:Chart.Series> <!-- a 'hidden' X axis --> <vc:Chart.AxesX> <vc:Axis Enabled="False"> <vc:Axis.Grids> <vc:ChartGrid Enabled="True" LineColor="#ddd" LineThickness="1"/> </vc:Axis.Grids> </vc:Axis> </vc:Chart.AxesX> <vc:Chart.PlotArea> <vc:PlotArea ShadowEnabled="False"/> </vc:Chart.PlotArea> </vc:Chart> </Grid> |
The code-behind required to add data to the chart is straightforward. However, you cannot simply create a new DataPointCollection and replace the current Series.DataPoints, instead you have to clear the existing collection, then rebuild it.
protected override void RenderDataToChart(List<List<Histogram.DataPoint>> rgbData) { AddDataToSeries(_chart.Chart.Series[0], rgbData[0]); AddDataToSeries(_chart.Chart.Series[1], rgbData[1]); AddDataToSeries(_chart.Chart.Series[2], rgbData[2]); } private void AddDataToSeries(DataSeries series, List<Histogram.DataPoint> list) { series.DataPoints.Clear(); foreach (var pt in list) { series.DataPoints.Add(new Visifire.Charts.DataPoint() { XValue = pt.Location, YValue = pt.Intensity }); } } |
Silverlight Toolkit
The Silverlight Toolkit XAML is quite verbose, mostly due to the performance enhancements described in my previous blog post.
<UserControl.Resources> <Style TargetType="dataVis:Legend" x:Key="CollapsedLegendStyle"> <Setter Property="Visibility" Value="Collapsed"/> <Setter Property="Width" Value="0"/> </Style> <Style TargetType="Control" x:Key="CollapsedStyle"> <Setter Property="Visibility" Value="Collapsed"/> </Style> <ControlTemplate x:Key="SimplifiedDataPoint" TargetType="tk:LineDataPoint"> </ControlTemplate> </UserControl.Resources> <Grid x:Name="LayoutRoot" Background="White"> <tk:Chart x:Name="chart" LegendStyle="{StaticResource CollapsedLegendStyle}" TitleStyle="{StaticResource CollapsedStyle}"> <!-- define the line series --> <tk:LineSeries ItemsSource="{Binding}" TransitionDuration="0" DependentValueBinding="{Binding Intensity}" IndependentValueBinding="{Binding Location}"> <tk:LineSeries.DataPointStyle> <Style TargetType="tk:LineDataPoint"> <Setter Property="Visibility" Value="Collapsed"/> <Setter Property="Template" Value="{StaticResource SimplifiedDataPoint}"/> <Setter Property="Background" Value="#A00"/> </Style> </tk:LineSeries.DataPointStyle> </tk:LineSeries> <tk:LineSeries ItemsSource="{Binding}" TransitionDuration="0" DependentValueBinding="{Binding Intensity}" IndependentValueBinding="{Binding Location}"> <tk:LineSeries.DataPointStyle> <Style TargetType="tk:LineDataPoint"> <Setter Property="Visibility" Value="Collapsed"/> <Setter Property="Template" Value="{StaticResource SimplifiedDataPoint}"/> <Setter Property="Background" Value="#0A0"/> </Style> </tk:LineSeries.DataPointStyle> </tk:LineSeries> <tk:LineSeries ItemsSource="{Binding}" TransitionDuration="0" DependentValueBinding="{Binding Intensity}" IndependentValueBinding="{Binding Location}"> <tk:LineSeries.DataPointStyle> <Style TargetType="tk:LineDataPoint"> <Setter Property="Visibility" Value="Collapsed"/> <Setter Property="Template" Value="{StaticResource SimplifiedDataPoint}"/> <Setter Property="Background" Value="#00A"/> </Style> </tk:LineSeries.DataPointStyle> </tk:LineSeries> <!-- configure the axes --> <tk:Chart.Axes> <tk:LinearAxis Orientation="X" Height="0"> </tk:LinearAxis> </tk:Chart.Axes> </tk:Chart> </Grid> |
However, the code-behind is the most concise of all the charts I tested because the chart databinds directly to the properties of the DataPoint business objects.
protected override void RenderDataToChart(List<List<DataPoint>> rgbData) { ((LineSeries)_chart.Chart.Series[0]).ItemsSource = rgbData[0]; ((LineSeries)_chart.Chart.Series[1]).ItemsSource = rgbData[1]; ((LineSeries)_chart.Chart.Series[2]).ItemsSource = rgbData[2]; } |
Dynamic Data Display
The D3 charts are quite different to the others which I have tested. These charts were developed by a Microsoft team based in Russia and are released on codeplex. They claim outstanding performance with large volumes of data, and are often recommended on sites such as stackoverflow when questions relating to charting performance arise.
The XAML markup for the D3 charts is pretty minimal!
<Grid x:Name="LayoutRoot" Background="White"> <d3:ChartPlotter Name="plotter"> </d3:ChartPlotter> </Grid> |
However, this is because the D3 charts do not support configuration via markup. It took me quite a while to work out how to configure the charts in code-behind, the D3 APIs are not very intuitive. I am not the only one to have noticed this; Lee Campbell, in his “WPF Charting Comparisons” blog post stated ” … it took me hours of reading forums, looking at samples and coding to just get my Model showing on the screen”. Oh dear!
I had to resort to navigating the visual tree (using Linq to VisualTree) to locate the pan and zoom controls which are added to the chart by default, and remove them.
However, in fairness, the Silverlight version of D3 charts is a partial port of the WPF version, but both share a similar programmatic style of usage.
The following code is used to configure the chart in code-behind:
public DDDChart() { InitializeComponent(); this.Loaded += new RoutedEventHandler(DDDChart_Loaded); } private LineGraph InitGraph(Color color) { var animatedX = new List<double>(); var animatedY = new List<double>(); // add some points, otherwise we get some layout-related exception animatedX.Add(0); animatedY.Add(0); // create the X & Y sources _xSource = new EnumerableDataSource<double>(animatedX); _xSource.SetXMapping(x => x); _ySource = new EnumerableDataSource<double>(animatedY); _ySource.SetYMapping(y => y); // Adding graph to plotter var graph = new LineGraph(new CompositeDataSource(_xSource, _ySource), ""); graph.LineColor = color; graph.LineThickness = 1; plotter.Children.Add(graph); return graph; } private void DDDChart_Loaded(object sender, RoutedEventArgs e) { // remove the mouse pan and zoom controls var navigationControl = plotter.Children.OfType<MouseNavigation>().Single(); plotter.Children.Remove(navigationControl); var zoomControl = plotter.Descendants().OfType<buttonsNavigation>().Single(); ((Panel)zoomControl.Ancestors().First()).Children.Remove(zoomControl); _graphOne = InitGraph(Color.FromArgb(255,200,0,0)); _graphTwo = InitGraph(Color.FromArgb(255, 0, 200, 0)); _graphThree = InitGraph(Color.FromArgb(255, 0, 0, 200)); // Force everything plotted to be visible plotter.FitToView(); plotter.Legend.Visibility = Visibility.Collapsed; } |
The following code is used to change the data for each series. Again, the D3 APIs are a little complex. Also, the chart does not have a mode where the X & Y axes compute their range based on the data. Instead, this is performed programatically via FitToView.
protected override void RenderDataToChart(List<List<DataPoint>> rgbData) { RenderDataToGraph(_chart.LineGraphR, rgbData[0]); RenderDataToGraph(_chart.LineGraphG, rgbData[1]); RenderDataToGraph(_chart.LineGraphB, rgbData[2]); // re-scale the chart based on the rendered data _chart.Plotter.FitToView(); } private void RenderDataToGraph(LineGraph graph, List<DataPoint> histogram) { var source = graph.DataSource as CompositeDataSource; // obtain the two sources which the composite is composed of var xSource = source.DataParts.ElementAt(0) as EnumerableDataSource<double>; var ySource = source.DataParts.ElementAt(1) as EnumerableDataSource<double>; var dataX = new List<double>(); var dataY = new List<double>(); foreach(var point in histogram) { dataX.Add(point.Location); dataY.Add(point.Intensity); } xSource.Data = dataX; ySource.Data = dataY; } |
Conclusions
In summary, the Visiblox and Visifire charts seem to have the cleanest API, with concise XAML markup to define the charts and little code-behind required to update the series. The Silverlight Toolkit charts XAML markup is a bit verbose, mostly due to performance optimisation. Finally, the D3 charts have a complex and difficult to follow API. In terms of performance, the Visiblox and D3 charts give similar results, the Visifire charts are a little behind with, with a frame rate that is approximately 1/3 of the leading charts, and the Silverlight Toolkit charts come last.
You can download the full sourcecode of this comparison here: ChartPerformance.zip
NOTE: To build the examples you need to download the charting components from their respective web pages:
Finally, a couple of my colleagues have created similar charting tests using other technologies, you might be interested in Graham’s Flex implementation, or Chris’s cute HTML5 implementation.
Regards, Colin E.


email: ceberhardt@scottlogic.co.uk
on Google+



WPF itself has a huge bug in it http://lukhezo.com/2011/09/24/itemscontrol-performance-improvements-in-net-4-5/
In the following links: http://www.visifire.com/blog/2011/10/20/performance-optimised-initial-render-now-2x-faster/
visifire claim “Performance optimized. Initial render now 2x faster!”
Does this release will make visifire catch visiblox?
thx!
Jane,
Visifire is one of the fastest charting component now. Please check out the blog post for more info.
http://www.visifire.com/blog/2011/12/02/fast-silverlight-charts/
This blog post compares Visifire with Visiblox using few samples. You can play around with it & decide who is fast!
Hi Vivek,
Thanks for your comment, it looks like Visifire and other charting component vendors are raising their game! Regarding the specific test you link to, on my machine Visiblox and Visifire have a similar framerate in the second test. However, I agree, Visifire does render faster.
It is worth noting that the Visifire charts use a special ‘quick line series’ that has stripped down functionality in order to provide a performance boost. Whereas the Visiblox series being tested is the ‘full’ line series which supports tooltips, selection, styling, etc …
Regardless, congratulations to Visifire on raising their game!
Colin E.
[...] a lot of data on the charts and the performance comparisons on Colin Eberhardt’s blog here, as well as opinions on Stack Overflow led me to select Visiblox. I found the examples to be a [...]
[...] a dead project. The paid for alternatives that are reasonably priced were a disappointment. Some have good performance characteristics but their focus is different from ours. They are very quick when redrawing a [...]
I ran the automated tests on my MacBook and the results profile looked quite different. Obviously the absolute numbers were different but the relationship was even more skewed towards Visiblox. I got the following results: Visiblox ~47fps, Visisfire ~5fps, DDD ~27fps. I don’t know what it is about the Mac’s Silverlight runtime that causes this or perhaps it’s just because I’m running on a slightly lower powered machine but Visiblox appears to be faster by a much larger margin.
I’ve plugged amCharts Quick Charts into your test suite. Here are the results:
http://devblog.ailon.org/devblog/post/2010/12/17/amCharts-Quick-Charts-in-e2809cVisiblox-Performance-Teste2809d.aspx
Hi Alan,
Nice work, amChart Quick Chart looks like it is a fast, basic, charting component. I have double-checked your figures here:
http://www.scottlogic.co.uk/blog/colin/visiblox-charts-vs-amcharts-quick-charts/
Colin E.
[...] Visiblox, Visifire, DynamicDataDisplay – Charting Performance Comparison (Colin Eberhardt) [...]
Silverlight Charts – a Performance Comparison…
Thank you for submitting this cool story – Trackback from DotNetShoutout…
A very interesting comparison indeed, Colin – thanks for sharing these measurements and the code.
At the same time it’s a pity you’re unable to publish the names and source code of Vendor A and Vendor B – you’ve got as all guessing who they could be (and my guess would be they aren’t small players)!
No problem. I cannot publish names, but what i can tell you is that they both appear on page on if you google for ‘Silverlight Charts’