Гістограма за допомогою gnuplot?


202

Я знаю, як створити гістограму (просто використовуйте "з полями") в gnuplot, якщо мій файл .dat вже має належним чином скопійовані дані. Чи є спосіб взяти список номерів і gnuplot надати гістограму на основі діапазонів і розмірів біна, які надає користувач?


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

1
Bin - це діапазон значень, зібраний разом для кожної смужки гістограми. Кожна скринька має нижню та верхню межу, і всі дані зі значенням у цьому діапазоні зараховуються до цього рядка. Binned означає, що мій файл даних вже впорядкований по тому, скільки точок даних потрапляє в кожний відрізок, щоб він був готовий до графіку як гістограма.
mary

Відповіді:


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
Я думаю, що відповідь Кріса нижче надає важливий момент, щоб помітити всіх, хто хоче зробити гістограму в 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як аргумент, то використовуйте його. :-)
Мітар

78

Будьте дуже обережні: усі відповіді на цій сторінці неявно приймають рішення про те, звідки починається бінінг - лівий край ліворуч, якщо вам подобається, - з рук користувача. Якщо користувач поєднує будь-яку з цих функцій для бінінгу даних із власним рішенням про те, з чого починається бінінг (як це робиться на блозі, який пов’язаний вище), наведені вище функції є неправильними. Маючи довільну відправну точку для бінінгу "Min", правильна функція:

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

Ви можете зрозуміти, чому це правильно послідовно (це допомагає намалювати кілька бункерів і крапку десь в одній з них). Відніміть Мін від точки даних, щоб побачити, наскільки далеко він знаходиться в діапазоні. Потім розділіть на binwidth так, щоб ви працювали ефективно в одиницях 'bins'. Потім "підлогу" отримайте результат, щоб перейти до лівого краю цього контейнера, додайте 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) = ширина * підлога (x / ширина), неправильно відображає його на 1;
  • відповідь mas90, bin (x) = ширина * пол (x / ширина) + binwidth / 2.0, неправильно відображає його на 1,5.

Відповідь Born2Smile правильна лише в тому випадку, якщо межі біна виникають при (n + 0,5) * binwidth (де 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, потрапляють у один і той же бін. Ця (очевидно небажана поведінка), швидше за все, пов'язана з функцією "підлога".

Знизу - мій невеликий внесок у спробу цього обійти.

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; можна було б узагальнити це більш умовними твердженнями, щоб отримати щось ще більш загальне.


6

Нам не потрібно використовувати рекурсивний метод, він може бути повільним. Моє рішення - використання визначеної користувачем функції rint intesd instrinsic function 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

Гаразд, можливо, пояснення таке коротке, що його неможливо зрозуміти без конкретнішої тестової справи. Я зроблю короткий редагування вашої відповіді , так що я можу скасувати downvote;)
Крістофа

Розглянемо цілі числа нормального розподілу. Оскільки вони є цілими числами, багато з них матимуть однакову х / ширину. Скажімо, це число 1,3. З підлогою (х / ширина + 0,5) всі вони будуть призначені для сміття 1. Але що 1,3 насправді означає "щільність", це те, що 70% з них повинні знаходитись у відро 1 і 30% у біні 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))

Ось сценарій для порівняння деяких пропонованих функцій бін із цим:

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.