Public
Edited
May 8
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
viewof color_steps = slider({
min: 2,
max: 10,
step: 1,
value: 10,
title: "Cantidad de colores",
description: "Control para la cantidad de colores a visualizar en la paleta."
})
Insert cell
// Ejemplo, se pueden definir colores mediante HEX, nombre, HSL, RGB/RGBA
swatches(["#ff3399", "hotpink", "hsl(330, 100%, 70.5%)", "rgba(128, 0, 128, 0.2)"])
Insert cell
{
const boxSize = 30;
const spacing = 16;
const padding = 4;
const fontSize = 14;

const palettes = [];

// Paleta 1
const baseColors = ["#ff5c5c", "#ffcc4d", "#94d82d", "#339af0", "#6f42c1", "#ff9f1c", "#2ec4b6", "#e71d36", "#011627", "#bcb8b1"];
palettes.push({
label: "Paleta 1",
colors: baseColors.slice(0, color_steps)
});

// Paleta 2
const redInterpolator = d3.scaleLinear()
.domain([0, 0.5, 1])
.range(["#000000", "#ff0000", "#ffcc66"])
.interpolate(d3.interpolateRgb);
palettes.push({
label: "Paleta 2",
colors: d3.quantize(redInterpolator, Math.max(2, color_steps))
});

// Paleta 3
palettes.push({
label: "Paleta 3:",
colors: d3.quantize(d3.interpolateRgb("#f5d5c0", "#5e3c2a"), Math.max(2, color_steps))
});

// Paleta 4
palettes.push({
label: "Paleta 4",
colors: d3.quantize(d3.interpolateBlues, Math.max(2, color_steps)).reverse()
});

const svgWidth = boxSize * 30;
const svgHeight = palettes.length * (boxSize + fontSize + spacing);

const svg = d3.create("svg")
.attr("width", svgWidth)
.attr("height", svgHeight)
.style("font-family", "sans-serif");

palettes.forEach((p, row) => {
const y = row * (boxSize + fontSize + spacing);

svg.append("text")
.attr("x", 0)
.attr("y", y + fontSize - 2)
.attr("font-size", fontSize)
.text(p.label);

svg.selectAll(null)
.data(p.colors)
.join("rect")
.attr("x", (d, i) => i * boxSize)
.attr("y", y + fontSize + 2)
.attr("width", boxSize - padding)
.attr("height", boxSize)
.attr("fill", d => d);
});

return svg.node();
}

Insert cell
Insert cell
viewof lum_steps = slider({
min: 0,
max: 100,
step: 1,
value: 10,
title: "Luminosidad",
description: "Control para la luminosidad del color."
})
Insert cell
{
const boxSize = 30;
const fontSize = 14;
const padding = 4;

const baseBlue = d3.quantize(d3.interpolateBlues, Math.max(2, color_steps)).reverse();

function adjustLuminosity(c, l) {
const color = d3.color(c);
const f = Math.abs(l - 50) / 25;
return l > 50 ? color.brighter(f).formatHex() : color.darker(f).formatHex();
}

const adjusted = baseBlue.map(c => adjustLuminosity(c, lum_steps));

const svg = d3.create("svg")
.attr("width", boxSize * adjusted.length)
.attr("height", boxSize + fontSize + 8)
.style("font-family", "sans-serif");

svg.append("text")
.attr("x", 0)
.attr("y", fontSize)
.attr("font-size", fontSize)
.text(`Paleta azul ajustada (Luminosidad = ${lum_steps})`);

svg.selectAll("rect")
.data(adjusted)
.join("rect")
.attr("x", (d, i) => i * boxSize)
.attr("y", fontSize + 4)
.attr("width", boxSize - padding)
.attr("height", boxSize)
.attr("fill", d => d);

return svg.node();
}

