Istogramma usando gnuplot?


202

So come creare un istogramma (basta usare "con le caselle") in gnuplot se il mio file .dat contiene già dati correttamente raccolti. C'è un modo per prendere un elenco di numeri e fare in modo che gnuplot fornisca un istogramma basato su intervalli e dimensioni del cestino fornite dall'utente?


2
Se non ottieni una risposta, ci sono altri strumenti che sono fatti per fare queste cose. Uso Root ( root.cern.ch ) molti altri qui usano R, e ci sono almeno alcune altre opzioni.
dmckee --- ex-moderatore gattino

1
Bin è l'intervallo di valori raccolti insieme per ciascuna barra dell'istogramma. Ogni bin ha un limite inferiore e superiore e tutti i dati con un valore in quell'intervallo vengono conteggiati verso quella barra. In cinta significa che il mio file di dati è già organizzato in base al numero di punti di dati che rientrano in ciascun cestino, quindi è pronto per essere tracciato come un istogramma.
Maria,

Risposte:


225

sì, ed è rapido e semplice anche se molto nascosto:

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

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

controlla help smooth freqper capire perché quanto sopra crea un istogramma

per gestire gli intervalli basta impostare la variabile xrange.


11
Penso che la risposta di @ ChrisW qui sotto porti un punto importante da notare per chiunque voglia fare un istogramma in Gnuplot.
Abhinav,

2
Fai molta attenzione, funziona solo se non c'è un bin "mancante" nel set ... Questa funzione fissa il valore y di un bin mancante sul valore y del bin precedente non mancante. Questo può essere molto fuorviante !!!
PinkFloyd,

1
Vorrei aggiungere set boxwidth binwidtha sopra. È stato davvero utile per me.
Jaakko,

90

Ho un paio di correzioni / aggiunte alla risposta molto utile di Born2Smile:

  1. I contenitori vuoti hanno causato la casella per il cestino adiacente di estendersi erroneamente nel suo spazio; evitare questo usandoset boxwidth binwidth
  2. Nella versione di Born2Smile, i bin sono resi come centrati sul loro limite inferiore. Dovrebbero estendersi rigorosamente dal limite inferiore al limite superiore. Questo può essere corretto modificando la binfunzione:bin(x,width)=width*floor(x/width) + width/2.0

10
In realtà quella seconda parte dovrebbe essere bin(x,width)=width*floor(x/width) + binwidth/2.0(calcoli in virgola mobile)
bgw

8
Intendi bin(x,width)=width*floor(x/width) + width/2.0. Se stiamo passando widthcome argomento, allora usalo. :-)
Mitar,

78

Fai molta attenzione: tutte le risposte in questa pagina stanno implicitamente prendendo la decisione di dove inizia il binning - il bordo sinistro del cestino più a sinistra, se vuoi - dalle mani dell'utente. Se l'utente sta combinando una di queste funzioni per il binning dei dati con la propria decisione su dove inizia il binning (come è fatto sul blog che è collegato sopra) le funzioni sopra sono tutte errate. Con un punto di partenza arbitrario per il binning 'Min', la funzione corretta è:

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

Puoi capire perché questo è corretto in sequenza (aiuta a disegnare alcuni bin e un punto da qualche parte in uno di essi). Sottrai Min dal tuo punto dati per vedere quanto è lontano l'intervallo di binning. Quindi dividi per binwidth in modo da lavorare efficacemente in unità di "bin". Quindi 'pavimenta' il risultato per andare al bordo sinistro del cestino, aggiungi 0,5 per andare al centro del cestino, moltiplica per la larghezza in modo da non lavorare più in unità di bidoni ma in scala assoluta di nuovo, quindi aggiungi nuovamente l'offset minimo che hai sottratto all'inizio.

Considera questa funzione in azione:

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

ad es. il valore 1.1 rientra davvero nel cestino sinistro:

  • questa funzione la mappa correttamente al centro del cestino sinistro (0.75);
  • La risposta di Born2Smile, bin (x) = larghezza * piano (x / larghezza), la mappa erroneamente su 1;
  • risposta di mas90, bin (x) = larghezza * piano (x / larghezza) + binwidth / 2.0, mappa erroneamente su 1,5.

La risposta di Born2Smile è corretta solo se i limiti del bin si verificano in (n + 0,5) * binwidth (dove n viene eseguito su numeri interi). La risposta di mas90 è corretta solo se i limiti del bin si verificano in n * binwidth.


