Подтвердить что ты не робот

Самый эффективный способ построения тысяч точек данных с помощью WPF?

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

EDIT: эти точки данных не меняются один раз, поэтому, если есть потенциальная оптимизация, сообщите мне (сегменты линий заморожены прямо сейчас).

EDIT: Я попробовал StreamGeometry. По какой-то причине создание графики занимало больше времени, но это не проблема. Рисунок на графике после рисования всех точек все еще медленнее, чем предыдущий метод. Я думаю, что слишком много точек данных для WPF для решения.

EDIT: я немного экспериментировал, и я заметил, что производительность немного улучшилась за счет преобразования координат, которые ранее были в double to int, чтобы предотвратить подпиксельные линии сглаживания WPF.

EDIT: Спасибо за все ответы, предлагающие уменьшить количество сегментов линии. Я сократил их до двух раз больше горизонтального разрешения для ступенчатых линий и не более горизонтального разрешения для простых линий, и производительность сейчас очень хорошая.

4b9b3361

Ответ 1

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

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

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

Ответ 2

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

(EDIT: изменено "DirectX" в исходном ответе на "Direct3D" )

Ответ 3

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

Согласно Pavan Podila в 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

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

ZedGraph

Удачи!

Ответ 5

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

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

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

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

Наконец, я только заметил, что Charles Petzold написал журнал MSDN статья, где наилучшим решением (в любом случае) (для графика разброса) был подход DrawingVisual.

Ответ 6

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

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

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

Ответ 7

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

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

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

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

Ответ 8

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

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

Ответ 9

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

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