1

Hello I have a big database from where I take like 1500 values in order to show in a chart.

My issues is that it takes a long time to display all the points, I think is because of animation settings.

How can I change the speed of the animation or is there a way to display the points faster?

<UserControl x:Class="Ipte.UI.Pages.StatisticsPage"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:gcl="clr-namespace:GuiControlLibrary;assembly=GuiControlLibrary"
        xmlns:toolkit="http://schemas.microsoft.com/wpf/2008/toolkit"
             xmlns:time="clr-namespace:Ipte.UI"
        xmlns:chartToolkit="clr-namespace:System.Windows.Controls.DataVisualization.Charting;assembly=System.Windows.Controls.DataVisualization.Toolkit"
        mc:Ignorable="d"
        Height="800" Width="1200">
    <UserControl.Resources>
        <Style x:Key="Scater" TargetType="chartToolkit:ScatterDataPoint">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="chartToolkit:ScatterDataPoint">
                        <Viewbox x:Name="viewbox">
                            <!--<Ellipse Width="1" Height="1" Fill="Black"/>-->
                        </Viewbox>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
            <Setter Property="Width" Value="4"/>
            <Setter Property="Height" Value="4"/>
        </Style>
    </UserControl.Resources>
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>
        <Grid x:Name="filterGrid" Grid.Column="0" Margin="4">
            <StackPanel>
                <TextBlock Text="" Margin="2"/>
                <toolkit:DatePicker x:Name="dpStartDate" Margin="2" />
                <time:TimePicker x:Name="tpStartTime" Margin="2"/>             
                <TextBlock Text="End date &amp; time:" Margin="2"/>
                <toolkit:DatePicker x:Name="dpEndDate" Margin="2"/>
                <time:TimePicker x:Name="tpEndTime" Margin="2"/>

                <gcl:GuiGroupBox Header="Select router" BorderBrush="LightGray">
                    <UniformGrid Rows="2" Columns="2">
                        <CheckBox x:Name="cbEr11" Content="ER 1.1" Margin="2"/>
                        <CheckBox x:Name="cbEr12" Content="ER 1.2" Margin="2"/>
                        <CheckBox x:Name="cbEr21" Content="ER 2.1" Margin="2"/>
                        <CheckBox x:Name="cbEr22" Content="ER 2.1" Margin="2"/>
                    </UniformGrid>
                </gcl:GuiGroupBox>
                <TextBlock Text="" Margin="2"/>
                <ComboBox x:Name="cmbGoodBad" Margin="2"/>
                <TextBlock Text="" Margin="2"/>
                <TextBox x:Name="" Margin="2"/>
                <TextBlock Text="" Margin="2"/>
                <TextBox x:Name="" Margin="2"/>
                <gcl:GuiGroupBox Header="Select value" BorderBrush="LightGray">
                    <StackPanel>
                        <RadioButton x:Name="combValueA" Content="Value A" Margin="2"/>
                        <RadioButton x:Name="combValueB" Content="Value B" Margin="2"/>
                        <RadioButton x:Name="combValueC" Content="Value C" Margin="2"/>
                    </StackPanel>
                </gcl:GuiGroupBox>
                <Button x:Name="btnResetFilters" Content="Reset filters" Margin="2 10 2 2" Click="ResetFilters_Click"/>
                <Button x:Name="btnUpdateChart" Content="Update Chart" Margin="2 2 2 2" Click="UpdateChartAndFilters_Click"/>
                <Button x:Name="btnLoadFile" Content="Load file..." Grid.Column="0" VerticalAlignment="Top" Margin="2" Visibility="Visible" Click="OpenFile_Click"/>
            </StackPanel>
            <Button x:Name="deleteDatabase" Content="Delete database" Grid.Column="0" VerticalAlignment="Bottom" Margin="2" Click="deleteDatabase_Click"/>
        </Grid>
        <chartToolkit:Chart Grid.Column="1" x:Name="dataChart">
            <chartToolkit:Chart.Series>
                <chartToolkit:ScatterSeries x:Name="scatterSeries"
                                        ItemsSource="{Binding}"
                                        DependentValueBinding="{Binding Path=Value}"
                                        IndependentValueBinding="{Binding Path=Key}" 
                                        IsSelectionEnabled="False"
                                           AnimationSequence="Simultaneous">
                    <chartToolkit:ScatterSeries.IndependentAxis>
                        <chartToolkit:DateTimeAxis Orientation="X" Title="Time"/>
                    </chartToolkit:ScatterSeries.IndependentAxis>
                    <chartToolkit:ScatterSeries.DependentRangeAxis>
                        <chartToolkit:LinearAxis Orientation="Y" Title="Points" x:Name="yAxis"/>
                    </chartToolkit:ScatterSeries.DependentRangeAxis>
                </chartToolkit:ScatterSeries>
                <chartToolkit:LineSeries x:Name="lineSeriesMax"
                                         Title="Maximum"
                                         ItemsSource="{Binding}"
                                         DependentValueBinding="{Binding Path=Value}"
                                         IndependentValueBinding="{Binding Path=Key}">
                </chartToolkit:LineSeries>
                <chartToolkit:LineSeries x:Name="lineSeriesMin"
                                         Title="Minimum"
                                         ItemsSource="{Binding}"
                                         DependentValueBinding="{Binding Path=Value}"
                                         IndependentValueBinding="{Binding Path=Key}">
                </chartToolkit:LineSeries>
                <chartToolkit:LineSeries x:Name="lineSeriesAvg"
                                         Title="Average"
                                         ItemsSource="{Binding}"
                                         DependentValueBinding="{Binding Path=Value}"
                                         IndependentValueBinding="{Binding Path=Key}">
                </chartToolkit:LineSeries>
            </chartToolkit:Chart.Series>
        </chartToolkit:Chart>
    </Grid>
