Dashboards com Python (Parte 2)

11 minute read

Desenvolvendo gráficos com matplotlib, Plotly e Dash (Parte 2 de 3)!

Olá 😀!

Neste texto vou dar sequência a criação de Dashboards com Python, onde vou estudar como gerar gráficos com o Plotly. Na Parte 1 preparei os dados e criei os gráficos com o matplotlib. Já na Parte 3 criei os Dashboards.

Você pode baixar o notebook construído até aqui neste link e a planilha com os dados neste outro link.

Introdução

Agora vamos utilizar o Plotly para gerar os gráficos. Através desta biblioteca, podemos gerar gráficos interativos onde é possível mostrar algumas informações ao passar o mouse em pontos no gráfico. A “desvantagem” é que os gráficos gerados são salvos em arquivos “.html”.

Para desenhar os gráficos e gerar os arquivos html, o Plotly combina script Python com marcações (tags) de HTML e estilo de CSS. Eu tenho conhecimento básico de HTML e CSS, e não tive dificuldade nenhuma em entender os passos. Caso você não saiba nada de HTML e CSS, talvez tenha alguma dificuldade, mas não desanime, pois não é nada complicado.

De qualquer forma, os gráficos gerados com o Plotly são elegantes e não precisam de muita edição. Depois que você entende a sua sintaxe, a coisa fica bem dinâmica e relativamente simples.

Gráficos com Plotly

Para gerar gráficos com o Plotly precisamos montar duas estruturas: uma com os dados do gráfico, e outra com o estilo do gráfico. A estrutura dos dados geralmente é chamada de traço (trace), e corresponde ao conjunto de dados separados em listas (cada conjunto está em uma posição na lista). No gráfico de linhas, teremos um traço para o ano de 1998, um outro traço para o ano de 1999, outro para o de 2000 e assim por diante. Já o layout, é um conjunto de informações específicas para o design do gráfico (HTML e CSS). Depois basta combinar as duas estruturas em uma Figura do Plotly e pronto.

Para começar, precisamos importar o Plotly:

import plotly.offline as pyo
import plotly.graph_objs as go


Então, Vamos lá!

Gráfico de dispersão com linhas

Vamos começar com o primeiro ano (1998, setando i = 0). Incialmente, criamos o traço para este conjunto de dados:

traco = [go.Scatter(
                    x = df_aux.columns.values[1:13], # os dados do eixo x
                    y = df_aux.loc[i][1:13] # acessando os dados dos meses (dados do eixo y),
                    mode = 'lines+markers' # define o tipo de gráfico, neste caso vai ter linhas e marcadores
)]

Depois criamos um layout simples para o traço:

layout = go.Layout(
                   title = 'Número de focos de queimadas ao longo do ano'
)

Depois criamos uma instância de figura do Plotly, combinando o traço com o layout:

fig = go.Figure(data=tracos, layout=layout)

E por fim basta gerar o arquivo:

pyo.plot(fig,filename = 'scatter-plot.html')

Figura 1 - Gráfico de dispersão com linhas e pontos gerados com o Plotly.

print do gráfico de linhas e pontos gerados com o Plotly

Você pode ver o gráfico interativo clicando aqui.

Podemos editar um pouco mais este gráfico antes de gerar o gráfico com todos os anos. Adicionando o parâmetro name podemos dar um nome ao traço (legenda):

name = str(df_aux['Ano'][i]), # adiciono o nome do traço

Também podemos alterar o que é apresentado quando passamos o mouse sobre um ponto. Podemos alterar para qualquer coisa que quisermos, mas dependendo do que se deseja adicionar, pode ser bem complicado.

hovertemplate = df_aux.columns.values[1:13] + ' de ' + str(df_aux['Ano'][i]) + '<br>nº de focos: ' + [str(i) for i in list(df_aux.loc[i][1:13])],

Ainda alterando o hover, podemos mexer na sua aparência, passando o parâmetro hoverlabel para o layout:

showlegend=True, # garante que a legenda será mostrada
hovermode = "closest", # garante que o hover irá mostrar os dados do ponto mais próximo a seta do mouse
hoverlabel=dict(bgcolor="white", # altera a cor de fundo
                font_size=16, # altera o tamanho da fonte
                font_family="Roboto") # altera a fonte de texto

Figura 2 - Gráfico de dispersão editado com linhas e pontos gerados com o Plotly.

print do gráfico de linhas e pontos editado que foi gerado com o Plotly.

Você pode ver o gráfico interativo clicando aqui.

Agora falta apenas melhorar os eixos. Vou adicionar o nome ao eixo x e passar uma linha (y=0) preta para demarcar o gráfico:

xaxis = dict(title = 'Meses', linecolor='rgba(0,0,0,1)'), # Nome do eixo x / adiciona uma linha preta em y=0

E vou fazer a mesma coisa para o eixo y:

yaxis = dict(title = 'Número de focos de queimadas', linecolor='rgba(0,0,0,1)'), # Nome do eixo y / adiciona uma linha preta em x=0

Figura 3 - Gráfico de dispersão editado com linhas e pontos gerados com o Plotly.

print do gráfico de linhas e pontos editado que foi gerado com o Plotly.

Você pode ver o gráfico interativo clicando aqui.

Agora vamos adicionar os demais anos ao gráfico. Para isso, precisamos criar um traço para cada série de dados. A forma mais fácil de fazer isto é colocar a criação de traços dentro de um loop for, e percorrer ao longo dos anos. Então vou criar uma lista vazia chamada tracos, que a cada iteração receberá um novo traço. Depois é só passar esta lista para a Figura.

df_aux = df[df['Bioma'] == df['Bioma'].unique()[0]] # Dividindo o data frame para ter apenas os dados de 1 bioma
# criando os traços
tracos = []
for i in range(df_aux.shape[0]):
    tracos.append(go.Scatter(
                        x = df_aux.columns.values[1:13], # os dados do eixo x
                        y = df_aux.loc[i][1:13], # acessando os dados dos meses (dados do eixo y)
                        mode = 'lines+markers', # define o tipo de gráfico, neste caso vai ter linhas e marcadores
                        name = str(df_aux['Ano'][i]), # adiciono o nome do traço
                        hovertemplate = df_aux.columns.values[1:13] + ' de ' + str(df_aux['Ano'][i]) + '<br>nº de focos: '
                        + [str(i) for i in list(df_aux.loc[i][1:13])] , # alterando o template do hover
    ))
# criando o layout
layout = go.Layout(
                   title = 'Número de focos de queimadas ao longo do ano no bioma: ' + df['Bioma'].unique()[0],
                   showlegend=True, # garante que a legenda será mostrada
                   hovermode = "closest", # garante que o hover irá mostrar os dados do ponto mais próximo a seta do mouse
                   hoverlabel=dict(bgcolor="white", # altera a cor de fundo
                                    font_size=16, # altera o tamanho da fonte
                                    font_family="Roboto"), # altera a fonte de texto
                   xaxis = dict(title = 'Meses', linecolor='rgba(0,0,0,1)'), # Nome do eixo x / adiciona uma linha preta em y=0
                   yaxis = dict(title = 'Número de focos de queimadas', linecolor='rgba(0,0,0,1)'),
)
# Criando a figura
fig = go.Figure(data=tracos, layout=layout)
pyo.plot(fig,filename = 'scatter-plot.html') # gerando o arquivo

Figura 4 - Gráfico de dispersão editado com linhas e pontos gerados com o Plotly para o total de focos de queimadas no bioma Amazônia ao longo de todo o período avaliado.

print do gráfico de linhas e pontos para todos os anos do periodo avaliado que foi gerado com o Plotly.

Você pode ver o gráfico interativo clicando aqui.

Agora falta criar o mesmo gráfico para os outros biomas, o que pode ser feito com um novo for loop (como foi feito anteriormente), ou apenas alterando a primeira linha para o bioma desejado.

Gráfico de barras

Agora vamos gerar o gráfico de barras para o total de focos de queimadas registrado ao longo do período. Vou seguir com a mesma estratégia de fazer para o primeiro ano, e depois expandir para os outros anos.

A estrutura é exatamente a mesma: criamos o traço com os dados para o gráfico (agora o gráfico de barras), e criamos o layout. Depois juntamos em uma figura, e geramos o arquivo .html.

