Published
Edited
May 27, 2021
6 stars
Insert cell
Insert cell
rawdata = FileAttachment("pypl.csv").csv({typed: true})
Insert cell
Insert cell
Plot.areaY(rawdata, Plot.stackY({
x: "date",
y: "value",
fill: "name",
})).plot({ width })
Insert cell
Insert cell
top10 = d3.groupSort(rawdata,
// v is an array of data elements for each group
v => {
if(order == "maximum value")
return -d3.max(v, d => d.value) // get the maximum value, negative makes it descending
if(order == "last value")
return -v[v.length - 1].value // get the last value for each group in descending order
},
// group by the name of the programming language
d => d.name)
.slice(0, 10)
Insert cell
Insert cell
{
let select = order === "maximum value" ? Plot.selectMaxX : Plot.selectLast
return Plot.barX(data, Plot.groupY({x: "max"}, select({
x: "value",
y: "name",
fill: "name"
}))).plot({
color: { domain: top10 },
y: { domain: top10 },
marginLeft: 80
})
}
Insert cell
Insert cell
data = rawdata.filter(d => top10.indexOf(d.name) >= 0)
Insert cell
Plot.areaY(data, Plot.stackY({
x: "date",
y: "value",
fill: "name",
order: "appearance",
offset: "expand"
}))
.plot({
marks: [
// let's add the text labels to the end of the plot
Plot.text(data, Plot.selectLast(Plot.stackY({
x: "date",
y: "value",
z: "name",
order: "appearance",
offset: "expand",
fill: "name",
text: "name",
textAnchor: "start", dx: 2, dy: 3
})))
],
y: { percent: true },
color: { domain: top10 },
marginRight: 60,
width
})
Insert cell
Insert cell
Insert cell
// Quarterly average
Plot.areaY(data, Plot.stackY(Plot.binX({y: "mean"}, {
x: "date",
y: "value",
fill: "name",
thresholds: d3.utcMonth.every(months),
order: "value",
curve: "catmull-rom",
}))).plot({
marks: [
Plot.text(data, Plot.selectLast(Plot.stackY({
x: "date",
y: "value",
z: "name",
order: "value",
offset: "expand",
fill: "name",
text: "name",
textAnchor: "start", dx: 3 + months, dy: 3
})))
],
y: { percent: true },
color: { domain: top10 },
width, marginRight: 60
})
Insert cell
Insert cell
Insert cell
Plot.plot({
marks: [
bumpMarks(data, {
x: "date",
z: "name",
stroke: "name",
order: d => d["value"],
strokeWidth: 5,
highlightStroke: 10,
r: 0,
reverse: true
})
],
x: { ticks: 14, tickSize: 0, label: null },
y: { axis: null, domain: [10.5, 1] },
color: { domain: top10 },
width,
marginTop: 20,
marginBottom: 35,
marginLeft: 75,
marginRight: 75,
grid: true,
})
Insert cell
Insert cell
Plot.plot({
marks: [
bumpMarks(data, {
x: "date",
z: "name",
stroke: "name",
order: d => d["value"],
strokeWidth: 2,
// highlightStroke: 10,
r: 2,
reverse: true
})
],
x: { ticks: 14, tickSize: 0, label: null },
y: { axis: null, domain: [10.5, 1] },
color: { domain: top10 },
width,
marginTop: 20,
marginBottom: 35,
marginLeft: 75,
marginRight: 75,
grid: true,
})
Insert cell
Insert cell
function bumpMarks(data, {r = 3, highlightStroke = 0, curve = "bump-x", ...options}) {
const stack = Plot.stackY2(options);
let marks = [
Plot.line(data, {...stack, stroke: stack.z, curve, fill: null}),
Plot.text(data, Plot.selectFirst({...stack, text: stack.z, dx: -(5 + r), textAnchor: "end", fill: "currentColor"})),
Plot.text(data, Plot.selectLast({...stack, text: stack.z, dx: (5 + r), textAnchor: "start", fill: "currentColor"})),
];
if(r) {
const stackSelection = Plot.map(
{x: series => series.map(date => date.getUTCMonth() === 0 ? date : null)},
stack
);
marks.push(Plot.dot(data, {...stackSelection, fill: stack.z, r}))
marks.push(Plot.text(data, {fill: stack.z, dy: -6, ...stackSelection, text: stack.y}))
}
if(highlightStroke) {
marks.push(keepZ(language, Plot.line(data, {...stack,
stroke: stack.z,
strokeWidth: highlightStroke,
curve,
fill: null
})))
}
return marks
}
Insert cell
// this is one way to hide the unselected lines. we just remove them from the DOM
keepZ = (language, mark) => {
const _render = mark.render;
mark.render = function(_, __, {z}) {
return d3.select(_render.apply(this, arguments))
.call(g => g.selectChildren().filter(([i]) => z[i] !== language).remove())
.node();
}
return mark;
}
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