Analisando os votos dos deputados com Tableau

Arthur
8 min readNov 20, 2023

--

Gosto de pensar que uma boa análise de dados é similar a pintura de um quadro. Os dados são minha tela, e as ferramentas que utilizo para extrair insights são meus pincéis. Às vezes, pode ser difícil obter esses insights, por isso existem ferramentas que podem nos ajudar. Hoje, vamos falar sobre uma delas.

Introdução

Esse post é a versão em português do seguinte artigo

A história por trás deste post é o fato de que venho aprendendo Tableau nos últimos meses para utilizar no meu trabalho, e devo dizer que tem sido uma jornada repleta de conhecimento. O Tableau é uma ferramenta muito poderosa, e se alguém souber como utilizá-lo, pode se tornar um grande aliado no processo de análise e extração de insights a partir de qualquer conjunto de dados.

Dito isso, ainda não sou um especialista em Tableau, então estive em busca de algum projeto de análise de dados que pudesse abordar no meu tempo livre com o intuito de aprimorar minhas habilidades com o Tableau. Foi quando me deparei com este link que contém os resultados de alguns projetos relevantes votados na Câmara dos Deputados do Brasil de março de 2019 a dezembro de 2022. Isso me deu a ideia de criar um dashboard no Tableau para analisar melhor os votos desses deputados.

Optei por utilizar os mesmos dados do G1, pois eles já haviam selecionado os projetos mais importantes. Isso significava que eu precisava implementar o webscrapper no site deles para coletar os dados. Na próxima seção deste post, vou explicar como consegui realizar isso.

Web Scrapping

Para coletar dados do site, utilizei Python juntamente com o Selenium, uma ferramenta que auxilia programas de computador a interagirem com navegadores da web, como o Chrome ou o Firefox. É comumente utilizado para automatizar tarefas em sites, como clicar em botões, preencher formulários e obter dados.

Aqui está uma visão geral do que fiz:

1. Usei o Selenium para interagir com o site.
2. Coletei todos os detalhes sobre os votos dos deputados.
3. Processei e salvei essas informações em um arquivo CSV que pode ser posteriormente importado para o Tableau para análise.

O primeiro e o terceiro passo foram rápidos de configurar. No entanto, o segundo levou algum tempo. Tive que inspecionar cuidadosamente o código HTML para localizar as tags e atributos corretos que apontavam para os dados específicos que eu queria coletar. O código a seguir demonstra como recuperar tanto o nome do projeto quanto sua data correspondente, buscando por tags de classe específicas. Cada string que utilizei no método find_elements representa uma classe CSS que encontrei ao analisar o código HTML.

project_name = driver.find_elements(By.CSS_SELECTOR, ".ProjectCard_title__1wX4b")[0].text
project_round = driver.find_elements(By.CSS_SELECTOR, ".ProjectCard_round__1B6kB")[0].text
project_name += " - " + project_round

project_vote_date = driver.find_elements(By.CSS_SELECTOR, ".ProjectCard_date__13ql0")[0].text

O script Python completo pode ser visto no final do post. Após executar o script, obtive o seguinte arquivo CSV. Cada linha no arquivo CSV representa o voto de um deputado para um projeto específico em uma data específica. O arquivo completo contém 80.675 linhas, envolvendo 679 deputados de 32 partidos políticos diferentes.

Tableau

O dashboard pode ser acessado aqui

Depois de reunir os dados, importei-os com sucesso para o Tableau e comecei a trabalhar no dashboard. Meu objetivo era criar um dashboard amigável que facilitasse a compreensão de como os votos estavam distribuídos entre diferentes estados e partidos. Para alcançar isso, decidi incorporar um mapa para fornecer uma representação visual. Esta foi minha primeira experiência com visualização de mapas no Tableau, e posso dizer que o Tableau simplifica bastante o processo. O dashboard pode ser acessado aqui. Como forma de alcançar um público mais amplo, decidi adicionar um filtro que permite aos usuários alternar entre português e inglês. Para acelerar o processo de tradução dos nomes dos projetos, usei o ChatGPT para traduzir rapidamente todos os 159 projetos.

