HOWTO · Matplotlib

Como traçar um histograma para uma lista de dados em Matplotlib

Trace um histograma a partir de uma lista Python com o plt.hist() do Matplotlib e depois ajuste os seus bins, a densidade e a cor.

Nesta página

Para traçar um histograma a partir de uma lista Python, passe a lista diretamente para a função plt.hist() do Matplotlib. A função agrupa os valores em intervalos chamados bins, conta quantos valores caem em cada intervalo e desenha uma barra por intervalo, de modo que a forma do gráfico mostra como os valores estão distribuídos. Uma lista Python comum serve como entrada; você não precisa convertê-la antes em um array NumPy ou em uma Series do pandas. Este artigo traça uma lista de 21 números inteiros de 0 a 9, depois ajusta os bins, as alturas das barras e a cor das barras, e por fim mostra o que acontece com um número de bins inválido e com uma lista vazia.

Traçar um histograma a partir de uma lista com plt.hist()

Sem argumentos extras, o plt.hist() divide o intervalo de dados em dez bins de largura igual. O exemplo também captura os três valores retornados pela função e os imprime, para que você veja exatamente como a lista foi agrupada:

import matplotlib.pyplot as plt

data = [3, 4, 2, 3, 4, 5, 4, 7, 8, 5, 4, 6, 2, 1, 0, 9, 7, 6, 6, 5, 4]
counts, bin_edges, patches = plt.hist(data)
print("counts:", counts.tolist())
print("bin_edges:", bin_edges.tolist())
plt.xlabel("Value")
plt.ylabel("Count")
plt.title("Histogram of data")
plt.show()
counts: [1.0, 1.0, 2.0, 2.0, 5.0, 3.0, 3.0, 2.0, 1.0, 1.0]
bin_edges: [0.0, 0.9, 1.8, 2.7, 3.6, 4.5, 5.4, 6.3, 7.2, 8.1, 9.0]

Histograma dos 21 valores da lista desenhado pelo plt.hist() com os dez bins padrão; a barra mais alta cobre os valores de 3,6 a 4,5 e tem uma contagem de 5.

O plt.hist() retorna três valores. counts contém o número de observações em cada bin, bin_edges fornece os limites dos intervalos e patches contém os artistas das barras, caso você precise alterar o estilo de barras individuais depois. O número de itens em counts é o número de bins, enquanto bin_edges sempre tem um item a mais, porque marca as duas extremidades de cada intervalo. Aqui o intervalo de dados vai de 0 a 9, portanto cada um dos dez bins padrão tem 0,9 de largura, e a barra mais alta é o intervalo de 3,6 a 4,5, que contém as cinco ocorrências do valor 4. Você pode omitir a atribuição e chamar apenas plt.hist(data) se precisar somente do gráfico.

Definir o número de bins ou as bordas dos bins

O parâmetro bins controla como os dados são divididos. Passar um inteiro como bins=20 cria esse número de intervalos de largura igual ao longo do intervalo de dados:

import matplotlib.pyplot as plt

data = [3, 4, 2, 3, 4, 5, 4, 7, 8, 5, 4, 6, 2, 1, 0, 9, 7, 6, 6, 5, 4]
counts, bin_edges, patches = plt.hist(data, bins=20)
print("counts:", counts.tolist())
print("number of bins:", len(counts))
plt.xlabel("Value")
plt.ylabel("Count")
plt.title("Histogram with 20 bins")
plt.show()
counts: [1.0, 0.0, 1.0, 0.0, 2.0, 0.0, 2.0, 0.0, 5.0, 0.0, 0.0, 3.0, 0.0, 3.0, 0.0, 2.0, 0.0, 1.0, 0.0, 1.0]
number of bins: 20

A mesma lista traçada com 20 bins; muitos dos bins estreitos ficam vazios porque os dados contêm apenas números inteiros de 0 a 9.

Vinte bins são demais para esta lista pequena: como os valores são inteiros, um em cada dois bins fica vazio e a distribuição parece mais ruidosa do que é. Em geral, bins muito poucos podem ocultar a estrutura dos dados, enquanto muitos bins estreitos podem fazer um conjunto de dados pequeno parecer irregular, por isso escolha um número de bins adequado ao tamanho e à dispersão da sua lista. Em vez de um inteiro, você pode passar uma sequência de valores de borda como bins=[0, 2, 4, 6, 8, 10] para definir você mesmo os limites dos intervalos; os intervalos podem então ter larguras diferentes. Quando as contagens abrangem um intervalo amplo, o argumento opcional log=True muda o eixo das contagens para uma escala logarítmica, para que as barras menores continuem visíveis ao lado de uma barra alta. Ele altera apenas a escala do eixo, não os valores de entrada nem a divisão em bins.

