Самый эффективный способ построения графиков тысяч точек данных с помощью WPF? - PullRequest
23 голосов
/ 04 июня 2009

Я написал диаграмму, которая отображает финансовые данные. Производительность была хорошей, когда я рисовал менее 10.000 точек, отображаемых в виде соединенной линии, используя PathGeometry вместе с PathFigure и LineSegment s. Но теперь мне нужно отобразить до 100 000 точек одновременно (без прокрутки), и это уже очень медленно с 50 000 точек. Я думал о StreamGeometry, но я не уверен, так как это в основном то же самое, что PathGeometry выводит информацию как поток байтов. У кого-нибудь есть идея сделать это намного более производительным, или, может быть, кто-то уже сделал что-то подобное?

РЕДАКТИРОВАТЬ: Эти точки данных не меняются после рисования, поэтому, если есть потенциал для его оптимизации, пожалуйста, дайте мне знать (отрезки линий сейчас заморожены).

РЕДАКТИРОВАТЬ: я пытался StreamGeometry. По какой-то причине создание графики заняло еще больше времени, но это не проблема. Рисование на графике после рисования всех точек по-прежнему происходит так же медленно, как и в предыдущем методе. Я думаю, что для WPF слишком много точек данных.

РЕДАКТИРОВАТЬ: Я немного поэкспериментировал и заметил, что производительность немного улучшилась за счет преобразования координат, которые ранее были в двойные, в int, чтобы предотвратить сглаживание субпиксельных линий WPF.

РЕДАКТИРОВАТЬ: Спасибо за все ответы, предлагающие уменьшить количество отрезков. Я уменьшил их до не более чем в два раза горизонтального разрешения для ступенчатых линий и не более чем до горизонтального разрешения для простых линий, и производительность сейчас довольно хорошая.

Ответы [ 9 ]

17 голосов
/ 05 июня 2009

Я бы посчитал, что нужно уменьшить количество точек, которые вы пытаетесь отрисовать. У вас может быть 50000 точек данных, но вы вряд ли сможете разместить их все на экране; даже если вы наметили каждую точку на одном экране, вам понадобится 100 000 пикселей с горизонтальным разрешением, чтобы нарисовать их все! Даже в D3D много рисовать.

Поскольку у вас больше шансов получить что-то вроде 2048 пикселей, вы также можете уменьшить точки, которые вы рисуете, и нарисовать приблизительную кривую, которая умещается на экране и имеет всего пару тысяч верт. Если, например, пользователь строит график времени, включающий 10000 точек, то перед построением графика уменьшите эти 10000 точек до 1000. Есть множество методов, которые вы можете попробовать, от простого усреднения до срединного соседа до гауссовой свертки до (мое предложение) бикубической интерполяции . Рисование любого количества точек, больше половины разрешения экрана, будет просто пустой тратой .

Когда пользователь увеличивает часть графика, вы можете выполнить повторную выборку, чтобы получить более высокое разрешение и более точное подгонку кривой.

6 голосов
/ 04 июня 2009

Когда вы начинаете работать с сотнями тысяч различных вершин и векторов в вашей геометрии, вам, вероятно, следует подумать о переносе графического кода для использования графического фреймворка вместо зависимости от WPF (который, хотя и построен на основе Direct3D и поэтому способен удивительно эффективного рендеринга векторной графики, имеет много дополнительных затрат, что снижает его эффективность). В WPF можно размещать как графические окна Direct3D, так и OpenGL - я бы предложил двигаться в этом направлении, а не продолжать работать только в WPF.

(РЕДАКТИРОВАТЬ: изменил "DirectX" в исходном ответе на "Direct3D")

5 голосов
/ 18 января 2013

Другая идея заключается в использовании элемента управления Image со свойством Source, для которого установлено DrawingImage, которое вы динамически создали.

По словам Павана Подила из публикации WPF Control Development Unleashed, этот подход может быть очень полезным, когда у вас есть тысячи и тысячи визуальных элементов, которые не нуждаются в интерактивности. Проверьте страницу 25 его книги для получения дополнительной информации.