A interação no dashboard é simples: os usuários podem navegar pelos projetos usando o filtro no topo, e todos os gráficos serão atualizados conforme necessário. Eles também podem alternar entre as visualizações de Percentagem ou Valor para ver como os votos estão distribuídos usando as visualizações de gráfico de barras. O tipo de voto mostrado no gráfico de barras no canto superior direito também pode ser utilizado para filtrar as visualizações de partido e tabela abaixo. No canto inferior direito, temos uma tabela simples que lista todos os deputados e seus respectivos votos. Além disso, o mapa serve a um duplo propósito. Ele atua como um mapa de calor, permitindo que os usuários observem como os votos estão distribuídos pelos estados brasileiros. Além disso, funciona como um filtro, permitindo que os usuários escolham um estado específico no mapa, o que, por sua vez, filtra as outras visualizações de acordo.

Insights

  • Alguns projetos claramente geraram mais discordância do que outros. Por exemplo, a proposta de incluir o COAF (Conselho de Controle de Atividades Financeiras) no Ministério da Justiça foi um dos projetos mais controversos, como pode ser visto abaixo. Podemos observar que a maioria da região Nordeste votou contra.
  • Também fiquei bastante surpreso quando notei que alguns deputados votaram contra a proposta de revogação do mandato de Flordelis. Para aqueles que podem não estar cientes, Flordelis era uma deputada que foi considerada culpada de planejar o assassinato de seu marido, entre outros crimes. Portanto, foi inesperado ver algumas pessoas se opondo a isso. A imagem abaixo mostra que a maioria dos deputados votou a favor, enquanto sete votaram contra.

Conclusões e Dicas

  • Para ser sincero, percebi que o dashboard ficou um pouco lento depois de publicá-lo. No geral, acredito que a experiência do usuário ainda seja aceitável, mas eu esperava que ele rodasse um pouco mais rápido. O problema principal ocorre quando o usuário tenta filtrar o dashboard, seja clicando no mapa ou no gráfico de barras de votos, pois leva alguns segundos para o dashboard ser atualizado.
  • Enfrentei algumas dificuldades ao carregar o arquivo CSV no Tableau. Tive que fazer isso algumas vezes e observei que o Tableau, às vezes, apresentava problemas para carregar o arquivo com precisão — perdendo algumas linhas ou duplicando outras. Para evitar isso, certifiquei-me de que o total de linhas exibido no Tableau correspondia ao total de linhas no arquivo.
  • Uma funcionalidade que gostei muito é a opção de controle de visibilidade que o Tableau oferece. Com essa função, posso dar ao usuário a possibilidade de ocultar e mostrar qualquer visualização no dashboard com base em um conjunto de parâmetros. Utilizei isso para habilitar os interruptores de Percentagem (%) e Idioma. A imagem abaixo ilustra onde encontrá-lo:
  • Outra dica valiosa é implementar um processo de revisão do dashboard, se possível. Construir dashboards no Tableau é semelhante à criação de qualquer outro software. Portanto, é crucial realizar testes e pedir a outra pessoa para revisar o dashboard. Isso ajuda a prevenir erros e garante insights precisos. Para isso, é importante construir um dashboard bem organizado com nomes significativos e claros para os campos calculados, parâmetros, sheets, etc. Isso pode facilitar muito o processo de revisão.
  • Minha impressão geral é que o Tableau torna a análise de dados muito mais rápida. Depois de preparar meus dados, criar um dashboard útil foi rápido e fácil com o Tableau. Uma última dica é processar todos os dados antes de carregá-los no Tableau. Dessa forma, o Tableau pode se concentrar em criar as melhores visualizações sem lidar com o processamento de dados, o que pode tornar o dashboard mais lento.

Source Code

Abaixo, segue o código que usei para extrair os dados do G1. É necessário instalar o Selenium e o Pandas para executá-lo.

from selenium import webdriver
from selenium.webdriver.common.by import By
import pandas as pd
from data_to_eng import proj_translations

class VotesScrapper:
def __init__(self, driver=webdriver.Firefox()):
self.driver = driver
self.link = "https://interativos.g1.globo.com/politica/2019/como-votam/camara-dos-deputados/brasil"
self.number_pages = 14

def go_next_page(self):
next_page = None
for item in self.driver.find_elements(By.CSS_SELECTOR, ".Pagination_item__1JGT8 "):
if item.get_attribute('title') == "Próxima página":
next_page = item
break
if next_page is not None:
next_page.click()

