cargosInfo = {
const data = {
"6985692b0019b011d4a9": { nombre: "Gobernador", prioridad: 10 },
"6985692d002caedc8a05": { nombre: "Alcalde", prioridad: 9 },
"6985692f000d5fa06665": { nombre: "Vicegobernador", prioridad: 8 },
"698569300002b7e2c898": { nombre: "Subgobernador", prioridad: 7 },
"6985692f0026fc9818f9": { nombre: "Asambleistas Regionales por Poblacion", prioridad: 6 },
"6985692e0017dcaedf70": { nombre: "Asambleistas Regionales por Territorio", prioridad: 5 },
"6985693100241f41ca8b": { nombre: "Corregidor", prioridad: 4 }
};
return data;
}
territorioInfo = {
const data = {
"6983986f27930b142391": { nombre: "Departamento de La Paz", prioridad: 10 },
"698398675bb38121fa86": { nombre: "Departamento de Cochabamba", prioridad: 10 },
"69839869e17caed5adf0": { nombre: "Departamento de Santa Cruz", prioridad: 10 },
"6983986da5e5ba7df366": { nombre: "Departamento de Potosi", prioridad: 8 },
"6983986484ff3fbbd1ce": { nombre: "Departamento de Beni", prioridad: 8 },
"6983986b655f81d387ea": { nombre: "Departamento de Tarija", prioridad: 8 },
"698398662dbd3f8849d5": { nombre: "Departamento de Chuquisaca", prioridad: 8 },
"69839868858161e0b8a0": { nombre: "Departamento de Pando", prioridad: 8 },
"6983986c6c9ac55f6440": { nombre: "Departamento de Oruro", prioridad: 8 },
"69839a1ea14be0c0f130": { nombre: "Municipio de La Paz", prioridad: 9 },
"698398f5670464b78148": { nombre: "Municipio de El Alto", prioridad: 9 },
"6983991d0f5226b8f547": { nombre: "Municipio de Cochabamba", prioridad: 9 },
"698399613415da3b0042": { nombre: "Municipio de Santa Cruz de la Sierra", prioridad: 9 },
"698398830087d877f5f0": { nombre: "Municipio de Cobija", prioridad: 7 },
"698398afe8eb95ee9732": { nombre: "Municipio de Trinidad", prioridad: 7 },
"69839992e8227ce2c00c": { nombre: "Municipio de Oruro", prioridad: 7 },
"698399a8a3c3fe144248": { nombre: "Municipio de Sucre", prioridad: 7 },
"69839a0b3109ff07b9ec": { nombre: "Municipio de Potosí", prioridad: 7 },
"698399e96916e0cb08d3": { nombre: "Municipio de Tarija", prioridad: 7 },
};
return data;
}
nombreCargo = (cargoId) => {
const info = cargosInfo[cargoId]
return (info && info.nombre) || cargoId || "(Sin dato)"
}
prioridadCargo = (cargoId) => {
const info = cargosInfo[cargoId]
return (info && info.prioridad) || 1
}
nombreTerritorio = (cargoId) => {
const info = territorioInfo[cargoId]
return (info && info.nombre) || cargoId || "(Sin dato)"
}
prioridadTerritorio = (cargoId) => {
const info = territorioInfo[cargoId]
return (info && info.prioridad) || 1
}
// Fuente principal
candidatos = FileAttachment("datos/candidatos.csv").csv()
// Normalizar vacíos
esVacio = (v) => {
if (v === null || v === undefined) return true
const t = String(v).trim().toLowerCase()
return t === "" || t === "nan" || t === "null" || t === "none" || t === "s/n"
}
// Campos evaluados para completitud de perfil
campos = [
"ci",
"militancia",
"trayectoria",
"estudios",
"label",
"item",
"foto",
"youtube",
"facebook",
"instagram",
"tiktok",
"twitter",
"partido",
"territorio",
"cargo"
]
totalCampos = campos.length
// Cálculo por candidato
candidatosCompletitud = candidatos.map((c) => {
const llenos = campos.filter((k) => !esVacio(c[k])).length
const faltantes = totalCampos - llenos
const completitud = llenos / totalCampos
const camposFaltantes = campos.filter((k) => esVacio(c[k]))
const cargoNombre = nombreCargo(c.cargo)
const territorioNombre = nombreTerritorio(c.territorio)
const prioridad_cargo = prioridadCargo(c.cargo)
const prioridad_territorio = prioridadTerritorio(c.territorio)
const puntajeImportancia = faltantes + prioridad_cargo + prioridad_territorio
return {
...c,
llenos,
faltantes,
camposFaltantes,
cargoNombre,
territorioNombre,
puntajeImportancia,
completitud,
completitudPct: Math.round(completitud * 100)
}
})
totalCandidatos = candidatosCompletitud.length
promedioCompletitud = totalCandidatos
? candidatosCompletitud.reduce((acc, d) => acc + d.completitud, 0) / totalCandidatos
: 0
perfilesCompletos = candidatosCompletitud.filter((d) => d.completitud === 1).length
sinFoto = candidatosCompletitud.filter((d) => esVacio(d.foto)).length
// Completitud por campo
completitudCampos = campos.map((campo) => {
const llenos = candidatosCompletitud.filter((d) => !esVacio(d[campo])).length
return {
campo,
llenos,
total: totalCandidatos,
pct: totalCandidatos ? (llenos / totalCandidatos) * 100 : 0
}
})
// Promedio por tipo de candidatura
completitudCandidatura = Array.from(
candidatosCompletitud.reduce((m, d) => {
const k = d.cargoNombre
if (!m.has(k)) m.set(k, [])
m.get(k).push(d.completitud)
return m
}, new Map()),
([cargo, valores]) => ({
cargo,
pct: (valores.reduce((a, b) => a + b, 0) / valores.length) * 100
})
).sort((a, b) => b.pct - a.pct)
// Ranking con menor completitud
peorCompletitud = [...candidatosCompletitud]
.sort((a, b) => b.puntajeImportancia - a.puntajeImportancia)
.slice(0, 12)
cargosDisponibles = ["(Todos)", ...new Set(candidatosCompletitud.map((d) => d.cargoNombre))]
partidosDisponibles = ["(Todos)", ...new Set(candidatosCompletitud.map((d) => d.partido || "(Sin dato)"))]