</UserControl>

This is the way my points are displayed:

Charting

jsanalytics
  • 13,058
  • 4
  • 22
  • 43
thiseful
  • 57
  • 7
  • Can you provide the way you're databinding is working (viewmodel etc.), and how you populate your data please? – TripleEEE Dec 07 '16 at 12:50
  • the data is taken from a Sqllite database and it is put in 4 ObservableCollection> in order to display it – thiseful Dec 07 '16 at 13:14
  • Do you add your data with `.Add(x)` or do you use `.AddRange(List)`? I think `ObservableCollection` will throw an `CollectionChangedEvent` (subscribe and test this!) on every point added, which will lead to render operations - you should deactivate this Information (derive and supress Eventcall with bool flag) if this happens and just throw the Information on last item added. – TripleEEE Dec 07 '16 at 13:22
  • the Event is thrown at the last item added in the list – thiseful Dec 07 '16 at 14:35

3 Answers3

6

I know this is an older question but I wanted to share my thoughts on charting in WPF that goes beyond just plotting a few bars or scatter points or lines.

Probably everyone agrees that the stock WPF library was not built and intended to handle many thousands or even millions of datapoints when it comes to charting. Whatever workarounds I tried such as data sampling, I was never really satisfied with stock WPF charting capabilities. If you are working to chart data other than just as a one-time prototyping pursuit I highly recommend you to look at a professional WPF charting library.

I have in particular used Scichart, a third party vendor WPF library, for many years and cannot speak highly enough of its capabilities. I often chart hundreds of thousands, sometimes millions of scatter data points and most recently also rendered 3D charts with tons of data and find Scichart highly performant. It costs more than "free" but I find the investment more than worth it because (and I try to incorporate your questions here):

  • The 2D and 3D libraries are rock solid, what I mean with that is that rendering performance is stellar, bindings just work, virtually anything can be customized, full MVVM support

  • The documentation and support forum are probably the best part of what Scichart has to offer. Most questions, even trickier ones are addressed already and if something can't be found then other users or the support team respond in a timely fashion.

  • In particular to your question, with Scichart you simply add the dataset all at once as array via binding or directly and it renders within milliseconds. Its real-time capabilities are also amazing if you need to add data points one by one.

