【问题标题】:Improving the performance of drawing a huge number of points with help of mschart component借助 mschart 组件提高绘制海量点的性能
【发布时间】:2025-12-21 04:20:20
【问题描述】:

我目前正在开发一个包含多个模块的 Windows 窗体应用程序。其中一位负责绘制生成的模拟数据。情节的想法实际上很简单,但我正在努力有效地渲染数据。

所以我的问题是:

  1. 绘制如此大量数据的最佳方法是什么?
  2. 在位图上绘图是正确的选择吗?
  3. 我是否缺少一个基本的 .net 框架或其他为我提供此功能的框架?

要绘制的点以(时间,位置)形式的列表点提供,即我们有两个轴。

我尝试了以下方法:

我尝试一次绘制所有电梯的点 --> 是资源密集型的,并且在调整大小事件时会重新绘制整个情节。做了两个测试:

  1. 在预定义的视口中绘制整个图,但这不是一个好主意,因为图形变得混乱。
  2. 定义时间和位置有多少像素(例如 1 秒 = 1 像素)并使面板(其中的图片框)可滚动。这比第一个选项效果更好,但如果数据太大会导致内存不足异常。

其他可能的方法:

为绘图定义一个范围(例如 timeRange = 10 分钟),然后只绘制该范围。我想象滚动有问题,因为当用户滚动时,我必须重新定义绘图的起点(范围起点所在的位置)。

非常感谢您的帮助以及任何建议、想法、cmets 等。

编辑:

我尝试了 PatrickTaW 关于使用 MS Chart 的建议。事实上,这是一个更好、更容易的选择,因为到目前为止它作为我的版本被更好地编程。虽然,我提供了几个系列的数据,但我仍然遇到性能问题。也就是说,我有以下问题

  1. 绘制数据大约需要一分钟时间
  2. 放大时(通过启用相应的属性,显示here 和找到的提示here),滚动变慢。如果它可以有点流动,那就太好了......
  3. 我无法或不知道如何缩小!

参考 TaW 的评论(见下文)关于我对大数据的意思的缺失信息 - 要绘制的模拟数据代表几个小时的时间段(例如 2 -3 小时),并且应该以 60 秒的间隔查看。

我的主要问题图表的表现

一些可能有帮助的诊断数据(使用秒表测量 DrawChart 方法,包括其内部步骤):

  • chart1.Series.Clear() 耗时:00:00:00
  • 填充图表 1.Series.Add(...data..) 占用:00:00:03.8230000
  • 配置图表 1 耗时:00:00:03.8240000
  • plotView.DrawChart(points) 拍摄时间:00:00:03.8290000

这告诉我图表模块中的绘图需要很长时间......

感谢您的帮助和时间。

【问题讨论】:

  • 现在_这么大量的数据_到底是什么意思??据我所知,你没有给我们任何数字。查看图表控件(来自工具箱的数据部分)!
  • @TaW:感谢有关缺失数据的提示。我在上面提供了它们(检查:问题的编辑部分)
  • 现在这相当于 10-15k 个数据点,对吧?其中你想看到什么的窗口 - 60??
  • @Rustom 你必须以任何方式一次绘制所有数据吗?
  • @TaW:在我从 xml 文件中加载数据后,确定内存中数据的大小。 xml 文件大小约为 50 MB,模拟数据约为。 3.5 小时(约 62'000 点,时间以 [ms] 为单位,位置以 [m] 为单位)。是的,我想以 60 秒的间隔查看窗口。

标签: c# winforms performance plot mschart


【解决方案1】:

只显示需要的部分无疑是占用资源和时间最少的选项。当然,在您显示的数据点的窗口大小的某个地方有一个收支平衡点,但我想最多几百个点这将是最好的解决方案......

你可以试试这个:

DataPoint[] data60k1 = new DataPoint[60000];
int windowSize = 60;
HScrollBar scroller = new HScrollBar();

private void button14_Click(object sender, EventArgs e)
{
    // creating a few test data..
    for (int i = 0; i < data60k1.Length; i++) data60k1[i] = 
                                              new DataPoint(i, 3 + Math.Sin(i / 100f));

    // set up a HScrollBar:
    chart1.Controls.Add(scroller);
    scroller.Dock = DockStyle.Bottom;
    scroller.Maximum = data60k1.Length - windowSize;
    scroller.LargeChange = windowSize ;
    scroller.Scroll += scroller_Scroll;
    // show first portion..
    scroller_Scroll(null, null);
}

void scroller_Scroll(object sender, ScrollEventArgs e)
{
    chart1.Series[0].Points.Clear();
    for (int i = scroller.Value; i < scroller.Value + windowSize; i++) 
                 chart1.Series[0].Points.Add(data60k1[i]);
}

您可以更改windowSize 来控制放大和缩小。您可以将SmallChange 设置为windowSize 的一部分。

【讨论】:

  • 我创建了一个新项目并测试了您的示例。工作完美!我会将这个想法应用到我的案例中并更新您:) 非常感谢。
  • 非常感谢!它运作良好。不过我不得不稍微扭曲一下,尤其是在滚动时将点添加到系列中的部分。您当前的版本要求这些点是连续的(1..n)。我的观点不是,所以它导致了 IndexOutOfBoundException,我不得不将该部分更改为:if (pointsDict.ContainsKey(i)) { series.Points.Add(new DataPoint(i, pointsDict[i])); }。我明白你只是给我举个例子。所以再次感谢:)
【解决方案2】:

是的,您缺少一个这样做的 .net 组件,在 winforms 中您可以使用只需设置 A Serie 的图表组件(您可以从一系列图表类型中进行选择,包括我认为的点类型是你想要的),他们只插入一次 DataPoints 并让 .net 为你处理工作

【讨论】:

  • 您好帕特里克,感谢您的建议。我试过了,但不幸的是我仍然遇到问题(检查:问题的编辑部分)
【解决方案3】:

我使用托管 DirectX 库来渲染大约 100,000 个点。一点也不坏。在此之前,我尝试了 WPF,这花了很多时间。准确地说,我使用了这个库:http://www.codeproject.com/Articles/113991/Using-Direct-D-with-WPF

【讨论】:

    【解决方案4】:

    当向图表添加 x,y 点时,您可以每 10 个点添加一次。而不是数组中的所有 22.000 个数据。

           int TakeEveryNthPoint = 10;  
           double[] = new double[22000] {}; // your data
    
            for (int i = 0; i < data.Length; i++)
            {
                if (i % TakeEveryNthPoint != 0)
                    continue;
    
                chart1.Series[0].Points.AddXY(i, data[i]);
            }
    

    或者:

    如果您不需要一些低于 阈值水平平均 的值,您可能根本不添加它们。

    但请确保 threadhold 值消除了许多不必要的值,以便您可以看到性能改进

           double[] data = new double[22000] {}; // your data
           int thresholdValue= 10; 
    
           // get top 25%  of points
           int thresholdValueAuto= (data.Avg() + data.Max())/2; 
    
            for (int i = 0; i < data.Length; i++)
            {
                if (data[i] < thresholdValueAuto )
                    continue;
    
                chart1.Series[0].Points.AddXY(i, data[i]);
            }
    

    【讨论】: