Histogram za pomocą gnuplot?


202

Wiem, jak utworzyć histogram (po prostu użyj „z pudełkami”) w gnuplot, jeśli mój plik .dat ma już odpowiednio binowane dane. Czy istnieje sposób, aby wziąć listę liczb i poprosić gnuplot o dostarczenie histogramu opartego na zakresach i rozmiarach bin dostarczanych przez użytkownika?


2
Jeśli nie otrzymasz odpowiedzi, istnieją inne narzędzia, które służą do takich czynności. Używam Roota ( root.cern.ch ), wielu innych tutaj używa R, a jest co najmniej kilka innych opcji.
dmckee --- były moderator kociąt

1
Bin to zakres wartości zebranych razem dla każdego słupka na histogramie. Każdy przedział ma dolny i górny limit, a wszystkie dane o wartości z tego zakresu są liczone do tego paska. Binned oznacza, że ​​mój plik danych jest już uporządkowany według liczby punktów danych przypadających na każdy pojemnik, więc jest gotowy do wykreślenia jako histogram.
mary

Odpowiedzi:


225

tak, a jego szybkie i proste, ale bardzo ukryte:

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

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

sprawdzić help smooth freq dlaczego powyższe tworzy histogram

aby poradzić sobie z zakresami, po prostu ustaw zmienną xrange.


11
Myślę, że odpowiedź @ ChrisW poniżej przynosi ważną uwagę dla każdego, kto chce zrobić histogram w Gnuplot.
Abhinav

2
Bądź bardzo ostrożny, działa to tylko wtedy, gdy w zestawie nie ma „brakującego pojemnika” ... Ta funkcja naprawia wartość y brakującego pojemnika na wartość y poprzedniego nie brakującego pojemnika. To może być bardzo mylące !!!
PinkFloyd

1
Dodałbym set boxwidth binwidthdo powyższego. To było dla mnie bardzo pomocne.
Jaakko

90

Mam kilka poprawek / dodatków do bardzo przydatnej odpowiedzi Born2Smile:

  1. Puste pojemniki spowodowały, że pudełko sąsiedniego pojemnika niepoprawnie rozciągało się na swoje miejsce; unikaj tego przy użyciuset boxwidth binwidth
  2. W wersji Born2Smile pojemniki są renderowane jako wyśrodkowane na ich dolnej granicy. Ściśle powinny rozciągać się od dolnej granicy do górnej granicy. Można to poprawić, modyfikując binfunkcję:bin(x,width)=width*floor(x/width) + width/2.0

10
Właściwie ta druga część powinna być bin(x,width)=width*floor(x/width) + binwidth/2.0(obliczenia zmiennoprzecinkowe)
bgw

8
Masz na myśli bin(x,width)=width*floor(x/width) + width/2.0. Jeśli przekazujemy widthjako argument, użyj go. :-)
Mitar

78

Bądź bardzo ostrożny: wszystkie odpowiedzi na tej stronie domyślnie podejmują decyzję, od czego zaczyna się binowanie - lewa krawędź najbardziej lewego pojemnika, jeśli chcesz - z rąk użytkownika. Jeśli użytkownik łączy dowolną z tych funkcji do binowania danych ze swoją własną decyzją o tym, gdzie zaczyna się binowanie (jak dzieje się to na blogu, do którego prowadzi link powyżej), wszystkie powyższe funkcje są niepoprawne. W przypadku dowolnego punktu początkowego dla binowania „Min” poprawną funkcją jest:

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

Możesz zrozumieć, dlaczego jest to poprawne sekwencyjnie (pomaga narysować kilka koszy i punkt gdzieś w jednym z nich). Odejmij Min od punktu danych, aby zobaczyć, jak daleko znajduje się w zakresie binningu. Następnie podziel przez szerokość pasma, aby efektywnie pracować w jednostkach „pojemników”. Następnie „podłóż” wynik, aby przejść do lewej krawędzi tego kosza, dodaj 0,5, aby przejść do środka kosza, pomnóż przez szerokość, aby nie pracować już w jednostkach pojemników, ale w skali absolutnej jeszcze raz, a następnie w końcu dodajmy przesunięcie Min odjęte na początku.

Rozważ tę funkcję w działaniu:

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

np. wartość 1.1 naprawdę wpada do lewego pojemnika:

  • ta funkcja poprawnie mapuje go na środek lewego pojemnika (0,75);
  • Odpowiedź Born2Smile, bin (x) = width * floor (x / width), niepoprawnie odwzorowuje ją na 1;
  • odpowiedź mas90, bin (x) = szerokość * floor (x / width) + binwidth / 2.0, niepoprawnie odwzorowuje na 1,5.

Odpowiedź Born2Smile jest poprawna tylko wtedy, gdy granice bin występują przy (n + 0,5) * binwidth (gdzie n przebiega przez liczby całkowite). Odpowiedź mas90 jest poprawna tylko wtedy, gdy granice bin występują przy n * binwidth.


48

Czy chcesz wykreślić taki wykres? wprowadź opis zdjęcia tutaj tak? Następnie możesz spojrzeć na mój artykuł na blogu: http://gnuplot-surishing.blogspot.com/2011/09/statistic-analysis-and-histogram.html

Kluczowe wiersze z kodu:

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

Jak zwykle, Gnuplot jest fantastycznym narzędziem do rysowania słodko wyglądających wykresów i można go wykonywać do wszelkiego rodzaju obliczeń. Jednak ma on na celu wykreślanie danych zamiast służyć jako kalkulator i często łatwiej jest używać zewnętrznego programu (np. Octave) do wykonywania bardziej „skomplikowanych” obliczeń, zapisywać te dane w pliku, a następnie używać Gnuplot do tworzenia wykres. W przypadku powyższego problemu sprawdź, czy funkcja „hist” to Octave using [freq,bins]=hist(data), a następnie wykreśl to w Gnuplot za pomocą

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

7

Uważam tę dyskusję za niezwykle przydatną, ale napotkałem pewne problemy z „zaokrąglaniem”.

Mówiąc dokładniej, stosując szerokość przedziału 0,05, zauważyłem, że dzięki technikom przedstawionym powyżej, punkty danych, które odczytują 0,1 i 0,15, mieszczą się w tym samym przedziale. To (oczywiście niepożądane zachowanie) jest najprawdopodobniej spowodowane funkcją „podłogi”.

Poniżej mój mały wkład w próbę obejścia tego.

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

Ta metoda rekurencyjna jest dla x> = 0; można to uogólnić za pomocą bardziej warunkowych stwierdzeń, aby uzyskać coś jeszcze bardziej ogólnego.


6

Nie musimy używać metody rekurencyjnej, może być powolna. Moje rozwiązanie wykorzystuje zdefiniowaną przez użytkownika funkcję rint instesd funkcji instrinsic int lub floor.

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

Ta funkcja da rint(0.0003/0.0001)=3, podczas gdy int(0.0003/0.0001)=floor(0.0003/0.0001)=2.

Czemu? Proszę spojrzeć na funkcję Perl int i zera dopełniające


4

Mam małą modyfikację rozwiązania Born2Smile.

Wiem, że to nie ma większego sensu, ale możesz chcieć na wszelki wypadek. Jeśli twoje dane są liczbami całkowitymi i potrzebujesz rozmiaru pojemnika zmiennoprzecinkowego (być może do porównania z innym zestawem danych lub gęstością wydruku w drobniejszej siatce), musisz dodać losową liczbę od 0 do 1 wewnątrz podłogi. W przeciwnym razie wystąpią skoki z powodu błędu zaokrąglania. floor(x/width+0.5)nie zrobi tego, ponieważ utworzy wzór niezgodny z oryginalnymi danymi.

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

1
Nie spotkałeś się z takimi sytuacjami, ale możesz później. Możesz to przetestować z normalnie dystrybuowanymi liczbami całkowitymi z pływającym sd i histogramami z bin = 1, i bin = sd Zobacz, co otrzymujesz z lewą (0) i bez niej. Złapałem błąd współpracownika podczas przeglądania jego rękopisu. Jego wyniki zmieniły się z absolutnie nonsensownych w piękną figurę zgodnie z oczekiwaniami.
path4

Ok, może wyjaśnienie jest tak krótkie, że nie można go zrozumieć bez bardziej konkretnego przypadku testowego. Zrobię krótką edycję twojej odpowiedzi, abym mógł cofnąć głosowanie;)
Christoph

Rozważ liczby całkowite rozkładu normalnego. Ponieważ są to liczby całkowite, wiele z nich będzie miało tę samą wartość x / szerokość. Powiedzmy, że liczba ta wynosi 1,3. W przypadku podłogi (x / szerokość + 0,5) wszystkie z nich zostaną przypisane do bin 1. Ale 1.3 tak naprawdę oznacza pod względem gęstości, że 70% z nich powinno znajdować się w bin 1, a 30% w bin 2. rand (0 ) utrzymuje odpowiednią gęstość. Tak więc 0,5 tworzy wartości szczytowe, a rand (0) to prawda. Założę się, że liczba według hsxz będzie znacznie płynniejsza przy użyciu rand (0) zamiast 0,5. To nie tylko zaokrąglanie w górę, to zaokrąglanie w górę bez zakłóceń.
path4

3

Jeśli chodzi o funkcje binowania, nie spodziewałem się rezultatów oferowanych do tej pory funkcji. Mianowicie, jeśli moja szerokość przedziału wynosi 0,001, te funkcje centrowały pojemniki na 0,0005 punktów, podczas gdy uważam, że bardziej intuicyjne jest, aby pojemniki były wyśrodkowane na granicach 0,001.

Innymi słowy, chciałbym mieć

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

Wymyślona funkcja binowania to

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

Oto skrypt, aby porównać niektóre z oferowanych funkcji bin do tej:

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
}

a oto wynik

   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
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.