Public
Edited
Nov 20, 2022
Fork of Cereal Data
Insert cell
Insert cell
// The purpose of this project is to display an animated bar chart of various cereals and how much of a certain attribute
// is in it, such as Protein, or Sugars. The animated portion occurs whenever a user clicks on a different option in the pop up menu
Insert cell
a1-cereals.csv
Type Table, then Shift-Enter. Ctrl-space for more options.

Insert cell
alphabet = [..."ABCDEFGHIJKLMNOPQRSTUVWXYZ"]
Insert cell
chart1 = {
const svg = d3.create("svg")
.attr("viewBox", [0, 0, width, 33])
.attr("font-family", "sans-serif")
.attr("font-size", 10)
.style("display", "block");

svg.selectAll("text")
.data(alphabet)
.join("text")
.attr("x", (d, i) => i * 17)
.attr("y", 17)
.attr("dy", "0.35em")
.text(d => d);

return svg.node();
}
Insert cell
htl.html`<svg viewBox="0 0 ${width} 33" font-family="sans-serif" font-size="10" style="display: block;">
${alphabet.map((d, i) => htl.svg`<text x="${i * 17}" y="17" dy="0.35em">${d}</text>`)}
</svg>`
Insert cell
randomLetters = {
while (true) {
yield d3.shuffle(alphabet.slice())
.slice(Math.floor(Math.random() * 10) + 5)
.sort(d3.ascending);
await Promises.delay(3000);
}
}
Insert cell
chart2 = {
const svg = d3.create("svg")
.attr("viewBox", [0, 0, width, 33])
.attr("font-family", "sans-serif")
.attr("font-size", 10)
.style("display", "block");

let text = svg.selectAll("text");

return Object.assign(svg.node(), {
update(letters) {
text = text
.data(letters)
.join("text")
.attr("x", (d, i) => i * 17)
.attr("y", 17)
.attr("dy", "0.35em")
.text(d => d);
}
});
}
Insert cell
chart2.update(randomLetters)
Insert cell
chart3 = {
const svg = d3.create("svg")
.attr("viewBox", [0, 0, width, 33])
.attr("font-family", "sans-serif")
.attr("font-size", 10)
.style("display", "block");

let text = svg.selectAll("text");

return Object.assign(svg.node(), {
update(letters) {
text = text
.data(letters, d => d)
.join(
enter => enter.append("text")
.attr("y", 17)
.attr("dy", "0.35em")
.text(d => d),
update => update,
exit => exit.remove()
)
.attr("x", (d, i) => i * 17);
}
});
}
Insert cell
chart3.update(randomLetters)
Insert cell
chart4 = {
const svg = d3.create("svg")
.attr("viewBox", [0, 0, width, 33])
.attr("font-family", "sans-serif")
.attr("font-size", 10)
.style("display", "block");

let text = svg.selectAll("text");

return Object.assign(svg.node(), {
update(letters) {
const t = svg.transition().duration(750);

text = text
.data(letters, d => d)
.join(
enter => enter.append("text")
.attr("y", -7)
.attr("dy", "0.35em")
.attr("x", (d, i) => i * 17)
.text(d => d),
update => update,
exit => exit
.call(text => text.transition(t).remove()
.attr("y", 41))
)
.call(text => text.transition(t)
.attr("y", 17)
.attr("x", (d, i) => i * 17));
}
});
}
Insert cell
chart4.update(randomLetters)
Insert cell
cdata = FileAttachment("a1-cereals.csv").csv({typed: true})
Insert cell
viewof nutdata0 =
Inputs.select(new Map(
[["Protein", { name: "Protein", data: [...cdata].sort((a, b) => d3.descending(a.Protein, b.Protein))}],
["Fat", { name: "Fat", data: [...cdata].sort((a, b) => d3.descending(a.Fat, b.Fat))}],
["Fiber", { name: "Fiber", data: [...cdata].sort((a, b) => d3.descending(a.Fiber, b.Fiber))}],
["Sugars", { name: "Sugars", data: [...cdata].sort((a, b) => d3.descending(a.Sugars, b.Sugars))}]]), {label: "Nutrition fact"});
Insert cell
chart = {
const svg = d3.create("svg")
.attr("viewBox", [0, 0, width, height]);

// For the initial render, reference the current age non-reactively.
const nutdata1 = viewof nutdata0.value.data;
const nutname1 = viewof nutdata0.value.name;

const x = d3.scaleLinear()
.domain([0, 20])
.rangeRound([margin.left, width - margin.right]);

const y = d3.scaleBand()
.domain(nutdata1.map(d => d.Cereal))
.rangeRound([margin.top, margin.top + 20 * cdata.length]);

let bar = svg.append("g")
.attr("fill", "steelblue")
.selectAll("rect")
.data(nutdata1, d => d.Cereal)
.join("rect")
.style("mix-blend-mode", "multiply")
.attr("x", x(0))
.attr("y", d => y(d.Cereal))
.attr("width", d => x(d[nutname1]) - x(0))
.attr("height", y.bandwidth() - 1);

const gx = svg.append("g")
.call(xAxis, x);

const gy = svg.append("g")
.call(yAxis, y);

return Object.assign(svg.node(), {
update(nutdata4) {
const t = svg.transition().duration(750);
const nutdata3 = viewof nutdata0.value.data;
const nutname3 = viewof nutdata0.value.name;

gx.transition(t)
.call(xAxis, x.domain([0, 20]));

gy.transition(t)
.call(yAxis, y.domain(nutdata3.map(d => d.Cereal)));

bar = bar
.data(nutdata3, d => d.Cereal)
.call(bar => bar.transition(t)
.attr("width", d => x(d[nutname3]) - x(0))
.attr("y", d => y(d.Cereal)));
}
});
}
Insert cell
chart.update(nutdata0)
Insert cell
xAxis = (g, x) => g
.attr("transform", `translate(0,${margin.top})`)
.call(d3.axisTop(x).ticks(width / 80))
.call(g => (g.selection ? g.selection() : g).select(".domain").remove())
Insert cell
yAxis = (g, y) => g
.attr("transform", `translate(${margin.left},0)`)
.call(d3.axisLeft(y).tickSizeOuter(0))
Insert cell
height = margin.top + 20 * 10
Insert cell
margin = ({top: 30, right: 20, bottom: 0, left: 150})
Insert cell

One platform to build and deploy the best data apps

Experiment and prototype by building visualizations in live JavaScript notebooks. Collaborate with your team and decide which concepts to build out.
Use Observable Framework to build data apps locally. Use data loaders to build in any language or library, including Python, SQL, and R.
Seamlessly deploy to Observable. Test before you ship, use automatic deploy-on-commit, and ensure your projects are always up-to-date.
Learn more