Tamanho da bandeja no Matplotlib (histograma)

149

Estou usando o matplotlib para fazer um histograma.

Existe alguma maneira de definir manualmente o tamanho dos compartimentos em oposição ao número de compartimentos?

Sam Creamer
fonte

Respostas:

270

Na verdade, é bem fácil: em vez do número de posições, você pode fornecer uma lista com os limites da posição. Eles também podem ser distribuídos de forma desigual:

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

Se você apenas deseja distribuí-los igualmente, basta usar o range:

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

Adicionado à resposta original

A linha acima funciona apenas para datanúmeros inteiros. Como o macrocosme aponta, para carros alegóricos você pode usar:

import numpy as np
plt.hist(data, bins=np.arange(min(data), max(data) + binwidth, binwidth))
CodingCat
fonte
20
substitua o intervalo (...) pelo np.arange (...) para que ele funcione com flutuadores.
Macrocosme
6
qual é a largura de caixa aqui? você definiu esse valor antes?
usar o seguinte comando
1
Acredito binwidth neste exemplo poderia ser encontrado por: (data.max() - data.min()) / number_of_bins_you_want. A + binwidthpode ser alterado para apenas 1para tornar este um exemplo mais facilmente compreendido.
Jarad 22/0118
2
Além da excelente solução do CodingCat acima, para dados flutuantes, se você quiser que as barras do histograma sejam centradas em torno de x-ticks inteiros em vez de ter os limites da barra nos x-ticks, tente o seguinte ajuste: bins = np.arange (dmin - 0.5, dmax + 0.5 + binwidth, binwidth)
DaveW 13/08
3
opcionais lw = 5, color = "white"ou semelhantes inserções de espaços em branco entre barras
PatrickT
13

Para os compartimentos N, as bordas da bandeja são especificadas pela lista de valores N + 1, onde o primeiro N fornece as bordas inferiores da bandeja e o +1 fornece a borda superior da última bandeja.

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)

Observe que o linspace produz uma matriz de min_edge a max_edge dividida em valores N + 1 ou N bins

Alef
fonte
1
Observe que os compartimentos incluem seu limite inferior e excluem seu limite superior, com exceção do compartimento N + 1 (último), que inclui os dois limites.
Lukewitmer 01/03
4

Eu acho que a maneira mais fácil seria calcular o mínimo e o máximo dos dados que você possui e depois calcular L = max - min. Em seguida, você divide Lpela largura desejada da lixeira (suponho que isso seja o que você quer dizer com tamanho da lixeira) e usa o teto desse valor como o número de lixeiras.

Il-Bhima
fonte
isso é exatamente o que eu tinha em mente, obrigado. Só queria saber se havia uma maneira mais simples, mas isso parece encontrar obrigado!
Sam Creamer
Usando números redondos, não tenho tamanho de lixeira redonda com essa abordagem. Alguém experimentou isso?
amigos estão dizendo sobre bruno urani
3

Eu gosto que as coisas aconteçam automaticamente e que as caixas caiam em valores "agradáveis". O seguinte parece funcionar muito bem.

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

O resultado possui compartimentos em intervalos agradáveis ​​de tamanho de compartimento.

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

histograma de caixas computadas

pagar adiantado
fonte
Exatamente o que eu estava procurando! No entanto, em alguns casos, os n_bins são arredondados para baixo devido à precisão do ponto flutuante. Por exemplo, para desired_bin_size=0.05, min_boundary=0.850, max_boundary=2.05o cálculo de n_binsse torna int(23.999999999999993)o que resulta em 23 em vez de 24, e, por conseguinte, um bin muito poucos. Um arredondamento antes da conversão de número inteiro funcionou para mim:n_bins = int(round((max_boundary - min_boundary) / desired_bin_size, 0)) + 1
M. Schlenker
3

Eu uso quantis para fazer caixas uniformes e ajustadas à amostra:

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

insira a descrição da imagem aqui

Wojciech Moszczyński
fonte
1
Boa ideia. Você pode substituir a lista de quantis por np.arange(0, 1.01, 0.5)ou np.linspace(0, 1, 21). Não há arestas, mas entendo que as caixas têm área igual, mas largura diferente no eixo X?
Tomasz Gandor 13/06
2

Eu tive o mesmo problema do OP (acho!), Mas não consegui fazê-lo funcionar da maneira especificada pela Lastalda. Não sei se interpretei a pergunta corretamente, mas encontrei outra solução (provavelmente é uma maneira muito ruim de fazer isso).

Foi assim que eu fiz:

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

O que cria isso:

imagem mostrando o gráfico do histograma criado no matplotlib

Portanto, o primeiro parâmetro basicamente 'inicializa' a lixeira - estou criando especificamente um número que está entre o intervalo que eu defini no parâmetro bins.

Para demonstrar isso, observe a matriz no primeiro parâmetro ([1,11,21,31,41]) e a matriz 'bin' no segundo parâmetro ([0,10,20,30,40,50]) :

  • O número 1 (da primeira matriz) fica entre 0 e 10 (na matriz 'bandejas')
  • O número 11 (da primeira matriz) fica entre 11 e 20 (na matriz 'caixas')
  • O número 21 (da primeira matriz) fica entre 21 e 30 (na matriz 'bandejas'), etc.

Então, eu estou usando o parâmetro 'pesos' para definir o tamanho de cada caixa. Esta é a matriz usada para o parâmetro de pesos: [10,1,40,33,6].

Portanto, o compartimento de 0 a 10 recebe o valor 10, o compartimento de 11 a 20 recebe o valor de 1, o compartimento de 21 a 30 recebe o valor de 40 etc.

bluguy
fonte
3
Eu acho que você tem um mal-entendido básico sobre como a função do histograma funciona. Ele espera dados brutos. Portanto, no seu exemplo, sua matriz de dados deve conter 10 valores entre 0 e 10, 1 valor entre 10 e 20 e assim por diante. Então a função faz a soma E o desenho. O que você está fazendo acima é uma solução alternativa, porque você já possui as somas (que você insere no gráfico usando incorretamente a opção "pesos"). Espero que isso esclareça alguma confusão.
precisa saber é o seguinte
-1

Para um histograma com valores x inteiros, acabei usando

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

O deslocamento de 0,5 centraliza os compartimentos nos valores do eixo x. A plt.xtickschamada adiciona uma marca para cada número inteiro.

Adversus
fonte