I strongly suggest you give them a try, they offer a trial license. I tried charting with DevExpress, of which I also own a license, and their charting capabilities top out beyond a few datapoints and their charts are imho better suited for dashboards with few data points. I also tried and used Arction's lightningchart library for a while and while raw performance was on par with Scichart, their styling is absolutely horrific, their MVVM capabilities are all but non existent, in fact when you take a look at their documentation you see that a lot of solution suggestions to problems are presented in code behind. Their support forum and Q&A repository is also very sparsely populated, something that usually really turns me off because at some point every developer will encounter issues he/she needs to look up for a solution.

To be honest, if you only look to chart 1500 data points and have a DevExpress license then by all means, use them, because I think they can still handle 1500 points, though more might become tricky. But if you ever see the need for charting capabilities of larger data sets then I can't speak of Scichart highly enough. Why? Because I worked with that library since early version 1.3.x.xxxx. I truly believe they are the best charting library out there in WPF space.

Matt
  • 7,004
  • 11
  • 71
  • 117
  • It is a good library but depending on the project, a minimum of 1000 Euro per developer is a sharp price tag for plotting just 1500 data points. – mcy Mar 26 '19 at 11:17
  • @mcy, hence my saying if you only work with 1500 or so data points then there are other solutions. Quality costs money. And for the features and performance Scichart provides the price is more than justified imho. – Matt Mar 27 '19 at 06:55
2

What contributes the most to slow down your chart is all the events generated to draw your series point-by-point as they are added to the view model collection. Adding them all at once solves that problem:

enter image description here

Extend ObservableCollection to support AddRange, as shown HERE:

public class ObservableCollectionRange<T> : ObservableCollection<T>
{
    public void AddRange(IEnumerable<T> items)
    {
        this.CheckReentrancy();
        foreach (var item in items)
            this.Items.Add(item);
        this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
    }
}

And then use it in your view model:

public class MyViewModel
{
    public ObservableCollectionRange<KeyValuePair<double, double>> Power { get; set; }
    public ObservableCollectionRange<KeyValuePair<double, double>> PowerAvg { get; set; }

    public MyViewModel()
    {
        Power = new ObservableCollectionRange<KeyValuePair<double, double>>();
        PowerAvg = new ObservableCollectionRange<KeyValuePair<double, double>>();
    }

    public void Add(double x, double y)
    {
        Power.Add(new KeyValuePair<double, double>(x, y));
        
        double xmin = Power.Min(kvp => kvp.Key);
        double xmax = Power.Max(kvp => kvp.Key);

        double ymin = Power.Min(kvp => kvp.Value);
        double ymax = Power.Max(kvp => kvp.Value);
        double yavg = Power.Average(kvp => kvp.Value);

        PowerAvg.Clear(); 
        PowerAvg.Add(new KeyValuePair<double, double>(xmin, yavg));
        PowerAvg.Add(new KeyValuePair<double, double>(xmax, yavg));
    }

    public void AddRange(IEnumerable<KeyValuePair<double, double>> items)
    {
        Power.AddRange(items);

        double xmin = Power.Min(kvp => kvp.Key);
        double xmax = Power.Max(kvp => kvp.Key);

        double ymin = Power.Min(kvp => kvp.Value);
        double ymax = Power.Max(kvp => kvp.Value);
        double yavg = Power.Average(kvp => kvp.Value);

        PowerAvg.Clear();
        PowerAvg.Add(new KeyValuePair<double, double>(xmin, yavg));
        PowerAvg.Add(new KeyValuePair<double, double>(xmax, yavg));
    }
}

And at button click event:

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        ShowPoints();
    }

    private void ShowPoints()
    {
        Random random = new Random();
        ObservableCollection<KeyValuePair<double, double>> oc = new ObservableCollection<KeyValuePair<double, double>>();

        for (int i = 1; i <= 1500; i++)
            oc.Add(new KeyValuePair<double, double>(i, random.NextDouble()));

        vm.AddRange(oc);
    }
General Grievance
  • 4,555
  • 31
  • 31
  • 45
jsanalytics
  • 13,058
  • 4
  • 22
  • 43
0

If your main priority is Line charts and you consider switching to a third-party component vendor, you may consider DevExpress ChartControl as a suitable option.

For instance, the latest version of DevExpress components ships with the "Large Datasource" demo module, where up to 500K points can be shown without major performance degradation (this includes interactive operations such as scrolling and zooming).

AlexK
  • 128
  • 5