Mostrar a densidade de probabilidade em vez das contagens

Por padrão, as alturas das barras são contagens. Defina density=True quando quiser uma densidade de probabilidade em vez disso. O Matplotlib então escala as alturas de modo que a área total das barras seja 1:

import matplotlib.pyplot as plt

data = [3, 4, 2, 3, 4, 5, 4, 7, 8, 5, 4, 6, 2, 1, 0, 9, 7, 6, 6, 5, 4]
counts, bin_edges, patches = plt.hist(data, bins=10, density=True)
print("densities:", [round(d, 4) for d in counts.tolist()])
area = sum(d * (bin_edges[i + 1] - bin_edges[i]) for i, d in enumerate(counts))
print("total area:", round(area, 6))
plt.xlabel("Value")
plt.ylabel("Probability density")
plt.title("Probability histogram of data")
plt.show()
densities: [0.0529, 0.0529, 0.1058, 0.1058, 0.2646, 0.1587, 0.1587, 0.1058, 0.0529, 0.0529]
total area: 1.0

Histograma de densidade de probabilidade da lista desenhado com density=True; as alturas das barras são densidades e a área total das barras é 1.

Com density=True, o primeiro valor da tupla retornada contém densidades em vez de contagens, e o exemplo verifica a normalização multiplicando cada densidade pela largura do seu bin e somando as áreas, o que resulta exatamente em 1. Observe que a altura de uma barra individual é uma densidade, e não a probabilidade do seu intervalo; a probabilidade de um intervalo é a área da sua barra, ou seja, a altura multiplicada pela largura. Essa distinção importa quando os bins têm larguras diferentes, porque uma barra larga pode representar mais probabilidade do que uma barra estreita mais alta. Lembre-se de atualizar o rótulo do eixo vertical ao fazer a troca, como faz o exemplo, para que o gráfico explique o que significam as alturas das suas barras.

Alterar a cor das barras

O parâmetro color define a cor de preenchimento das barras:

import matplotlib.pyplot as plt

data = [3, 4, 2, 3, 4, 5, 4, 7, 8, 5, 4, 6, 2, 1, 0, 9, 7, 6, 6, 5, 4]
plt.hist(data, bins=10, color="red")
plt.xlabel("Value")
plt.ylabel("Count")
plt.title("Red histogram of data")
plt.show()

O histograma da lista com barras vermelhas, desenhado com dez bins e o parâmetro color definido como vermelho.

Qualquer especificação de cor do Matplotlib funciona, como um nome como "red", uma cadeia hexadecimal como "#1f77b4" ou um código de uma única letra. As opções de apresentação combinam-se livremente numa única chamada; por exemplo, plt.hist(data, bins=20, density=True, color="red") desenha vinte barras vermelhas com alturas de densidade. Seja qual for a combinação de opções, mantenha o título e os rótulos dos eixos alinhados com elas: um gráfico de densidade não deve manter um rótulo de contagem, e um gráfico com vinte bins não deve afirmar que mostra os dez padrão.

Lidar com um número de bins inválido e uma lista vazia

Vale a pena conhecer dois erros de entrada antes que eles o surpreendam. O primeiro é um número de bins que não é positivo:

import matplotlib.pyplot as plt

data = [3, 4, 2, 3, 4, 5, 4, 7, 8, 5, 4, 6, 2, 1, 0, 9, 7, 6, 6, 5, 4]
plt.hist(data, bins=0)
Traceback (most recent call last):
  ...
ValueError: `bins` must be positive, when an integer

bins=0 (e qualquer inteiro negativo) levanta um ValueError e nada é desenhado. Se o número de bins vier de uma entrada do usuário ou de um cálculo, valide se ele é um inteiro positivo antes de traçar, ou passe em vez disso uma sequência de bordas. O segundo caso é uma lista vazia, que se comporta de maneira muito diferente: não é erro algum.

import matplotlib.pyplot as plt

counts, bin_edges, patches = plt.hist([])
print("counts:", counts.tolist())
print("bin_edges:", [round(e, 2) for e in bin_edges.tolist()])
counts: [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
bin_edges: [0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0]

Sem dados, o plt.hist() recorre ao intervalo padrão de 0 a 1, retorna dez contagens iguais a zero e desenha um conjunto de eixos vazio sem levantar exceção. Isso torna a lista vazia um modo de falha silencioso: se os seus dados vêm de um arquivo, de uma consulta ou de um filtro, verifique se a lista não está vazia antes de traçar, para que um conjunto de dados ausente não se transforme em um gráfico em branco que parece um resultado válido.