Published
Edited
Sep 6, 2022
Insert cell
Insert cell
Insert cell
chart = {
const chart = new G2.Chart({
width,
height: 1200
});
const xy = (node) => node.encode("x", "State").encode("y", "Change");
const formatter = d3.format(metric === "absolute" ? "+,d" : "+.1%");

chart.coordinate({ type: "transpose" }).data(states);

chart
.interval()
.transform({
type: "connector",
callback: (data) =>
data.map((d) =>
Object.assign(d, {
Change:
metric === "absolute" ? d[2019] - d[2010] : d[2019] / d[2010] - 1
})
)
})
.transform({ type: "sortBy", fields: ["Change"] })
.scale("y", {
tickCount: 15,
nice: true,
field: "",
guide: {
position: "top",
formatter,
label: { style: { fontSize: 10, fill: "black" } }
}
})
.scale("color", {
guide: null,
range: [d3.schemeRdBu[3][0], d3.schemeRdBu[3][2]]
})
.scale("x", { guide: null })
.call(xy)
.encode("color", (d) => d.Change < 0);

chart.annotationLineY().data([0]).encode("y", 0).style("stroke", "black");

chart
.text()
.call(xy)
.encode("text", (d) => (d.Change < -0 ? "" : formatter(d.Change)))
.style("fontSize", 10)
.style("fill", "black")
.style("dy", 5)
.style("dx", 5);

chart
.text()
.encode("x", "State")
.encode("y", 0)
.encode("text", "State")
.style("fill", "black")
.style("fontSize", 10)
.style("textAnchor", "end")
.style("dy", 5)
.style("dx", -5);

chart
.text()
.data([0])
.scale("x", { type: "identity", independent: true })
.encode("x", 0)
.encode("y", 0)
.encode("text", "← decrease · Change in population · increase →")
.style("fill", "black")
.style("fontSize", 10)
.style("textAnchor", "middle")
.style("dy", -30);

chart.render();

return node(chart);
}
Insert cell
Inputs.table(states)
Insert cell
Insert cell
Insert cell
Insert cell
{
const formatter = metric === "absolute" ? "+,d" : "+.1%";
const xy = { x: "State", y: "Change" };
const options = {
width,
coordinates: [{ type: "transpose" }],
data: {
value: states,
transform: [
{
type: "derive",
Change: (d) =>
metric === "absolute" ? d[2019] - d[2010] : d[2019] / d[2010] - 1
}
]
},
children: [
{
type: "interval",
scale: {
color: {
type: "divergingOrdinal",
range: d3.schemeRdBu[3],
display: false
},
y: {
tickCount: 15,
title: false,
nice: true,
position: "top",
formatter
},
x: { display: false }
},
transform: [{ type: "sortX", channel: "y" }],
encode: { ...xy, color: "Change" }
},
{ type: "lineY", data: [0] },
{
type: "text",
encode: {
...xy,
text: { value: "Change", formatter },
textAnchor: (d) => (d.Change < 0 ? "end" : "start"),
dx: (d) => (d.Change < 0 ? 5 : -5)
}
},
{
type: "text",
encode: {
...xy,
y: 0,
text: "State",
textAnchor: (d) => (d.Change < 0 ? "start" : "end"),
dx: (d) => (d.Change < 0 ? -5 : 5)
}
},
{
type: "text",
data: [0, 0, "← decrease · Change in population · increase →"],
scale: { x: { type: "identity" } },
style: { textAnchor: "middle", dy: -30 }
}
]
};
return md`A better description...`;
}
Insert cell
{
const formatter = metric === "absolute" ? "+,d" : "+.1%";
const options = {
type: "interval",
data: {
value: states,
transform: [
{
type: "derive",
Change: (d) =>
metric === "absolute" ? d[2019] - d[2010] : d[2019] / d[2010] - 1
}
]
},
facets: [
{
type: "symmetry",
encode: { x: (d) => d.Change < 0 },
title: "← decrease · Change in population · increase →"
}
],
transform: [{ type: "sortX", channel: "y" }],
coordinates: [{ type: "transpose" }],
scale: {
color: {
type: "divergingOrdinal",
range: d3.schemeRdBu[3],
display: false
},
y: {
tickCount: 15,
title: false,
nice: true,
position: "top",
formatter
}
},
encode: {
x: "State",
y: (d) => Math.abs(d.Change),
text: { value: "Change", formatter }
}
};
return md`Maybe the best description?`;
}
Insert cell
Insert cell
// D3
DivergingBarChart(states, {
x:
metric === "absolute"
? (d) => d[2019] - d[2010]
: (d) => d[2019] / d[2010] - 1,
y: (d) => d.State,
yDomain: d3.groupSort(
states,
([d]) => d[2019] - d[2010],
(d) => d.State
),
xFormat: metric === "absolute" ? "+,d" : "+%",
xLabel: "← decrease · Change in population · increase →",
width,
marginRight: 70,
marginLeft: 70,
colors: d3.schemeRdBu[3]
})
Insert cell
Plot.plot({
width,
x: {
tickFormat: "+%"
},
marginLeft: 100,
color: {
range: [d3.schemeRdBu[3][2], d3.schemeRdBu[3][0]]
},
marks: [
Plot.barX(states, {
x: (d) => d[2019] / d[2010] - 1,
y: "State",
fill: (d) => d[2019] < d[2010],
sort: { y: "x" }
})
]
})
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