简体   繁体   English

如何快速将数据点添加到 WPF 图表

[英]How To Add Data Points Fast To A WPF Chart

Hello I have a big database from where I take like 1500 values in order to show in a chart.您好,我有一个大数据库,我从中获取 1500 个值以便在图表中显示。

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:这是我的观点的显示方式:

制图

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.我知道这是一个较老的问题,但我想分享我对 WPF 中图表的想法,而不仅仅是绘制一些条形图或散点或线。

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.可能每个人都同意股票 WPF 库不是构建的,并且在图表方面旨在处理数千甚至数百万个数据点。 Whatever workarounds I tried such as data sampling, I was never really satisfied with stock WPF charting capabilities.无论我尝试过什么变通方法(例如数据采样),我都对现有的 WPF 图表功能感到不满意。 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.如果您正在绘制数据图表,而不仅仅是作为一次性原型制作的追求,我强烈建议您查看专业的 WPF 图表库。

I have in particular used Scichart , a third party vendor WPF library, for many years and cannot speak highly enough of its capabilities.多年来,我特别使用了第三方供应商 WPF 库Scichart ,并且对其功能评价不够高。 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.我经常绘制数十万,有时甚至数百万的散点数据点,最近还用大量数据渲染了 3D 图表,发现 Scichart 的性能非常好。 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 2D 和 3D 库是坚如磐石的,我的意思是渲染性能非常出色,绑定可以正常工作,几乎任何东西都可以定制,完整的 MVVM 支持

  • The documentation and support forum are probably the best part of what Scichart has to offer.文档和支持论坛可能是 Scichart 提供的最好的部分。 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.特别是对于您的问题,使用 Scichart,您只需通过绑定或直接将数据集一次性添加为数组,并在几毫秒内呈现。 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.我尝试使用 DevExpress 绘制图表,我也拥有许可证,它们的图表功能超过了几个数据点,而且他们的图表更适合数据点少的仪表板。 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.我还尝试并使用了一段时间Arction 的闪电图库,虽然原始性能与 Scichart 相当,但它们的样式绝对是可怕的,它们的 MVVM 功能几乎不存在,事实上,当您查看他们的文档时,您会看到许多解决问题的建议都在后面的代码中提出。 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.老实说,如果你只看 1500 个数据点的图表并拥有 DevExpress 许可证,那么一定要使用它们,因为我认为它们仍然可以处理 1500 个点,尽管更多可能会变得棘手。 But if you ever see the need for charting capabilities of larger data sets then I can't speak of Scichart highly enough.但是,如果您看到对更大数据集的图表功能的需求,那么我对 Scichart 的评价就不够高了。 Why?为什么? Because I worked with that library since early version 1.3.x.xxxx.因为我从早期版本 1.3.x.xxxx 开始就使用该库。 I truly believe they are the best charting library out there in WPF space.我真的相信它们是 WPF 领域中最好的图表库。

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:一次添加它们可以解决这个问题:

在此处输入图像描述

Extend ObservableCollection to support AddRange , as shown HERE :扩展ObservableCollection以支持AddRange ,如下所示

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);
    }

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.如果您的主要优先级是折线图并且您考虑切换到第三方组件供应商,您可以考虑 DevExpress ChartControl 作为合适的选择。

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).例如,最新版本的 DevExpress 组件附带“大数据源”演示模块,其中可以显示多达 500K 点而不会显着降低性能(这包括滚动和缩放等交互操作)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM