Public
Edited
May 3
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
{
// Dimensiones del gráfico y márgenes
const width = 600; // Ancho total del SVG
const height = 400; // Alto total del SVG
const margin = { top: 20, right: 20, bottom: 40, left: 50 }; // Márgenes internos

// Datos para la gráfica
const data = [
{ pais: "Brasil", valor: 50 },
{ pais: "Uruguay", valor: 40 },
{ pais: "Argentina", valor: 35 },
{ pais: "Chile", valor: 28 },
{ pais: "Paraguay", valor: 22 }
];

// Creamos un área de dibujo SVG
const svg = d3.create("svg")
.attr("width", width)
.attr("height", height);
const x = d3.scaleBand()
.domain(data.map(d => d.pais))
.range([margin.left, width - margin.right])
.padding(0.1);

const y = d3.scaleLinear()
.domain([0, d3.max(data, d => d.valor)])
.range([height - margin.bottom, margin.top]);

// Ejes
svg.append("g")
.attr("transform", `translate(0,${height - margin.bottom})`)
.call(d3.axisBottom(x));

svg.append("g")
.attr("transform", `translate(${margin.left},0)`)
.call(d3.axisLeft(y));

// Tooltip
const tooltip_group = svg.append("g")
.style("visibility", "hidden");

const tooltip_text = tooltip_group.append("text")
.attr("text-anchor", "middle")
.style("font-family", '-apple-system, BlinkMacSystemFont, "Segoe UI", Arial, sans-serif')
.style("font-size", "10px")
.style("fill", "orange")
.style("font-weight", "bold")
.text("");

const margen_tooltip = 10;

// Dibujamos las barras con interactividad
const barras = svg.selectAll("rect")
.data(data)
.enter()
.append("rect")
.attr("x", d => x(d.pais))
.attr("y", d => y(d.valor))
.attr("width", x.bandwidth())
.attr("height", d => y(0) - y(d.valor))
.attr("fill", "steelblue")
.on("mouseover", function (event, d) {
d3.select(this).attr("fill", "orange");
tooltip_text.text(d.valor);
tooltip_group
.attr("transform", `translate(${x(d.pais) + x.bandwidth() / 2}, ${y(d.valor) - margen_tooltip})`)
.style("visibility", "visible");
})
.on("mouseout", function () {
d3.select(this).attr("fill", "steelblue");
tooltip_group.style("visibility", "hidden");
});

return svg.node();
}

Insert cell
Insert cell
Insert cell
Insert cell
{
const width = 600;
const height = 400;
const margin = { top: 20, right: 20, bottom: 40, left: 50 };

const data = [
{ pais: "Brasil", valor: 50 },
{ pais: "Uruguay", valor: 40 },
{ pais: "Argentina", valor: 35 },
{ pais: "Chile", valor: 28 },
{ pais: "Paraguay", valor: 22 }
];

const svg = d3.create("svg")
.attr("width", width)
.attr("height", height);

const x = d3.scaleBand()
.domain(data.map(d => d.pais))
.range([margin.left, width - margin.right])
.padding(0.1);

const y = d3.scaleLinear()
.domain([0, d3.max(data, d => d.valor)])
.nice()
.range([height - margin.bottom, margin.top]);

svg.append("g")
.attr("transform", `translate(0,${height - margin.bottom})`)
.call(d3.axisBottom(x));

svg.append("g")
.attr("transform", `translate(${margin.left},0)`)
.call(d3.axisLeft(y));

// Tooltip como elemento SVG de texto
const tooltip = svg.append("text")
.attr("text-anchor", "middle")
.attr("font-family", "sans-serif")
.attr("font-size", "12px")
.attr("font-weight", "bold")
.attr("fill", "black")
.style("visibility", "hidden");

svg.selectAll("rect")
.data(data)
.enter()
.append("rect")
.attr("x", d => x(d.pais))
.attr("y", d => y(d.valor))
.attr("width", x.bandwidth())
.attr("height", d => y(0) - y(d.valor))
.attr("fill", "steelblue")
.on("mouseover", function(event, d) {
d3.select(this).attr("fill", "orange");

const xPos = x(d.pais) + x.bandwidth() / 2;
const yPos = y(d.valor) - 8;

tooltip.text(`${d.pais}: ${d.valor}`)
.attr("x", xPos)
.attr("y", yPos)
.style("visibility", "visible");
})
.on("mouseout", function() {
d3.select(this).attr("fill", "steelblue");
tooltip.style("visibility", "hidden");
});

return svg.node();
}

