Eleições presidenciais em João Pessoa - 2º turno#

Este notebook apresenta o resultado das eleicões presidenciais em João Pessoa (PB) no 2º turno por local de votação, bem como as etapas que segui para obter o resultado a partir dos boletins de urna e da base de eleitorado com os locais de votação disponibilizados no site do TSE.

O objetivo é conseguir ver onde cada candidato se saiu melhor de acordo com a região da cidade, obtendo um nível de detalhe maior do que aquele observado no agregado por zona eleitoral.

Mapa final - 2º turno#

Pontos em tons azuis onde Bolsonaro venceu. Pontos em tons vermelhos onde Lula venceu. Quando a cor é mais escura, significa que o candidato obteve mais de 55% dos votos válidos. A cor cinza representa empate.

Clique no ponto para obter os detalhes.

m
Make this Notebook Trusted to load map: File -> Trust Notebook

Procedimento#

import pandas as pd
import geopandas as gpd
import matplotlib.pyplot as plt

Boletins de urna#

Base dos boletins de urna do TSE para a Paraíba, disponível em https://dadosabertos.tse.jus.br/dataset/resultados-2022-boletim-de-urna.

df = pd.read_csv('bweb_2t_PB.csv', encoding='latin-1', sep=';')
df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 76363 entries, 0 to 76362
Data columns (total 45 columns):
 #   Column                       Non-Null Count  Dtype  
---  ------                       --------------  -----  
 0   DT_GERACAO                   76363 non-null  object 
 1   HH_GERACAO                   76363 non-null  object 
 2   ANO_ELEICAO                  76363 non-null  int64  
 3   CD_TIPO_ELEICAO              76363 non-null  int64  
 4   NM_TIPO_ELEICAO              76363 non-null  object 
 5   CD_PLEITO                    76363 non-null  int64  
 6   DT_PLEITO                    76363 non-null  object 
 7   NR_TURNO                     76363 non-null  int64  
 8   CD_ELEICAO                   76363 non-null  int64  
 9   DS_ELEICAO                   76363 non-null  object 
 10  SG_UF                        76363 non-null  object 
 11  CD_MUNICIPIO                 76363 non-null  int64  
 12  NM_MUNICIPIO                 76363 non-null  object 
 13  NR_ZONA                      76363 non-null  int64  
 14  NR_SECAO                     76363 non-null  int64  
 15  NR_LOCAL_VOTACAO             76363 non-null  int64  
 16  CD_CARGO_PERGUNTA            76363 non-null  int64  
 17  DS_CARGO_PERGUNTA            76363 non-null  object 
 18  NR_PARTIDO                   76363 non-null  int64  
 19  SG_PARTIDO                   76363 non-null  object 
 20  NM_PARTIDO                   76363 non-null  object 
 21  DT_BU_RECEBIDO               76363 non-null  object 
 22  QT_APTOS                     76363 non-null  int64  
 23  QT_COMPARECIMENTO            76363 non-null  int64  
 24  QT_ABSTENCOES                76363 non-null  int64  
 25  CD_TIPO_URNA                 76363 non-null  int64  
 26  DS_TIPO_URNA                 76363 non-null  object 
 27  CD_TIPO_VOTAVEL              76363 non-null  int64  
 28  DS_TIPO_VOTAVEL              76363 non-null  object 
 29  NR_VOTAVEL                   76363 non-null  int64  
 30  NM_VOTAVEL                   76363 non-null  object 
 31  QT_VOTOS                     76363 non-null  int64  
 32  NR_URNA_EFETIVADA            76363 non-null  int64  
 33  CD_CARGA_1_URNA_EFETIVADA    76363 non-null  object 
 34  CD_CARGA_2_URNA_EFETIVADA    76363 non-null  float64
 35  CD_FLASHCARD_URNA_EFETIVADA  76363 non-null  object 
 36  DT_CARGA_URNA_EFETIVADA      76363 non-null  object 
 37  DS_CARGO_PERGUNTA_SECAO      76363 non-null  object 
 38  DS_AGREGADAS                 76363 non-null  object 
 39  DT_ABERTURA                  76363 non-null  object 
 40  DT_ENCERRAMENTO              76363 non-null  object 
 41  QT_ELEITORES_BIOMETRIA_NH    76363 non-null  int64  
 42  DT_EMISSAO_BU                76363 non-null  object 
 43  NR_JUNTA_APURADORA           76363 non-null  int64  
 44  NR_TURMA_APURADORA           76363 non-null  int64  
dtypes: float64(1), int64(22), object(22)
memory usage: 26.2+ MB

Filtra apenas algumas colunas de interesse, cidade de João Pessoa e eleição presidencial.

