Published
Edited
Jul 1, 2020
Insert cell
Insert cell
chart = {
const svg = d3.create("svg")
.attr("viewBox", [0, 0, width, height])
.attr("font-family", "sans-serif")
.attr("font-size", 10)
.attr("stroke-miterlimit", 1);

const gradient = DOM.uid();
svg.append("linearGradient")
.attr("id", gradient.id)
.attr("gradientUnits", "userSpaceOnUse")
.attr("x1", 0)
.attr("y1", 0)
.attr("x2", 0)
.attr("y2", height)
.selectAll("stop")
.data([
{offset: 0, color: positiveColor},
{offset: 1, color: negativeColor}
])
.join("stop")
.attr("offset", d => d.offset)
.attr("stop-color", d => d.color);
svg.append("g")
.call(xAxis)
.selectAll("text")
.attr("color", "gray")
.attr("font-size", 12);

svg.append("g")
.call(yAxis)
.selectAll("text")
.attr("color", "gray")
.attr("font-size", 18);

svg.append("path")
.attr("fill", "none")
.attr("stroke", gradient)
.attr("stroke-width", 5)
.attr("d", line(data_new.series[0].values));
if (!mutable lookup) mutable lookup = new Date(data_new.dates[0]);
const bar = svg
.append("line")
.attr("stroke", "#ccc")
.attr("stroke-width", 1.5)
.attr("y2", height)
.attr("x1", x(mutable lookup))
.attr("x2", x(mutable lookup));
const legendDate = svg
.append("text")
.style("font", "30px sans-serif")
.attr("fill", "#ccc")
.attr("x", 10)
.attr("y", 100);
const legendValue = svg
.append("text")
.style("font", "30px sans-serif")
.attr("fill", "#ccc")
.attr("x", 10)
.attr("y", 130);
const formatTime = d3.utcFormat("%d/%m/%Y");
function update(date) {
const i = bisect.right(data_new.dates, date);

if (i < data_new.dates.length && i > 0) {
legendDate.text(`${formatTime(data_new.dates[i])}`);
legendDate.attr("x", (i > data_new.dates.length/2)? x(data_new.dates[i])-160 : x(data_new.dates[i]));
legendValue.text(`mobilidade: ${data_new.series[0].values[i]}%`);
legendValue.attr("x", (i > data_new.dates.length/2)? x(data_new.dates[i])-235 : x(data_new.dates[i]));
}
mutable lookup = new Date(date);
bar.attr("x1", x(mutable lookup)).attr("x2", x(mutable lookup));
}
svg.on("mousemove click touchmove", function() {
const m = d3.mouse(this);
update(x.invert(m[0]));
});
update(mutable lookup);
return svg.node();
}
Insert cell
state = "ES"
Insert cell
local = "Parques"
Insert cell
localList = [...new Set(data_raw_new.series.map(d => d.type))]
Insert cell
mutable lookup = null
Insert cell
bisect = d3.bisector(d => d)
Insert cell
positiveColor = "darkred" //#861657
Insert cell
negativeColor = "steelblue"
Insert cell
file = "https://hackcovid.s3-us-west-2.amazonaws.com/data/rt_data.csv"
Insert cell
data_raw_new = {
//const data = d3.csvParse(await FileAttachment("brazil_mobility@2.csv").text());
const data = await d3.csv("https://hackcovid.s3-us-west-2.amazonaws.com/data/data_mobility.csv", d3.autoType)
const columns = data.columns.slice(2);
return {
series: data.map(d => ({
name: d.sub_region_1.replace(/, ([\w-]+).*/, " $1"),
type: d.local.replace(/, ([\w-]+).*/, " $1"),
values: columns.map(k => +d[k])
})),
dates: columns.map(d3.utcParse("%Y-%m-%d"))
};
}
Insert cell
data_new = {
const series = data_raw_new.series.filter(d => d.name === state & d.type === local);
const dates = data_raw_new.dates;
series[0].values = series[0].values.map(d => (d < 100)? d: 100) //limit to 100
return {
series,
dates
}
}
Insert cell
line = d3.line()
.defined(d => !isNaN(d))
.x((d, i) => x(data_new.dates[i]))
.y(d => y(d))
Insert cell
x = d3.scaleUtc()
.domain(d3.extent(data_new.dates))
.rangeRound([margin.left, width - margin.right])
Insert cell
y = d3.scaleLinear()
.domain([-100, 100])
.rangeRound([height - margin.bottom, margin.top])
.clamp(true)
Insert cell
xAxis = g => g
.attr("transform", `translate(0,${height - margin.bottom})`)
.call(d3.axisBottom(x).ticks(width / 120).tickSizeOuter(0))
Insert cell
yAxis = g => g
.attr("transform", `translate(${margin.left},0)`)
.call(d3.axisLeft(y).tickFormat(d => `${d}%`))
.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")
.attr("id", "mobility-title")
.text(""))
.call(g => g.selectAll(".tick line")
.select(function() { return this.parentNode.appendChild(this.cloneNode()); })
.attr("stroke-opacity", d => d === 100 ? 0.1 : 0.3)
.attr("stroke-width", 2)
.attr("stroke", "#ccc")
.attr("x2", width - margin.left - margin.right))
Insert cell
height = 600
Insert cell
width = 600
Insert cell
margin = ({top: 20, right: 30, bottom: 30, left: 55})
Insert cell
d3.timeFormatDefaultLocale(locale);
Insert cell
Insert cell
d3 = require("d3@5", "d3-array@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