web-dev-qa-db-fra.com

histogrammes graphiques dont la hauteur des barres est égale à 1 dans matplotlib

Je voudrais tracer un histogramme normalisé à partir d'un vecteur en utilisant matplotlib. J'ai essayé ce qui suit:

plt.hist(myarray, normed=True)

aussi bien que:

plt.hist(myarray, normed=1)

mais aucune option ne produit un axe des ordonnées à partir de [0, 1] tel que la hauteur des barres de l'histogramme soit égale à 1. J'aimerais produire un tel histogramme - comment puis-je le faire?

merci!

73
user248237

Il serait plus utile de proposer un exemple de travail plus complet (ou dans ce cas non-travail).

J'ai essayé ce qui suit:

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, density=True)
fig.canvas.draw()
plt.show()

Cela produira en effet un histogramme sous forme de diagramme à barres avec un axe des ordonnées allant de [0,1].

En outre, conformément à la documentation hist (c'est-à-dire 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))

Essayez ceci après les commandes ci-dessus:

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

Je reçois 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 mesure sera l’unité, mais que l’intégrale au-dessus des mesures est l’unité. Dans mon cas, np.sum(n) a renvoyé environ 7.2767.

42
dtlussier

Si vous voulez que la somme de toutes les barres soit égale à l’unité, pondérez chaque groupe par le nombre total de valeurs:

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

J'espère que ça aide, même si le fil est assez vieux ...

182
Carsten König

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

J'ai trouvé un indice dans la question suivante - Python: histogramme avec une surface normalisée à autre chose que 1

Mais je n'ai pas réussi à trouver un moyen de faire en sorte que les barres imitent la caractéristique histtype = "step" hist (). Cela m'a dirigé vers: Matplotlib - Histogramme en étapes avec données déjà regroupées

Si la communauté le trouve acceptable, j'aimerais proposer une solution qui synthétise les idées des deux publications susmentionnées.

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, j'ai remarqué que la barre la plus à gauche ou la barre à la droite de l'histogramme ne se fermait pas en touchant le point le plus bas de l'axe des ordonnées. Dans un tel cas, l'ajout d'un élément 0 à la mendicité ou à la fin de y a permis d'obtenir le résultat nécessaire.

Je pensais juste partager mon expérience. Merci.

18
Killer

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 se monte à 1 avec:

> print sum(results*binWidth)
1.0
10
Yuri Brovman