2011-03-16 17 views
88

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

bins, n=hist() 

pero no me gustó. ¿Alguna recomendación?

Respuesta

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

enter image description here

La interfaz orientada a objetos también es sencillo:

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

Si está utilizando personalizados contenedores (no constantes), puede pasar a calcular los anchos usando np.diff, pase el ancho a ax.bar y use ax.set_xticks para etiquetar los bordes de la bandeja:

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

enter image description here

+0

¿Hay una manera de pasar el bin bordes para el eje x de la gráfica de barras? – CMCDragonkai

+0

@CMCDragonkai: el parámetro 'width' de' plt.bar' puede aceptar un objeto similar a una matriz (en lugar de un escalar). Por lo tanto, podría usar 'width = np.diff (bins)' en lugar de 'width = 0.7 * (bins [1] - bins [0])'. – unutbu

+0

Pero el ajuste de 'ancho' por sí solo solo establece el ancho de la barra ¿no? Estoy hablando de las etiquetas del eje x (es decir, quiero ver que los bordes reales del contenedor sean etiquetas en el eje x). Debería ser similar a cómo funciona 'plt.hist'. – CMCDragonkai

16

Si no desea que las barras puede representar 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() 

histogram

+4

También puede usar 'ax.step'. – tacaswell

5

Si usted está dispuesto a utilizar pandas:

pandas.DataFrame({'x':hist[1][1:],'y':hist[0]}).plot(x='x',kind='bar') 
+26

Si va a sugerir el uso de 'pandas', probablemente debería incluir un enlace a su sitio y un ejemplo más que explica lo que está sucediendo. – tacaswell

6

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

Aquí hay una solución que no requiere la importación de numpy. Solo importo numpy para generar los datos x que se trazarán. Se basa en la función hist en lugar de la función bar como en el answer por @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') 

enter image description here

También puedes ver el matplotlib gallery y la matplotlib examples.

+0

"Aquí hay una solución, que no requiere numpy" - la primera línea de código importa numpy :) –

+0

@Martin R. Eso es solo para generar los datos que se trazarán. Ver las líneas 4-6. Sin uso de numpy. –

+0

Lo sé, lo sé, esto no fue realmente una queja. –

0

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

La función de histograma de Numpy, para mi molestia (aunque, agradezco que haya una buena razón para ello), devuelve los bordes de cada contenedor, en lugar del valor del contenedor. Mientras que esto tiene sentido para los números de coma flotante, que pueden estar dentro de un intervalo (es decir, el valor central no es muy significativo), este no es el resultado deseado 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 evitar esto, utilicé np.digitize para cuantificar la entrada y devolver un número discreto de intervalos, junto con la fracción de conteos para cada contenedor. Puede editar fácilmente para obtener el número entero de conteos.

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