Insert cell
Insert cell
// Resolución ejercicio c)
iris = d3.csv("https://raw.githubusercontent.com/holtzy/D3-graph-gallery/master/DATA/iris.csv", d => ({
longitud_sepalo: +d.Sepal_Length,
longitud_petalo: +d.Petal_Length,
especie: d.Species,
area_petalo: (+d.Petal_Length * +d.Petal_Width) / 2
}))
Insert cell
Insert cell
// Resolución ejercicio d)
x = d3.scaleLinear()
.domain(d3.extent(iris, d => d.longitud_sepalo))
.range([0, 350])
Insert cell
y = d3.scaleLinear()
.domain(d3.extent(iris, d => d.longitud_petalo))
.range([350, 0])
Insert cell
Insert cell
{
const width = 350;
const height = 350;
const margin = { top: 20, right: 20, bottom: 50, left: 60 };

const color = d3.scaleOrdinal()
.domain([...new Set(iris.map(d => d.especie))])
.range(d3.schemeSet1);

const svg = d3.create("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.style("font-family", "sans-serif");

const plot = svg.append("g")
.attr("transform", `translate(${margin.left},${margin.top})`);

// Eje X
plot.append("g")
.attr("transform", `translate(0,${height})`)
.call(d3.axisBottom(x));

// Etiqueta del eje X
plot.append("text")
.attr("x", width / 2)
.attr("y", height + 35)
.attr("text-anchor", "middle")
.attr("font-size", 12)
.text("Longitud del sépalo");

// Eje Y
plot.append("g")
.call(d3.axisLeft(y));

// Etiqueta del eje Y
plot.append("text")
.attr("transform", "rotate(-90)")
.attr("x", -height / 2)
.attr("y", -45)
.attr("text-anchor", "middle")
.attr("font-size", 12)
.text("Longitud del pétalo");

// Puntos
plot.selectAll("circle")
.data(iris)
.join("circle")
.attr("cx", d => x(d.longitud_sepalo))
.attr("cy", d => y(d.longitud_petalo))
.attr("r", 4)
.attr("fill", d => color(d.especie))
.attr("opacity", 0.8);

return svg.node();
}

Insert cell
Insert cell
Insert cell
{
const width = 420;
const height = 350;
const margin = { top: 20, right: 50, bottom: 40, left: 60 }; // ¡más espacio a la derecha!

const color = d3.scaleSequential(d3.interpolateReds)
.domain(d3.extent(iris, d => d.area_petalo));

const radius = d3.scaleLinear()
.domain(d3.extent(iris, d => d.area_petalo))
.range([3, 10]);

const svg = d3.create("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.style("font-family", "sans-serif");

const plot = svg.append("g")
.attr("transform", `translate(${margin.left},${margin.top})`);

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

plot.append("g")
.call(d3.axisLeft(y));

// Etiquetas de ejes
plot.append("text")
.attr("x", width / 2)
.attr("y", height + 35)
.attr("text-anchor", "middle")
.attr("font-size", 12)
.text("Longitud del sépalo");

plot.append("text")
.attr("transform", "rotate(-90)")
.attr("x", -height / 2)
.attr("y", -45)
.attr("text-anchor", "middle")
.attr("font-size", 12)
.text("Longitud del pétalo");

// Puntos
plot.selectAll("circle")
.data(iris)
.join("circle")
.attr("cx", d => x(d.longitud_sepalo))
.attr("cy", d => y(d.longitud_petalo))
.attr("r", d => radius(d.area_petalo))
.attr("fill", d => color(d.area_petalo))
.attr("opacity", 0.8);

// === Leyenda vertical de color ===
const legendHeight = 200;
const legendWidth = 10;
const legendX = width + 40; // desplazado más lejos
const legendY = (height - legendHeight) / 2;

const defs = svg.append("defs");
const gradient = defs.append("linearGradient")
.attr("id", "legend-gradient-vertical")
.attr("x1", "0%").attr("x2", "0%")
.attr("y1", "100%").attr("y2", "0%");

gradient.selectAll("stop")
.data(d3.ticks(0, 1, 10))
.join("stop")
.attr("offset", d => `${d * 100}%`)
.attr("stop-color", d => color(
color.domain()[0] + d * (color.domain()[1] - color.domain()[0])
));

svg.append("rect")
.attr("x", legendX)
.attr("y", legendY)
.attr("width", legendWidth)
.attr("height", legendHeight)
.attr("fill", "url(#legend-gradient-vertical)");

svg.append("g")
.attr("transform", `translate(${legendX + legendWidth},${legendY})`)
.call(d3.axisRight(d3.scaleLinear()
.domain(color.domain())
.range([legendHeight, 0]))
.ticks(6)
.tickFormat(d3.format(".1f")));

svg.append("text")
.attr("x", legendX + 20)
.attr("y", legendY - 8)
.attr("text-anchor", "middle")
.attr("font-size", 12)
.text("Área del pétalo");

return svg.node();
}

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