Histograma Matplotlib

107

Entonces tengo un pequeño problema. Tengo un conjunto de datos en scipy que ya está en formato de histograma, por lo que tengo el centro de los contenedores y el número de eventos por contenedor. ¿Cómo puedo trazar ahora es como un histograma? Intenté simplemente hacer

bins, n=hist()

pero eso no le gustó. ¿Alguna recomendación?

madtowneast
fuente

Respuestas:

239
import matplotlib.pyplot as plt
import numpy as np

mu, sigma = 100, 15
x = mu + sigma * np.random.randn(10000)
hist, bins = np.histogram(x, bins=50)
width = 0.7 * (bins[1] - bins[0])
center = (bins[:-1] + bins[1:]) / 2
plt.bar(center, hist, align='center', width=width)
plt.show()

ingrese la descripción de la imagen aquí

La interfaz orientada a objetos también es sencilla:

fig, ax = plt.subplots()
ax.bar(center, hist, align='center', width=width)
fig.savefig("1.png")

Si está utilizando contenedores personalizados (no constantes), puede pasar calcular los anchos usando np.diff, pasar los anchos ax.bary usar ax.set_xtickspara etiquetar los bordes del contenedor:

import matplotlib.pyplot as plt
import numpy as np

mu, sigma = 100, 15
x = mu + sigma * np.random.randn(10000)
bins = [0, 40, 60, 75, 90, 110, 125, 140, 160, 200]
hist, bins = np.histogram(x, bins=bins)
width = np.diff(bins)
center = (bins[:-1] + bins[1:]) / 2

fig, ax = plt.subplots(figsize=(8,3))
ax.bar(center, hist, align='center', width=width)
ax.set_xticks(bins)
fig.savefig("/tmp/out.png")

plt.show()

ingrese la descripción de la imagen aquí

unutbu
fuente
¿Hay alguna forma de pasar los bordes del contenedor al eje x del gráfico de barras?
CMCDragonkai
plt.barEl widthparámetro de @CMCDragonkai: puede aceptar un objeto similar a una matriz (en lugar de un escalar). Entonces podría usar en width = np.diff(bins)lugar de width = 0.7 * (bins[1] - bins[0]).
unutbu
Pero la widthconfiguración por sí sola solo establece el ancho de la barra, ¿verdad? Estoy hablando de las etiquetas del eje x (es decir, quiero ver que los bordes del contenedor reales son etiquetas en el eje x). Debería ser similar a cómo plt.histfunciona.
CMCDragonkai
2
@CMCDragonkai: podría usar ax.set_xtickspara configurar las etiquetas x. Agregué un ejemplo arriba para mostrar lo que quiero decir.
unutbu
22

Si no quiere barras, puede trazarlo así:

import numpy as np
import matplotlib.pyplot as plt

mu, sigma = 100, 15
x = mu + sigma * np.random.randn(10000)

bins, edges = np.histogram(x, 50, normed=1)
left,right = edges[:-1],edges[1:]
X = np.array([left,right]).T.flatten()
Y = np.array([bins,bins]).T.flatten()

plt.plot(X,Y)
plt.show()

histograma

Matthias123
fuente
6
También puede utilizar ax.step.
tacaswell
12

Sé que esto no responde a su pregunta, pero siempre termino en esta página, cuando busco la solución matplotlib para histogramas, porque el simple histogram_demose eliminó de la página de la galería de ejemplos de matplotlib.

Aquí hay una solución, que no requiere numpyser importada. Solo importo numpy para generar los datos xque se trazarán. Se basa en la función en histlugar de la función barcomo en la respuesta de @unutbu.

import numpy as np
mu, sigma = 100, 15
x = mu + sigma * np.random.randn(10000)

import matplotlib.pyplot as plt
plt.hist(x, bins=50)
plt.savefig('hist.png')

ingrese la descripción de la imagen aquí

Consulte también la galería de matplotlib y los ejemplos de matplotlib .

tommy.carstensen
fuente
"Aquí hay una solución, que no requiere numpy" - primera línea de código importa numpy :)
Martin R.
2
@Martin R. Eso es solo para generar los datos que se trazarán. Vea las líneas 4-6. Sin uso de numpy.
tommy.carstensen
6

Si está dispuesto a usar pandas:

pandas.DataFrame({'x':hist[1][1:],'y':hist[0]}).plot(x='x',kind='bar')
Michael Malak
fuente
27
Si va a sugerir el uso pandas, probablemente debería incluir un enlace a su sitio y un ejemplo más detallado que explique lo que está sucediendo.
tacaswell
0

Creo que esto podría ser útil para alguien.

La función de histograma de Numpy, para mi disgusto (aunque aprecio que hay una buena razón para ello), devuelve los bordes de cada contenedor, en lugar del valor del contenedor. Si bien esto tiene sentido para los números de punto flotante, que pueden estar dentro de un intervalo (es decir, el valor central no es muy significativo), esta no es la salida deseada cuando se trata de valores discretos o enteros (0, 1, 2, etc.) . En particular, la longitud de los contenedores devueltos desde np.histogram no es igual a la longitud de los recuentos / densidad.

Para solucionar esto, utilicé np.digitize para cuantificar la entrada y devolver un número discreto de bins, junto con una fracción de recuentos para cada bin. Puede editar fácilmente para obtener el número entero de recuentos.

def compute_PMF(data)
    import numpy as np
    from collections import Counter
    _, bins = np.histogram(data, bins='auto', range=(data.min(), data.max()), density=False)
    h = Counter(np.digitize(data,bins) - 1)
    weights = np.asarray(list(h.values())) 
    weights = weights / weights.sum()
    values = np.asarray(list(h.keys()))
    return weights, values
####

Refs:

[1] https://docs.scipy.org/doc/numpy/reference/generated/numpy.histogram.html

[2] https://docs.scipy.org/doc/numpy/reference/generated/numpy.digitize.html

sirgogo
fuente