Insert cell
Insert cell
Insert cell
Insert cell
{
const width = 600;
const height = 400;
const margin = { top: 20, right: 20, bottom: 40, left: 50 };

const data = [
{ pais: "Brasil", valor: 50 },
{ pais: "Uruguay", valor: 40 },
{ pais: "Argentina", valor: 35 },
{ pais: "Chile", valor: 28 },
{ pais: "Paraguay", valor: 22 }
];

const svg = d3.create("svg")
.attr("width", width)
.attr("height", height);

const x = d3.scaleBand()
.domain(data.map(d => d.pais))
.range([margin.left, width - margin.right])
.padding(0.1);

const y = d3.scaleLinear()
.domain([0, d3.max(data, d => d.valor)])
.range([height - margin.bottom, margin.top]);

svg.append("g")
.attr("transform", `translate(0,${height - margin.bottom})`)
.call(d3.axisBottom(x));

svg.append("g")
.attr("transform", `translate(${margin.left},0)`)
.call(d3.axisLeft(y));

const tooltip_group = svg.append("g")
.style("visibility", "hidden");

const tooltip_text = tooltip_group.append("text")
.attr("text-anchor", "middle")
.style("font-family", '-apple-system, BlinkMacSystemFont, "Segoe UI", Arial, sans-serif')
.style("font-size", "10px")
.style("fill", "orange")
.style("font-weight", "bold")
.text("");

const margen_tooltip = 10;

let seleccionada = null;

const barras = svg.selectAll("rect")
.data(data)
.enter()
.append("rect")
.attr("x", d => x(d.pais))
.attr("y", d => y(d.valor))
.attr("width", x.bandwidth())
.attr("height", d => y(0) - y(d.valor))
.attr("fill", "steelblue")
.on("mouseover", function(event, d) {
if (seleccionada !== d.pais) {
d3.select(this).attr("fill", "orange");

tooltip_text.text(`${d.pais}: ${d.valor}`);
tooltip_group
.attr("transform", `translate(${x(d.pais) + x.bandwidth() / 2}, ${y(d.valor) - margen_tooltip})`)
.style("visibility", "visible");
}
})
.on("mouseout", function(event, d) {
if (seleccionada !== d.pais) {
d3.select(this).attr("fill", "steelblue");
tooltip_group.style("visibility", "hidden");
}
})
.on("click", function(event, d) {
if (seleccionada === d.pais) {
// Deseleccionar
d3.select(this).attr("fill", "steelblue");
seleccionada = null;
} else {
// Desmarcar la barra anterior si había
barras.attr("fill", b => (b.pais === seleccionada ? "steelblue" : d3.select(this).attr("fill")));
// Marcar la nueva
d3.select(this).attr("fill", "hotpink");
seleccionada = d.pais;
}
tooltip_group.style("visibility", "hidden");
});

return svg.node();
}

