No post Refinando a apresentação do matplotlib eu mostrei como melhorar o layout dos gráficos do matplotlib utilizando o seaborn. Continuando com as dicas para refinar a apresentação dos gráficos em matplotlib vou mostrar como construir um gráfico mais científico, semelhante aos que aparecem em livros de cálculo da graduação. Para isso vou apresentar as funções despine e offset_spines do seaborn e algumas de suas opções.

O layout padrão coloca os gráficos em uma caixa, como se fosse uma borda. No entanto, alguns gráficos ficam mais atrativos quando colocamos apenas o eixo x-y, sem a caixa, ou ainda sem as bordas e com linhas de grade em tom suave.

Vamos começar observando o gráfico abaixo de uma série temporal sintética simulando um processo estocástico geométrico sem coeficiente linear (drift).

In [4]:
import seaborn as sn
sn.set_context("talk")

ts = cumprod(exp(random.randn(200)*0.02))
In [5]:
sn.set_style("ticks")
plot(ts);

No gráfico acima temos os ticks no eixo y que delimitam os níveis. Uma informação interessante de se obter visualmente é a duração da série em determinadas faixas. No gráfico acima essa informação está presente mas não está clara. Uma forma de se obter isso é a criação de linhas de grade (grids).

In [6]:
plot(ts)
grid();

A inclusão de linhas de grade ajudam a melhorar a interpretação do gráfico ficando fácil observar os intervalos de oscilação da série temporal. Com a inclusão das grades podemos observar com detalhes quando a série ultrapassa as linhas de grade. Para séries temporais longas, onde a observação temporal é relevante essa funcionalidade ajuda na interpretação do gráfico.

Para melhorar a visualização vou remover a caixa usando a função despine e manter as linhas de grade apenas para o eixo y.

In [7]:
plot(ts)
sn.despine()
grid(axis='y')

Agora vou remover o eixo y mantendo as linhas de grade para ressaltar os níveis de oscilação.

In [8]:
plot(ts)
sn.despine(left=True)
grid(axis='y')

Para destacar ainda mais os dados vou desacolplar os eixos do gráfico realçando as linhas de grade. A função offset_spines desloca os eixos do gráfico uma quantidade de pontos. Na função despine usamos o argumento bottom=True para remover o eixo x, mantendo as marcas (ticks).

In [9]:
plot(ts)
sn.offset_spines(20)
sn.despine(left=True, bottom=True)
grid(axis='y')

Ou ainda removendo os ticks, para isso definimos os estilo como whitegrid.

In [10]:
sn.set_style("whitegrid")
plot(ts)
sn.offset_spines()
sn.despine(left=True, bottom=True)
grid(False, axis='x')

Note que agora tivemos que retirar as linhas de grade referentes ao eixo x (grid(False, axis='x')), dado que o estilo já define linhas de grade.

Conclusão

Francamente nem sei como reproduzir essas funcionalidades utilizando apenas o matplotlib, no tutorial do seaborn eles mencionam que não seria possível fazer isso utilizando os parâmetros do matplotlib, acho que cabe uma verificação.

As funções despine e offset_spines permitem enriquecer a visualização dos gráficos com comandos simples e intuitivos. Estes ajustes são importantes para que você destaque nos gráficos a informação que se acredita relevante. Afinal, esse é um dos objetivos da visualização, melhorar a comunicação. A informação já está lá você somente precisa fazer com que ela seja mais facilmente digerida.

Abaixo segue uma aplicação prática do que acabamos de discutir. Um gráfico de rentabilidade de ativos (PETR4 e BOVA11) contra o CDI (um investimento em renda fixa, CDB por exemplo). Note que mesmo com a maré ruim do mercado ambos os ativos bateram o CDI nos primeiros 6 meses do ano (2014).

In [11]:
import Quandl

# baixando os dados - a partir do começo do ano
ts = Quandl.get(["GOOG/BVMF_PETR4.4", "GOOG/BVMF_BOVA11.4", "BCB/12"], trim_start='2014-01-01')
ts = ts.rename(columns={'GOOG.BVMF_PETR4 - Close': 'PETR4', 'GOOG.BVMF_BOVA11 - Close': 'BOVA11',
                   'BCB.12 - Value': 'CDI'})

# separando ações da taxa de juros
stocks = ts.drop('CDI', 1)
cdi = ts.CDI/100 # as taxas de juros vem em unidades %

# calculando a variação percentual das ações
varp = exp(log(stocks).diff()) - 1
varp = varp.dropna() # removendo os NaN

# juntando com o CDI e calculando a variação percentual acumulada
varp = varp.join(cdi) + 1
varp = (varp.cumprod() - 1)*100

# montando o gráfico
varp.plot()
sn.despine(left=True, bottom=True)
grid(False, axis='x')
title('Rentabilidade')
ylabel('%')
xlabel('');
No authentication tokens found: usage will be limited.
See www.quandl.com/api for more information.
Returning Dataframe for  [u'GOOG.BVMF_PETR4.4', u'GOOG.BVMF_BOVA11.4', u'BCB.12']