// Draw only: every point and label was computed in Python (login_chart).
{
const series = ["list", "set"];
const rows = login_chart.curves;
const picked = login_chart.picks[logins]; // the two dots for the chosen number of logins
return Plot.plot({
width: 860, height: 330, marginLeft: 80, marginRight: 60, marginBottom: 48,
style: {fontSize: "16px", background: "transparent"},
x: {type: "log", label: "number of logins →", labelAnchor: "center", grid: true, tickFormat: "~s",
ticks: [1, 10, 100, 1e3, 1e4, 1e5, 1e6, 1e7]},
y: {type: "log", label: "↑ total time (s)", grid: true, tickFormat: ",~g",
ticks: [0.1, 1, 10, 100, 1e3, 1e4, 1e5]},
color: {domain: series, range: ["#2a78d6", "#eb6834"], legend: true, swatchSize: 16},
marks: [
Plot.line(rows, {x: "logins", y: "seconds", stroke: "s", strokeWidth: 2}),
Plot.ruleX([logins], {stroke: "#52514e", strokeDasharray: "4 4"}),
Plot.dot(picked, {x: "logins", y: "seconds", fill: "s", r: 6, stroke: "white", strokeWidth: 2}),
// label the two dots: list label above its dot, set label below it (above it near the
// right edge, where below would hit the x-axis). dy is a constant, so one mark per series.
...[["list", -14], ["set", logins < 1e5 ? 14 : -14]].map(([s, dy]) =>
Plot.text(picked.filter(d => d.s === s), {x: "logins", y: "seconds", text: d => `${d.s}: ${d.label}`,
dx: logins < 1e5 ? 10 : -10, dy, textAnchor: logins < 1e5 ? "start" : "end", fontWeight: "bold"})),
Plot.tip(rows, Plot.pointer({x: "logins", y: "seconds",
title: d => `${d.s}\n${d3.format(",.0f")(d.logins)} logins\n${d.label}`}))
]
});
}