Public
Edited
Sep 29, 2023
57 forks
11 stars
Insert cell
Insert cell
Insert cell
Insert cell
alphabet = [..."ABCDEFGHIJKLMNOPQRSTUVWXYZ"]
Insert cell
{
let data = d3
.shuffle(alphabet.slice())
.slice(Math.floor(Math.random() * 10) + 5)
.sort(d3.ascending);

const width = 500;
const height = 50;
const margin = { top: 10, bottom: 10, left: 50, right: 10 };

const svg = d3
.create("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom);

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

const yScale = d3
.scalePoint()
.domain(["enter", "update", "exit"])
.range([0, height]);

const xScale = d3.scalePoint().domain(alphabet).range([10, width]);

g.append("g").call(d3.axisLeft(yScale));

while (true) {
yield svg.node();
// yield data;

// Selection
const textSelection = g.selectAll(".letter").data(data, (d) => d);

// Enter
textSelection
.enter()
.append("text")
.attr("class", "letter")
.attr("y", yScale("enter") + 5)
.attr("x", (d) => xScale(d))
.style("font", "14px sans-serif")
.style("fill", "green")
.text((d) => d);

// Update
textSelection
.transition()
.duration(1000)
.attr("y", yScale("update") + 5)
.style("fill", "#000");

// Exit
textSelection
.exit()
.transition()
.duration(1000)
.style("fill", "red")
.attr("y", yScale("exit") + 5)
.transition()
.duration(1000)
.style("opacity", 0)
.remove();

await Promises.delay(3000);
data = d3
.shuffle(alphabet.slice())
.slice(Math.floor(Math.random() * 10) + 5)
.sort(d3.ascending);
}
}
Insert cell
Insert cell
Insert cell
{
let data = d3
.shuffle(alphabet.slice())
.slice(Math.floor(Math.random() * 10) + 5)
.sort(d3.ascending);

const width = 500;
const height = 50;
const margin = { top: 10, bottom: 10, left: 50, right: 10 };

const svg = d3
.create("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom);

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

const yScale = d3
.scalePoint()
.domain(["enter", "update", "exit"])
.range([0, height]);

const xScale = d3.scalePoint().domain(alphabet).range([10, width]);

g.append("g").call(d3.axisLeft(yScale));

while (true) {
yield svg.node();
// yield data

g.selectAll(".letter")
.data(data, (d) => d)
.join(
(enter) =>
enter
.append("text")
.attr("fill", "green")
.attr("class", "letter")
.attr("x", (d) => xScale(d))
.attr("y", yScale("enter") + 5)
.style("font", "14px sans-serif")
.text((d) => d),
(update) =>
update
.attr("fill", "black")
.call((update) =>
update.transition().attr("y", yScale("update") + 5)
),
(exit) =>
exit.attr("fill", "red").call((exit) =>
exit
.transition()
.attr("y", yScale("exit") + 5)
.transition()
.remove()
)
); // Anything we add after our join will apply to the enter + update elements that remain

// If we don't care about handling enter + update differently, and we just want to remove our exited elements, You can do it all this way.
// g.selectAll(".letter")
// .data(data, (d) => d)
// .join("text")
// .attr("class", "letter")
// .attr("y", yScale("enter") + 5)
// .attr("x", (d) => xScale(d))
// .style("font", "14px sans-serif")
// .text((d) => d);

await Promises.delay(3000);
data = d3
.shuffle(alphabet.slice())
.slice(Math.floor(Math.random() * 10) + 5)
.sort(d3.ascending);
}
}
Insert cell
Insert cell
Insert cell
{
const width = 500;
const height = 200;
const r = 25;

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

const x = d3
.scalePoint()
.domain([0, 1, 2, 3, 4])
.range([0, width])
.padding(0.5);

svg
.selectAll("circle")
.data(d3.range(5).map(Object))
.join("circle")
.attr("cx", (_, i) => x(i))
.attr("cy", height / 2)
.attr("r", r)
.transition()
.duration(6000)
.delay((d) => d * 750)
.ease(d3.easeElastic)
.attr("cx", width - r);

return svg.node();
}
Insert cell
Insert cell
Insert cell
iris
Insert cell
d3.groups(iris, (d) => d.species)
Insert cell
{
const width = 600;
const height = 400;
const margin = { top: 20, bottom: 20, left: 50, right: 50 };

const div = htl.html`<div></div>`;

const categories = d3.groups(iris, (d) => d.species);

const buttons = d3
.select(div)
.selectAll("button")
.data(categories)
.join("button");

buttons.text((d) => d[0]);

const svg = d3
.select(div)
.append("div")
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom);

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

const x = d3
.scaleLinear()
.domain(d3.extent(iris, (d) => d["sepalLength"]))
.range([0, width]);

const y = d3
.scaleLinear()
.domain(d3.extent(iris, (d) => d["sepalWidth"]))
.range([height, 0]);

const color = d3
.scaleOrdinal()
.domain(categories.map((d) => d[0]))
.range(d3.schemeDark2);

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

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

const circles = g
.selectAll("circle")
.data(iris.filter((d) => d.species == "setosa"))
.join("circle")
.attr("r", 4)
.style("stroke", "#000")
.attr("cx", (d) => x(d.sepalLength))
.attr("cy", (d) => y(d.sepalWidth))
.style("fill", (d) => color(d.species));

buttons.on("click", (event, d) => {
g.selectAll("circle")
.data(d[1], (d) => d)
.join(
(enter) =>
enter
.append("circle")
.attr("r", 4)
.style("stroke", "#000")
.attr("cx", (d) => x(d.sepalLength))
.attr("cy", (d) => y(d.sepalWidth))
.style("fill", (d) => color(d.species)),
(update) =>
update
.attr("cx", (d) => x(d.sepalLength))
.attr("cy", (d) => y(d.sepalWidth))
.style("fill", (d) => color(d.species)),
(exit) =>
exit
.attr("fill", "red")
.call((exit) =>
exit.transition().duration(2000).attr("r", 0).remove()
)
);
});

return div;
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
iris.csv
Type Table, then Shift-Enter. Ctrl-space for more options.

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