Public
Edited
Apr 10
Insert cell
Insert cell
Insert cell
Insert cell
html`<svg width="100" height="100">
<circle cx="40" cy="60" r="20" style="fill:red;">
</circle>`
Insert cell
html`<svg width="110" height="110">
<polygon points="50,5 20,99 95,39 5,39 80,99" style="fill:blue;stroke:red;stroke-width:5;fill-rule:evenodd;" />
</circle>`
Insert cell
Insert cell
// tres círculos con el mismo centro, distinto tamaño. Se dibujan de mayor a menor según el radio para que los más chicos queden "arriba"
{
const svgContainer = d3.create("svg")
.attr("width", 256)
.attr("height", 256);

// Centro de los círculos
const centerXCoordinate = 128;
const centerYCoordinate = 128;

// Defino los radios a usar
const circleRadii = [105,70,35];

// Defindo los colores para cada radio
const circleColors = ["green", "purple", "red"];

// Agrego los círculos al contenedor
svgContainer.selectAll("circle")
.data(circleRadii)
.enter()
.append("circle")
.attr("cx", centerXCoordinate) //mismo centro para todos
.attr("cy", centerYCoordinate) //mismo centro para todos
.attr("r", d => d) // info de radios
.attr("fill", (d, index) => circleColors[index]); // info de colores

// 12. Return the root SVG node, which Observable will render in the notebook [8-13].
return svgContainer.node();
}
Insert cell
Insert cell
{
// parámetros de la grilla
// todos círculos iguales, dos gradientes de colores, izq a derecha, arriba a abajo, extremos negro, rojo, verde, amarillo
// el color de cada círculo depende de la posición x,y en la grilla
const width = 350;
const height = 350;
const cols = 17;
const rows = 17;
const radius = 10;
const padding = 5;

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

// Funcion que define el color según la posición x,y en la grilla
function getColor(xRatio, yRatio) {
// Define the start and end colors for the horizontal interpolation at the top and bottom.
const topStartColor = "black";
const topEndColor = "red";
const bottomStartColor = "green";
const bottomEndColor = "yellow";

// Defino la "posición" en el gradiente horizontal en funciuón de la posición horizontal en la grilla
const topColor = d3.interpolateRgb(topStartColor, topEndColor)(xRatio);
const bottomColor = d3.interpolateRgb(bottomStartColor, bottomEndColor)(xRatio);

// Luego determinar el color en base al gradiente horizontal, agrego el efecto del gradiente vertical en función de la posición y
return d3.interpolateRgb(topColor, bottomColor)(yRatio);
}

// Grilla. Cada ejecución del ciclo (cominado i, j) agrega un círculo a la grilla
for (let i = 0; i < cols; i++) {
for (let j = 0; j < rows; j++) {
// calculo los ratios x e y para poder usar la interpolación
const xRatio = i / (cols - 1);
const yRatio = j / (rows - 1);

// calculo la posición del centro del círculo i,j.
const cx = i * (radius * 2 + padding) + radius;
const cy = j * (radius * 2 + padding) + radius;

// Agrego el círculo al svg
svgContainer.append("circle")
.attr("cx", cx)
.attr("cy", cy)
.attr("r", radius)
.attr("fill", getColor(xRatio, yRatio)); // Set the fill color using the getColor function
}
}

// 5. Return the root SVG node.
return svgContainer.node();
}

Insert cell
Insert cell
// grilla de cícrculos rellenos negros cuyo diámetro depende de la distancia al centro

{
const width = 500;
const height = 500;
const cols = 17; // Número de columnas
const rows = 17; // Número de filas
const maxRadius = 12; // Tamaño máximo de los círculos

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

// Centro del patrón
const centerX = (cols - 1) / 2;
const centerY = (rows - 1) / 2;
const maxDist = Math.sqrt(centerX ** 2 + centerY ** 2); // Distancia máxima al centro

// Escala de tamaño ajustada para mayor cambio en radios (el incremento del radio no es lineal)
const radiusScale = d3.scalePow().exponent(4)
.domain([0, 1])
.range([maxRadius * 0.1, maxRadius]);

// Dibujar la cuadrícula
for (let i = 0; i < cols; i++) {
for (let j = 0; j < rows; j++) {
const dist = Math.sqrt((i - centerX) ** 2 + (j - centerY) ** 2) / maxDist; // Normalizar distancia
const radius = radiusScale(1 - dist); // Cambio más rápido en tamaño

svg.append("circle")
.attr("cx", i * (width / cols))
.attr("cy", j * (height / rows))
.attr("r", radius)
.attr("fill", "black");
}
}

return svg.node();
}