def get_info_card(self):
project_name = self.driver.find_elements(By.CSS_SELECTOR, ".ProjectCard_title__1wX4b")[0].text
round = self.driver.find_elements(By.CSS_SELECTOR, ".ProjectCard_round__1B6kB")[0].text
project_name += " - " + round
print(f"Collecting: {project_name}")

vote_date = self.driver.find_elements(By.CSS_SELECTOR, ".ProjectCard_date__13ql0")[0].text
vote_date = vote_date.replace("Votado em ", "")

needed_votes = self.driver.find_elements(By.CSS_SELECTOR, ".BarChart_textNecessaryVotes__3BaO7")
if needed_votes:
needed_votes = needed_votes[0].text
needed_votes = needed_votes.replace(" votos necessários", "")
else:
needed_votes = ""

project_desc = self.driver.find_elements(By.CSS_SELECTOR, ".ProjectCard_description__2MES2")[0].text
count_votes_list = (self.driver.find_elements(By.CSS_SELECTOR, ".Accordion_container__3K-ma"))
info = []
for vote_type in count_votes_list:
vote = None
if "| Sim" in vote_type.text:
vote = "Sim"
elif "| Não votou" in vote_type.text:
vote = "Não votou"
elif "| Não" in vote_type.text:
vote = "Não"
elif "| Abstenção" in vote_type.text:
vote = "Abstenção"
elif "| Obstrução" in vote_type.text:
vote = "Obstrução"
elif "| Ausente" in vote_type.text:
vote = "Ausente"
if vote is not None:
vote_type.find_elements(By.CSS_SELECTOR,".Accordion_anchor__1HBuv")[0].click()
congressmen_list = vote_type.find_elements(By.CSS_SELECTOR,".ListCandidates_listItem__3a7hN")
for congressman in congressmen_list:
name = congressman.find_elements(By.CSS_SELECTOR, ".ListCandidates_candidateName__2NH81")[0].text
party = congressman.find_elements(By.CSS_SELECTOR, ".ListCandidates_candidateParty__1Wac9")[0].text
state = congressman.find_elements(By.CSS_SELECTOR, ".ListCandidates_candidateState__1FYOr")[0].text
info.append([project_name, vote_date, project_desc, name, party, state, vote, needed_votes])
vote_type.find_elements(By.CSS_SELECTOR,".Accordion_anchor__1HBuv")[0].click()
return info

def translate_votes(self, voto):
if voto == "Sim":
return "Yes"
elif voto == "Não":
return "No"
elif voto == "Não votou":
return "Didn't vote"
elif voto == "Abstenção":
return "Abstention"
elif voto == "Ausente":
return "Absent"
elif voto == "Obstrução":
return "Obstruction"

def build_df(self, data):
df = pd.DataFrame(data, columns=["Projeto", "Data", "Descricao",
"Dept Nome", "Dept Partido",
"Dept Estado", "Voto", "Votos necessarios"])
df = df.drop_duplicates()
#Creating English columns that will be used in the dashboard
df["Project"] = df.Projeto.apply(lambda proj_name: proj_translations[proj_name])
df["Vote"] = df["Voto"].apply(lambda voto: self.translate_votes(voto))

df["Dept State"] = df["Dept Estado"]
df["Dept Name"] = df["Dept Nome"]
df["Dept Party"] = df["Dept Partido"]
df["Date"] = df["Data"]
return df

def run(self, output_filename="data.csv"):
self.driver.get(self.link)

list_of_proj_cards = []
for _ in range(self.number_pages):
for card in self.driver.find_elements(By.CSS_SELECTOR, ".Card_wrapper__3sGYE "):
list_of_proj_cards.append(card.find_elements(By.CSS_SELECTOR, ".Card_link__2A8I-")[0].get_attribute('href'))
self.go_next_page()

all_data = []
for idx, card_link in enumerate(list_of_proj_cards):
print(f"Processing: {idx+1} of {len(list_of_proj_cards)}")
self.driver.get(card_link)
all_data += self.get_info_card()

df = self.build_df(all_data)
df.to_csv(output_filename, index=False)
self.driver.quit()
print("Done !!!")

if __name__ == "__main__":
VotesScrapper().run()

--

--