Insert cell
Insert cell
{
// Dimensiones y márgenes del SVG
const width = 600;
const height = 400;
const margin = { top: 20, right: 20, bottom: 40, left: 50 };

// Datos por país con valor total y desglose en hombres y mujeres
const data = [
{ pais: "Brasil", valor: 50, hombres: 35, mujeres: 15 },
{ pais: "Uruguay", valor: 40, hombres: 5, mujeres: 35 },
{ pais: "Argentina", valor: 35, hombres: 15, mujeres: 20 },
{ pais: "Chile", valor: 28, hombres: 22, mujeres: 6 },
{ pais: "Paraguay", valor: 22, hombres: 20, mujeres: 2 }
];

// Crear el SVG donde se dibujará todo
const svg = d3.create("svg")
.attr("width", width)
.attr("height", height);

// Escala horizontal (X): países → posición
const x = d3.scaleBand()
.domain(data.map(d => d.pais)) // Nombres de países
.range([margin.left, width - margin.right]) // Espacio disponible
.padding(0.1); // Separación entre barras

// Escala vertical (Y): valores → altura
const y = d3.scaleLinear()
.domain([0, d3.max(data, d => d.valor)]) // De 0 al máximo valor total
.range([height - margin.bottom, margin.top]); // Desde abajo hacia arriba

// Agregar eje X (inferior)
svg.append("g")
.attr("transform", `translate(0,${height - margin.bottom})`)
.call(d3.axisBottom(x));

// Agregar eje Y (izquierdo)
svg.append("g")
.attr("transform", `translate(${margin.left},0)`)
.call(d3.axisLeft(y));

// Variable que indica qué país está seleccionado actualmente (o null)
let seleccionada = null;

// Función principal que renderiza el gráfico en función de los datos y la selección
function render(data, seleccionada) {
// Unimos los datos a grupos SVG, uno por país
const groups = svg.selectAll(".barra-grupo")
.data(data, d => d.pais) // Usamos el nombre del país como clave
.join("g") // Maneja automáticamente enter/update/exit: crea nuevos <g> si es necesario, actualiza los existentes, y elimina los que ya no están
.attr("class", "barra-grupo")
.attr("transform", d => `translate(${x(d.pais)},0)`); // Posicionamos el grupo

// Limpiamos el contenido previo de cada grupo antes de redibujar
groups.selectAll("*").remove();

// Para cada grupo (país), dibujamos la barra simple o la barra apilada
groups.each(function(d) {
const g = d3.select(this); // Seleccionamos el grupo actual
const barWidth = x.bandwidth(); // Ancho de cada barra

// Si el país está seleccionado → mostrar como barra apilada
if (d.pais === seleccionada) {
const total = d.valor; // Valor total
const h = d.hombres;
const m = d.mujeres;

const yH = y(h); // Y del tope del segmento hombres
const yM = y(h + m); // Y del tope del segmento mujeres
const heightH = y(0) - yH; // Altura de hombres
const heightM = y(0) - y(m); // Altura de mujeres

// Rectángulo inferior: hombres
g.append("rect")
.attr("class", "apilada")
.attr("y", yH)
.attr("width", barWidth)
.attr("height", heightH)
.attr("fill", "#f1a1bc") // Rosa suave
.on("click", () => manejarClick(d)); // Permite deselección con clic

// Porcentaje centrado para hombres
g.append("text")
.attr("x", barWidth / 2)
.attr("y", yH + heightH / 2)
.attr("text-anchor", "middle")
.attr("dominant-baseline", "middle")
.style("font-size", "12px")
.style("fill", "black")
.style("font-family", '-apple-system, BlinkMacSystemFont, "Segoe UI", Arial, sans-serif')
.style("font-weight", "bold") // Negrita
.text(Math.round((h / total) * 100) + "%");

// Rectángulo superior: mujeres
g.append("rect")
.attr("class", "apilada")
.attr("y", yM)
.attr("width", barWidth)
.attr("height", heightM)
.attr("fill", "#7bbfa7") // Verde azulado
.on("click", () => manejarClick(d));

// Porcentaje centrado para mujeres
g.append("text")
.attr("x", barWidth / 2)
.attr("y", yM + heightM / 2)
.attr("text-anchor", "middle")
.attr("dominant-baseline", "middle")
.style("font-size", "12px")
.style("fill", "black")
.style("font-family", '-apple-system, BlinkMacSystemFont, "Segoe UI", Arial, sans-serif')
.style("font-weight", "bold") // Negrita
.text(Math.round((m / total) * 100) + "%");

// Si el país no está seleccionado → mostrar barra simple
} else {
g.append("rect")
.attr("class", "barra")
.attr("y", y(d.valor))
.attr("width", barWidth)
.attr("height", y(0) - y(d.valor))
.attr("fill", "steelblue")
// Hover interacciones (solo si no está seleccionada)
.on("mouseover", function() {
if (seleccionada !== d.pais)
d3.select(this).attr("fill", "orange");
})
.on("mouseout", function() {
if (seleccionada !== d.pais)
d3.select(this).attr("fill", "steelblue");
})
.on("click", () => manejarClick(d)); // Clic para seleccionar
}
});
}

// Función que gestiona el clic en una barra (selección/deselección)
function manejarClick(d) {
if (seleccionada === d.pais) {
seleccionada = null; // Si estaba seleccionada → deseleccionamos
} else {
seleccionada = d.pais; // Si no → seleccionamos
}
render(data, seleccionada); // Siempre redibujamos el gráfico luego de un click
}

// Primer renderizado
render(data, seleccionada);

// Devolvemos el nodo SVG para visualizar
return svg.node();
}

Insert cell
Insert cell
Insert cell
Insert cell
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