Insert cell
Insert cell
// Grilla de triángulos equiláteros
// Cada fila repite el patrón de un triángulo azul "para arriba"y uno rojo "para abajo"
// Luego se repiten las filas

{
const numRows = 17;
const numTrianglesPerRow = 32; // Triángulos totales por fila
const triangleWidth = 20; // Base del triángulo
const triangleHeight = Math.sqrt(3) / 2 * triangleWidth; // Altura del triángulo
const horizontalSpacing = -6; // Espaciado horizontal entre triángulos
const verticalSpacing = 5; // Espaciado vertical entre triángulos
const svgHeight = numRows * (triangleHeight + verticalSpacing) + 10; // Alto del SVG
const svgWidth = numTrianglesPerRow * (triangleWidth + horizontalSpacing) - horizontalSpacing - 15; // Ancho del SVG

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

const rowData = [...Array(numRows).keys()]; // creo un array con el número de fila (0 a 16)
const triangleData = [...Array(numTrianglesPerRow).keys()]; // creo un array con posición dentro de la fila (0 a 31)

//creo todos los triángulos y luego los traslado a su posición. para cada triángulo necesito las coordenadas x.y de cada vértice (es un polígono)
const triangleUpPoints = `0,${-triangleHeight / 2} ${triangleWidth / 2},${triangleHeight / 2} ${-triangleWidth / 2},${triangleHeight / 2}`; //
const triangleDownPoints = `0,${triangleHeight / 2} ${triangleWidth / 2},${-triangleHeight / 2} ${-triangleWidth / 2},${-triangleHeight / 2}`;
// a cada fila le agrego la cantidad de triángulos determinada, alternando entre un triangulo y otro.
rowData.forEach((rowIndex) => {
const row = svg.append("g")
.attr("transform", `translate(0, ${rowIndex * (triangleHeight + verticalSpacing) + 5})`);

row.selectAll("polygon")
.data(triangleData)
.enter()
.append("polygon")
.attr("points", (d) => d % 2 === 0 ? triangleUpPoints : triangleDownPoints)
.attr("transform", (d) => `translate(${d * (triangleWidth + horizontalSpacing) + triangleWidth / 2 - 7}, ${triangleHeight / 2})`)
.style("fill", (d) => d % 2 === 0 ? "yellow" : "white")
.style("stroke", (d) => d % 2 === 0 ? "blue" : "red")
.style("stroke-width", 2);
});

return svg.node();
}

Insert cell
Insert cell
// fila de hexágonos
// cada fila aumenta el espesor de la línea
// según si la fila es par o impar cambia la posición inicial
{
// Parámetros base
const cols = 7;
const rows = 7;
const radius = 25;
const hexHeight = radius * 2;
const hexWidth = Math.sqrt(3) * radius;
const vertSpacing = hexHeight - 5; // separación vertical
const horizSpacing = hexWidth + 7; // separación horizontal
const svgWidth = cols * horizSpacing + 50;
const svgHeight = rows * vertSpacing + 50;

// Crear el SVG
const svg = d3.create("svg")
.attr("width", svgWidth)
.attr("height", svgHeight);

// Generar la grilla
for (let row = 0; row < rows; row++) {
for (let col = 0; col < cols; col++) {
const x = col * horizSpacing + (row % 2 === 1 ? horizSpacing / 2 : 0) + 25; // la posición inicial de la fila depende de si la fila es par o impar
const y = row * vertSpacing + 25;

svg.append("polygon")
.attr("points", hexagon(x, y, radius)) // llamo a la función
.style("fill", "none")
.style("stroke", "black")
.style("stroke-width", 1 + row * 0.6); // grosor de línea aumenta con la fila
}
}

return svg.node();
}

Insert cell
// Función para generar hexágonos en x,y de radio r.
function hexagon(x, y, r) {
var x1 = x;
var y1 = y - r;
var x2 = x + Math.cos(Math.PI / 6) * r;
var y2 = y - Math.sin(Math.PI / 6) * r;
var x3 = x + Math.cos(Math.PI / 6) * r;
var y3 = y + Math.sin(Math.PI / 6) * r;
var x4 = x;
var y4 = y + r;
var x5 = x - Math.cos(Math.PI / 6) * r;
var y5 = y + Math.sin(Math.PI / 6) * r;
var x6 = x - Math.cos(Math.PI / 6) * r;
var y6 = y - Math.sin(Math.PI / 6) * r;

var path = x1 + ',' + y1 + " " + x2 + ',' + y2 + " " + x3 + ',' + y3 + " " + x4 + ',' + y4 + " " + x5 + ',' + y5 + " " + x6 + ',' + y6;
return path;
}
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