df_aux = df[df['Bioma'] == df['Bioma'].unique()[0]] # Dividindo o data frame para ter apenas os dados de 1 bioma
traco = [go.Bar(
                x = df_aux['Ano'], # os dados do eixo x
                y = df_aux['Total'])] # acessando os dados dos anos (dados do eixo y)

layout = go.Layout(
                  title = 'Total de focos de queimadas ao longo de todo o período avaliado no bioma: ' +
                  df['Bioma'].unique()[0], # adicionando um titulo
                    )
# Criando a figura
fig = go.Figure(data = traco, layout = layout)
pyo.plot(fig, filename = 'bar-plot.html')# gerando o arquivo

Figura 5 - Gráfico de barras gerado com o Plotly.

print do gráfico de barras que foi gerado com o Plotly.

Você pode ver o gráfico interativo clicando aqui.

Agora falta adicionar detalhes. A única coisa diferente que vou fazer é especificar os labels do eixo x, para que seja apresentado o ano abaixo de cada barra no eixo x, e também vou remover o formato dos ticks no eixo y para que apareça o número inteiro.

df_aux = df[df['Bioma'] == df['Bioma'].unique()[0]] # Dividindo o data frame para ter apenas os dados de 1 bioma
traco = [go.Bar(
                x = df_aux['Ano'], # os dados do eixo x
                y = df_aux['Total'],
                name = df['Bioma'].unique()[0],
                hovertemplate = ['Total de focos de queimadas: ' + i for i in [str(i) for i in (df_aux['Total'])]],
)] # acessando os dados dos anos (dados do eixo y)

layout = go.Layout(
                  title = 'Total de focos de queimadas ao longo de todo o período avaliado no bioma: ' +
                  df['Bioma'].unique()[0], # adicionando um titulo
                  xaxis = dict(title = 'Anos', linecolor='rgba(0,0,0,1)', tickmode = 'array', tickvals = df_aux['Ano'], ticktext = df_aux['Ano']), # adicionando nome eo eixo x, barra (y=0) na cor preta, e fixando o ano abaixo de todas as barras
                  yaxis = dict(title = 'Total de queimadas por ano', linecolor='rgba(0,0,0,1)', tickformat=False), # adicionando nome no eixo y, passando uma linha preta em x = 0, e removendo a formatação padrão dos ticks, para que não apareça o K
                  showlegend=True, # adicionando a legenda
                  hoverlabel=dict(bgcolor="white", # alterando a cor de fundo do hover
                                    font_size=16, # alterando o tamanho da letra no hover
                                    font_family="Roboto") # alterando a fonte do hover

                    )
# Criando a figura
fig = go.Figure(data = traco, layout = layout)
pyo.plot(fig, filename = 'bar-plot.html')# gerando o arquivo

Figura 6 - Gráfico de barras gerado com o Plotly para o total de focos de queimadas identificados no bioma Amazônia em todo o período avaliado.

print do gráfico de barras editado que foi gerado com o Plotly.

Você pode ver o gráfico interativo clicando aqui.

Gráfico de pizza

Agora vamos ao gráfico de pizza. É muito semelhante ao que fizemos até agora, mas vamos precisar explicitar os valores de y através do parâmetro values, e os valores de x através do parâmetro labels. Mas a estrutura permanece a mesma.

df_aux = df[df['Bioma'] == df['Bioma'].unique()[0]] # Dividindo o data frame para ter apenas os dados de 1 bioma
traco = [go.Pie(
                labels = df_aux['Ano'], # adicionando os labels das fatias de pizza
                values = df_aux['Total'], # adicionando o tamanho das fatais de pizza

)]

layout = go.Layout(
                    title_text='Total de focos de queimadas ao longo de todo o período avaliado no bioma: ' +
                    df['Bioma'].unique()[0], # adicionando um titulo
                  )
# Criando a figura
fig = go.Figure(data = traco, layout = layout)
pyo.plot(fig, filename = 'pie-plot.html')# gerando o arquivo

Figura 7 - Gráfico de pizza obtido com o Plotly para o total de focos de queimadas no bioma Amazônia ao longo de todo o período avaliado.

print do gráfico de pizza que foi gerado com o Plotly.

Você pode ver o gráfico interativo clicando aqui.