df = df[df['NM_MUNICIPIO'] == 'JOÃO PESSOA']
df = df[df['DS_ELEICAO'] == 'Eleição Geral Federal 2022']
df = df[['NR_ZONA', 'NR_SECAO', 'NM_VOTAVEL', 'QT_VOTOS', 'QT_APTOS', 'QT_COMPARECIMENTO', 'QT_ABSTENCOES']]
df.info()
<class 'pandas.core.frame.DataFrame'>
Int64Index: 5806 entries, 0 to 76358
Data columns (total 7 columns):
 #   Column             Non-Null Count  Dtype 
---  ------             --------------  ----- 
 0   NR_ZONA            5806 non-null   int64 
 1   NR_SECAO           5806 non-null   int64 
 2   NM_VOTAVEL         5806 non-null   object
 3   QT_VOTOS           5806 non-null   int64 
 4   QT_APTOS           5806 non-null   int64 
 5   QT_COMPARECIMENTO  5806 non-null   int64 
 6   QT_ABSTENCOES      5806 non-null   int64 
dtypes: int64(6), object(1)
memory usage: 362.9+ KB

Locais de votação#

Carrega a base de locais de votação do TSE para o Brasil, disponível em https://dadosabertos.tse.jus.br/dataset/eleitorado-atual.

ldf = pd.read_csv('eleitorado_local_votacao_ATUAL.csv', encoding='latin-1', sep=';')
ldf.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 496512 entries, 0 to 496511
Data columns (total 35 columns):
 #   Column                        Non-Null Count   Dtype  
---  ------                        --------------   -----  
 0   DT_GERACAO                    496512 non-null  object 
 1   HH_GERACAO                    496512 non-null  object 
 2   AA_ELEICAO                    496512 non-null  int64  
 3   DT_ELEICAO                    0 non-null       float64
 4   DS_ELEICAO                    496512 non-null  object 
 5   NR_TURNO                      496512 non-null  int64  
 6   SG_UF                         496512 non-null  object 
 7   CD_MUNICIPIO                  496512 non-null  int64  
 8   NM_MUNICIPIO                  496512 non-null  object 
 9   NR_ZONA                       496512 non-null  int64  
 10  NR_SECAO                      496512 non-null  int64  
 11  CD_TIPO_SECAO_AGREGADA        496512 non-null  int64  
 12  DS_TIPO_SECAO_AGREGADA        496512 non-null  object 
 13  NR_LOCAL_VOTACAO              496512 non-null  int64  
 14  NM_LOCAL_VOTACAO              496512 non-null  object 
 15  CD_TIPO_LOCAL                 496512 non-null  int64  
 16  DS_TIPO_LOCAL                 496512 non-null  object 
 17  DS_ENDERECO                   496512 non-null  object 
 18  NM_BAIRRO                     496512 non-null  object 
 19  NR_CEP                        496512 non-null  int64  
 20  NR_TELEFONE_LOCAL             496512 non-null  object 
 21  NR_LATITUDE                   496512 non-null  float64
 22  NR_LONGITUDE                  496512 non-null  float64
 23  CD_SITU_LOCAL_VOTACAO         496512 non-null  int64  
 24  DS_SITU_LOCAL_VOTACAO         496512 non-null  object 
 25  CD_SITU_ZONA                  496512 non-null  int64  
 26  DS_SITU_ZONA                  496512 non-null  object 
 27  CD_SITU_SECAO                 496512 non-null  int64  
 28  DS_SITU_SECAO                 496512 non-null  object 
 29  CD_SITU_LOCALIDADE            496512 non-null  int64  
 30  DS_SITU_LOCALIDADE            496512 non-null  object 
 31  CD_SITU_SECAO_ACESSIBILIDADE  496512 non-null  int64  
 32  DS_SITU_SECAO_ACESSIBILIDADE  496512 non-null  object 
 33  QT_ELEITOR                    496512 non-null  int64  
 34  QT_ELEITOR_ELEICAO            496512 non-null  int64  
dtypes: float64(3), int64(16), object(16)
memory usage: 132.6+ MB

Seleciona na base de locais de votação apenas o município de João Pessoa e alguns campos de interesse.

ldf = ldf[ldf['NM_MUNICIPIO'] == 'JOÃO PESSOA']
ldf = ldf[['NM_BAIRRO', 'NR_LATITUDE', 'NR_LONGITUDE', 'NR_ZONA', 'NR_SECAO', 'NR_LOCAL_VOTACAO', 'NM_LOCAL_VOTACAO']]
ldf.head()
NM_BAIRRO NR_LATITUDE NR_LONGITUDE NR_ZONA NR_SECAO NR_LOCAL_VOTACAO NM_LOCAL_VOTACAO
76 IPES -7.105861 -34.858250 1 155 1457 ESC ESTADUAL MONS PEDRO ANISIO BEZERRA
124 FUNCIONARIOS II -7.182127 -34.881353 77 171 1368 ESCOLA ESTADUAL JOSÉ DO PATROCINIO
197 MANGABEIRA I -7.169732 -34.841285 70 166 1350 ESCOLA ESTADUAL DE 1 GRAU PEDRO LINS VIEIRA DE...
266 CENTRO -7.115360 -34.883176 1 6 1040 FAC. CIÊNCIAS MÉDICAS (ANTIGO COLÉGIO PIO XII)
597 MANGABEIRA II -7.178120 -34.839369 70 443 1929 ESCOLA ESTADUAL DE ENSINO FUNDAMENTAL JOÃO ROB...

