2010-10-05 7 views
56

Mi piacerebbe tracciare un istogramma normalizzato da un vettore usando matplotlib. Ho provato la seguente:istogrammi di tracciatura con altezze di barra pari a 1 in matrice

plt.hist(myarray, normed=True) 

nonché:

plt.hist(myarray, normed=1) 

ma nessuna opzione produce un asse y da [0, 1] in modo tale che le altezze di nervatura della somma istogramma a 1. I 'Mi piacerebbe produrre un tale istogramma - come posso farlo?

grazie!

+1

So che questo è vecchio, ma per riferimento e chiunque visiti questa pagina futuro, questo tipo di diffusione asse si chiama un asse di "densità di probabilità"! – ChristineB

+0

OP se sei ancora in giro forse vorresti cambiare la risposta accettata. –

risposta

39

Sarebbe più utile se poneste un esempio di lavoro più completo (o in questo caso non funzionante).

Ho provato il seguente:

import numpy as np 
import matplotlib.pyplot as plt 

x = np.random.randn(1000) 

fig = plt.figure() 
ax = fig.add_subplot(111) 
n, bins, rectangles = ax.hist(x, 50, normed=True) 
fig.canvas.draw() 
plt.show() 

ciò possa produrre un istogramma grafico a barre con un asse y che va da [0,1].

Inoltre, come per la documentazione hist (cioè ax.hist? da ipython), credo che la somma è troppo bella:

*normed*: 
If *True*, the first element of the return tuple will 
be the counts normalized to form a probability density, i.e., 
``n/(len(x)*dbin)``. In a probability density, the integral of 
the histogram should be 1; you can verify that with a 
trapezoidal integration of the probability density function:: 

    pdf, bins, patches = ax.hist(...) 
    print np.sum(pdf * np.diff(bins)) 

Dare questo una prova dopo i comandi di cui sopra:

np.sum(n * np.diff(bins)) 

I ottenere un valore di ritorno di 1.0 come previsto. Ricorda che normed=True non significa che la somma del valore di ogni barra sarà l'unità, ma piuttosto l'integrale sopra le barre è l'unità. Nel mio caso np.sum(n) restituito circa 7.2767.

13

So che questa risposta è troppo tardi considerando che la domanda è datata 2010 ma mi sono imbattuto in questa domanda perché mi trovavo di fronte a un problema simile. Come già affermato nella risposta, normed = True indica che l'area totale sotto l'istogramma è uguale a 1 ma la somma delle altezze non è uguale a 1. Tuttavia, volevo, per comodità di interpretazione fisica di un istogramma, fare una con somma delle altezze pari a 1.

ho trovato un suggerimento nella seguente domanda - Python: Histogram with area normalized to something other than 1

Ma non ero in grado di trovare un modo di rendere bar imitano il histtype = "step" caratteristica hist(). Questo mi ha portato a: Matplotlib - Stepped histogram with already binned data

Se la comunità lo trova accettabile, vorrei proporre una soluzione che sintetizzi idee da entrambi i post precedenti.

import matplotlib.pyplot as plt 

# Let X be the array whose histogram needs to be plotted. 
nx, xbins, ptchs = plt.hist(X, bins=20) 
plt.clf() # Get rid of this histogram since not the one we want. 

nx_frac = nx/float(len(nx)) # Each bin divided by total number of objects. 
width = xbins[1] - xbins[0] # Width of each bin. 
x = np.ravel(zip(xbins[:-1], xbins[:-1]+width)) 
y = np.ravel(zip(nx_frac,nx_frac)) 

plt.plot(x,y,linestyle="dashed",label="MyLabel") 
#... Further formatting. 

questo ha funzionato meravigliosamente per me anche se in alcuni casi ho notato che la più "bar" a sinistra oa destra più "bar" del istogramma non chiudere toccando il punto più basso del Y- asse. In tal caso l'aggiunta di un elemento 0 all'inizio o alla fine di y ha prodotto il risultato necessario.

Ho solo pensato di condividere la mia esperienza. Grazie.

+0

penso che tu abbia bisogno di norma = Vero pure in plt.hist. Anche in Python 3 devi usare la lista (zip (...)). –

146

Se si desidera che la somma di tutte le barre di essere uguale all'unità, peso ogni bin per il numero totale di valori:

weights = np.ones_like(myarray)/float(len(myarray)) 
plt.hist(myarray, weights=weights) 

Speranza che aiuta, anche se il filo è abbastanza vecchio ...

+8

Ottima risposta. Nota che se myarray è un python 'array_like' piuttosto che un array numpy dovrai lanciare' len (myarray) 'su' float'. – cmh

+0

Anche se myarray è multidimensionale e stai usando solo una dimensione, come myarray [0 ,:], puoi scambiare len (myarray) con np.size (myarray [0 ,:]) e funzionerà allo stesso modo. (Altrimenti, dice che l'oggetto non è chiamabile). – ChristineB

8

Ecco un'altra semplice soluzione che utilizza il metodo np.histogram().

myarray = np.random.random(100) 
results, edges = np.histogram(myarray, normed=True) 
binWidth = edges[1] - edges[0] 
plt.bar(edges[:-1], results*binWidth, binWidth) 

È infatti possibile controllare che le somme totali fino a 1 con:

> print sum(results*binWidth) 
1.0 
Problemi correlati