Published
Edited
Feb 13, 2021
Insert cell
Insert cell
Insert cell
chart = {
const svg = d3.create("svg")
.attr("viewBox", [0, 0, width, height])
.style("overflow", "visible");

svg.append("g")
.call(xAxis);

svg.append("g")
.call(yAxis);

const path = svg.append("g")
.attr("fill", "none")
.attr("stroke", "steelblue")
.attr("stroke-width", 1.5)
.attr("stroke-linejoin", "round")
.attr("stroke-linecap", "round")
.selectAll("path")
.data(data.series)
.join("path")
.attr("d", d => line(d.values))
.attr("stroke", d => d.color);

return svg.node();
}
Insert cell
wordList = {
const wordData = await d3.csv("https://gist.githubusercontent.com/rahulbot/5194d5b966d231ece8c85d06ce30ae05/raw/1b48b6d599ea69cdee807201f835d395132d11bc/words.csv")
return wordData.map(row => row['term']);
}
Insert cell
data = {
const datasetNames = ['left', 'center-left', 'center', 'center-right', 'right'];
// colors: https://colorbrewer2.org/#type=diverging&scheme=RdYlBu&n=5
const partisanColors = ["#2c7bb6", "#abd9e9","#808080", "#fdae61", "#d7191c"];
const datasets = await Promise.all([
d3.csv("https://gist.githubusercontent.com/rahulbot/5194d5b966d231ece8c85d06ce30ae05/raw/1b48b6d599ea69cdee807201f835d395132d11bc/center-left.csv"),
d3.csv("https://gist.githubusercontent.com/rahulbot/5194d5b966d231ece8c85d06ce30ae05/raw/1b48b6d599ea69cdee807201f835d395132d11bc/left.csv"),
d3.csv("https://gist.githubusercontent.com/rahulbot/5194d5b966d231ece8c85d06ce30ae05/raw/1b48b6d599ea69cdee807201f835d395132d11bc/center.csv"),
d3.csv("https://gist.githubusercontent.com/rahulbot/5194d5b966d231ece8c85d06ce30ae05/raw/1b48b6d599ea69cdee807201f835d395132d11bc/center-right.csv"),
d3.csv("https://gist.githubusercontent.com/rahulbot/5194d5b966d231ece8c85d06ce30ae05/raw/1b48b6d599ea69cdee807201f835d395132d11bc/right.csv"),
]);
const termData = datasets.map(dataset => dataset.filter(row => row['word'] == selectedTerm))
return {
y: "% Stories mentioning "+selectedTerm,
series: termData.map((s, idx) => ({
name: datasetNames[idx],
values: s.map(r => r['percentage']),
color: partisanColors[idx]
})),
dates: termData[0].map(r => d3.timeParse("%Y-%m-%d")(r['date']))
};
}
Insert cell
height = 300
Insert cell
width = 800
Insert cell
margin = ({top: 20, right: 20, bottom: 50, left: 30})
Insert cell
x = d3.scaleUtc()
.domain(d3.extent(data.dates))
.range([margin.left, width - margin.right]);
Insert cell
y = d3.scaleLinear()
//.domain([0, d3.max(data.series, d => d3.max(d.values))]).nice()
.domain([0, 1]) // fix max so we can compare more easily
.range([height - margin.bottom, margin.top]);
Insert cell
xAxis = g => g
.attr("class","axis")
.attr("transform", `translate(0,${height - margin.bottom})`)
.call(d3.axisBottom(x).ticks(data.dates.length).tickFormat(d3.timeFormat("%b-%d")))
.selectAll("text")
.attr("transform", "rotate(90)")
.style("text-anchor", "start")
.attr("x", 10)
Insert cell
yAxis = g => g
.attr("class","axis")
.attr("transform", `translate(${margin.left},0)`)
.call(d3.axisLeft(y))
.call(g => g.select(".domain").remove())
.call(g => g.select(".tick:last-of-type text").clone()
.attr("x", 3)
.attr("text-anchor", "start")
.attr("font-weight", "bold")
.text(data.y))
Insert cell
line = d3.line()
.defined(d => !isNaN(d))
.x((d, i) => x(data.dates[i]))
.y(d => y(d))
.curve(d3.curveBasis)
Insert cell
d3 = require("d3@6")
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