Associando as coordenadas dos locais de votação ao resultado dos boletins de urna#

Prepara para a junção entre as bases usando a zona e a seção como chave.

ldf = ldf.set_index(['NR_ZONA', 'NR_SECAO'])
df = df.set_index(['NR_ZONA', 'NR_SECAO'])
df = df.join(ldf, lsuffix='', rsuffix='__LOCAL')
df.info()
<class 'pandas.core.frame.DataFrame'>
MultiIndex: 5806 entries, (1, 1) to (77, 402)
Data columns (total 10 columns):
 #   Column             Non-Null Count  Dtype  
---  ------             --------------  -----  
 0   NM_VOTAVEL         5806 non-null   object 
 1   QT_VOTOS           5806 non-null   int64  
 2   QT_APTOS           5806 non-null   int64  
 3   QT_COMPARECIMENTO  5806 non-null   int64  
 4   QT_ABSTENCOES      5806 non-null   int64  
 5   NM_BAIRRO          5803 non-null   object 
 6   NR_LATITUDE        5803 non-null   float64
 7   NR_LONGITUDE       5803 non-null   float64
 8   NR_LOCAL_VOTACAO   5803 non-null   float64
 9   NM_LOCAL_VOTACAO   5803 non-null   object 
dtypes: float64(3), int64(4), object(3)
memory usage: 491.8+ KB
df['NM_BAIRRO'].unique()
array(['CENTRO', 'TAMBIÁ', 'TORRE', 'ROGER', 'EXPEDICIONARIOS',
       'CONJUNTO PEDRO GONDIM', 'ESTADOS', 'MANDACARU', 'IPES',
       'TREZE DE MAIO', 'PADRE ZE', 'JARDIM LUNA', 'JOAO AGRIPINO',
       'TAMBAUZINHO', 'CASTELO BRANCO I', 'CASTELO BRANCO', 'MIRAMAR',
       'JAGUARIBE', 'RANGEL', 'CRISTO REDENTOR', 'CRUZ DAS ARMAS',
       'ILHA DO BISPO', 'ERNESTO GEISEL', 'MANGABEIRA I', 'MANGABEIRA II',
       'JOSE AMERICO DE ALMEIDA', 'VALENTINA DE FIGUEIREDO I',
       'MANGABEIRA VI', 'VALENTINA DE FIGUEIREDO II', 'MANGABEIRA VIII',
       'MANGABEIRA IV', 'MANGABEIRA VII', 'VALENTINA FIGUEIREDO', 'BESSA',
       'TAMBAU', 'MANAIRA', 'ALTIPLANO CABO BRANCO', 'CABO BRANCO',
       'BANCARIOS', 'PENHA', 'JARDIM OCEANIA', nan, 'ALTO DO MATEUS',
       'NOVAIS', 'FUNCIONARIOS I', 'JARDIM PLANALTO', 'FUNCIONARIOS II',
       'COSTA E SILVA', 'ERNANI SATIRO', 'JARDIM VENEZA', 'GROTAO',
       'FUNCIONARIOS III', 'INDUSTRIAS', 'CONJUNTO JOSE VIEIRA DINIZ',
       'JOAO PAULO II', 'GRAMAME', 'PARATIBE'], dtype=object)

Salvando o resultado parcial até então.

df.to_csv('eleicao_presidencial_2022_jp_2_turno.csv', sep=';', encoding='utf-8')

Base de bairros#

Carregando a base de bairros de João Pessoa do repositório geodata-jp.

bairros = gpd.read_file('https://raw.githubusercontent.com/paulovitorweb/geodata-jp/main/data/bairros.geojson')
bairros = bairros.drop(columns=['perimetro', 'area', 'hectares', 'densidade'])
bairros.info()
<class 'geopandas.geodataframe.GeoDataFrame'>
RangeIndex: 64 entries, 0 to 63
Data columns (total 3 columns):
 #   Column    Non-Null Count  Dtype   
---  ------    --------------  -----   
 0   cod       64 non-null     object  
 1   nome      64 non-null     object  
 2   geometry  64 non-null     geometry
dtypes: geometry(1), object(2)
memory usage: 1.6+ KB

Converte para um sistema de coordenadas métrico apropriado e plota.

bairros = bairros.to_crs('EPSG:31985')
bairros.plot()
<AxesSubplot: >
../../_images/eleicoes_presidenciais_jp_2t_33_1.png

Votos válidos#

Para calcular os votos válidos precisamos excluir os votos brancos e nulos.

df = df.query('NM_VOTAVEL not in ("Branco", "Nulo")')
df['NM_VOTAVEL'].unique()
array(['JAIR BOLSONARO', 'LULA'], dtype=object)
df.info()
<class 'pandas.core.frame.DataFrame'>
MultiIndex: 2916 entries, (1, 1) to (77, 402)
Data columns (total 10 columns):
 #   Column             Non-Null Count  Dtype  
---  ------             --------------  -----  
 0   NM_VOTAVEL         2916 non-null   object 
 1   QT_VOTOS           2916 non-null   int64  
 2   QT_APTOS           2916 non-null   int64  
 3   QT_COMPARECIMENTO  2916 non-null   int64  
 4   QT_ABSTENCOES      2916 non-null   int64  
 5   NM_BAIRRO          2914 non-null   object 
 6   NR_LATITUDE        2914 non-null   float64
 7   NR_LONGITUDE       2914 non-null   float64
 8   NR_LOCAL_VOTACAO   2914 non-null   float64
 9   NM_LOCAL_VOTACAO   2914 non-null   object 
dtypes: float64(3), int64(4), object(3)
memory usage: 257.5+ KB

Tratando valores nulos#

Existem valores nulos para os locais de votação. Vamos dar uma olhada.

df[df['NM_BAIRRO'].isnull()]
NM_VOTAVEL QT_VOTOS QT_APTOS QT_COMPARECIMENTO QT_ABSTENCOES NM_BAIRRO NR_LATITUDE NR_LONGITUDE NR_LOCAL_VOTACAO NM_LOCAL_VOTACAO
NR_ZONA NR_SECAO
76 389 JAIR BOLSONARO 1 36 31 5 NaN NaN NaN NaN NaN
389 LULA 29 36 31 5 NaN NaN NaN NaN NaN

Fiz uma pesquisa rápida e não encontrei. Vamos seguir como NÃO IDENTIFICADO.

df = df.fillna(value={'NM_LOCAL_VOTACAO': 'NÃO IDENTIFICADO'})

Resultado por local de votação e candidato#

Vamos agrupar por local de votação e candidato.

df1 = df.groupby(['NM_LOCAL_VOTACAO', 'NM_VOTAVEL']).agg({'QT_VOTOS': 'sum'})
df1
QT_VOTOS
NM_LOCAL_VOTACAO NM_VOTAVEL
ACADEMIA DE COMERCIO EPITACIO PESSOA JAIR BOLSONARO 974
LULA 1034
ASSOCIAÇÃO DOS SERVIDORES DA POLÍCIA FEDERAL - PROX PARQUE PB II JAIR BOLSONARO 741
LULA 577
CENEC - CENTRO EDUCACIONAL CENECISTA JAIR BOLSONARO 1425
... ... ...
UFPB CENTRAL DE AULAS LULA 4916
UNIVERSIDADE ESTADUAL DA PARAÍBA - UEPB JAIR BOLSONARO 2730
LULA 2604
VIA MEDICINA COLEGIO E CURSO JAIR BOLSONARO 1354
LULA 1107

420 rows × 1 columns

Um teste para saber se estou no caminho certo. Segundo o G1 Paraíba (https://g1.globo.com/pb/paraiba/noticia/2022/10/30/eleicoes-em-joao-pessoa-pb-veja-como-foi-a-votacao-no-2o-turno.ghtml):

  • Lula (PT): 229.251 votos (50,10%)

  • Jair Bolsonaro (PL): 228.326 votos (49,90%)

votos_por_candidato = df1.groupby(level=1).sum()
votos_por_candidato
QT_VOTOS
NM_VOTAVEL
JAIR BOLSONARO 228326
LULA 229251
votos_por_candidato['PERCENTUAL'] = votos_por_candidato['QT_VOTOS'] / votos_por_candidato['QT_VOTOS'].sum()
votos_por_candidato.sort_values('QT_VOTOS', ascending=False)
QT_VOTOS PERCENTUAL
NM_VOTAVEL
LULA 229251 0.501011
JAIR BOLSONARO 228326 0.498989

É isso, confere.

Agora, por local de votação.

df1 = df1.unstack()
df1
QT_VOTOS
NM_VOTAVEL JAIR BOLSONARO LULA
NM_LOCAL_VOTACAO
ACADEMIA DE COMERCIO EPITACIO PESSOA 974 1034
ASSOCIAÇÃO DOS SERVIDORES DA POLÍCIA FEDERAL - PROX PARQUE PB II 741 577
CENEC - CENTRO EDUCACIONAL CENECISTA 1425 1451
CENEC - ESCOLA CENECISTA JOÃO REGIS AMORIM 2474 2146
CENTRO DA CIDADANIA OTAVIANO FERNANDES COUTINHO 409 466
... ... ...
NÃO IDENTIFICADO 1 29
SERVICO SOCIAL DA INDUSTRIA - SESI 190 215
UFPB CENTRAL DE AULAS 3297 4916
UNIVERSIDADE ESTADUAL DA PARAÍBA - UEPB 2730 2604
VIA MEDICINA COLEGIO E CURSO 1354 1107

210 rows × 2 columns

Preciso obter as coordenadas dos locais.

df2 = df.groupby(['NM_LOCAL_VOTACAO']).agg({'NR_LATITUDE': 'mean', 'NR_LONGITUDE': 'mean'})
df2
NR_LATITUDE NR_LONGITUDE
NM_LOCAL_VOTACAO
ACADEMIA DE COMERCIO EPITACIO PESSOA -7.122656 -34.884473
ASSOCIAÇÃO DOS SERVIDORES DA POLÍCIA FEDERAL - PROX PARQUE PB II -7.080441 -34.836433
CENEC - CENTRO EDUCACIONAL CENECISTA -7.163410 -34.827805
CENEC - ESCOLA CENECISTA JOÃO REGIS AMORIM -7.177847 -34.867251
CENTRO DA CIDADANIA OTAVIANO FERNANDES COUTINHO -7.170910 -34.838149
... ... ...
NÃO IDENTIFICADO NaN NaN
SERVICO SOCIAL DA INDUSTRIA - SESI -7.123403 -34.885977
UFPB CENTRAL DE AULAS -7.141083 -34.848948
UNIVERSIDADE ESTADUAL DA PARAÍBA - UEPB -7.157929 -34.872929
VIA MEDICINA COLEGIO E CURSO -7.119153 -34.834591

210 rows × 2 columns

Vamos unir os dois dataframes para chegar a uma base agregada por local de votação com as coordenadas e os votos dos candidatos pivotados para colunas.

result = df2.join(df1, lsuffix='COORD_', rsuffix='QT_VOTOS_')
/tmp/ipykernel_925/2064493752.py:1: FutureWarning: merging between different levels is deprecated and will be removed in a future version. (1 levels on the left, 2 on the right)
  result = df2.join(df1, lsuffix='COORD_', rsuffix='QT_VOTOS_')
result = result.reset_index()
result
NM_LOCAL_VOTACAO NR_LATITUDE NR_LONGITUDE (QT_VOTOS, JAIR BOLSONARO) (QT_VOTOS, LULA)
0 ACADEMIA DE COMERCIO EPITACIO PESSOA -7.122656 -34.884473 974 1034
1 ASSOCIAÇÃO DOS SERVIDORES DA POLÍCIA FEDERAL -... -7.080441 -34.836433 741 577
2 CENEC - CENTRO EDUCACIONAL CENECISTA -7.163410 -34.827805 1425 1451
3 CENEC - ESCOLA CENECISTA JOÃO REGIS AMORIM -7.177847 -34.867251 2474 2146
4 CENTRO DA CIDADANIA OTAVIANO FERNANDES COUTINHO -7.170910 -34.838149 409 466
... ... ... ... ... ...
205 NÃO IDENTIFICADO NaN NaN 1 29
206 SERVICO SOCIAL DA INDUSTRIA - SESI -7.123403 -34.885977 190 215
207 UFPB CENTRAL DE AULAS -7.141083 -34.848948 3297 4916
208 UNIVERSIDADE ESTADUAL DA PARAÍBA - UEPB -7.157929 -34.872929 2730 2604
209 VIA MEDICINA COLEGIO E CURSO -7.119153 -34.834591 1354 1107

210 rows × 5 columns

Calcular os votos válidos por local de votação.

result['QT_VOTOS_VALIDOS'] = result.iloc[:, 3:].sum(axis=1)
result
NM_LOCAL_VOTACAO NR_LATITUDE NR_LONGITUDE (QT_VOTOS, JAIR BOLSONARO) (QT_VOTOS, LULA) QT_VOTOS_VALIDOS
0 ACADEMIA DE COMERCIO EPITACIO PESSOA -7.122656 -34.884473 974 1034 2008
1 ASSOCIAÇÃO DOS SERVIDORES DA POLÍCIA FEDERAL -... -7.080441 -34.836433 741 577 1318
2 CENEC - CENTRO EDUCACIONAL CENECISTA -7.163410 -34.827805 1425 1451 2876
3 CENEC - ESCOLA CENECISTA JOÃO REGIS AMORIM -7.177847 -34.867251 2474 2146 4620
4 CENTRO DA CIDADANIA OTAVIANO FERNANDES COUTINHO -7.170910 -34.838149 409 466 875
... ... ... ... ... ... ...
205 NÃO IDENTIFICADO NaN NaN 1 29 30
206 SERVICO SOCIAL DA INDUSTRIA - SESI -7.123403 -34.885977 190 215 405
207 UFPB CENTRAL DE AULAS -7.141083 -34.848948 3297 4916 8213
208 UNIVERSIDADE ESTADUAL DA PARAÍBA - UEPB -7.157929 -34.872929 2730 2604 5334
209 VIA MEDICINA COLEGIO E CURSO -7.119153 -34.834591 1354 1107 2461

210 rows × 6 columns

result['LULA'] = result[('QT_VOTOS', 'LULA')]
result['BOLSONARO'] = result[('QT_VOTOS', 'JAIR BOLSONARO')]
result = result[['NM_LOCAL_VOTACAO', 'NR_LATITUDE', 'NR_LONGITUDE', 'LULA', 'BOLSONARO', 'QT_VOTOS_VALIDOS']]
result
NM_LOCAL_VOTACAO NR_LATITUDE NR_LONGITUDE LULA BOLSONARO QT_VOTOS_VALIDOS
0 ACADEMIA DE COMERCIO EPITACIO PESSOA -7.122656 -34.884473 1034 974 2008
1 ASSOCIAÇÃO DOS SERVIDORES DA POLÍCIA FEDERAL -... -7.080441 -34.836433 577 741 1318
2 CENEC - CENTRO EDUCACIONAL CENECISTA -7.163410 -34.827805 1451 1425 2876
3 CENEC - ESCOLA CENECISTA JOÃO REGIS AMORIM -7.177847 -34.867251 2146 2474 4620
4 CENTRO DA CIDADANIA OTAVIANO FERNANDES COUTINHO -7.170910 -34.838149 466 409 875
... ... ... ... ... ... ...
205 NÃO IDENTIFICADO NaN NaN 29 1 30
206 SERVICO SOCIAL DA INDUSTRIA - SESI -7.123403 -34.885977 215 190 405
207 UFPB CENTRAL DE AULAS -7.141083 -34.848948 4916 3297 8213
208 UNIVERSIDADE ESTADUAL DA PARAÍBA - UEPB -7.157929 -34.872929 2604 2730 5334
209 VIA MEDICINA COLEGIO E CURSO -7.119153 -34.834591 1107 1354 2461

210 rows × 6 columns

Certo, temos um resultado. Mas não faz sentido os votos não estarem como inteiros.

result = result.astype({'LULA': 'int', 'BOLSONARO': 'int', 'QT_VOTOS_VALIDOS': 'int'})
result
NM_LOCAL_VOTACAO NR_LATITUDE NR_LONGITUDE LULA BOLSONARO QT_VOTOS_VALIDOS
0 ACADEMIA DE COMERCIO EPITACIO PESSOA -7.122656 -34.884473 1034 974 2008
1 ASSOCIAÇÃO DOS SERVIDORES DA POLÍCIA FEDERAL -... -7.080441 -34.836433 577 741 1318
2 CENEC - CENTRO EDUCACIONAL CENECISTA -7.163410 -34.827805 1451 1425 2876
3 CENEC - ESCOLA CENECISTA JOÃO REGIS AMORIM -7.177847 -34.867251 2146 2474 4620
4 CENTRO DA CIDADANIA OTAVIANO FERNANDES COUTINHO -7.170910 -34.838149 466 409 875
... ... ... ... ... ... ...
205 NÃO IDENTIFICADO NaN NaN 29 1 30
206 SERVICO SOCIAL DA INDUSTRIA - SESI -7.123403 -34.885977 215 190 405
207 UFPB CENTRAL DE AULAS -7.141083 -34.848948 4916 3297 8213
208 UNIVERSIDADE ESTADUAL DA PARAÍBA - UEPB -7.157929 -34.872929 2604 2730 5334
209 VIA MEDICINA COLEGIO E CURSO -7.119153 -34.834591 1107 1354 2461

210 rows × 6 columns

Melhor.

Vamos salvar o resultado parcial em um arquivo que pode ser útil fora daqui.

result.to_csv('eleicao_presidencial_2022_jp_2_turno_por_local_de_votacao.csv', sep=';', encoding='utf-8')

Mapas#

Vamos tentar obter alguns mapas para analisar.

gdf = gpd.GeoDataFrame(
    result, geometry=gpd.points_from_xy(result.NR_LONGITUDE, result.NR_LATITUDE), crs='EPSG:4326')
gdf.plot()
<AxesSubplot: >
../../_images/eleicoes_presidenciais_jp_2t_67_1.png

Oxe. Parece que temos uma ou mais coordenadas erradas.

result.sort_values('NR_LONGITUDE')
NM_LOCAL_VOTACAO NR_LATITUDE NR_LONGITUDE LULA BOLSONARO QT_VOTOS_VALIDOS geometry
151 ESCOLA MUNICIPAL DE ENSINO FUNDAMENTAL PROF. A... -7.173992 -34.929570 1912 1903 3815 POINT (-34.92957 -7.17399)
66 ESC. MUN. ANAYDE BEIRIZ (PROVISÓRIO)- ENTRADA ... -7.175178 -34.919875 1748 1662 3410 POINT (-34.91987 -7.17518)
102 ESCOLA ESTADUAL DE ENS. FUND. D. JOSE MARIA PIRES -7.183092 -34.919803 556 578 1134 POINT (-34.91980 -7.18309)
112 ESCOLA ESTADUAL DE ENSINO FUNDAMENTAL SANTOS D... -7.176929 -34.917247 492 615 1107 POINT (-34.91725 -7.17693)
68 ESC. MUN. LYNALDO C. DE ALBUQUERQUE - AO LADO ... -7.178657 -34.914477 1194 1101 2295 POINT (-34.91448 -7.17866)
... ... ... ... ... ... ... ...
26 COLÉGIO IPI -1.000000 -1.000000 365 459 824 POINT (-1.00000 -1.00000)
172 ESCOLA MUNICIPAL PROF. AFONSO PEREIRA DA SILVA -1.000000 -1.000000 870 624 1494 POINT (-1.00000 -1.00000)
7 CENTRO DE FORMAÇÃO DE EDUCADORES DE JOÃO PESSOA -1.000000 -1.000000 789 727 1516 POINT (-1.00000 -1.00000)
183 ESCOLA SÃO JOSÉ -1.000000 -1.000000 739 753 1492 POINT (-1.00000 -1.00000)
205 NÃO IDENTIFICADO NaN NaN 29 1 30 POINT EMPTY

210 rows × 7 columns

Alguns locais não têm coordenadas válidas. Vamos ver quais são e corrigir isso.

Inserindo coordenadas faltantes#

result[result['NR_LATITUDE'] > -2]
NM_LOCAL_VOTACAO NR_LATITUDE NR_LONGITUDE LULA BOLSONARO QT_VOTOS_VALIDOS geometry
7 CENTRO DE FORMAÇÃO DE EDUCADORES DE JOÃO PESSOA -1.0 -1.0 789 727 1516 POINT (-1.00000 -1.00000)
26 COLÉGIO IPI -1.0 -1.0 365 459 824 POINT (-1.00000 -1.00000)
61 ESC. ESTADUAL PADRE IBIAPINA -1.0 -1.0 505 449 954 POINT (-1.00000 -1.00000)
172 ESCOLA MUNICIPAL PROF. AFONSO PEREIRA DA SILVA -1.0 -1.0 870 624 1494 POINT (-1.00000 -1.00000)
183 ESCOLA SÃO JOSÉ -1.0 -1.0 739 753 1492 POINT (-1.00000 -1.00000)
197 INSTITUTO EDUCACIONAL NOSSA SENHORA DA CONCEIÇ... -1.0 -1.0 165 181 346 POINT (-1.00000 -1.00000)

Pesquisei no Google Maps e cheguei a essas coordenadas.

coords = {
    'CENTRO DE FORMAÇÃO DE EDUCADORES DE JOÃO PESSOA': (-7.172783, -34.836622),
    'COLÉGIO IPI': (-7.207003, -34.842519),
    'ESC. ESTADUAL PADRE IBIAPINA': (-7.099499, -34.865680), # não é Mandacaru, e sim Alto do Céu
    'ESCOLA MUNICIPAL PROF. AFONSO PEREIRA DA SILVA': (-7.177313, -34.818340),
    'ESCOLA SÃO JOSÉ': (-7.121386, -34.869185),
    'INSTITUTO EDUCACIONAL NOSSA SENHORA DA CONCEIÇÃO - IENSC': (-7.203284, -34.846888),
}

for index in result[result['NR_LATITUDE'] == -1.0].index:
    result.loc[index, 'NR_LATITUDE'] = coords[result.loc[index, 'NM_LOCAL_VOTACAO']][0]
    result.loc[index, 'NR_LONGITUDE'] = coords[result.loc[index, 'NM_LOCAL_VOTACAO']][1]
gdf = gpd.GeoDataFrame(
    result, geometry=gpd.points_from_xy(result.NR_LONGITUDE, result.NR_LATITUDE), crs='EPSG:4326')
gdf = gdf.to_crs('EPSG:31985')

Vamos plotar e ver se deu certo.

gdf.plot()
<AxesSubplot: >
../../_images/eleicoes_presidenciais_jp_2t_78_1.png

Conheço essa cidade rs. Vamos ver com a base de bairros que carregamos anteriormente.

fig, ax = plt.subplots(1, 1, figsize=(11,11))
bairros.plot(ax=ax, alpha=0.3, zorder=1)
gdf.plot(ax=ax, alpha=0.9, edgecolor='k', zorder=2)
<AxesSubplot: >
../../_images/eleicoes_presidenciais_jp_2t_80_1.png

Mapa dos locais de votação segundo candidato com melhor desempenho#

A ideia é ver onde cada candidato se saiu melhor.

import folium
gdf = gdf[gdf['NM_LOCAL_VOTACAO'] != 'NÃO IDENTIFICADO']
gdf
NM_LOCAL_VOTACAO NR_LATITUDE NR_LONGITUDE LULA BOLSONARO QT_VOTOS_VALIDOS geometry
0 ACADEMIA DE COMERCIO EPITACIO PESSOA -7.122656 -34.884473 1034 974 2008 POINT (291876.187 9212267.351)
1 ASSOCIAÇÃO DOS SERVIDORES DA POLÍCIA FEDERAL -... -7.080441 -34.836433 577 741 1318 POINT (297165.064 9216957.874)
2 CENEC - CENTRO EDUCACIONAL CENECISTA -7.163410 -34.827805 1451 1425 2876 POINT (298154.696 9207785.093)
3 CENEC - ESCOLA CENECISTA JOÃO REGIS AMORIM -7.177847 -34.867251 2146 2474 4620 POINT (293803.677 9206170.805)
4 CENTRO DA CIDADANIA OTAVIANO FERNANDES COUTINHO -7.170910 -34.838149 466 409 875 POINT (297015.349 9206951.020)
... ... ... ... ... ... ... ...
204 MOTIVA AMBIENTAL -7.114607 -34.828009 2415 2841 5256 POINT (298110.808 9213182.752)
206 SERVICO SOCIAL DA INDUSTRIA - SESI -7.123403 -34.885977 215 190 405 POINT (291710.415 9212184.152)
207 UFPB CENTRAL DE AULAS -7.141083 -34.848948 4916 3297 8213 POINT (295809.151 9210245.133)
208 UNIVERSIDADE ESTADUAL DA PARAÍBA - UEPB -7.157929 -34.872929 2604 2730 5334 POINT (293167.475 9208371.215)
209 VIA MEDICINA COLEGIO E CURSO -7.119153 -34.834591 1107 1354 2461 POINT (297385.639 9212676.975)

209 rows × 7 columns

m = folium.Map(
    location=[-7.146122, -34.852709], 
    zoom_start=12, 
    tiles='cartodbpositron', 
    control_scale=True
)

def get_color(label):
    color = {
        "LULA_GANHOU": '#FF0000',
        "LULA_GANHOU_MAIS_55": '#8B0000',
        "BOLSONARO_GANHOU": '#0000FF',
        "BOLSONARO_GANHOU_MAIS_55": '#00008B',
        "EMPATE": '#303030'
    }
    return color[label]

def get_label(index):
    label = 'ERRO'
    lula, bolsonaro, total = gdf.loc[index, 'LULA'], gdf.loc[index, 'BOLSONARO'], \
        gdf.loc[index, 'QT_VOTOS_VALIDOS']
    sorted_values = sorted([lula, bolsonaro], reverse=True)
    if sorted_values[0] == sorted_values[1]:
        label = 'EMPATE'
    elif lula == sorted_values[0]:
        label = 'LULA_GANHOU'
        if lula / total > 0.55:
            label = 'LULA_GANHOU_MAIS_55'
    elif bolsonaro == sorted_values[0]:
        label = 'BOLSONARO_GANHOU'
        if bolsonaro / total > 0.55:
            label = 'BOLSONARO_GANHOU_MAIS_55'
    return label

def get_popup(index):
    lula, bolsonaro, total, nome_local = gdf.loc[index, 'LULA'], gdf.loc[index, 'BOLSONARO'], \
        gdf.loc[index, 'QT_VOTOS_VALIDOS'], gdf.loc[index, 'NM_LOCAL_VOTACAO']
    def percent(value):
        return "{0:.1%}".format(value/total)
    html_votos = f"""
        <p><b>Lula</b>: {lula} ({percent(lula)})</p>
        <p><b>Bolsonaro</b>: {bolsonaro} ({percent(bolsonaro)})</p>
        <p><b>Total</b>: {total}</p>
    """
    return f"""
        <div style='width:300px'>
            <p><b>{nome_local} - 2º TURNO</b></p>
            {html_votos}
        </div>
    """

for index in gdf.index:
    label = get_label(index)
    coords_location = gdf.loc[index, 'NR_LATITUDE'], gdf.loc[index, 'NR_LONGITUDE']
    folium.CircleMarker(
        coords_location, 
        radius=7, 
        color='#FFF',
        fill_color=get_color(label),
        fill_opacity=1,
        popup=get_popup(index),
        weight=2
    ).add_to(m)

Mapa final#

Pontos em tons azuis onde Bolsonaro venceu. Pontos em tons vermelhos onde Lula venceu. Quando a cor é mais escura, significa que o candidato obteve mais de 55% dos votos válidos. A cor cinza representa empate.

m
Make this Notebook Trusted to load map: File -> Trust Notebook