Observação
Clique aqui para baixar o código de exemplo completo
O ciclo de vida de um enredo #
Este tutorial visa mostrar o início, o meio e o fim de uma única visualização usando o Matplotlib. Começaremos com alguns dados brutos e terminaremos salvando a figura de uma visualização personalizada. Ao longo do caminho, tentamos destacar alguns recursos interessantes e melhores práticas usando o Matplotlib.
Observação
Este tutorial é baseado nesta excelente postagem de blog de Chris Moffitt. Ele foi transformado neste tutorial por Chris Holdgraf.
Uma observação sobre interfaces explícitas e implícitas #
Matplotlib tem duas interfaces. Para obter uma explicação das compensações entre as interfaces explícitas e implícitas, consulte Matplotlib Application Interfaces (APIs) .
Na interface orientada a objetos (OO) explícita, utilizamos diretamente instâncias de
axes.Axes
para construir a visualização em uma instância de
figure.Figure
. Na interface implícita, inspirada e modelada no MATLAB, usa uma interface baseada em estado global que é encapsulada no
pyplot
módulo para plotar os "Eixos atuais". Veja os tutoriais do pyplot para uma visão mais aprofundada da interface do pyplot.
A maioria dos termos é direta, mas a principal coisa a lembrar é que:
A Figura é a imagem final que pode conter 1 ou mais Eixos.
Os eixos representam um gráfico individual (não confunda isso com a palavra "eixo", que se refere ao eixo x/y de um gráfico).
Chamamos métodos que fazem a plotagem diretamente dos Axes, o que nos dá muito mais flexibilidade e poder na customização da nossa plotagem.
Observação
Em geral, prefira a interface explícita sobre a interface pyplot implícita para plotagem.
Nossos dados #
Usaremos os dados da postagem da qual este tutorial foi derivado. Ele contém informações de vendas para várias empresas.
import numpy as np
import matplotlib.pyplot as plt
data = {'Barton LLC': 109438.50,
'Frami, Hills and Schmidt': 103569.59,
'Fritsch, Russel and Anderson': 112214.71,
'Jerde-Hilpert': 112591.43,
'Keeling LLC': 100934.30,
'Koepp Ltd': 103660.54,
'Kulas Inc': 137351.96,
'Trantow-Barrows': 123381.38,
'White-Trantow': 135841.99,
'Will LLC': 104437.60}
group_data = list(data.values())
group_names = list(data.keys())
group_mean = np.mean(group_data)
Primeiros passos #
Esses dados são naturalmente visualizados como um gráfico de barras, com uma barra por grupo. Para fazer isso com a abordagem orientada a objetos, primeiro geramos uma instância de figure.Figure
e
axes.Axes
. A Figura é como uma tela, e os Eixos são uma parte dessa tela na qual faremos uma determinada visualização.
Observação
As figuras podem ter vários eixos nelas. Para obter informações sobre como fazer isso, consulte o tutorial Tight Layout .
fig, ax = plt.subplots()
Agora que temos uma instância de Axes, podemos plotar em cima dela.
fig, ax = plt.subplots()
ax.barh(group_names, group_data)
<BarContainer object of 10 artists>
Controlando o estilo #
Existem muitos estilos disponíveis no Matplotlib para permitir que você adapte sua visualização às suas necessidades. Para ver uma lista de estilos, podemos usar
style
.
print(plt.style.available)
['Solarize_Light2', '_classic_test_patch', '_mpl-gallery', '_mpl-gallery-nogrid', 'bmh', 'classic', 'dark_background', 'fast', 'fivethirtyeight', 'ggplot', 'grayscale', 'seaborn-v0_8', 'seaborn-v0_8-bright', 'seaborn-v0_8-colorblind', 'seaborn-v0_8-dark', 'seaborn-v0_8-dark-palette', 'seaborn-v0_8-darkgrid', 'seaborn-v0_8-deep', 'seaborn-v0_8-muted', 'seaborn-v0_8-notebook', 'seaborn-v0_8-paper', 'seaborn-v0_8-pastel', 'seaborn-v0_8-poster', 'seaborn-v0_8-talk', 'seaborn-v0_8-ticks', 'seaborn-v0_8-white', 'seaborn-v0_8-whitegrid', 'tableau-colorblind10']
Você pode ativar um estilo com o seguinte:
plt.style.use('fivethirtyeight')
Agora vamos refazer o gráfico acima para ver como fica:
fig, ax = plt.subplots()
ax.barh(group_names, group_data)
<BarContainer object of 10 artists>
O estilo controla muitas coisas, como cor, larguras de linha, planos de fundo, etc.
Personalizando o enredo #
Agora temos um gráfico com a aparência geral que queremos, então vamos ajustá-lo para que esteja pronto para impressão. Primeiro, vamos girar os rótulos no eixo x para que apareçam com mais clareza. Podemos obter acesso a esses rótulos com o axes.Axes.get_xticklabels()
método:
fig, ax = plt.subplots()
ax.barh(group_names, group_data)
labels = ax.get_xticklabels()
Se quisermos definir a propriedade de muitos itens de uma só vez, é útil usar a pyplot.setp()
função. Isso pegará uma lista (ou muitas listas) de objetos Matplotlib e tentará definir algum elemento de estilo de cada um.
fig, ax = plt.subplots()
ax.barh(group_names, group_data)
labels = ax.get_xticklabels()
plt.setp(labels, rotation=45, horizontalalignment='right')
[None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None]
Parece que isso cortou algumas das etiquetas na parte inferior. Podemos dizer ao Matplotlib para abrir espaço automaticamente para elementos nas figuras que criamos. Para fazer isso, definimos o autolayout
valor de nosso rcParams. Para obter mais informações sobre como controlar o estilo, layout e outros recursos de plotagens com rcParams, consulte
Personalizando Matplotlib com folhas de estilo e rcParams .
plt.rcParams.update({'figure.autolayout': True})
fig, ax = plt.subplots()
ax.barh(group_names, group_data)
labels = ax.get_xticklabels()
plt.setp(labels, rotation=45, horizontalalignment='right')
[None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None]
Em seguida, adicionamos rótulos ao gráfico. Para fazer isso com a interface OO, podemos usar o Artist.set()
método para definir as propriedades desse objeto Axes.
fig, ax = plt.subplots()
ax.barh(group_names, group_data)
labels = ax.get_xticklabels()
plt.setp(labels, rotation=45, horizontalalignment='right')
ax.set(xlim=[-10000, 140000], xlabel='Total Revenue', ylabel='Company',
title='Company Revenue')
[(-10000.0, 140000.0), Text(0.5, 87.00000000000003, 'Total Revenue'), Text(86.99999999999997, 0.5, 'Company'), Text(0.5, 1.0, 'Company Revenue')]
Também podemos ajustar o tamanho deste gráfico usando a pyplot.subplots()
função. Podemos fazer isso com o argumento da palavra-chave figsize .
Observação
Enquanto a indexação no NumPy segue a forma (linha, coluna), o argumento da palavra-chave figsize segue a forma (largura, altura). Isso segue as convenções de visualização, que infelizmente são diferentes daquelas da álgebra linear.
fig, ax = plt.subplots(figsize=(8, 4))
ax.barh(group_names, group_data)
labels = ax.get_xticklabels()
plt.setp(labels, rotation=45, horizontalalignment='right')
ax.set(xlim=[-10000, 140000], xlabel='Total Revenue', ylabel='Company',
title='Company Revenue')
[(-10000.0, 140000.0), Text(0.5, 86.99999999999997, 'Total Revenue'), Text(86.99999999999997, 0.5, 'Company'), Text(0.5, 1.0, 'Company Revenue')]
Para rótulos, podemos especificar diretrizes de formatação personalizadas na forma de funções. Abaixo definimos uma função que recebe um inteiro como entrada e retorna uma string como saída. Quando usados com Axis.set_major_formatter
ou
Axis.set_minor_formatter
, eles criarão e usarão automaticamente uma
ticker.FuncFormatter
classe.
Para esta função, o x
argumento é o rótulo original do tick e pos
é a posição do tick. Usaremos apenas x
aqui, mas ambos os argumentos são necessários.
def currency(x, pos):
"""The two arguments are the value and tick position"""
if x >= 1e6:
s = '${:1.1f}M'.format(x*1e-6)
else:
s = '${:1.0f}K'.format(x*1e-3)
return s
Podemos então aplicar essa função aos rótulos em nosso gráfico. Para fazer isso, usamos o xaxis
atributo de nossos eixos. Isso permite que você execute ações em um eixo específico em nosso gráfico.
fig, ax = plt.subplots(figsize=(6, 8))
ax.barh(group_names, group_data)
labels = ax.get_xticklabels()
plt.setp(labels, rotation=45, horizontalalignment='right')
ax.set(xlim=[-10000, 140000], xlabel='Total Revenue', ylabel='Company',
title='Company Revenue')
ax.xaxis.set_major_formatter(currency)
Combinando várias visualizações #
É possível desenhar vários elementos de plotagem na mesma instância de
axes.Axes
. Para fazer isso, simplesmente precisamos chamar outro dos métodos plot naquele objeto de eixos.
fig, ax = plt.subplots(figsize=(8, 8))
ax.barh(group_names, group_data)
labels = ax.get_xticklabels()
plt.setp(labels, rotation=45, horizontalalignment='right')
# Add a vertical line, here we set the style in the function call
ax.axvline(group_mean, ls='--', color='r')
# Annotate new companies
for group in [3, 5, 8]:
ax.text(145000, group, "New Company", fontsize=10,
verticalalignment="center")
# Now we move our title up since it's getting a little cramped
ax.title.set(y=1.05)
ax.set(xlim=[-10000, 140000], xlabel='Total Revenue', ylabel='Company',
title='Company Revenue')
ax.xaxis.set_major_formatter(currency)
ax.set_xticks([0, 25e3, 50e3, 75e3, 100e3, 125e3])
fig.subplots_adjust(right=.1)
plt.show()
Salvando nosso enredo #
Agora que estamos satisfeitos com o resultado de nossa plotagem, queremos salvá-la em disco. Existem muitos formatos de arquivo nos quais podemos salvar no Matplotlib. Para ver uma lista de opções disponíveis, use:
print(fig.canvas.get_supported_filetypes())
{'eps': 'Encapsulated Postscript', 'jpg': 'Joint Photographic Experts Group', 'jpeg': 'Joint Photographic Experts Group', 'pdf': 'Portable Document Format', 'pgf': 'PGF code for LaTeX', 'png': 'Portable Network Graphics', 'ps': 'Postscript', 'raw': 'Raw RGBA bitmap', 'rgba': 'Raw RGBA bitmap', 'svg': 'Scalable Vector Graphics', 'svgz': 'Scalable Vector Graphics', 'tif': 'Tagged Image File Format', 'tiff': 'Tagged Image File Format', 'webp': 'WebP Image Format'}
Podemos então usar o figure.Figure.savefig()
para salvar a figura no disco. Observe que existem vários sinalizadores úteis que mostramos abaixo:
transparent=True
torna o fundo da figura salva transparente se o formato o suportar.dpi=80
controla a resolução (pontos por polegada quadrada) da saída.bbox_inches="tight"
ajusta os limites da figura ao nosso enredo.
# Uncomment this line to save the figure.
# fig.savefig('sales.png', transparent=False, dpi=80, bbox_inches="tight")
Tempo total de execução do script: ( 0 minutos 3,918 segundos)