25

我写了一个显示财务数据的图表。PathGeometry当我使用withPathFigureLineSegments绘制显示为连接线的少于 10.000 个点时,性能很好。但是现在我需要同时显示多达 100.000 个点(无需滚动),而且 50.000 个点已经很慢了。我在想StreamGeometry,但我不确定,因为它基本上与PathGeometry将信息存储为字节流相同。有没有人有想法让这个性能更高,或者也许有人已经做了类似的事情?

编辑:这些数据点一旦绘制就不会改变,所以如果有可能对其进行优化,请告诉我(线段现在被冻结)。

编辑:我试过 StreamGeometry。由于某种原因,创建图形需要更长的时间,但这不是问题。绘制完所有点后在图表上绘制仍然和以前的方法一样慢。我认为 WPF 需要处理的数据点太多了。

编辑:我做了一些实验,我注意到通过将以前的坐标转换为 int 来防止 WPF 抗锯齿子像素线,性能有所提高。

编辑:感谢所有建议减少线段数量的回复。我已经将它们降低到最多两倍的阶梯线水平分辨率和最多简单线的水平分辨率,现在性能非常好。

4

9 回答 9

19

我会考虑对您尝试渲染的点数进行下采样。您可能有 50,000 个数据点,但不太可能将它们全部显示在屏幕上;即使您在一个显示器上绘制了每个点,您也需要100,000像素的水平分辨率才能将它们全部绘制出来!即使在 D3D 中也有很多东西要画。

由于您更有可能拥有类似 2,048 像素的东西,因此您也可以减少要绘制的点并绘制一条适合屏幕且只有几千个顶点的近似曲线。例如,如果用户绘制一个包含 10000 个点的时间框架,则在绘制图形之前将这 10000 个点下采样到 1000 个。您可以尝试多种技术,从简单平均到中值邻域到高斯卷积到(我的建议)双三次插值绘制任何大于 1/2 屏幕分辨率的点将是一种浪费

当用户放大图形的一部分时,您可以重新采样以获得更高的分辨率和更准确的曲线拟合。

于 2009-06-04T20:13:08.540 回答
6

当您开始处理几何图形中数十万个不同的顶点和向量时,您可能应该考虑迁移图形代码以使用图形框架而不是依赖于 WPF(虽然 WPF 构建在 Direct3D 之上,因此能够非常高效矢量图形渲染,有很多额外的开销会影响其效率)。可以在 WPF 中同时托管 Direct3D 和 OpenGL 图形渲染窗口——我建议改变这个方向,而不是继续单独在 WPF 中工作。

(编辑:将原始答案中的“DirectX”更改为“Direct3D”)

于 2009-06-04T19:48:44.347 回答
5

刚刚遇到这个问题,但正如我在这个线程中提到的,最高效的方法可能是针对 WPF 的 Visual layer 进行编程

WPF 中的一切可视化最终都会违背这一层......因此它是所有这些方法中最轻量级的。

有关更多信息,请参阅。Matthew MacDonald 的C# 2008 中的 Pro WPF的第 14 章也有一个很好的部分。

作为另一个参考......请参阅 Pavan Podila 的WPF Control Development Unleashed一书的第 2 章。在第 13 页,他讨论了 DrawingVisuals 如何成为图表组件的绝佳选择。

最后,我刚刚注意到Charles Petzold写了一篇 MSDN 杂志文章,其中最好的整体(无论如何性能)解决方案(散点图)是 DrawingVisual 方法。

于 2009-09-25T17:55:48.200 回答
5

另一个想法是使用 Image 控件,并将 Source 属性设置为您动态创建的 DrawingImage。

根据 WPF Control Development Unleashed 中的 Pavan Podila 的说法,当您拥有成千上万个不需要任何交互性的视觉效果时,这种方法会非常有用。查看他的书的第 25 页了解更多信息。

这是一个旧线程,但我认为值得一提的是,您可以通过使用 MouseUp() 事件来实现与上述方法的交互性。您知道图像视口的大小、图像的分辨率和鼠标的位置。例如,您可以通过附加到 UserControl_SizeChanged 事件的计时器来维护集合 actualScreenPoints:

    double xworth = viewport.ActualWidth / (XEnd - XStart);
    double xworth = viewport.ActualHeight / (YEnd - YStart);
    List<Point> actualScreenPoints = new List<Point>(); 
    for (var i = 0; i < points.Count; i++)
    {
        double posX = points[i].X * xworth;
        double posY = points[i].Y * yworth;
        actualScreenPoints.Add(posX, posY);
    }

然后当您的 MouseUp() 事件触发时,检查集合中的任何点是否在 +-2px 内。在给定点上有您的 MouseUp。

于 2013-01-18T01:15:16.497 回答
4

我不知道它的扩展性如何,但我在 WPF 中使用 ZedGraph 取得了一些成功(WindowsFormsPresenter 中的 WinForms 控件)。我很惊讶还没有人提到它。即使您不打算将其用于当前项目,也值得一看。

ZedGraph

祝你好运!

于 2009-06-11T19:56:08.090 回答
3

我相信保留在 WPF 框架中的唯一可能更快的方法是在自定义控件中覆盖 OnRender。然后,您可以将几何体直接渲染到持久场景,剔除视野之外的任何东西。如果用户一次只能看到一小部分数据集,那么仅靠剔除就足够了。

有了这么多数据点,当整个数据集都在视图中时,用户不太可能看到完整的细节。因此,考虑简化数据集以获得完整视图,然后在放大时显示更详细的视图也可能是值得的。

编辑:另外,给 StreamGeometry 一个镜头。它存在的全部原因是性能,除非您尝试过,否则您永远不会知道。

于 2009-06-04T19:55:07.423 回答
1

这是一个非常好的问题,它的核心问题是“任何用户都可以实际使用包含 100,000 个离散点的屏幕或从中做出业务决策吗?”。

遵循 GUI 设计理念中的最佳实践,答案应该是No,这会让我质疑是否没有其他方法可以满足应用程序的要求。

如果确实有在屏幕上显示 100,000 个点且不滚动的真实案例,那么使用屏幕外缓冲区是可行的方法。将您的图像合成为位图,然后根据需要将该位图放到您的窗口/页面上。这样繁重的工作只完成一次,之后每次需要绘制窗口时都可以使用硬件加速。

希望这可以帮助。

于 2009-06-11T19:49:52.537 回答
0

我没有使用过 WPF(免责声明),但我怀疑你的性能问题是因为你的代码试图通过你的所有数据拟合一条平滑的曲线,并且所需的时间随着数量的增加而几何(或更糟)增加数据点。

我不知道这在外观上是否可以接受,但尝试通过用直线将每个点连接到最后一个点来绘制数据。这应该使时间到图形与数据点的数量成正比,并且与图形一样多的点最终可能看起来完全一样。

于 2009-06-04T20:12:04.267 回答
0

另一个想法是使用 Image 控件,并将 Source 属性设置为您动态创建的 DrawingImage。

根据WPF Control Development Unleashed中的Pavan Podila的说法,当您拥有成千上万个不需要任何交互性的视觉效果时,这种方法会非常有用。查看他的书的第 25 页了解更多信息。

于 2009-10-17T00:00:14.437 回答