This is a migrated thread and some comments may be shown as answers.

RadCartesianChart DateTimeCategoricalAxis Performance issue

9 Answers 305 Views
ChartView
This is a migrated thread and some comments may be shown as answers.
Damien
Top achievements
Rank 1
Damien asked on 02 Feb 2021, 02:40 PM

I have a rad cartesian chart that displays temperature data that are fed at 1s interval.

 

There are several series. 

After about 5-10min, the UI becomes slow and unresponsive. I've tried several render option, Xaml, Bitmap & Direct2DRenderOptions with Batch mode but it still being an issue.

It doesn't seem to happen using scatter series, but then I cannot format the time label on the C

 

<telerik:RadCartesianChart  VirtualizingPanel.IsVirtualizing="True" Background="White"
            Zoom="{Binding Zoom,UpdateSourceTrigger=PropertyChanged,Mode=TwoWay}"
                                   PanOffset="{Binding PanOffSet,UpdateSourceTrigger=PropertyChanged,Mode=TwoWay}"
            Grid.Column="2"  Grid.Row="1"  x:Name="TemperaturelineChart" HorizontalAlignment="Stretch" 
                                    VerticalAlignment="Stretch" EmptyContent="Waiting Data...&#xD;&#xA;">

        <telerik:RadCartesianChart.Resources>
                <Style TargetType="telerik:PanZoomBar">
                    <Setter Property="Visibility" Value="{Binding IsScrollbarVisible}"/>
                </Style>

                </telerik:RadCartesianChart.Resources>

            <telerik:RadCartesianChart.Series>
                <telerik:LineSeries>
                    <telerik:LineSeries.RenderOptions>
                        <telerik:Direct2DRenderOptions DefaultVisualsRenderMode="Batch"/>
                    </telerik:LineSeries.RenderOptions>
                </telerik:LineSeries>
            </telerik:RadCartesianChart.Series>

            <telerik:RadCartesianChart.HorizontalAxis >

                <telerik:DateTimeCategoricalAxis LabelRotationAngle="90" SmartLabelsMode="SmartStep"
                                                 MajorTickInterval="10" LabelFormat="HH:mm">

                   
                    </telerik:DateTimeCategoricalAxis>

            </telerik:RadCartesianChart.HorizontalAxis>
            
            
            <telerik:RadCartesianChart.VerticalAxis >
                <telerik:LinearAxis  SmartLabelsMode="SmartStep" Minimum="0" Maximum="{Binding ElementName=Slider, Path=Value, Mode=OneWay}">
                </telerik:LinearAxis>
              
            </telerik:RadCartesianChart.VerticalAxis>
            
            
            <telerik:RadCartesianChart.Behaviors>
                <telerik:ChartPanAndZoomBehavior ZoomMode="Both" />
            </telerik:RadCartesianChart.Behaviors>
            <telerik:RadCartesianChart.InputBindings>
                <MouseBinding Command="{Binding ZoomResetCommand}" MouseAction="RightClick"/>
            </telerik:RadCartesianChart.InputBindings>
        </telerik:RadCartesianChart>
    </Grid>
</commonUtilities:BasePaneView>

 

 

Points added as:

 

            CategoricalDataPoint point = new CategoricalDataPoint
            {
                Label = time,
                Value = Temperature,
                Category = time
            };


            Serie.DataPoints.Add(point);

 

How can I improve performances?

9 Answers, 1 is accepted

Sort by
0
Dinko | Tech Support Engineer
Telerik team
answered on 05 Feb 2021, 10:17 AM

Hi Damien,

Thank you for the provided code snippet.

Looking at the code, the DataPoints collection is populated directly with CategoricalDataPoint. I would suggest avoiding using such a method. The best way is to populate the series using MVVM. You can check the Create Data-Bound Chart help article which describes this approach with code snippets.

Give it a try and let me know if the performance improves. 

Regards,
Dinko
Progress Telerik

Virtual Classroom, the free self-paced technical training that gets you up to speed with Telerik and Kendo UI products quickly just got a fresh new look + new and improved content including a brand new Blazor course! Check it out at https://learn.telerik.com/.

0
Damien
Top achievements
Rank 1
answered on 05 Feb 2021, 11:17 AM

Hi Dinko,

Thank you for your suggestion.

The example pointed shows the binding for one serie, however, I have multiple series.

The amount of series is not known in advance and some can be added / removed or hidden on the fly.

Do you have an example for binding in such situation ? I suppose it would need something like ObservableCollection<ObservableCollection<DataPoint>> ?

And the binding:

<telerik:RadCartesianChart.Series CategoryBinding="Name" ValueBinding="QuantitySold" ItemsSource="{Binding Series}"

</telerik:RadCartesianChart.Series>

 

Is that possible?

Thanks

0
Dinko | Tech Support Engineer
Telerik team
answered on 05 Feb 2021, 01:05 PM

Hello Damien,

Yes, this is possible. When you have a dynamic number of series, you can use the ChartSeriesProvider functionality of the chart. You can check the corresponding article, which describes how you can set-up the chart.

