Вопрос

Я знаю, как создать гистограмму (просто используйте «с прямоугольниками») в gnuplot, если в моем файле .dat уже есть правильно распределенные данные.Есть ли способ взять список чисел и заставить gnuplot предоставить гистограмму на основе диапазонов и размеров ячеек, предоставленных пользователем?

Это было полезно?

Решение

да, и это быстро и просто, хотя и очень скрытно:

binwidth=5
bin(x,width)=width*floor(x/width)

plot 'datafile' using (bin($1,binwidth)):(1.0) smooth freq with boxes

проверить help smooth freq чтобы понять, почему приведенное выше представляет собой гистограмму

чтобы работать с диапазонами, просто установите переменную xrange.

Другие советы

У меня есть пара исправлений/дополнений к очень полезному ответу Born2Smile:

  1. Из-за пустых контейнеров коробка соседнего контейнера неправильно выдвигалась на его пространство;избегайте этого, используя set boxwidth binwidth
  2. В версии Born2Smile ячейки отображаются по центру их нижней границы.Строго говоря, они должны простираться от нижней границы до верхней границы.Это можно исправить, изменив bin функция: bin(x,width)=width*floor(x/width) + width/2.0

Будь очень осторожен:все ответы на этой странице неявно принимают решение о том, где начинается группировка - левый край самой левой ячейки, если хотите, - из рук пользователя.Если пользователь комбинирует любую из этих функций для группирования данных со своим собственным решением о том, где начинается группировка (как это сделано в блоге, ссылка на который приведена выше), все вышеперечисленные функции неверны.При произвольной отправной точке для группирования «Мин» правильная функция:

bin(x) = width*(floor((x-Min)/width)+0.5) + Min

Почему это правильно, можно понять последовательно (помогает нарисовать несколько бинов и точку где-то в одном из них).Вычтите Min из вашей точки данных, чтобы увидеть, насколько далеко она находится в диапазоне биннинга.Затем разделите на ширину ячейки, чтобы эффективно работать с единицами «ячейки».Затем «полируйте» результат, чтобы перейти к левому краю этого интервала, добавьте 0,5, чтобы перейти к середине интервала, умножьте на ширину, чтобы вы больше не работали в единицах интервалов, а в абсолютном масштабе. еще раз, затем, наконец, добавьте обратно минимальное смещение, которое вы вычли в начале.

Рассмотрим эту функцию в действии:

Min = 0.25 # where binning starts
Max = 2.25 # where binning ends
n = 2 # the number of bins
width = (Max-Min)/n # binwidth; evaluates to 1.0
bin(x) = width*(floor((x-Min)/width)+0.5) + Min

напримерзначение 1,1 действительно попадает в левый интервал:

  • эта функция правильно сопоставляет его с центром левого интервала (0,75);
  • Ответ Born2Smile, bin(x)=width*floor(x/width), неправильно сопоставляет его с 1;
  • Ответ mas90, bin(x)=width*floor(x/width) + binwidth/2.0, неправильно сопоставляет его с 1,5.

Ответ Born2Smile верен только в том случае, если границы интервала находятся на уровне (n+0,5)*ширина интервала (где n превышает целые числа).Ответ mas90 верен только в том случае, если границы интервалов находятся на уровне n*binwidth.

Хотите построить такой график?enter image description hereда?Тогда вы можете посмотреть статью в моем блоге: http://gnuplot-surprising.blogspot.com/2011/09/statistic-anaанализ-and-histogram.html

Ключевые строки из кода:

n=100 #number of intervals
max=3. #max value
min=-3. #min value
width=(max-min)/n #interval width
#function used to map a value to the intervals
hist(x,width)=width*floor(x/width)+width/2.0
set boxwidth width*0.9
set style fill solid 0.5 # fill style

#count and plot
plot "data.dat" u (hist($1,width)):(1.0) smooth freq w boxes lc rgb"green" notitle

Как обычно, Gnuplot — фантастический инструмент для построения привлекательных графиков, с помощью которого можно выполнять любые виды вычислений. Однако, он предназначен для отображения данных, а не для использования в качестве калькулятора, и часто проще использовать внешнюю программу (например,Octave), чтобы выполнить более «сложные» вычисления, сохраните эти данные в файле, а затем используйте Gnuplot для создания графика.Для решения вышеуказанной проблемы проверьте функцию «hist» в Octave, используя [freq,bins]=hist(data), затем постройте это в Gnuplot, используя

