Visualizing raw data is important in any application, so that you can quickly and clearly understand large quantities of data and compare different kinds of data sets. One of the most commonly used chart types is the line chart. It is represented by a series of data points on a straight line. It should be capable of visualizing a large amount of data points, as would be the typical requirement in most applications.
We built this chart with plotting a lot of data points in mind and included several optimizations to handle high numbers of data points while still providing a smooth experience to users. Still, more optimizations can be done at the application level to get the best possible performance when loading more than 100K data points, and those techniques are explained in this blog post.
The line series was built for providing rich customization of individual lines, so it will not be good for loading a high number of data points and performing real-time data updates. However, we also have a FastLineSeries. It is commonly used to load a huge number of data points as it renders the line with a single points collection. The configuration of FastLineSeries, such as setting the items source and binding paths, is the same as any other series. The following code snippet shows how to configure the fast line series in XAML code.
<chart:SfChart.Series> <chart:FastLineSeries XBindingPath="XValue" YBindingPath="YValue" ItemsSource="{Binding Data}"/> </chart:SfChart.Series>
Plotting data markers and labels for each data point will be look messy when you plot many data points. Nevertheless, it is important to track the data points at required indexes. That is where tooltips and a trackball come into play. A tooltip will display data when you touch any data point. Similarly, the trackball will display the information of the nearest data point along with a vertical line when you touch and hold it on the chart area. Customize the appearance of both trackball and tooltip labels using built-in APIs and data templates. The following code snippet shows how to enable tooltips and the trackball and customize their labels using a data template.
Enable and customize tooltips using a data template.
<chart:FastLineSeries EnableTooltip="true"> <chart:FastLineSeries.TooltipTemplate> <DataTemplate> <Label Text="{Binding TooltipString}" /> </DataTemplate> </chart:FastLineSeries.TooltipTemplate> </chart:FastLineSeries>
Enable the trackball.
<chart:SfChart.ChartBehaviors> <chart:ChartTrackballBehavior/> </chart:SfChart.ChartBehaviors>
Customize the trackball labels with a data template
<chart:FastLineSeries> <chart:FastLineSeries.TrackballLabelTemplate> <DataTemplate> <Label Text="{Binding TooltipString}" /> </DataTemplate> </chart:FastLineSeries.TrackballLabelTemplate > </chart:FastLineSeries>
By default, the stroke width of a fast line series is 2. It causes a delay if you render the line with two pixels rather than a single pixel. So, set the StrokeWidth of FastLineSeries to 1 if you don’t have any specific requirement to render the line with the thickness of two. The thickness of the line can be increased at runtime. You can render the line with a thickness of one at load time and, after zooming to a certain level, you can increase the thickness to two or more to see the line clearly. The following code snippet demonstrates how to configure the thickness of the line.
<chart:SfChart.Series> <chart:FastLineSeries StrokeWidth="1" /> </chart:SfChart.Series>
After binding your data to the ItemsSource property of ChartSeries, the chart will always listen to the changes that happen in your data if it implements the INotifyCollectionChanged interface. But in some cases, you may add bulk objects to your data collection. If you think those updates in the chart do not make any sense, you are able to stop the chart from being updated for each modification in the items source collection. It is possible with the Charts control using the SuspendSeriesNotification and ResumeSeriesNotification methods. The chart will not respond to any change in the items source collection after the SuspendSeriesNotification method is invoked. It will be updated with latest data after the ResumeSeriesNotification method is invoked. Refer to the following code snippet.
Chart.SuspendSeriesNotification(); //Make the required changes in the items source that don’t need to be updated in UI immediately. Chart.ResumeSeriesNotification();
The anti-aliasing support renders the line with smooth edges. But, this is not very important when you plot a huge number of data points. Disable the anti-aliasing of the line using EnableAntiAliasing property of FastLineSeries. Enable the anti-aliasing at runtime, though, whenever you want the line to be anti-aliased. The following code snippet shows how to disable the anti-aliasing feature.
<chart:SfChart.Series> <chart:FastLineSeries EnableAntiAliasing="false" /> </chart:SfChart.Series>
Do not use the CategoryAxis when you do not have any specific need to show the string values in the x-axis. Whereas CategoryAxis populates the labels based on the individual data points, the NumericalAxis and DateTimeAxis populate the labels based on the points’ ranges and intervals. These axes always give good performance when loading a high number of data points. The following code snippet shows how to configure the NumericalAxis as the primary axis.
<chart:SfChart.PrimaryAxis> <chart:NumericalAxis/> </chart:SfChart.PrimaryAxis>
Because the quality of the default rendering is better with FastLineSeries, the Xamarin.Forms FastLineSeries has been mapped with it instead of FastLineBitmapSeries in the UWP platform. The FastLineSeries plots the data using polylines, but FastLineBitmapSeries plots the data using bitmap, which is faster than polyline rendering. To replace FastLineSeries with FastLineBitmapSeries, you need to write a custom renderer, as shown in the following code snippet.
public class ChartRendererExt : SfChartRenderer { protected override void OnElementChanged(ElementChangedEventArgs e) { base.OnElementChanged(e); Native.SfChart chart = this.Control as Native.SfChart; chart.Series.Clear(); //Replace the fast line series with fast line bitmap series foreach (var formsSeries in e.NewElement.Series) { if (formsSeries is FastLineSeries) { Native.FastLineBitmapSeries fastLine = new Native.FastLineBitmapSeries(); formsSeries.PropertyChanged += (sender, a) => { if(a.PropertyName.Contains("ItemsSource")) { fastLine.ItemsSource = formsSeries.ItemsSource; } }; var properties = SfChartRenderer.GetPropertiesChanged(typeof(ChartSeries), formsSeries); foreach (var name in properties) { ChartSeriesMapping.OnXyDataSeriesPropertiesChanged(name, formsSeries as FastLineSeries, fastLine); } chart.Series.Add(fastLine); } } } }
All the above techniques help to improve the loading time and provide smooth, real-time updates in a complex application. However, the performance is still dependent on the device and its configuration. We have applied these optimizations and tested the control with 500K data points. It loads within a second in all the Xamarin.Forms platforms. We have used an iPhone 7 to test iOS, Google Pixel for Android, and a device with 16GB RAM and an Intel Core i5 7th Gen 7200U to perform this test on the Windows platform.
The following GitHub repository contains the example project with all the proposed optimizations. You can download or clone it to perform this test in your environment.
https://github.com/SyncfusionExamples/xamarin.forms-sfchart-performance
Please share your valuable feedback about this article in the comments section below. If you have any specific requirement related to chart performance, you can also contact us through our support forum or Direct-Trac. We are happy to assist you!
If you enjoyed this post, we think you will also like: