2010-10-05 3 views
56

Je voudrais tracer un histogramme normalisé à partir d'un vecteur en utilisant matplotlib. J'essayé ce qui suit:tracer des histogrammes dont la hauteur des barres est égale à 1 dans matplotlib

plt.hist(myarray, normed=True) 

ainsi que:

plt.hist(myarray, normed=1) 

mais ni option produit un axe y à partir de [0, 1] de telle sorte que les hauteurs de la barre de la somme de l'histogramme à 1. I J'aimerais produire un tel histogramme - comment puis-je le faire?

merci!

+1

Je sais que c'est vieux, mais pour référence future et tous ceux qui visitent cette page, ce type de propagation de l'axe est appelé un axe "densité de probabilité"! – ChristineB

+0

OP si vous êtes toujours là peut-être que vous voulez changer la réponse acceptée. –

Répondre

39

Il serait plus utile si vous posiez un exemple de travail plus complet (ou dans ce cas, non fonctionnel).

J'ai essayé les éléments suivants:

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() 

Cela fait produire un histogramme graphique à barres avec un axe y qui va de [0,1].

En outre, selon la documentation hist (c.-à-ax.hist? de ipython), je pense que la somme est bien aussi:

*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)) 

Donner cette solution après les commandes ci-dessus:

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

I obtenir une valeur de retour de 1.0 comme prévu. Rappelez-vous que normed=True ne signifie pas que la somme de la valeur à chaque barre sera l'unité, mais plutôt que l'intégrale sur les barres est l'unité. Dans mon cas np.sum(n) retourné environ 7.2767.

13

Je sais que cette réponse est trop tard étant donné que la question est datée 2010 mais je suis tombé sur cette question car je faisais face à un problème similaire moi-même. Comme déjà indiqué dans la réponse, normed = True signifie que la surface totale sous l'histogramme est égale à 1 mais la somme des hauteurs n'est pas égale à 1. Cependant, je voulais, pour faciliter l'interprétation physique d'un histogramme, faire un avec la somme des hauteurs égales à 1.

J'ai trouvé un indice dans la question suivante - Python: Histogram with area normalized to something other than 1

Mais je ne pouvais trouver un moyen de faire des barres imitent la histtype = fonction « étape » hist(). Cela m'a détourné à: Matplotlib - Stepped histogram with already binned data

Si la communauté le trouve acceptable, je voudrais mettre en avant une solution qui synthétise des idées à partir des deux postes ci-dessus.

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. 

Cela a fonctionné à merveille pour moi bien que dans certains cas, je l'ai remarqué que la gauche la plus « bar » ou le droit le plus « barre » de l'histogramme ne ferme pas en touchant le point le plus bas de la Y- axe. Dans un tel cas, l'ajout d'un élément 0 au début ou à la fin de y a permis d'obtenir le résultat nécessaire.

Je pensais juste partager mon expérience. Je vous remercie.

+0

Je pense que vous avez besoin normed = True aussi bien dans plt.hist. Toujours dans Python 3, vous devez utiliser list (zip (...)). –

146

Si vous voulez que la somme de toutes les barres à l'unité égale, le poids de chaque bac par le nombre total de valeurs:

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

espoir qui aide, bien que le fil est assez vieux ...

+8

Bonne réponse. Notez que si myarray est un python 'array_like' plutôt qu'un tableau numpy, vous devrez lancer' len (myarray) 'à float'. – cmh

+0

Aussi, si myarray est multidimensionnel et que vous n'utilisez qu'une dimension, comme myarray [0 ,:], alors vous pouvez échanger len (myarray) avec np.size (myarray [0 ,:]) et ça marchera de la même façon. (Sinon, il dit que l'objet n'est pas appelable.) – ChristineB

8

Voici une autre solution simple utilisant la méthode 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) 

Vous pouvez en effet vérifier que le total des sommes à 1 avec:

> print sum(results*binWidth) 
1.0 
Questions connexes