set style histogram rowstacked gap 0
set style fill solid 0.5 border lt -1
plot "./data.dat" smooth freq with boxes

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

Точнее, используя ширину интервала 0,05, я заметил, что при использовании методов, представленных здесь выше, точки данных с значениями 0,1 и 0,15 попадают в один и тот же интервал.Это (очевидно нежелательное поведение), скорее всего, связано с функцией «пол».

Далее мой небольшой вклад в попытку обойти это.

bin(x,width,n)=x<=n*width? width*(n-1) + 0.5*binwidth:bin(x,width,n+1)
binwidth = 0.05
set boxwidth binwidth
plot "data.dat" u (bin($1,binwidth,1)):(1.0) smooth freq with boxes

Этот рекурсивный метод предназначен для x >=0;можно было бы обобщить это с помощью более условных утверждений, чтобы получить нечто еще более общее.

Нам не нужно использовать рекурсивный метод, он может быть медленным.Мое решение заключается в использовании пользовательской функции rint вместо встроенной функции int илиfloor.

rint(x)=(x-int(x)>0.9999)?int(x)+1:int(x)

Эта функция даст rint(0.0003/0.0001)=3, пока int(0.0003/0.0001)=floor(0.0003/0.0001)=2.

Почему?Пожалуйста, посмотрите Функция Perl int и заполнение нулями

У меня есть небольшая модификация решения Born2Smile.

Я знаю, что это не имеет особого смысла, но на всякий случай вам это может пригодиться.Если ваши данные целочисленные и вам нужен размер ячейки с плавающей запятой (возможно, для сравнения с другим набором данных или плотности графика в более мелкой сетке), вам нужно будет добавить случайное число от 0 до 1 внутри пола.В противном случае будут всплески из-за ошибки округления. floor(x/width+0.5) не подойдет, поскольку создаст шаблон, не соответствующий исходным данным.

binwidth=0.3
bin(x,width)=width*floor(x/width+rand(0))

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

Другими словами, я хотел бы иметь

Bin 0.001 contain data from 0.0005 to 0.0014
Bin 0.002 contain data from 0.0015 to 0.0024
...

Функция биннинга, которую я придумал, это

my_bin(x,width)     = width*(floor(x/width+0.5))

Вот скрипт для сравнения некоторых из предлагаемых функций bin с этой:

rint(x) = (x-int(x)>0.9999)?int(x)+1:int(x)
bin(x,width)        = width*rint(x/width) + width/2.0
binc(x,width)       = width*(int(x/width)+0.5)
mitar_bin(x,width)  = width*floor(x/width) + width/2.0
my_bin(x,width)     = width*(floor(x/width+0.5))

binwidth = 0.001

data_list = "-0.1386 -0.1383 -0.1375 -0.0015 -0.0005 0.0005 0.0015 0.1375 0.1383 0.1386"

my_line = sprintf("%7s  %7s  %7s  %7s  %7s","data","bin()","binc()","mitar()","my_bin()")
print my_line
do for [i in data_list] {
    iN = i + 0
    my_line = sprintf("%+.4f  %+.4f  %+.4f  %+.4f  %+.4f",iN,bin(iN,binwidth),binc(iN,binwidth),mitar_bin(iN,binwidth),my_bin(iN,binwidth))
    print my_line
}

и вот результат

   data    bin()   binc()  mitar()  my_bin()
-0.1386  -0.1375  -0.1375  -0.1385  -0.1390
-0.1383  -0.1375  -0.1375  -0.1385  -0.1380
-0.1375  -0.1365  -0.1365  -0.1375  -0.1380
-0.0015  -0.0005  -0.0005  -0.0015  -0.0010
-0.0005  +0.0005  +0.0005  -0.0005  +0.0000
+0.0005  +0.0005  +0.0005  +0.0005  +0.0010
+0.0015  +0.0015  +0.0015  +0.0015  +0.0020
+0.1375  +0.1375  +0.1375  +0.1375  +0.1380
+0.1383  +0.1385  +0.1385  +0.1385  +0.1380
+0.1386  +0.1385  +0.1385  +0.1385  +0.1390
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top