Как я могу нарисовать сглаженные / округленные / изогнутые линейные графики?(С #) - PullRequest
7 голосов
/ 08 декабря 2010

Я измеряю некоторые данные о производительности системы, чтобы сохранить их в базе данных. Из этих точек данных я рисую линейные графики с течением времени. По своей природе эти точки данных немного шумные, т.е. каждая точка отклоняется, по крайней мере, немного от локального среднего значения. Рисуя линейный график прямо из одной точки в другую, он создает неровные графики. При большом масштабе времени, таком как> 10 точек данных на пиксель, этот шум сжимается в область с широкими зубчатыми линиями, которая, скажем, имеет высоту 20 пикселей вместо 1 пикселя, как в меньших масштабах.

Я читал про сглаживание линий, сглаживание, упрощение и все эти вещи. Но все, что я нашел, похоже, связано с чем-то другим.

Мне не нужно сглаживать, .NET уже делает это для меня при рисовании линии на экране.

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

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

Чтобы привести пример, просто взгляните на приложение системного монитора Linux / Gnome. Я рисую недавнее использование процессора / памяти / сети сглаженной линией. Это может быть немного упрощено, но я бы попробовал и посмотрел, смогу ли я его настроить.

Я бы предпочел код на C #, но алгоритмы или код на других языках тоже подойдут, если я могу перенести его на C # без внешних ссылок.

Ответы [ 5 ]

6 голосов
/ 08 декабря 2010

Вы можете сделать некоторое сглаживание данных.Вместо использования реальных данных, примените простой алгоритм сглаживания, который сохраняет пики, такие как фильтр Савицкого-Голай.

Здесь вы можете получить коэффициенты .

.do is:

Возьмите верхние коэффициенты с сайта, на который я ссылался:

// For np = 5 = 5 data points
var h = 35.0;
var coeff = new float[] { 17, 12, -3 }; // coefficients from the site
var easyCoeff = new float[] {-3, 12, 17, 12, -3}; // Its symmetrical
var center = 2; // = the center of the easyCoeff array

// теперь для каждой точки из ваших данных вы вычисляете сглаженную точку:

smoothed[x] = 
   ((data[x - 2] * easyCoeff[center - 2]) +
    (data[x - 1] * easyCoeff[center - 1]) +
    (data[x - 0] * easyCoeff[center - 0]) +
    (data[x + 1] * easyCoeff[center + 1]) +
    (data[x + 2] * easyCoeff[center + 2])) / h;

Первые 2 и последние 2 точки вы не можете сгладить при использовании 5 точек.

Если вы хотите, чтобы ваши данные были более «сглаженными», вы можете поэкспериментировать с коэффициентами с большими точками данных.

Теперь вы можете провести линию через ваши «сглаженные» данные.Чем больше ваш np = количество баллов, тем сглаживаются ваши данные.Но вы также теряете максимальную точность, но не так сильно, когда просто усредняете несколько точек вместе.

2 голосов
/ 08 декабря 2010

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

1 голос
/ 08 декабря 2010

Я думаю, что вы ищете, это рутина для предоставления «сплайнов».Вот ссылка, описывающая сплайны:

http://en.wikipedia.org/wiki/Spline_(mathematics)

Если это так, у меня нет рекомендаций для библиотеки сплайнов, но первоначальный поиск в Google нашел кучу.

Извините за отсутствие кода, но, надеюсь, знание терминологии поможет вам в поиске.

Боб

0 голосов
/ 08 декабря 2010

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

Если 10 недостаточно, вы можете хранить гораздо больше.Вам не нужно пересчитывать среднее значение с нуля, либо:

new_average = (old_average*10 - replaced_sample + new_sample)/10

Если вы не хотите сохранять все 10, вы можете приблизиться к этому:

new_average = old_average*9/10 + new_sample/10

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

Если вы реализуете это, сделайте что-то вроде этого:

new_average = old_average*min(9,number_of_samples)/10 + new_sample/10
number_of_samples++

, чтобы избежать начального увеличения.Вы также должны отрегулировать соотношение 9/10, 1/10, чтобы фактически отразить период времени каждой выборки, потому что ваш таймер не будет запускать точно один раз в секунду.

0 голосов
/ 08 декабря 2010

Уменьшите количество точек данных, используя MIN / MAX / AVG перед их отображением.Это будет выглядеть лучше и будет быстрее

...