Optimizing WPF/Silverlight Chart Performance for Real-Time Data

Kiril Matev / Thursday, April 7, 2011

The XAML platform allows us to deliver rich interaction to our users much cheaper when compared against Windows Forms. One of the areas this is most useful is data visualization. At Infragistics we’ve recognized the ability of the XAML platform to power amazing visualizations and we’ve implemented a number of data visualization components (chart, map, pivot gridheatmapgauge) in our NetAdvantage for Data Visualization product, which is available for both Silverlight and WPF. One of the components in this product is the XamDataChart, which allows you to visualize large datasets, or real-time data streams, with rich styling delivering interaction capabilities such as zooming and panning.

Often you’re confronted with real-time data scenarios, and you’d like to know how to tune the XamDataChart for maximum performance. This blogpost describes how you can do that, and illustrates the approach using a sample project. Even though the sample project is implemented in WPF, the same optimization tips apply for the Silverlight version of the XamDataChart as well. 

Turn off Series Value Markers

Value markers are visual elements which denote a data point in the series. As you’re plotting rapidly-changing real-time data, specific points are of less interest than the trend and the bounds of the incoming values. This is why removing value markers will not decrease the ability of the user to make decisions based on the data. Removing the data markers improves performance significantly, as the XamDataChart no longer has to draw value markers for all data points when a new data point is added.

Fix the Width of the Y-Axis Labels

Changes of the axis scale due to changing values in the axis also changes the plot width, causing the series to be refreshed in the newly available plot area. Fixing the width of the Y-Axis labels using the Extent property of the LabelSettings of the axis allows the axis labels to change in response to values shown in the plot, but prevents their widths from changing, saving an additional refresh of the plot area. Here’s the code you can use to fix the widths of the axis labels of the Y axis to 40:

<ig:NumericYAxis x:Name="yAxis1">
      <ig:NumericYAxis.LabelSettings>
             <ig:AxisLabelSettings Extent="40" />
      </ig:NumericYAxis.LabelSettings>
</ig:NumericYAxis>

Use CategoryXAxis instead of CategoryDateTimeXAxis

The CategoryDateTimeXAxis currently assumes that the data arrives in random order and needs to be sorted before it is displayed. This is why for real-time data streams, each new point forces a re-sort of the data, causing a performance hit. Using the CategoryXAxis instead, which assumes that chart data arrives in order, improves performance twice measured using the Frames per Second metric.

Use DataTemplates for Axis Labels*

In versions 10.3 and earlier, a performance improvement can be gained by using explicitly defined DataTemplates for the axis labels, instead of setting them via the Label property of the axis. In our 11.1 release (which the sample in this post is built upon) you no longer have to do this, and can rely on setting the Label property directly to achieve maximum performance. In case you’re using 10.3 or earlier, you can use a DataTemplate such as the one below to show the Date member in a short-date format:

<ig:CategoryXAxis.Label>
      <DataTemplate>
            <TextBlock Text="{Binding Item.Date, StringFormat=d}" />
      </DataTemplate>
</ig:CategoryXAxis.Label>

Adjust the Resolution of the Series

The Resolution property sets the rendering resolution for a series. It allows you to control the fidelity of the line plotted to the data, with the maximum fidelity being set by default to 1. Larger Resolution values reduce the fidelity of the line, but improve performance significantly. This is appropriate for scenarios with rapidly changing data, when the direction of change and boundary values are more important than specific values.

It draws a line composed of 2000 random values refreshed 10 times per second, allowing you to change the Resolution values and see how this impacts performance in terms of Frames per Second. Refreshes are performed in batches – 2000 data values are flushed at once, and new 2000 random data values are added 10 times per second, which should ideally produce 10FPS to reflect the changing data.

Note: Plotting random data is the worst-case scenario for WPF to render, because of a limitation in the underlying WPF rasterizers (which is absent from Silverlight). This currently limits the speed at which any line can be rendered in any chart on the market. Still, on any real data set without random data, you will see a much better level of performance, as shown by the first sample project in the blog post. The chart in the first sample is refreshed every 10ms, comfortably achieving 60 Frames Per Second (on a 60Hz monitor refresh rate, this is the maximum visible to the user) without an increase in the CPU load.

Resolution

Frames Per Second

Total CPU Usage

1 (default)

1-2

16%

2

8

15%

3

9

7%

 

Summary

In this blog post we looked at how we can handle high-speed data update scenarios in the XamDataChart. We showed how using a few simple property settings we can tune its performance to display near real-time data streams. This guidance enables you to confidently handle such high-speed scenarios, all the while providing the interactivity and rich styling delivered by the WPF platform. With all this information now available, you can consult with your users whether they would benefit from such functionality in the applications you're building.

If you have any questions or comments, you can reach me at kmatev@infragistics.com