Public
Edited
May 16, 2024
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Bplot_data = wan_tc
.filter(aq.escape((d) => _.includes(["US", "CN"], d.isoalpha2)))
.filter(aq.escape((d) => _.includes(["seats_inner", "seats_in"], d.key)))
.derive({ value_reljan: (d) => d.value_reljan / 2 })
.join_left(countries)
Insert cell
Cplot_data = wan_tc
.filter(aq.escape((d) => "DE" === d.isoalpha2))
.filter(aq.escape((d) => _.includes(["seats_inner", "seats_in"], d.key)))
.derive({ value_reljan: (d) => d.value_reljan / 2 })
Insert cell
Dplot_data = wan_tc_germany
.filter((d) => d.key === "seats_in")
.filter((d) => d.isoalpha2 !== "DE")
.groupby("date")
.orderby(aq.desc("value"))
.slice(0, 5)
.derive({ date_label: aq.escape((d) => timeformat_long(d.date)) })
.join(countries)
Insert cell
linear_color = {
const colors = ["#490a3d", "#bd1550", "lightgrey"]; //["#490a3d", "#bd1550", "#e97f02"]
var domain = [1, 0.6, 0];
return d3.scaleLinear().domain(domain).range(colors);
}
Insert cell
function beeswarmY(
data,
{ gap = -4, ticks = 50, dynamic, direction, ...options }
) {
const dots = Plot.dot(data, options);
const { render } = dots;

dots.render = function () {
const g = render.apply(this, arguments);
const circles = d3.select(g).selectAll("circle");

const nodes = [];
const [cx, cy, x, y, forceX, forceY] = [
"cy",
"cx",
"y",
"x",
d3.forceY,
d3.forceX
];
for (const c of circles) {
const node = {
x: +c.getAttribute(cx),
y: +c.getAttribute(cy),
r: 10
};
nodes.push(node);
}
const force = d3
.forceSimulation(nodes)
.force("x", forceX((d) => d[x]).strength(0.8))
.force(
"collide",
d3
.forceCollide()
.radius((d) => d.r + gap)
.iterations(3)
)
.tick(ticks)
.stop();
update();
if (dynamic) force.on("tick", update).restart();
return g;

function update() {
circles.attr(cx, (_, i) => nodes[i].x).attr(cy, (_, i) => nodes[i].y);
}
};

return dots;
}
Insert cell
function beeswarmY_text(
data,
{ gap = -4, ticks = 50, dynamic, direction, ...options }
) {
const dots = Plot.text(data, options);
const { render } = dots;

dots.render = function () {
const g = render.apply(this, arguments);
const circles = d3.select(g).selectAll("text");

const nodes = [];
const [cx, cy, x, y, forceX, forceY] = [
"y",
"x",
"y",
"x",
d3.forceY,
d3.forceX
];
for (const c of circles) {
const node = {
x: +c.getAttribute(cx),
y: +c.getAttribute(cy),
r: 10
};
nodes.push(node);
}
const force = d3
.forceSimulation(nodes)
.force("x", forceX((d) => d[x]).strength(0.8))
.force(
"collide",
d3
.forceCollide()
.radius((d) => d.r + gap)
.iterations(3)
)
.tick(ticks)
.stop();
update();
if (dynamic) force.on("tick", update).restart();
return g;

function update() {
circles.attr(cx, (_, i) => nodes[i].x).attr(cy, (_, i) => nodes[i].y);
}
};

return dots;
}
Insert cell
<style>
.plot .tick line:nth-child(2) {
stroke-opacity: 1;
color: #E1E5E5;
}
.plot .tick {
color: #313131;
}
.plot .tick > line {
color: #666;
}
.plot text {
font-size: 13px;
}
</style>
Insert cell
timeformat_long = {
const isfirstofyear = (d) => (d.getDate() == 1) & (d.getMonth() == 0);
return (d) =>
isfirstofyear(d) ? d3.timeFormat("%b / %y")(d) : d3.timeFormat("%b")(d);
}
Insert cell
color_highlight = (text, color) => {
const { r, g, b } = d3.rgb(color);
let text_color;
if ((r * 299 + g * 587 + b * 114) / 1000 < 160) {
text_color = "White";
} else {
text_color = "#111";
}

return `<span style="background: ${color}; color: ${text_color}; padding: 1px 3px;
border-radius: 4px">${text}</span>`;
}
Insert cell
Insert cell
wan_tc.view(3)
Insert cell
wan_tc = {
let raw = await aq.loadArrow(
await FileAttachment("timecourse_countries_20211026@1.arrow").url()
);
raw = raw.derive({
date: (d) => op.parse_date(d.date),
seats_all: (d) => d.seats_in + d.seats_out + d.seats_inner
});

let df = raw.fold(["seats_inner", "seats_out", "seats_in", "seats_all"]);

df = df
.join_left(
df
.filter((d) => d.date < op.datetime(2020, 0, 2))
.derive({ value_base: (d) => d.value })
.select("isoalpha2", "key", "value_base")
)
.derive({
value_reljan: (d) => d.value / d.value_base
})
.select(aq.not(["value_base", "value_2019"]));

return df;
}
Insert cell
_.max(wan_tc_germany.columnArray("date"))
Insert cell
wan_tc_germany = {
let raw = await aq.loadArrow(
await FileAttachment("timecourse_germany_20211026@1.arrow").url()
);
raw = raw.derive({
date: (d) => op.parse_date(d.date)
});

let df = raw.fold(["seats_in"]);

df = df
.join_left(
df
.filter((d) => d.date < op.datetime(2020, 0, 2))
.derive({ value_base: (d) => d.value })
.select("isoalpha2", "key", "value_base")
)
.derive({
value_reljan: (d) => d.value / d.value_base
})
.select(aq.not(["value_base", "value_2019"]));

return df;
}
Insert cell
countries = aq.loadArrow(
await FileAttachment("isoalpha2countries_2021005.arrow").url()
)
Insert cell
world_shape = (
await FileAttachment("_world_countries_alpha2.json").json()
).features.filter((d) => d.id !== "5")
Insert cell
import { aq, op } from "@uwdata/arquero"
Insert cell
d3 = require("d3@6")
Insert cell
Plot = require("@observablehq/plot@0.2")
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