48

Vuoi tracciare un grafico come questo? inserisci qui la descrizione dell'immagine sì? Quindi puoi dare un'occhiata al mio articolo sul blog: http://gnuplot-surprising.blogspot.com/2011/09/statistic-analysis-and-histogram.html

Linee chiave dal codice:

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

Come al solito, Gnuplot è uno strumento fantastico per tracciare grafici dall'aspetto dolce e può essere fatto per eseguire tutti i tipi di calcoli. Tuttavia , ha lo scopo di tracciare i dati piuttosto che fungere da calcolatrice ed è spesso più semplice utilizzare un programma esterno (ad esempio Octave) per eseguire calcoli più "complicati", salvare questi dati in un file, quindi utilizzare Gnuplot per produrre il grafo. Per il problema sopra, controlla la funzione "hist" che Octave sta usando [freq,bins]=hist(data), quindi tracciala in Gnuplot usando

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

7

Ho trovato questa discussione estremamente utile, ma ho riscontrato alcuni problemi di "arrotondamento".

Più precisamente, usando una larghezza di binario di 0,05, ho notato che, con le tecniche presentate qui sopra, i punti di dati che leggono 0,1 e 0,15 rientrano nello stesso cestino. Questo (comportamento ovviamente indesiderato) è molto probabilmente dovuto alla funzione "piano".

Di seguito è il mio piccolo contributo per cercare di aggirare questo.

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

Questo metodo ricorsivo è per x> = 0; si potrebbe generalizzare questo con più dichiarazioni condizionali per ottenere qualcosa di ancora più generale.


6

Non è necessario utilizzare il metodo ricorsivo, potrebbe essere lento. La mia soluzione sta usando una funzione definita dall'utente rint instesd della funzione strumentale int o floor.

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

Questa funzione darà rint(0.0003/0.0001)=3, mentreint(0.0003/0.0001)=floor(0.0003/0.0001)=2 .

Perché? Si prega di guardare la funzione int Perl e gli zeri di riempimento


4

Ho una piccola modifica alla soluzione di Born2Smile.

So che non ha molto senso, ma potresti volerlo per ogni evenienza. Se i tuoi dati sono interi e hai bisogno di una dimensione del contenitore mobile (forse per il confronto con un altro set di dati o la densità del diagramma nella griglia più fine), dovrai aggiungere un numero casuale compreso tra 0 e 1 all'interno del pavimento. Altrimenti, ci saranno picchi dovuti all'errore di arrotondamento. floor(x/width+0.5)non lo farà perché creerà un pattern non fedele ai dati originali.

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

1
Non hai riscontrato tali situazioni, ma potresti più tardi. Puoi testarlo con interi normalmente distribuiti con float sd e tracciare istogrammi con bin = 1 e bin = sd Guarda cosa ottieni con e senza il trucco rand (0). Ho riscontrato l'errore di un collaboratore durante la revisione del suo manoscritto. I suoi risultati sono passati da una totale assurdità a una bella figura come previsto.
path4,

Ok, forse la spiegazione è così breve, che non si può capire senza un caso di prova più concreto. Farò una breve modifica della tua risposta in modo da poter annullare il downvote;)
Christoph

Considera numeri interi di distribuzione normale. Poiché sono numeri interi, molti di essi avranno la stessa x / larghezza. Diciamo che il numero è 1.3. Con floor (x / larghezza + 0,5), tutti saranno assegnati al cestino 1. Ma ciò che 1.3 significa veramente in termini di densità è che il 70% di essi dovrebbe essere nel cestino 1 e il 30% nel cestino 2. rand (0 ) mantiene la densità corretta. Quindi, 0,5 crea picchi e rand (0) lo mantiene vero. Scommetto che la cifra di hsxz sarà molto più agevole usando rand (0) invece di 0,5. Non si tratta solo di arrotondare, ma di arrotondare senza perturbazioni.
path4,

3

Per quanto riguarda le funzioni di binning, non mi aspettavo il risultato delle funzioni finora offerte. Vale a dire, se la mia larghezza di bin è 0,001, queste funzioni centrano i bin su 0,0005 punti, mentre ritengo sia più intuitivo centrare i bin su 0,001.

In altre parole, mi piacerebbe avere

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

La funzione di binning che mi è venuta in mente è

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

Ecco uno script per confrontare alcune delle funzioni bin offerte con questa:

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
}

ed ecco l'output

   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
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.