Published unlisted
Edited
May 26, 2022
1 star
Insert cell
Insert cell
chart = {
const w = 1280;
const h = 720;
let svg = d3.create("svg").attr("viewBox", `0 0 ${w} ${h}`);

const pad = {
top: 70,
bottom: 50,
left: 70,
right: 190
};

let [min_year, max_year] = d3.extent(src, (d) => d.Year);
const scaleX = d3
.scaleTime()
.range([pad.left, w - pad.right])
.domain([min_year, max_year]);
const scaleY = d3
.scaleLinear()
.range([h - pad.top, pad.bottom])
.domain(d3.extent(src, (d) => d.Value));

const line = d3
.line()
.defined((d) => d.Value)
.x((d) => scaleX(d.Year))
.y((d) => scaleY(d.Value));

svg
.append("g")
.append("path")
.attr("d", line(src))
.attr("stroke", "black")
.attr("fill", "none");
svg
.selectAll("circle")
.data(src.filter((d) => d.Value))
.join("circle")
.attr("cx", (d) => scaleX(d.Year))
.attr("cy", (d) => scaleY(d.Value))
.attr("r", (d, i) => (d.endpoint ? 5 : 3))
.attr("fill", (d) => (d.endpoint ? "white" : "black"))
.attr("stroke", "black");

svg
.append("g")
.attr("transform", `translate(0, ${h - pad.bottom})`)
.call(
d3.axisBottom(scaleX).tickSizeOuter(0).tickFormat(d3.timeFormat("%Y"))
);
svg
.append("g")
.attr("transform", `translate(${pad.left / 2}, 0)`)
.call(d3.axisLeft(scaleY).tickSizeOuter(0));

return svg.node();
}
Insert cell
src = {
let src = [
{
Region: "East Asia & Pacific",
Name: "Australia",
Year: 1997,
Value: 15.540540540540499
},
{
Region: "East Asia & Pacific",
Name: "Australia",
Year: 1998,
Value: 15.540540540540499
},
{
Region: "East Asia & Pacific",
Name: "Australia",
Year: 1999,
Value: 22.4489795918367
},
{
Region: "East Asia & Pacific",
Name: "Australia",
Year: 2003,
Value: 25.3333333333333
},
{
Region: "East Asia & Pacific",
Name: "Australia",
Year: 2004,
Value: 24.6666666666667
},
{
Region: "East Asia & Pacific",
Name: "Australia",
Year: 2005,
Value: 24.6666666666667
},
{
Region: "East Asia & Pacific",
Name: "Australia",
Year: 2006,
Value: 24.6666666666667
},
{
Region: "East Asia & Pacific",
Name: "Australia",
Year: 2007,
Value: 26.6666666666667
},
{
Region: "East Asia & Pacific",
Name: "Australia",
Year: 2009,
Value: 27.3333333333333
},
{
Region: "East Asia & Pacific",
Name: "Australia",
Year: 2010,
Value: 24.6666666666667
},
{
Region: "East Asia & Pacific",
Name: "Australia",
Year: 2011,
Value: 24.6666666666667
},
{
Region: "East Asia & Pacific",
Name: "Australia",
Year: 2012,
Value: 24.6666666666667
},
{
Region: "East Asia & Pacific",
Name: "Australia",
Year: 2013,
Value: 26
},
{
Region: "East Asia & Pacific",
Name: "Australia",
Year: 2014,
Value: 26
},
{
Region: "East Asia & Pacific",
Name: "Australia",
Year: 2015,
Value: 26.6666666666667
},
{
Region: "East Asia & Pacific",
Name: "Australia",
Year: 2016,
Value: 28.6666666666667
},
{
Region: "East Asia & Pacific",
Name: "Australia",
Year: 2017,
Value: 28.6666666666667
},
{
Region: "East Asia & Pacific",
Name: "Australia",
Year: 2018,
Value: 28.6666666666667
},
{
Region: "East Asia & Pacific",
Name: "Australia",
Year: 2019,
Value: 30.463576158940398
},
{
Region: "East Asia & Pacific",
Name: "Australia",
Year: 2020,
Value: 30.463576158940398
},
{
Region: "East Asia & Pacific",
Name: "Australia",
Year: 2021,
Value: 31.125827814569501
}
].map(function (o, i) {
o.idx = i;
return o;
});

// Figure out the range of years.
let [min_year, max_year] = d3.extent(src, (d) => d.Year);
let years = d3.range(min_year, max_year + 1);

// Set up a Map to efficiently access the data by year
let data_map = d3.group(src, (o) => o.Year);

// Now, we'll iterate over the full range of years.
// When we find that a year is missing, we'll insert
// a simple object for that year with a null value.
// While we're at it, we'll parse the years to dates
// so we can add a proper time-scaled axis.
// We'll also mark any points adjacent to missing
// data as endpoints.
src = years.map(function (y) {
let d = data_map.get(y);
if (typeof d !== "undefined") {
d = d[0];
d.Year = d3.utcParse("%Y")(y);
return d;
} else {
let dm1 = data_map.get(y - 1);
if (dm1) {
dm1[0].endpoint = true;
}
let dp1 = data_map.get(y + 1);
if (dp1) {
dp1[0].endpoint = true;
}
return { Year: d3.utcParse("%Y")(y), Value: null };
}
});

return src;
}
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