Observe que por padrão o gráfico já esta na ordem da maior fatia para a menor fatia. Entretanto, ele começa no ângulo diferente (confesso que não identifiquei qual ângulo exato… esta próximo a 45°, mas não tenho certeza…). Para alterar a posição de inicio das fatias, basta passar o parâmetro rotation com o valor do ângulo que deseja utilizar. Entretanto, este parâmetro não me pareceu estar consolidado, pois ao trocar de dados, o ângulo inicial também muda (mesmo sem alterar o rotation).

Também podemos alterar a orientação do texto dentro das fatias, mudando o parâmetro insidetextorientation para ‘radial’ por exemplo.

df_aux = df[df['Bioma'] == df['Bioma'].unique()[0]] # Dividindo o data frame para ter apenas os dados de 1 bioma
traco = [go.Pie(
                labels = df_aux['Ano'], # adicionando os labels das fatias de pizza
                values = df_aux['Total'], # adicionando o tamanho das fatais de pizza
                rotation=-30, # mudando a posição inicial de preenchimento das fatias
                insidetextorientation='radial', # mudando a orientação do texto dentro das fatias
)]

layout = go.Layout(
                    title_text='Total de focos de queimadas ao longo de todo o período avaliado no bioma: ' +
                    df['Bioma'].unique()[0], # adicionando um titulo
                  )
# Criando a figura
fig = go.Figure(data = traco, layout = layout)
pyo.plot(fig, filename = 'pie-plot.html')# gerando o arquivo

Figura 8 - Gráfico de pizza obtido com o Plotly para o total de focos de queimadas no bioma Amazônia ao longo de todo o período avaliado.

print do gráfico de pizza que foi gerado com o Plotly.

Você pode ver o gráfico interativo clicando aqui.

Por fim, eu vou alterar o gráfico de pizza para um gráfico de rosquinha (donut). Ou seja, vou adicionar um buraco no centro da pizza, e inserir nesse buraco um texto indicando qual tipo de dado a que os dados correspondem. Para fazer isto, basta adicionar o parâmetro hole para o traço indicando o tamanho do buraco. E também precisamos passar a anotação texto que desejamos inserir, o que é feito através do parâmetro annotations que deve ser passado para o layout:

df_aux = df[df['Bioma'] == df['Bioma'].unique()[0]] # Dividindo o data frame para ter apenas os dados de 1 bioma
traco = [go.Pie(
                labels = df_aux['Ano'], # adicionando os labels das fatias de pizza
                values = df_aux['Total'], # adicionando o tamanho das fatais de pizza
#                 rotation=-45, # mudando a posição inicial de preenchimento das fatias
                insidetextorientation='radial', # mudando a orientação do texto dentro das fatias
                hole=.3, # transformando a pizza em uma rosquinha

)]

layout = go.Layout(
                    title_text='Total de focos de queimadas ao longo de todo o período avaliado no bioma: ' +
                    df['Bioma'].unique()[0], # adicionando um titulo
                    annotations=[dict(text = 'Total', # Colocando o que será inserido dentro do buraco
                                      x = .5, # posição de x do centro do buraco da rosquinha
                                      y = 0.5, # posição de y do centro do buraco da rosquinha
                                      font_size = 20, # tamanho da fonte
                                      font_family = "Roboto", # alterando a fonte do texto
                                      showarrow = False, # removendo a seta que vem por padrão inserida
                                     )],
                  )
# Criando a figura
fig = go.Figure(data = traco, layout = layout)
pyo.plot(fig, filename = 'pie-plot.html')# gerando o arquivo

Figura 9 - Gráfico de rosquinha obtido com o Plotly para o total de focos de queimadas no bioma Amazônia ao longo de todo o período avaliado.

print do gráfico de rosquinha que foi gerado com o Plotly.

Você pode ver o gráfico interativo clicando aqui.

Essa biblioteca é muito poderosa, gostaria de tê-la conhecido anteriormente 😅.

Você pode baixar o notebook construído até aqui neste link.

Com isso fecho esta parte com o Plotly, mas não encerramos com ele não. No Parte 3 vou utilizar os gráficos desenhados com o Plotly para criar os Dashboards utilizando o Dash. Te vejo lá 💪!