Insert cell
Insert cell
selector = selectDiv()
Insert cell
res = fetch('https://d2v5qzywcd0fzd.cloudfront.net/viz-decidechile/30annos/datos/data_demografia_years_v2.json')
Insert cell
data = res.json()
Insert cell
data
Type Table, then Shift-Enter. Ctrl-space for more options.

Insert cell
filterData = data.filter(d => d.year === years)
Insert cell
viewof years = slider({
title: "Año",
min: 1992,
max: 2050,
step: 1,
value: 2024
})
Insert cell
selectDiv = () => {
return html`
<div class="grid-container-select">
<div class="item5">${viewof years}</div>
</div>
`
}
Insert cell
titulo = (titulo) => {
return html`
<div class="titulo_mapa" style="font-family: 'Source Sans Pro', sans-serif;">${titulo}</div>
`;
}
Insert cell
Insert cell
function populationPyramidPlot(
data,
{
gender = "gender",
group = "group",
value = "population",
domain, // Arrays of values from 'group'. Can be use to assign particular order
facet, // The key of value based on which to generate facets
facetDirection = "x",

width = facet ? 960 : 400, // Width of the plot
height = facet ? undefined : 500, // Height of the plot

colorScheme = schemeContrasting, // Categoriecal color schemes like: d3.schemeAccent, d3.schemeCategory10,...
gap = 20, // Gap between two set of bar charts
maxValue = 1200000,
nticks = 4
} = {}
) {
const genderAccessor = accessor(gender);
const groupAccessor = accessor(group);
const valueAccessor = accessor(value);

domain = domain ?? [...new Set(data.map(groupAccessor))];
facetDirection = ["x", "y"].includes(facetDirection) ? facetDirection : "x";

const genders = [...new Set(data.map(genderAccessor))].sort().reverse();

const ticks = d3.ticks(0, maxValue, nticks);

const xAxis = [
Plot.ruleX(ticks, {
x: (d) => d,
dx: gap,
stroke: "currentColor",
strokeOpacity: 0.1,
}),
Plot.text(ticks, {
x: (d) => -d,
dx: -gap,
frameAnchor: "bottom",
dy: 10,
text: (d) => d3.format(".0f")(d).replace(/\B(?=(\d{3})+(?!\d))/g, ".") // Formatear el valor con separador de miles "."
}),

Plot.ruleX(ticks, {
x: (d) => -d,
dx: -gap,
stroke: "currentColor",
strokeOpacity: 0.1,
}),
Plot.text(ticks, {
x: (d) => d,
frameAnchor: "bottom",
dx: gap,
dy: 10,
text: (d) => d3.format(".0f")(d).replace(/\B(?=(\d{3})+(?!\d))/g, ".") // Formatear el valor con separador de miles "."
}),

Plot.text(
data,
Plot.selectFirst({
x: 0,
y: group,
dx: -gap,
dy: 40,
filter: (d) => genderAccessor(d) === genders[0],
text: (d) => `← ${genderAccessor(d).toUpperCase()}`,
textAnchor: "end",
fontWeight: "bold"
})
),
Plot.text(
data,
Plot.selectFirst({
x: 0,
y: group,
dx: gap,
dy: 40,
filter: (d) => genderAccessor(d) === genders[1],
text: (d) => `${genderAccessor(d).toUpperCase()} →`,
textAnchor: "start",
fontWeight: "bold"
})
)
];

const yAxis = [Plot.text(domain, { x: 0, text: (d) => d, y: (d) => d })];

const plot = Plot.plot({
width,
height,
marginBottom: 40,
marginLeft: 100,
marginRight: -10,
...(facet && {
facet: { label: null, data: data, [facetDirection]: facet}
}),
fx: {
axis: "top",
padding: 0.2,
label: "",
tickFormat: d3.format(".4") // Formato personalizado para el eje X con puntos como separadores de miles
},
color: {
type: "categorical",
legend: false,
domain: genders,
range: colorScheme
},
x: {
domain: [-maxValue, maxValue], // Asegura que el dominio del eje X vaya de -maxValue a maxValue
label: null,
tickFormat: Math.abs, // Only absolute value (without sign) is shown on ticks. Needed to show
axis: null
},
y: {
label: null,
domain,
reverse: true,
axis: null,
padding: 1 / 15,
align: 1
},
marks: [
xAxis, // customized
yAxis, // customized

Plot.barX(data, {
y: group,
x: (d) => -valueAccessor(d),
dx: -gap,
fill: gender,
filter: (d) => genderAccessor(d) === genders[0]
}),
Plot.barX(data, {
y: group,
x: value,
dx: gap,
fill: gender,
filter: (d) => genderAccessor(d) === genders[1]
})
]
});

d3.select(plot)
.selectAll("[aria-label=fx-axis] .tick text")
.style("font-weight", "bold")
.style("font-size", "0.75rem");

// Seleccionar y cambiar el tamaño de la fuente de los números en el eje y otras etiquetas
d3.select(plot)
.selectAll(".tick text") // Selecciona todos los textos de las ticks
.style("font-size", "12px"); // Cambia el tamaño de la fuente a 12px (ajusta según necesites)

return plot;
}
Insert cell
variablesY = ["Mujeres", "Hombres"]
Insert cell
coloresY = ["#47a5da", "#075376"]
Insert cell
grafico = graph(filterData, 'year')
Insert cell
Insert cell
function graph(data, facet) {
// Crear la escala de colores
const colorScale = d3.scaleOrdinal(schemeContrasting).domain(variablesY); // Dominio: lista de variablesY

// Definir el tamaño del contenedor
const containerWidth = 1200; // Ancho del contenedor
const containerHeight = 660; // Alto del contenedor

// Agregar el título
const tituloDiv = titulo(
"Estimación y Proyección de la Población de Chile 1992 - 2050"
); // Llama a la función titulo con el texto del título
tituloDiv.style.textAlign = "center"; // Alinear el título al centro
tituloDiv.style.marginBottom = "10px"; // Añadir margen inferior al título
tituloDiv.style.marginTop = "10px"; // Añadir margen inferior al título

// Agregar el gráfico populationPyramidPlot
const pyramidPlot = populationPyramidPlot(data, {
width: 1200, // Ancho del gráfico
height: 500, // Alto del gráfico
colorScheme: schemeContrasting, // Esquema de color para el gráfico de pirámide de población
maxValue: 1200000,
nticks: 4,
facet // The key of value based on which to generate facets
});

pyramidPlot.style.position = "relative"; // Establecer posición absoluta para el gráfico
pyramidPlot.style.left = "50%"; // Centrar horizontalmente el gráfico
pyramidPlot.style.transform = "translateX(-54.7%)";
pyramidPlot.style.marginTop = "-10px"; // Margen superior de 10px
pyramidPlot.style.marginBottom = "20px"; // Margen inferior de 20px

// Seleccionar y cambiar el tamaño de la fuente de los números en el eje y otras etiquetas
d3.select(pyramidPlot)
.selectAll(".tick text") // Selecciona todos los textos de las ticks
.style("font-size", "12px") // Cambia el tamaño de la fuente a 12px (ajusta según necesites)
.style("font-family", "'Source Sans Pro', sans-serif"); // Aplica la fuente Source Sans Pro

d3.select(pyramidPlot)
.selectAll("text") // Selecciona todos los textos
.style("font-family", "'Source Sans Pro', sans-serif"); // Aplica la fuente Source Sans Pro

// Crear el gráfico y la leyenda como elementos HTML
const container = document.createElement("div");
container.style.position = "relative"; // Establecer posición relativa para posicionar elementos hijos
container.style.width = containerWidth + "px"; // Establecer el ancho del contenedor
container.style.height = containerHeight + "px";
container.style.fontFamily = "'Source Sans Pro', sans-serif"; // Aplica la fuente Source Sans Pro al contenedor

// Agregar el título al contenedor principal
container.appendChild(tituloDiv); // Agregar el título antes del gráfico

// Crear la leyenda
const legend = d3
.select(document.createElement("div"))
.style("margin-bottom", "0px")
.style("margin-top", "10px")
.style("text-align", "center") // Alinear la leyenda al centro
.style("display", "flex") // Usar flexbox para la alineación
.style("justify-content", "center") // Centrar los elementos dentro del contenedor
.style("align-items", "center") // Alinear los elementos verticalmente
.style("font-family", "'Source Sans Pro', sans-serif"); // Aplica la fuente Source Sans Pro

variablesY.forEach((variableY, index) => {
const color = colorScale(variableY);
const legendItem = legend
.append("div")
.style("display", "flex") // Mostrar los elementos en línea usando flexbox
.style("align-items", "center") // Alinear verticalmente
.style("margin-right", "10px");

legendItem
.append("div")
.style("width", "10px")
.style("height", "10px")
.style("background-color", color)
.style("margin-right", "5px");

legendItem
.append("span")
.text(variableY)
.style("font-family", "'Source Sans Pro', sans-serif"); // Aplica la fuente Source Sans Pro
});

// Agregar el filtro externo
const filterDiv = selectDiv();
filterDiv.style.position = "relative"; // Establecer posición relativa para el filtro
filterDiv.style.marginTop = "10px"; // Margen superior de 10px
filterDiv.style.marginBottom = "10px"; // Margen inferior de 20px
filterDiv.style.fontFamily = "'Source Sans Pro', sans-serif"; // Aplica la fuente Source Sans Pro

// Crear el texto "Año"
const yearLabel = document.createElement("div");
yearLabel.innerText = "Año";
yearLabel.style.textAlign = "center"; // Alinear el texto al centro
yearLabel.style.marginTop = "-12px"; // Añadir margen superior
yearLabel.style.fontSize = "13px"; // Cambiar el tamaño de la fuente (puedes ajustar este valor según tus necesidades)
yearLabel.style.fontFamily = "'Source Sans Pro', sans-serif"; // Aplica la fuente Source Sans Pro

// Agregar la leyenda al contenedor principal
container.appendChild(legend.node()); // Agregar la leyenda antes del gráfico
container.appendChild(filterDiv); // Agregar el filtro
container.appendChild(yearLabel); // Agregar el texto "Año" antes del gráfico
container.appendChild(pyramidPlot); // Agregar el gráfico populationPyramidPlot al contenedor principal

// Agregar el logo "Powered by Unholster"
const unholsterLogoLink = document.createElement("a");
unholsterLogoLink.setAttribute("href", "https://unholster.com");
unholsterLogoLink.setAttribute("target", "_blank"); // Abrir enlace en una nueva pestaña
unholsterLogoLink.style.position = "absolute"; // Establecer posición absoluta para el logo
unholsterLogoLink.style.bottom = "50px"; // Posicionar el logo 10px desde el borde inferior
unholsterLogoLink.style.right = "120px"; // Posicionar el logo 10px desde el borde derecho

const unholsterLogo = document.createElement("img");
unholsterLogo.setAttribute(
"src",
"https://d2v5qzywcd0fzd.cloudfront.net/viz-decidechile/30annos/logo-unholster/Powered%20by%20Unholster%202.png"
);
unholsterLogo.setAttribute("height", "20");
unholsterLogoLink.appendChild(unholsterLogo);
container.appendChild(unholsterLogoLink);

// Agregar el texto en la esquina inferior izquierda
const bottomLeftText = document.createElement("div");
bottomLeftText.innerText = "Fuente: Instituto Nacional de Estadísticas"; // Aquí puedes cambiar el texto a lo que necesites
bottomLeftText.style.position = "absolute"; // Establecer posición absoluta para el texto
bottomLeftText.style.bottom = "50px"; // Posicionar el texto 0px desde el borde inferior
bottomLeftText.style.left = "110px"; // Posicionar el texto 50px desde el borde izquierdo
bottomLeftText.style.fontSize = "14px"; // Tamaño de fuente del texto
bottomLeftText.style.color = "#707070"; // Color del texto (puedes cambiarlo según tus necesidades)
bottomLeftText.style.fontFamily = "'Source Sans Pro', sans-serif"; // Aplica la fuente Source Sans Pro

container.appendChild(bottomLeftText); // Agregar el texto al contenedor principal

// Retornar el contenedor que incluye el gráfico, la leyenda y el filtro centrados
return container;
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
poweredByUnholster2 = FileAttachment("Powered by Unholster 2.png").image()
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more