Eleições presidenciais em João Pessoa - 2º turno
Contents
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
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: >
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: >
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: >
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: >
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