Sección 9 — Voto por partido
Interactividad: pasá el cursor para ver %
Lic. Roque Cantoia
@doxadata__
@rcantoia
---
title: ""
author: ""
format:
html:
theme: flatly
toc: true
self-contained: true
code-fold: true
code-summary: "Mostrar código"
code-tools: true
editor: visual
execute:
echo: false
warning: false
message: false
---
{fig-align="left" width="100"}
## Elecciones 13/04/25 - Reformador Distrito Único
### 1) Voto por partido político - Departamento General Obligado
```{r fig.height=8, fig.width=14, message=FALSE, warning=FALSE}
resultados_obligado <- read.csv(file = "C:/Users/Roque/Desktop/DOXA 2020/RESULTADOS 2025/paso por mesa 2025.csv", sep = ";")
library(dplyr)
library(tidyr)
library(purrr)
library(tibble)
library(stringr)
library(readxl)
library(ggplot2)
library(tidytext)
library(grid)
library(patchwork)
library(htmltools)
library(plotly)
convencionales_obligado <- resultados_obligado%>%
select(seccion, circuito,sorteo.Partido, Nombre.Lista, categoria, votos) %>%
group_by(seccion, sorteo.Partido, categoria)%>%
filter(categoria=="Reformador Distrito Único")
convencionales_obligado <- convencionales_obligado %>%
filter(seccion==9) %>%
group_by(seccion, sorteo.Partido) %>%
summarise(votos = sum(votos, na.rm = TRUE), .groups = "drop")
convencionales_obligado <- convencionales_obligado %>%
filter(seccion==9) %>%
group_by(seccion, sorteo.Partido) %>%
summarise(votos = sum(votos, na.rm = TRUE), .groups = "drop") %>%
group_by(seccion) %>%
mutate(total_seccion = sum(votos),
porcentaje = round((votos / total_seccion) * 100, 2)) %>%
ungroup()
tabla_convencionales_obligado <- convencionales_obligado %>%
filter(seccion==9) %>%
group_by(seccion, sorteo.Partido) %>%
summarise(votos = sum(votos, na.rm = TRUE), .groups = "drop") %>%
group_by(seccion) %>%
mutate(total_seccion = sum(votos),
porcentaje = round((votos / total_seccion) * 100, 2)) %>%
select(seccion, sorteo.Partido, porcentaje) %>%
pivot_wider(names_from = sorteo.Partido, values_from = porcentaje)
tabla_convencionales_obligado <- tabla_convencionales_obligado %>%
rename(UNIDOS = "78",
LLA = "69",
MAS_PARA_SANTAFE = "8",
SOMOS_VIDA = "21",
BLANCO_NULO = "0",
FIT = "5",
FRENTE_DE_LA_ESPERANZA = "3",
ACTIVEMOS = "14",
CONFLUENCIA ="52",
MODERADO = "55",
PAIS = "68",
FRENTE_AMPLIO_SOBERANIA="70",
ACUERDO_CI="50")
colores_partidos <- c(
"UNIDOS" = "#ff7f0e",
"LLA"= "#9467bd",
"MAS_PARA_SANTAFE" = "#1f77b4",
"SANTAFE_EN_cOMUN" = "#FF0000",
"PROP_FEDERAL" = "#2ca02c",
"SOMOS_VIDA" = "#AEDFF7",
"BLANCO_NULO"="#A9A9A9",
"Otros"= "#d62728",
"ACTIVEMOS"="#DC143C",
"COMPROMISO"="#FFD700",
"FRENTE_DE_LA_ESPERANZA"="#B8860B",
"FRENTE_AMPLIO_SOBERANIA"= "red",
"ACUERDO_CI"= "green",
"FIT"="#d62728",
"PAIS"="#FFD700")
df_bar_obligado <- tabla_convencionales_obligado %>%
# Excluí acá cualquier columna que NO sea partido:
select(-any_of(c("seccion", "circuito", "total_seccion", "total_circuito"))) %>%
pivot_longer(everything(), names_to = "Partido", values_to = "Porcentaje") %>%
mutate(
Partido = as.character(Partido),
Porcentaje = as.numeric(Porcentaje)
) %>%
filter(!is.na(Porcentaje))
df_bar_obligado <- df_bar_obligado %>% dplyr::filter(Partido != "seccion")
# Optional: título con número de sección si está presente en la tabla original
sec_lab_obligado <- if ("seccion" %in% names(tabla_convencionales_obligado)) {
paste0("Sección ", unique(tabla_convencionales_obligado$seccion))
} else NULL
# Orden de barras (desc)
ord_x <- df_bar_obligado %>% arrange(desc(Porcentaje)) %>% pull(Partido)
# Colores (usa tu paleta si existe)
if (exists("colores_partidos")) {
df_bar_obligado$color <- unname(colores_partidos[df_bar_obligado$Partido])
df_bar_obligado$color[is.na(df_bar_obligado$color)] <- "#9aa0a6"
} else {
df_bar_obligado$color <- "#9aa0a6"
}
# --- 2) Estilo card ---
css <- tags$style(HTML("
:root { --ro-card-bg: #ffffff; --ro-text: #222; --ro-subtext:#6b7280; }
.ro-wrap { max-width: 1200px; margin: 0 auto; }
.ro-card {
background: var(--ro-card-bg);
border-radius: 16px;
box-shadow: 0 8px 28px rgba(0,0,0,.08);
padding: 16px 18px 12px 18px;
border: 1px solid rgba(0,0,0,.06);
}
.ro-header { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin-bottom: 8px; }
.ro-title { font-weight: 700; font-size: 20px; color: var(--ro-text); margin: 0; }
.ro-sub { font-size: 12px; color: var(--ro-subtext); margin-left: auto; }
"))
# --- 3) Plotly con eje Y 0–50 y etiquetas verticales ---
plt <- plot_ly(
df_bar_obligado, type = "bar",
x = ~Partido, y = ~Porcentaje,
marker = list(color = ~color),
hovertemplate = "Partido: %{x}<br>Voto: %{y:.1f}%<extra></extra>"
) %>%
layout(
template = "plotly_white",
title = list(text = NULL),
xaxis = list(
title = "",
tickangle = -90, showticklabels = TRUE,
categoryorder = "array", categoryarray = ord_x,
automargin = TRUE,
ticks = "outside", tickwidth = 1, ticklen = 6, tickcolor = "rgba(0,0,0,0.15)"
),
yaxis = list(
title = "Porcentaje (%)",
rangemode = "tozero",
range = c(0, 50), # ← ESCALA 0 a 50
dtick = 10, # marcas cada 10 (ajustable)
gridcolor = "rgba(0,0,0,0.06)", zerolinecolor = "rgba(0,0,0,0.10)"
),
bargap = 0.25,
showlegend = FALSE,
paper_bgcolor = "rgba(0,0,0,0)",
plot_bgcolor = "#fafafa",
font = list(family = "Inter, system-ui, Segoe UI, Roboto, Helvetica, Arial", size = 13, color = "#222"),
margin = list(t = 10, r = 20, b = 160, l = 70)
) %>%
config(displaylogo = FALSE,
modeBarButtonsToRemove = c("autoScale2d","select2d","lasso2d","toggleSpikelines","hoverCompareCartesian"))
# --- 4) Render card ---
browsable(
tagList(
css,
div(class="ro-wrap",
div(class="ro-card",
div(class="ro-header",
h3(class="ro-title", if (is.null(sec_lab_obligado)) "Voto por partido" else paste0(sec_lab_obligado, " — Voto por partido")),
div(class="ro-sub", "Interactividad: pasá el cursor para ver %")
),
plt
)
)
)
)
```
### 2) Voto por Circuito electoral - Departamento General Obligado
```{r fig.height=8, fig.width=14, message=FALSE, warning=FALSE}
library(dplyr)
library(tidyr)
library(purrr)
library(tibble)
library(stringr)
library(readxl)
library(ggplot2)
library(tidytext)
library(grid)
library(patchwork)
library(htmltools)
library(plotly)
if (!requireNamespace("crosstalk", quietly = TRUE)) install.packages("crosstalk")
library(crosstalk)
convencionales_obligado <- resultados_obligado%>%
select(seccion, circuito,sorteo.Partido, Nombre.Lista, categoria, votos) %>% group_by(circuito, sorteo.Partido, categoria)%>%
filter(categoria=="Reformador Distrito Único")
library(dplyr)
convencionales_obligado <- convencionales_obligado %>%
filter(circuito >=2210, circuito<=2470) %>%
group_by(circuito, sorteo.Partido) %>%
summarise(votos = sum(votos, na.rm = TRUE), .groups = "drop") %>%
group_by(circuito) %>%
mutate(total_circuito = sum(votos),
porcentaje = round((votos / total_circuito) * 100, 2)) %>%
ungroup()
tabla_convencionales_obligado <- convencionales_obligado %>%
filter(circuito >= 2210, circuito <= 2470) %>%
group_by(circuito, sorteo.Partido) %>%
summarise(votos = sum(votos, na.rm = TRUE), .groups = "drop") %>%
group_by(circuito) %>%
mutate(total_circuito = sum(votos),
porcentaje = round((votos / total_circuito) * 100, 2)) %>%
select(circuito, sorteo.Partido, porcentaje) %>%
pivot_wider(names_from = sorteo.Partido, values_from = porcentaje)
tabla_convencionales_obligado <- tabla_convencionales_obligado %>%
rename(UNIDOS = "78",
LLA = "69",
MAS_PARA_SANTAFE = "8",
SOMOS_VIDA = "21",
BLANCO_NULO = "0",
FIT = "5",
FRENTE_DE_LA_ESPERANZA = "3",
ACTIVEMOS = "14",
CONFLUENCIA ="52",
MODERADO = "55",
PAIS = "68",
FRENTE_AMPLIO_SOBERANIA="70",
ACUERDO_CI="50")
library(ggplot2)
datos_largos_convencionales_obligado <- tabla_convencionales_obligado %>%
pivot_longer(cols = -c(circuito), # Todo excepto circuito
names_to = "Partido",
values_to = "Porcentaje")
datos_largos_convencionales_obligado <- datos_largos_convencionales_obligado %>%
mutate(localidad=recode(circuito,
"2210" = "Malabrigo",
"2220"= "Berna",
"2230"="Nicanor Molinas",
"22440"="Reconquista",
"22550"= "Avellaneda",
"2270"="Lanteri",
"2272"="Ing. Chanourdie",
"2280"="Las Garzas",
"2290"="El Sombrerito",
"3000"="Villa Ana",
"2320"="Villa Ocampo",
"2330"="Tacuarendí",
"2340"="San Antonio",
"2350"="Las Toscas",
"2370"="Villa Guillermina",
"2380"="El Rabón",
"2390"="Florencia",
"2395"="Campo Hardy",
"2444"="La Sarita",
"2450"="Arroyo Ceibal",
"2460"="Los Laureles",
"2470"="El Arazá"))
top8_convencionales_obligado <- datos_largos_convencionales_obligado %>%
group_by(localidad) %>%
slice_max(order_by = Porcentaje, n = 7, with_ties = FALSE) %>%
ungroup() %>%
arrange(localidad, desc(Porcentaje))
otros_convencionales_obligado <- datos_largos_convencionales_obligado %>%
anti_join(top8_convencionales_obligado, by = c("localidad", "Partido")) %>%
group_by(localidad) %>%
summarise(Partido = "Otros",
Votos = sum(Porcentaje),
Porcentaje = sum(Porcentaje))
final_convencionales_obligado <- bind_rows(top8_convencionales_obligado, otros_convencionales_obligado) %>%
arrange(localidad, desc(Porcentaje))
library(plotly)
colores_partidos <- c(
"UNIDOS" = "#ff7f0e",
"LLA"= "#9467bd",
"MAS_PARA_SANTAFE" = "#1f77b4",
"SANTAFE_EN_cOMUN" = "#FF0000",
"PROP_FEDERAL" = "#2ca02c",
"SOMOS_VIDA" = "#AEDFF7",
"BLANCO_NULO"="#A9A9A9",
"Otros"= "#d62728",
"ACTIVEMOS"="#DC143C",
"COMPROMISO"="#FFD700",
"FRENTE_DE_LA_ESPERANZA"="#B8860B",
"FRENTE_AMPLIO_SOBERANIA"= "red",
"ACUERDO_CI"= "green",
"FIT"="#d62728",
"PAIS"="#FFD700")
css <- tags$style(HTML("
:root { --ro-bg: #0b0c10; --ro-card-bg: #ffffff; --ro-text: #222; --ro-subtext:#6b7280; }
.ro-wrap { max-width: 1200px; margin: 0 auto; }
.ro-card {
background: var(--ro-card-bg);
border-radius: 16px;
box-shadow: 0 8px 28px rgba(0,0,0,.08);
padding: 16px 18px 12px 18px;
border: 1px solid rgba(0,0,0,.06);
}
.ro-header {
display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
margin-bottom: 8px;
}
.ro-title {
font-weight: 700; font-size: 20px; color: var(--ro-text); margin: 0 12px 0 0;
}
.ro-sub {
font-size: 12px; color: var(--ro-subtext); margin-left: auto;
}
/* Control selectize de crosstalk */
.ro-header .selectize-control { min-width: 260px; }
.ro-header .selectize-control.single .selectize-input {
border-radius: 12px; padding: 8px 12px; border: 1px solid #e5e7eb;
box-shadow: none; background: #f9fafb;
}
"))
# ====== Datos ======
df_obligado <- datos_largos_convencionales_obligado %>%
transmute(
localidad = as.character(localidad),
Partido = as.character(Partido),
Porcentaje = as.numeric(Porcentaje)
) %>%
filter(!is.na(localidad), !is.na(Partido), !is.na(Porcentaje))
# Paleta propia (si existe)
if (exists("colores_partidos")) {
df_obligado$color <- unname(colores_partidos[df_obligado$Partido])
}
# Compartir para filtro cliente
sd <- SharedData$new(df_obligado, group = "g_localidad")
sel_default <- if ("Reconquista" %in% unique(df_obligado$localidad)) "UNL" else unique(df_obligado$localidad)[1]
# Control SIN 'selected' (para compatibilidad con tu versión)
ctrl <- filter_select(
id = "sel_localidad", label = "Localidad:",
sharedData = sd, ~localidad, multiple = FALSE
)
# Script que fija el valor por defecto al cargar
set_default <- tags$script(HTML(sprintf("
document.addEventListener('DOMContentLoaded', function(){
var el = document.getElementById('sel_localidad');
function setSel(){
if(!el) return;
var s = el.querySelector('select');
if(s && s.selectize){ s.selectize.setValue('%s'); }
else { setTimeout(setSel, 80); }
}
setSel();
});
", sel_default)))
# ====== Plotly ======
plt <- plot_ly(
sd, type = "bar",
x = ~Partido, y = ~Porcentaje,
customdata = ~localidad,
marker = if ("color" %in% names(df_obligado)) list(color = ~color) else NULL,
hovertemplate = paste(
"Localidad: %{customdata}",
"<br>Partido: %{x}",
"<br>Voto: %{y:.1f}%<extra></extra>"
)
) %>%
layout(
template = "plotly_white",
title = list(text = NULL),
xaxis = list(
title = "", tickangle = -90, showticklabels = TRUE,
categoryorder = "total descending", automargin = TRUE,
ticks = "outside", tickwidth = 1, ticklen = 6, tickcolor = "rgba(0,0,0,0.15)"
),
yaxis = list(
title = "Porcentaje (%)", rangemode = "tozero",
gridcolor = "rgba(0,0,0,0.06)", zerolinecolor = "rgba(0,0,0,0.10)"
),
bargap = 0.25, uniformtext = list(minsize = 10, mode = "hide"),
showlegend = FALSE,
paper_bgcolor = "rgba(0,0,0,0)",
plot_bgcolor = "#fafafa",
font = list(family = "Inter, system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial", size = 13, color = "#222"),
margin = list(t = 10, r = 20, b = 160, l = 70)
) %>%
config(displaylogo = FALSE,
modeBarButtonsToRemove = c("autoScale2d","select2d","lasso2d","toggleSpikelines","hoverCompareCartesian"))
# ====== Composición estilizada ======
browsable(
tagList(
css,
div(class="ro-wrap",
div(class="ro-card",
div(class="ro-header",
h3(class="ro-title", "Voto por partido (filtrar por localidad)"),
ctrl,
div(class="ro-sub", "Interactividad: pasá el cursor para ver %")
),
plt
)
)
)
)
```
Lic. Roque Cantoia
@doxadata__
@rcantoia