Tamaño del contenedor en Matplotlib (histograma)

149

Estoy usando matplotlib para hacer un histograma.

¿Hay alguna forma de establecer manualmente el tamaño de los contenedores en lugar del número de contenedores?

Sam Creamer
fuente

Respuestas:

270

En realidad, es bastante fácil: en lugar del número de contenedores, puede dar una lista con los límites del contenedor. También se pueden distribuir de manera desigual:

plt.hist(data, bins=[0, 10, 20, 30, 40, 50, 100])

Si solo desea que se distribuyan por igual, simplemente puede usar el rango:

plt.hist(data, bins=range(min(data), max(data) + binwidth, binwidth))

Agregado a la respuesta original

La línea anterior funciona solo para datanúmeros enteros. Como señala el macrocosmos , para las carrozas puedes usar:

import numpy as np
plt.hist(data, bins=np.arange(min(data), max(data) + binwidth, binwidth))
CodingCat
fuente
20
reemplace range (...) con np.arange (...) para que funcione con flotantes.
macrocosme
66
¿Cuál es el ancho de bin aquí? ¿Has establecido ese valor antes?
UserYmY
1
Creo binwidth en este ejemplo se puede conocer a través de: (data.max() - data.min()) / number_of_bins_you_want. Se + binwidthpodría cambiar a solo 1para hacer de este un ejemplo más fácil de entender.
Jarad
2
Además de la excelente solución anterior de CodingCat, para datos flotantes, si desea que las barras de histograma se centren alrededor de los t-x enteros en lugar de tener los límites de la barra en los t-x, intente el siguiente ajuste: bins = np.arange (dmin - 0.5, dmax + 0.5 + binwidth, binwidth)
DaveW
3
opción lw = 5, color = "white"o similar inserta espacios en blanco entre las barras
PatrickT
13

Para N bins, los bordes del bin se especifican mediante una lista de valores de N + 1 donde el primer N da los bordes inferiores del bin y el +1 da el borde superior del último bin.

Código:

from numpy import np; from pylab import *

bin_size = 0.1; min_edge = 0; max_edge = 2.5
N = (max_edge-min_edge)/bin_size; Nplus1 = N + 1
bin_list = np.linspace(min_edge, max_edge, Nplus1)

Tenga en cuenta que linspace produce una matriz de min_edge a max_edge dividida en valores N + 1 o N bins

Alef
fuente
1
Tenga en cuenta que los contenedores incluyen su límite inferior y excluyen su límite superior, con la excepción del bin N + 1 (último) que incluye ambos límites.
lukewitmer
4

Supongo que la manera fácil sería calcular el mínimo y el máximo de los datos que tiene, luego calcular L = max - min. Luego se divide Lpor el ancho del contenedor deseado (supongo que esto es lo que quiere decir con el tamaño del contenedor) y usa el límite máximo de este valor como el número de contenedores.

Il-Bhima
fuente
eso es exactamente lo que tenía en mente, gracias. Me preguntaba si había una manera más simple, pero esto parece encontrar gracias.
Sam Creamer
Con números redondos no obtengo un tamaño de contenedor redondo con este enfoque. Alguien ha experimentado eso?
Brad Urani
3

Me gusta que las cosas sucedan automáticamente y que los contenedores caigan en valores "agradables". Lo siguiente parece funcionar bastante bien.

import numpy as np
import numpy.random as random
import matplotlib.pyplot as plt
def compute_histogram_bins(data, desired_bin_size):
    min_val = np.min(data)
    max_val = np.max(data)
    min_boundary = -1.0 * (min_val % desired_bin_size - min_val)
    max_boundary = max_val - max_val % desired_bin_size + desired_bin_size
    n_bins = int((max_boundary - min_boundary) / desired_bin_size) + 1
    bins = np.linspace(min_boundary, max_boundary, n_bins)
    return bins

if __name__ == '__main__':
    data = np.random.random_sample(100) * 123.34 - 67.23
    bins = compute_histogram_bins(data, 10.0)
    print(bins)
    plt.hist(data, bins=bins)
    plt.xlabel('Value')
    plt.ylabel('Counts')
    plt.title('Compute Bins Example')
    plt.grid(True)
    plt.show()

El resultado tiene contenedores en intervalos agradables de tamaño de contenedor.

[-70. -60. -50. -40. -30. -20. -10.   0.  10.  20.  30.  40.  50.  60.]

histograma de contenedores calculados

pagalo despues
fuente
¡Exactamente lo que estaba buscando! Sin embargo, en algunos casos, n_bins se redondea hacia abajo debido a la precisión de coma flotante. Por ejemplo, para desired_bin_size=0.05, min_boundary=0.850, max_boundary=2.05el cálculo de los n_binsconvierte en int(23.999999999999993)los cuales los resultados en 23 en lugar de 24 y, por tanto, una bandeja muy pocos. Un redondeo antes de la conversión de enteros funcionó para mí:n_bins = int(round((max_boundary - min_boundary) / desired_bin_size, 0)) + 1
M. Schlenker
3

Utilizo cuantiles para hacer contenedores uniformes y ajustados a la muestra:

bins=df['Generosity'].quantile([0,.05,0.1,0.15,0.20,0.25,0.3,0.35,0.40,0.45,0.5,0.55,0.6,0.65,0.70,0.75,0.80,0.85,0.90,0.95,1]).to_list()

plt.hist(df['Generosity'], bins=bins, normed=True, alpha=0.5, histtype='stepfilled', color='steelblue', edgecolor='none')

ingrese la descripción de la imagen aquí

Wojciech Moszczyński
fuente
1
Gran idea. Puede reemplazar la lista de cuantiles por np.arange(0, 1.01, 0.5)o np.linspace(0, 1, 21). No hay bordes, pero entiendo que las cajas tienen el mismo área, pero diferente ancho en el eje X?
Tomasz Gandor
2

Tuve el mismo problema que OP (¡creo!), Pero no pude hacer que funcionara de la manera que Lastalda especificó. No sé si he interpretado la pregunta correctamente, pero he encontrado otra solución (aunque probablemente sea una forma realmente mala de hacerlo).

Así fue como lo hice:

plt.hist([1,11,21,31,41], bins=[0,10,20,30,40,50], weights=[10,1,40,33,6]);

Lo que crea esto:

imagen que muestra el gráfico de histograma creado en matplotlib

Entonces, el primer parámetro básicamente 'inicializa' el bin: específicamente estoy creando un número que está entre el rango que configuré en el parámetro bins.

Para demostrar esto, observe la matriz en el primer parámetro ([1,11,21,31,41]) y la matriz 'bins' en el segundo parámetro ([0,10,20,30,40,50]) :

  • El número 1 (de la primera matriz) se encuentra entre 0 y 10 (en la matriz 'bins')
  • El número 11 (de la primera matriz) se encuentra entre 11 y 20 (en la matriz 'bins')
  • El número 21 (de la primera matriz) se encuentra entre 21 y 30 (en la matriz 'bins'), etc.

Luego estoy usando el parámetro 'pesos' para definir el tamaño de cada contenedor. Esta es la matriz utilizada para el parámetro de pesos: [10,1,40,33,6].

Entonces, el bin de 0 a 10 recibe el valor 10, el bin de 11 a 20 recibe el valor de 1, el bin de 21 a 30 recibe el valor de 40, etc.

Bluguy
fuente
3
Creo que tiene un malentendido básico sobre cómo funciona la función de histograma. Espera datos en bruto. Entonces, en su ejemplo, su matriz de datos debe contener 10 valores entre 0 y 10, 1 valor entre 10 y 20, y así sucesivamente. Entonces la función hace el resumen Y el dibujo. Lo que está haciendo arriba es una solución porque ya tiene las sumas (que luego inserta en el gráfico haciendo un mal uso de la opción "pesos"). Espero que esto aclare algo de confusión.
CodingCat
-1

Para un histograma con valores x enteros, terminé usando

plt.hist(data, np.arange(min(data)-0.5, max(data)+0.5))
plt.xticks(range(min(data), max(data)))

El desplazamiento de 0.5 centra los bins en los valores del eje x. La plt.xticksllamada agrega una marca para cada número entero.

Adversus
fuente