Histograma Matplotlib

107

Então, eu tenho um pequeno problema. Eu tenho um conjunto de dados em scipy que já está no formato de histograma, então tenho o centro das caixas e o número de eventos por caixa. Como posso agora plotar é como um histograma. Eu tentei apenas fazer

bins, n=hist()

mas não gostou disso. Alguma recomendação?

Madtowneast
fonte

Respostas:

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

insira a descrição da imagem aqui

A interface orientada a objetos também é direta:

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

Se estiver usando escaninhos personalizados (não constantes), você pode passar calcular as larguras usando np.diff, passar as larguras para ax.bare usar ax.set_xtickspara rotular as bordas do depósito:

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

insira a descrição da imagem aqui

unutbu
fonte
Existe uma maneira de passar as bordas do compartimento para o eixo x do gráfico de barras?
CMCDragonkai
plt.barO widthparâmetro de @CMCDragonkai: pode aceitar um objeto do tipo array (em vez de um escalar). Então você pode usar em width = np.diff(bins)vez de width = 0.7 * (bins[1] - bins[0]).
unutbu
Mas a widthconfiguração por si só define a largura da barra, certo? Estou falando sobre os rótulos do eixo x (ou seja, quero ver as bordas reais do compartimento sendo rótulos no eixo x). Deve ser semelhante a como plt.histfunciona.
CMCDragonkai
2
@CMCDragonkai: Você pode usar ax.set_xtickspara definir os xlabels. Eu adicionei um exemplo acima para mostrar o que quero dizer.
unutbu
22

Se você não quiser barras, pode representá-lo assim:

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
fonte
6
Você também pode usar ax.step.
tacaswell
12

Sei que isso não responde à sua pergunta, mas sempre acabo nesta página, quando procuro a solução matplotlib para histogramas, porque o simples histogram_demofoi removido da página da galeria de exemplos matplotlib.

Aqui está uma solução, que não precisa numpyser importada. Eu apenas importo numpy para gerar os dados xa serem plotados. Ele depende da função em histvez da função barcomo na resposta 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')

insira a descrição da imagem aqui

Verifique também a galeria matplotlib e os exemplos matplotlib .

tommy.carstensen
fonte
"Aqui está uma solução que não requer numpy" - a primeira linha de código importa numpy :)
Martin R.
2
@Martin R. Isso é apenas para gerar os dados a serem plotados. Consulte as linhas 4-6. Não adianta entorpecer.
tommy.carstensen
6

Se você estiver disposto a usar pandas:

pandas.DataFrame({'x':hist[1][1:],'y':hist[0]}).plot(x='x',kind='bar')
Michael Malak
fonte
27
Se você vai sugerir o uso pandas, provavelmente deve incluir um link para o site deles e um exemplo mais abrangente que explica o que está acontecendo.
tacaswell
0

Acho que isso pode ser útil para alguém.

A função de histograma do Numpy, para meu aborrecimento (embora, eu aprecie que haja uma boa razão para isso), retorna as bordas de cada caixa, em vez do valor da caixa. Embora isso faça sentido para números de ponto flutuante, que podem estar dentro de um intervalo (ou seja, o valor central não é super significativo), esta não é a saída desejada ao lidar com valores discretos ou inteiros (0, 1, 2, etc) . Em particular, o comprimento dos bins retornados de np.histograma não é igual ao comprimento das contagens / densidade.

Para contornar isso, usei np.digitize para quantizar a entrada e retornar um número discreto de caixas, junto com a fração de contagens para cada caixa. Você pode editar facilmente para obter o número inteiro de contagens.

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
fonte