Criando gráficos interativos com o Plotly Dash App

Matheus Ricardo dos Santos
6 min readNov 23, 2020

Neste artigo iremos analisar quais foram os partidos mais votados em cada estado do brasil para cada eleição desde 1996. Também criaremos uma aplicação web com uma simples dashboard capaz de interagir com os gráficos gerados.

1. Obtendo os dados

Os dados utilizados neste artigo foram obtidos através da plataforma Brasil.io que é um dos maiores repositórios de dados abertos do brasil. O dataset utilizado diz respeito aos candidatos que participaram de eleições entre 1996 e 2018. Esse dataset possui os dados de identificação dos candidatos em cada cidade e o seu respectivo número de votos.

Devido ao fato desse dataset ser muito grande, com aproximadamente 8GB, não podemos simplemente lê-lo da maneira convencional. Para isso, precisamos utiliazr uma abordagem de leitura por chunks.

# o parametro chunksize diz respeito ao número de linhas contidos em cada chunkvotacao_chunks = pd.read_csv('votacao-zona.csv', chunksize=10000)

Os chuncks são basicamente datasets menores que contém a mesma estrutura do dataset original. Para realizar a leitura do dataset precisamos iterar por cada chunk e pegar somente a informação que iremos utilizar.

No exemplo abaixo, para cada chunk está sendo realizada uma operação de agrupamento por ano de eleição, estado e partido. Isto é necessário pois é o que queremos para a nossa análise: para cada ano, em cada estado, saber qual foi o partido mais votado. Após o agrupamento, utiliamos a operação de soma sobre a coluna total_votos para obter o total de votos por partido em cada grupo e voltamos o dataset para o seu formato original com a função reset_index.

dfs = []for chunk in votacao_chunks:    columns = ['ano_eleicao', 'sigla_uf', 'nome_partido','numero_partido', 'sigla_partido', 'total_votos']    df_chunk = chunk[columns].groupby(by=['ano_eleicao', 'sigla_uf', 'sigla_partido', 'numero_partido', 'nome_partido']).sum().reset_index()    dfs.append(df_chunk)
# concatena cada chunk para gerar um novo dataset que contém somente os dados relevantes para a análiseresult = pd.concat(dfs, ignore_index=True).groupby(by=['ano_eleicao', 'sigla_uf', 'sigla_partido', 'numero_partido', 'nome_partido']).sum().reset_index()result.head()

O dataset resultante contém o número de votos por partido em cada estado em cada ano de eleição.

2.Modelando o dataset

No item anterior fizemos algumas alterações importantes para o formato final de nosso dataset. Neste item iremos realizar uma operação parecida para obter o dataset final.

Basicamente, precisamos agrupar novamente as linhas por ano e por estado para que seja possível recuperar o partido com o maior número de votos em cada grupo criado.

not_grouped = ['nome_partido', 'numero_partido', 'sigla_partido', 'total_votos']max_per_year_per_state = result.groupby(by=['ano_eleicao', 'sigla_uf']).apply(lambda df: df[not_grouped].iloc[df['total_votos'].argmax()]).reset_index()max_per_year_per_state.head()

Agora podemos facilmente recuperar qual partido foi o mais votado em um estado em um determinado ano. Neste exemplo escolhemos o ano de 2018 e o estado de São Paulo:

max_per_year_per_state.loc[(max_per_year_per_state['ano_eleicao']==2018) & (max_per_year_per_state['sigla_uf']=='SP')]

É importante lembrar que o número de votos está maior que o número de eleitores pois em 2018 tivemos eleições para presidente, governador, senador, deputado estadual e deputado federal, ou seja, cada eleitor votou em até 5 candidatos e em até 2 turnos.

3.Plotando os gráficos

O nosso objetivo agora é plotar dois tipos de gráfico: um gráfico (Choropleth Mapbox) que aplica uma cor em cada estado do Brasil para representar o partido mais votado no estado e um gráfico de barras que contém o número de votos de cada partido para um estado específico.

3.1.Choropleth Mapbox

A primeira coisa a se fazer é encontrar um geojson que representa a divisão de estados do Brasil. Para isso, utilizaremos o geojson do codeforamerica.

from urllib.request import urlopenwith urlopen(
'https://raw.githubusercontent.com/codeforamerica/click_that_hood/master/public/data/brazil-states.geojson') as response:
states = json.load(response)

Com o geojson carregado, podemos realizar o plot:

# dados da eleição de 2018
to_plot = max_per_year_per_state.loc[max_per_year_per_state['ano_eleicao']==2018]
fig_mapbox = px.choropleth_mapbox(to_plot, geojson=states, locations='sigla_uf', color='sigla_partido', mapbox_style="carto-positron", zoom=3, center = {"lat": -14.7024976, "lon": -45.8631977}, featureidkey="properties.sigla", hover_data=['sigla_uf', 'nome_partido', 'numero_partido', 'sigla_partido', 'total_votos'])fig_mapbox.update_layout(margin={"r":0,"t":0,"l":0,"b":0})fig_mapbox.show()

Como visto na iamgem acima, no ano de 2018 os partidos que receberam mais votos foram o PT e o PSL. O PT dominou a região nordeste enquanto o PSL dominou as regiões sul, centro, centro-oeste e norte do país.

3.2.Gráfico de Barras

Para plotar um gráfico de barras precisamos somente selecionar os dados por ano e estado. Portanto, não utilizaremos o dataset com os estados mais votados, e sim o dataset com os dados de cada partido por estado.

# selecionamos as eleições de 2018 no estado de São Paulo
bar_data = result[(result['ano_eleicao']==2018) & (result['sigla_uf']=='SP')]
fig_bar = px.bar(bar_data, x='sigla_partido', y='total_votos')fig_bar.show()

Podemos ver que os partidos mais votados em São Paulo no ano de 2018 foram respectivamente: PSL, PSDB, PT e PSB.

4.Dash App

Agora que já sabemos plotar ambos os gráficos precisamos do Dash App para podemos visualizá-los em um ambiente web. Primeiro, vamos importar as dependências:

import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output

Criamos um novo aplicativo com os estilos css:

external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']app = dash.Dash(__name__, external_stylesheets=external_stylesheets)

Inserimos os elementos html no layout da aplicação:

# elemento html do tipo dropdown para selecionar o ano dos dados
dropdown_year = html.Div([ dcc.Dropdown( id='years', options=[{'label': i, 'value': i} for i in votacao.ano_eleicao.unique()], value=2018)], style={'margin-bottom': '80px'})
# elemento html do tipo dropdown para selecionar o estado que os dados pertencem
dropdown_state = html.Div([ dcc.Dropdown(id='states', options=[{'label': i, 'value': i} for i in votacao.sigla_uf.unique()], value='SP')])
# elemento html que representa o gráfico Choropleth Mapbox
graph_votes_per_state = dcc.Graph(id='votes-per-state',figure=fig_mapbox)
# elemento html que representa o gráfico de barras
graph_votes_per_party = dcc.Graph(id='votes-per-party', figure=fig_bar)
app.layout = html.Div([ html.Div([ html.H2('Os partidos mais votados no Brazil desde 1996'),dropdown_year, dropdown_state], style={'width': '30%', 'display': 'flex', 'flex-direction': 'column', 'background-color': '#f8f8f8'}), html.Div([graph_votes_per_state, graph_votes_per_party],style={'width': '70%', 'display': 'inline-block'})], style={'display': 'flex'})

Declaramos os callbacks para que os gráficos sejam atualizados sempre que um valor de algum dos dropdowns é alterado:

@app.callback(Output('votes-per-party', 'figure'),Input('years', 'value'),Input('states', 'value'))def update_graph_bar(year, state):    bar = votacao[(votacao['ano_eleicao']==year) & (votacao['sigla_uf']==state)]    fig_bar = px.bar(bar, x='sigla_partido', y='total_votos')    return fig_bar@app.callback(Output('votes-per-state', 'figure'),Input('years', 'value'))def update_graph_map(year):    to_plot = max_per_year_per_state.loc[max_per_year_per_state['ano_eleicao']==year]    fig = px.choropleth_mapbox(to_plot, geojson=states, locations='sigla_uf', color='sigla_partido', mapbox_style="carto-positron", zoom=3, center = {"lat": -14.7024976, "lon": -45.8631977}, featureidkey="properties.sigla",hover_data=['sigla_uf', 'nome_partido', 'numero_partido', 'sigla_partido', 'total_votos'])    fig.update_layout(margin={"r":0,"t":0,"l":0,"b":0})    return fig

Por fim, iniciamos a aplicação localmente:

if __name__ == '__main__':    app.run_server(debug=True, use_reloader=False)

Basta acessar o endereço local impresso no console em que a aplciação está rodando. O resultado será o seguinte:

Resultado

O resultado final é uma aplicação web composta por uma dashboard capaz de modificar os gráficos com base nas alteraçoes feitas pelos usuários e um painel de visualização dos dados composto por gráficos gerados pelo plotly.

Você pode conferir a aplicação resultante no seguinte domínio: https://eleicao-br.herokuapp.com/
* É importante notar que devido ao geojson utilizado para plotar o mapa do Brasil ser grande, o plotly demora um pouco para redesenhar o mapa após a mudança no dropdown do ano.

--

--