Give this article a try, and let me know if further guidance is required.

Regards,
Dinko
Progress Telerik

Virtual Classroom, the free self-paced technical training that gets you up to speed with Telerik and Kendo UI products quickly just got a fresh new look + new and improved content including a brand new Blazor course! Check it out at https://learn.telerik.com/.

0
Damien
Top achievements
Rank 1
answered on 05 Feb 2021, 03:34 PM

Hi Dinko,

 

Thanks, I have implemented accordingly and it works. However the performance seems fairly similar as the previous method.

 

<telerik:RadCartesianChart  VirtualizingPanel.IsVirtualizing="True" Background="White"
            Zoom="{Binding Zoom,UpdateSourceTrigger=PropertyChanged,Mode=TwoWay}"
            PanOffset="{Binding PanOffSet,UpdateSourceTrigger=PropertyChanged,Mode=TwoWay}"
            Grid.Column="2"  Grid.Row="1"  x:Name="TemperaturelineChart" HorizontalAlignment="Stretch" 
            VerticalAlignment="Stretch" EmptyContent="Waiting Data...&#xD;&#xA;"
                                    >

            <telerik:RadCartesianChart.Series>
                <telerik:LineSeries>
                    <telerik:LineSeries.RenderOptions>
                        <telerik:Direct2DRenderOptions DefaultVisualsRenderMode="Batch"/>
                    </telerik:LineSeries.RenderOptions>
                </telerik:LineSeries>
            </telerik:RadCartesianChart.Series>

            <telerik:RadCartesianChart.HorizontalAxis >

                <telerik:DateTimeCategoricalAxis LabelRotationAngle="90" SmartLabelsMode="SmartStep"
                                                 MajorTickInterval="10" LabelFormat="HH:mm">

 
                    </telerik:DateTimeCategoricalAxis>

            </telerik:RadCartesianChart.HorizontalAxis>
            
            <telerik:RadCartesianChart.SeriesProvider>
                <telerik:ChartSeriesProvider Source="{Binding Series}">
                    <telerik:ChartSeriesProvider.SeriesDescriptors>
                        <telerik:CategoricalSeriesDescriptor CategoryPath="Category"  
                                                        ValuePath="Value"  
                                                        ItemsSourcePath="Items"
                                                             >
                            <telerik:CategoricalSeriesDescriptor.Style>
                                <Style TargetType="telerik:LineSeries">
                                    <Setter Property="StrokeThickness" Value="1" />
                                    <Setter Property="Visibility" Value="{Binding Visibility,UpdateSourceTrigger=PropertyChanged}" />
                                    <Setter Property="Stroke" Value="{Binding Color,UpdateSourceTrigger=PropertyChanged}" />
                                </Style>
                            </telerik:CategoricalSeriesDescriptor.Style>
                        </telerik:CategoricalSeriesDescriptor>

                    </telerik:ChartSeriesProvider.SeriesDescriptors>
                </telerik:ChartSeriesProvider>
            </telerik:RadCartesianChart.SeriesProvider>
        
        </telerik:RadCartesianChart>

0
Dinko | Tech Support Engineer
Telerik team
answered on 08 Feb 2021, 10:49 AM

Hello Damien,

Thank you for the provided code snippet.

You can check the following suggestions:

        1. Make sure there are no infinitely measured bounds

From the code snippet, I can see that the chart is placed inside a Grid. If you have the charts inside controls that measure to infinity (StackPanel, ScrollView, Auto-sized Grid Row/ColumnDefinitions, etc.). it will affect UI virtualization and cause significant rendering problems.

To eliminate this as a cause, give the RadChartViews a definitive Height and Width. If this improves things, then reconsider the parent elements or keep the explicit dimensions. I recommend star-sized Row/ColumnDefinitions because you can resize the charts and the window size changes (e.g. Width="*").

        2. Remove old data points from the ItemsSource as new ones come in.

In your first post, you mentioned that new data is coming every 1 second. In this case, you can consider removing the oldest data, which is not up-to-date anymore, while the new one arrives.

        3. Decrease data point density

There is only so far the human eye can distinguish a certain number of items within a certain density. Having 1000 data points that look the same as 10 data points is only wasting memory, and the app performance may suffer. In this case, you can use the Data Sampling functionality of the chart.

Give the above approaches a try, and let me know if you were able to increase the performance of the control.

Regards,
Dinko
Progress Telerik

Virtual Classroom, the free self-paced technical training that gets you up to speed with Telerik and Kendo UI products, quickly just got a fresh new look + new and improved content, including a brand new Blazor course! Check it out at https://learn.telerik.com/.

0
Damien
Top achievements
Rank 1
answered on 08 Feb 2021, 12:07 PM

Hi Dinko,

Thank you for your suggestions.

Points that are more than 2h old (means 3600*2) are already removed.

For the bounds, It seems to have improved the performances quite a bit. Maybe that should be included in the documentation. A general chart optimization page would be handy.

