Гистограмма с использованием gnuplot?


202

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


2
Если вы не получили ответа, есть другие инструменты, предназначенные для таких вещей. Я использую Root ( root.cern.ch ), многие другие здесь используют R, и есть по крайней мере несколько других вариантов.
dmckee --- котенок экс-модератора

1
Bin - это диапазон значений, собранных для каждого столбца гистограммы. Каждая ячейка имеет нижний и верхний пределы, и все данные со значением в этом диапазоне засчитываются в эту полосу. «Оформление» означает, что мой файл данных уже организован по тому, сколько точек данных попадает в каждую ячейку, поэтому он готов для построения гистограммы.
мэри

Ответы:


225

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

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.


11
Я думаю, что ответ @ ChrisW, приведенный ниже, приносит важный момент для тех, кто хочет создать гистограмму в Gnuplot.
Абхинав

2
Будьте очень осторожны, это работает только в том случае, если в наборе нет «отсутствующего» элемента ... Эта функция фиксирует значение y отсутствующего элемента в значении y предыдущего не отсутствующего элемента. Это может быть очень обманчивым !!!
PinkFloyd

1
Я бы добавил set boxwidth binwidthк выше. Это было действительно полезно для меня.
Яакко

90

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

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

10
На самом деле эта вторая часть должна быть bin(x,width)=width*floor(x/width) + binwidth/2.0(вычисления с плавающей запятой)
BGW

8
Вы имеете в виду bin(x,width)=width*floor(x/width) + width/2.0. Если мы передаем widthв качестве аргумента, то используйте его. :-)
Mitar

78

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

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) = ширина * этаж (x / ширина) + binwidth / 2.0, неправильно отображает его на 1,5.

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


48

Вы хотите построить график как этот? введите описание изображения здесь да? Тогда вы можете взглянуть на мою статью в блоге: http://gnuplot-surprising.blogspot.com/2011/09/statistic-analysis-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

10

Как обычно, 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

7

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

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

В дальнейшем мой небольшой вклад, чтобы попытаться обойти это.

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

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


6

Нам не нужно использовать рекурсивный метод, он может быть медленным. Мое решение - использовать пользовательскую функцию 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 и заполнение нулями


4

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

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

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

1
Вы не сталкивались с такими ситуациями, но вы можете позже. Вы можете протестировать его с нормально распределенными целыми числами с плавающей запятой sd и построить гистограммы с bin = 1 и bin = sd. Посмотрите, что вы получите с трюком rand (0) и без него. Я поймал ошибку соавтора при просмотре его рукописи. Его результаты изменились от абсолютно бессмысленного к красивой фигуре, как и ожидалось.
path4

Хорошо, возможно, объяснение настолько короткое, что невозможно понять его без более конкретного контрольного примера. Я кратко отредактирую ваш ответ, чтобы отменить отрицательное голосование;)
Кристоф

Рассмотрим целые числа нормального распределения. Поскольку они являются целыми числами, многие из них будут иметь одинаковую ширину x /. Допустим, это число составляет 1,3. С floor (x / width + 0.5) все они будут назначены для bin 1. Но что на самом деле означает 1.3 с точки зрения плотности, так это то, что 70% из них должны быть в bin 1 и 30% в bin 2. rand (0 ) сохраняет правильную плотность. Итак, 0.5 создает пики, а rand (0) сохраняет это значение. Бьюсь об заклад, цифра с помощью hsxz будет намного более гладкой, если использовать rand (0) вместо 0.5. Это не просто округление, это округление без возмущения.
path4

3

Что касается функций биннинга, я не ожидал результата функций, предлагаемых до сих пор. А именно, если моя ширина ячейки равна 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
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.