Public
Edited
Jan 19, 2023
Insert cell
Insert cell
shootings = {
const svg = d3
.create("svg")
.attr("viewBox", [0, 0, width, height])
.style("background", "white");

svg.append("g").call(xAxis);
svg.append("g").call(yAxis);
svg.append("g").call(yAxisRight);
// svg.append("g").call(grid);

const shootingsGroup = svg.append("g");
const blendMode = "multiply";

const series = [
{
yScale: yLaws,
prop: "laws",
color: colors[0]
},
{
yScale: yShootings,
prop: "shootings",
color: colors[1]
}
];

series.forEach((conf) => {
shootingsGroup
.append("path")
.attr("fill", conf.color)
.attr("fill-opacity", 0.1)
.style("mix-blend-mode", blendMode)
.attr("d", area(conf.yScale, conf.prop)(data));

shootingsGroup
.append("path")
.attr("stroke", conf.color)
.attr("stroke-width", 2)
.attr("opacity", 0.7)
.attr("fill", "none")
.attr("d", line(conf.yScale, conf.prop)(data));
});

return svg.node();
}
Insert cell
colors = ["#f8a71b", "#1d164c"]
Insert cell
curve = d3.curveBasis
Insert cell
area = (yScale, prop) =>
d3
.area()
.x((d) => x(d.date))
.y0(yScale(0))
.y1((d) => yScale(d[prop]))
.curve(curve)
Insert cell
line = (yScale, prop) =>
d3
.line()
.x((d) => x(d.date))
.y((d) => yScale(d[prop]))
.curve(curve)
Insert cell
yAxisRight = (g) =>
g
.attr("transform", `translate(${width - margin.right},0)`)
.call(d3.axisRight(yLaws))
// .call((g) => g.select(".domain").remove())
.call((g) =>
g.selectAll(".tick").attr("font-size", 12).attr("stroke-width", 1)
)
.call((g) =>
g
.append("text")
.attr("x", -(10 + 20))
.attr("y", margin.top)
.attr("dy", 12)
.attr("fill", "#000")
.attr("opacity", 0.75)
// .attr("text-anchor", "end")
.attr("font-size", 14)
// .attr("font-weight", "bold")
.attr("text-anchor", "end")
.text("Media mentions of gun laws")
)
.call(
(g) =>
g
.append("circle")
.attr("cx", -(10 + 8))
.attr("cy", margin.top + 8)
.attr("r", 8)
.attr("fill", colors[1])
.attr("fill-opacity", 0.1)
.attr("stroke", colors[1])
.attr("stroke-width", 2)
// .attr("font-weight", "bold")
)
// .call(
// (g) =>
// g
// .append("rect")
// .attr("x", -(10 + 16))
// .attr("y", margin.top)
// .attr("width", 16)
// .attr("height", 16)
// .attr("fill", colors[1])
// .attr("fill-opacity", 0.5)
// .attr("stroke", colors[1])
// .attr("stroke-width", 2)
// // .attr("font-weight", "bold")
// )
Insert cell
yAxis = (g) =>
g
.attr("transform", `translate(${margin.left},0)`)
.call(d3.axisLeft(yShootings))
// .call((g) => g.select(".domain").remove())
.call((g) =>
g.selectAll(".tick").attr("font-size", 12).attr("stroke-width", 1)
)
.call((g) =>
g
.append("text")
.attr("x", 10 + 20)
.attr("y", margin.top)
.attr("dy", 12)
.attr("fill", "#000")
.attr("opacity", 0.75)
.attr("font-size", 14)
// .attr("font-weight", "bold")
.attr("text-anchor", "start")
.text("Media mentions of mass shootings")
)
.call(
(g) =>
g
.append("circle")
.attr("cx", 10 + 8)
.attr("cy", margin.top + 8)
.attr("r", 8)
.attr("fill", colors[0])
.attr("fill-opacity", 0.1)
.attr("stroke", colors[0])
.attr("stroke-width", 2)
// .attr("font-weight", "bold")
)
// .call(
// (g) =>
// g
// .append("rect")
// .attr("x", 10)
// .attr("y", margin.top)
// .attr("width", 16)
// .attr("height", 16)
// .attr("fill", colors[0])
// .attr("fill-opacity", 0.5)
// .attr("stroke", colors[0])
// .attr("stroke-width", 2)
// // .attr("font-weight", "bold")
// )
Insert cell
xAxis = (g) =>
g
.attr("transform", `translate(0,${height - margin.bottom})`)
.call(
d3
.axisBottom(x)
.ticks(width / 80)
.tickSizeOuter(0)
// .tickFormat(d3.timeFormat("%b"))
)
.call((g) => g.select(".domain").attr("stroke-width", 1))
.call((g) => g.select(".tick").attr("stroke-width", 1))
Insert cell
yShootings = d3
.scaleLinear()
.domain([0, d3.max(data, (d) => d.shootings) * 1.15])
.range([height - margin.bottom, margin.top])
Insert cell
yLaws = d3
.scaleLinear()
.domain([0, d3.max(data, (d) => d.laws) * 1.15])
.range([height - margin.bottom, margin.top])
Insert cell
height = 600
Insert cell
x = d3
.scaleTime()
.domain(d3.extent(data, (d) => d.date))
.range([margin.left, width - margin.right])
Insert cell
Insert cell
margin = ({
left: 50,
right: 50,
top: 30,
bottom: 30
})
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