Before it was noticeably freezing after 2-3 minutes (few hundred points) and after 20~ minutes it was freezing so much that it actually created software issues.

After the bound set, after 15min the software becomes noticeably laggy (equivalent to 2-3 minutes before).

Parent Grid is currently set as follow, char has auto as its width and height:

        <Grid Height="auto" Width="auto">

        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="auto"></ColumnDefinition>
            <ColumnDefinition Width="auto" ></ColumnDefinition>
            <ColumnDefinition Width="*" ></ColumnDefinition>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"></RowDefinition>
            <RowDefinition Height="*"></RowDefinition>
        </Grid.RowDefinitions>

 

Can I use the samplingThreshold with the SeriesProvider ? I haven't find a way to do it.

Concerning data density, you are right, there is so many point eye can see, but reducing density also means reducing the refresh rate. For now I've set to only include point every 10 seconds. While this works, it's far from the best solution as the first few minutes only a few points are there, on a UI perspective it is not ideal.

Overall, a charting lib should be able to handle datasets with a few thousands of points easily in our days. (I'm running a quadcore I7).

0
Martin Ivanov
Telerik team
answered on 11 Feb 2021, 10:52 AM

Hello Damien,

My name is Martin and I am stepping in on the behalf of Dinko who is out of the office today. 

The chart should be able to easily handle situations with few thousands data points, especially with the Direct2D or the Bitmap render options. This said, can you please elaborate a bit more on your scenario by answering the following questions:

  • How many data points are added/removed at each tick of the timer (on each 1s)?
  • How many data points you have around the time when the chart freezes?
  • Is there any chance that you are using PointTemplate? If so, please remove it and see how is the performance.
  • Would it be possible to send over a runnable project showing the issue? This will allow us to test it locally and give you more concrete information about the performance and how to optimize it.

Also, you can check the 5 Easy Steps Towards a Fast Chart blog post on the chart's performance optimizations.

For the sampling feature and SeriesProvider you can check the CharSeriesProvider documentation. Basically, to use the ChartDataSource with the provider, you can set the ChartDataSourceStyle property of the series descriptor.

<telerik:CategoricalSeriesDescriptor.ChartDataSourceStyle> 
	<Style TargetType="telerik:ChartDataSource"> 
		<Setter Property="SamplingThreshold" Value="1" /> 
	</Style> 
</telerik:CategoricalSeriesDescriptor.ChartDataSourceStyle> 

Please try this and let me know how it goes.

Regards,
Martin Ivanov
Progress Telerik

Virtual Classroom, the free self-paced technical training that gets you up to speed with Telerik and Kendo UI products quickly just got a fresh new look + new and improved content including a brand new Blazor course! Check it out at https://learn.telerik.com/.

0
Damien
Top achievements
Rank 1
answered on 15 Feb 2021, 08:33 AM

Dear Martin,

 

Thank you for your reply.

- Each second, 1 single point is added on each serie (15-20) can be added. Note that they are not specifically synchronized together. 

- Pretty fast, after about 100-200 points on a serie.

- I'm not using point template. The XAML code is as previously posted.

- I could try to make a project, however, this is quite the basic implementation as I already posted the Xaml, on the C# level the only thing done is adding the points to the serie.

 

I tried the SamplingThreshold at a value of 5 and it did not seem to make any difference.

 

Furthermore, I noticed some axis error (chart attached). It might be related to the sampling Threshold. 

0
Martin Ivanov
Telerik team
answered on 16 Feb 2021, 01:06 PM

Hello Damien,

Thank you for the additional information. Can you also tell me what is the maximum number of data points expected to be plotted in the chart? Also, what is the number of data points when the application freezes?

Regards,
Martin Ivanov
Progress Telerik

Virtual Classroom, the free self-paced technical training that gets you up to speed with Telerik and Kendo UI products quickly just got a fresh new look + new and improved content including a brand new Blazor course! Check it out at https://learn.telerik.com/.

Damien
Top achievements
Rank 1
commented on 01 Sep 2022, 09:45 PM

Hi, per second sampling on 16 items for 3 hours for instance would yield 3*16*3600 -> 172'000 points.

Whilst we may not want to display update all points, at all time, it would be good to have some display down sampling abilities to limit the required processing power of the chart, whilst maintaining the ability to zoom in down to specific datapoint.

Dilyan Traykov
Telerik team
commented on 06 Sep 2022, 12:22 PM

Hi Damien,

Thank you for the clarification.

Can you, however, demonstrate how exactly you've set up the data sampling in a small sample project where the UI freeze is noticeable? I would then gladly profile the application and try to suggest possible optimizations for your particular setup.

On a side note, in one of your previous replies you mentioned some axis errors being shown, however, I did not see any errors in the attached image. Can you please elaborate on what these errors are?
Tags
ChartView
Asked by
Damien
Top achievements
Rank 1
Answers by
Dinko | Tech Support Engineer
Telerik team
Damien
Top achievements
Rank 1
Martin Ivanov
Telerik team
Share this question
or