Это старый поток, но я подумал, что стоит упомянуть, что вы могли бы достичь интерактивности с помощью вышеуказанного метода, используя событие MouseUp (). Вы знаете размер области просмотра изображения, разрешение изображения и положение мыши. Например, вы можете поддерживать коллекцию actualScreenPoints с помощью таймера, присоединенного к вашему событию UserControl_SizeChanged:

    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 на данный момент.

4 голосов
/ 25 сентября 2009

Просто столкнулся с этим вопросом, но, как я упоминал в этом потоке, , наиболее эффективный подход может заключаться в программировании на визуальном уровне WPF .

Все визуальное в WPF в конечном итоге идет вразрез с этим слоем ... и поэтому это самый легкий подход из всех.

См. это и это для получения дополнительной информации. Глава 14 книги Мэтью Макдональда Pro WPF в C # 2008 также содержит хороший раздел.

В качестве еще одной ссылки ... см. Главу 2 книги Павана Подила Разработка управления WPF развернута . На странице 13 он обсуждает, как DrawingVisuals будет отличным выбором для компонента построения диаграмм.

Наконец, я только что заметил, что Чарльз Петцольд написал статью MSDN Magazine , где лучшим общим решением (в любом случае) (для точечной диаграммы) был подход DrawingVisual.

4 голосов
/ 11 июня 2009

Я не знаю, насколько хорошо он масштабируется, но я добился определенного успеха, используя ZedGraph в WPF (элемент управления WinForms внутри WindowsFormsPresenter). Я удивлен, что никто еще не упомянул это. На это стоит взглянуть, даже если вы не планируете использовать его для своего текущего проекта.

ZedGraph

Удачи!

3 голосов
/ 04 июня 2009

Я считаю, что единственный способ, который может быть быстрее, оставаясь в платформе WPF, - это переопределить OnRender в пользовательском элементе управления. Затем вы можете визуализировать вашу геометрию непосредственно в сохраняемой сцене, отбраковав что-либо вне поля зрения. Если пользователь может видеть только небольшую часть набора данных одновременно, отбраковка может быть достаточной сама по себе.

При таком количестве точек данных маловероятно, что пользователь сможет увидеть полную информацию, когда весь набор данных находится в поле зрения. Поэтому, возможно, также стоит подумать об упрощении набора данных для полного просмотра и последующем отображении более подробного представления, если и когда они увеличатся.

Редактировать: Кроме того, дать StreamGeometry выстрел. Вся причина существования - производительность, и вы никогда не узнаете, пока не попробуете.

1 голос
/ 11 июня 2009

Это очень хороший вопрос, и в его сердце напрашивается вопрос: «Может ли любой пользователь использовать экран, содержащий 100 000 дискретных точек, на практике или по своему усмотрению?».

Следуя передовой практике в области разработки графического интерфейса, ответ должен быть Нет , что заставит меня задуматься о том, не существует ли другого способа удовлетворить требования к приложению.

Если действительно есть правдоподобный случай для отображения 100 000 точек на экране без прокрутки, тогда использование внеэкранного буфера - путь. Скомпонуйте свое изображение в растровое изображение, а затем добавьте это растровое изображение на свое окно / страницу по мере необходимости. Таким образом, тяжелый подъем выполняется только один раз, после чего аппаратное ускорение можно использовать каждый раз, когда нужно нарисовать окно.

Надеюсь, это поможет.

0 голосов
/ 17 октября 2009

Другая идея - использовать элемент управления Image со свойством Source, для которого установлено DrawingImage, которое вы динамически создали.

Согласно Павану Подиле в Разработка управления WPF , этот подход может быть очень полезным, когда у вас есть тысячи и тысячи визуальных элементов, которые не нуждаются в интерактивности. Проверьте страницу 25 его книги для получения дополнительной информации.

0 голосов
/ 05 июня 2009

Я не работал с WPF (заявление об отказе от ответственности), но я подозреваю, что ваша проблема с производительностью связана с тем, что ваш код пытается разместить плавную изогнутую линию на всех ваших данных, а требуемое время увеличивается геометрически (или хуже) с количество точек данных.

Я не знаю, будет ли это приемлемым с точки зрения внешнего вида, но попробуйте отобразить ваши данные, соединив каждую точку с последней прямой линией. Это должно привести к тому, что время на графике будет пропорционально количеству точек данных, и при таком количестве точек, которое у вас есть, график может в конечном итоге выглядеть одинаково.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...