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

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

9 ответов


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

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

plot 'datafile' using (bin(,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) + binwidth/2.0

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

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

вы можете видеть, почему это правильно последовательно (это помогает нарисовать несколько бункеров и точку где-то в одном из них). Вычитайте Min из точки данных, чтобы узнать, насколько далеко она находится в диапазоне биннинга. Затем разделите на binwidth, чтобы вы эффективно работали в единицах "бункеров". Затем " пол " результат, чтобы перейти к левому краю этого бункера, добавьте 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 является правильным, только если границы bin происходят в (n+0.5) * binwidth (где n проходит через целые числа). ответ mas90 верен только в том случае, если границы bin происходят в N*binwidth.


вы хотите построить график, как этот? enter image description here да? Тогда вы можете посмотреть на мою статью в блоге: 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(,width)):(1.0) smooth freq w boxes lc rgb"green" notitle

как обычно, Gnuplot-фантастический инструмент для построения сладких графиков, и его можно сделать для выполнения всевозможных вычислений. , Он предназначен для построения данных, а не для использования в качестве калькулятора, и часто проще использовать внешнюю программу (например, Октаву) для выполнения более "сложных" вычислений, сохранения этих данных в файле, а затем использовать Gnuplot для создания графика. Для вышеуказанной проблемы проверьте функцию" hist " - Октава, используя [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

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

точнее, используя binwidth 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(,binwidth,1)):(1.0) smooth freq with boxes

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


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

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

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

что касается функций binning, я не ожидал результата предлагаемых до сих пор функций. А именно, если моя binwidth равна 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
...

функция binning, которую я придумал, это

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