Public
Edited
Jun 8, 2023
1 star
Insert cell
Insert cell
Insert cell
Insert cell
numbers = Array.from({length: 24}, (_, i) => i)
Insert cell
Insert cell
map(width)
Insert cell
Insert cell
key = "199A45AE-E2E0-4D19-9237-A75B7AA5952E"
Insert cell
d1 = d3.min([
`${date.toISOString().slice(0, 11)}${d3.format("02d")(hour)}`,
new Date(+new Date() - 3600 * 1000).toISOString().slice(0, 13)
])
Insert cell
url = "https://www.airnowapi.org/aq/data/?startDate="+d1+"&endDate="+d1+"&parameters=PM25&BBOX=-130,25,-65,55&dataType=A&format=text/csv&verbose=0&monitorType=0&includerawconcentrations=0&API_KEY="+key
Insert cell
air = cachedData(url)
Insert cell
// Here’s a copy, in case the API stops working
//air = FileAttachment("air8June.csv").csv({typed: true})
Insert cell
Insert cell
color = ({
label: "PM2.5",
type: "threshold",
domain: [50, 100, 150, 200, 300],
range: [
"rgb(156, 216, 78)", // Good
"rgb(250, 207, 57)", // Moderate
"rgb(249, 144, 73)", // Unhealthy for Sensitive Groups
"rgb(246, 94, 95)", // Unhealthy
"rgb(160, 112, 182)", // Very Unhealthy
"rgb(160, 106, 123)" // Hazardous
]
})
Insert cell
Insert cell
Insert cell
Plot.plot({
color,
marks: [
Plot.dot(air, {
x: "lon",
y: "lat",
fill: "PM2.5",
r: 4,
stroke: "white"
})
]
})
Insert cell
Insert cell
Plot.plot({
projection: "albers",
color,
marks: [
Plot.dot(air, {
x: "lon",
y: "lat",
fill: "PM2.5",
stroke: "white",
fx: "date"
})
]
})
Insert cell
// Group by date, and return the group with the largest key.
recent = d3
.greatest(
d3.group(air, (d) => d.date),
(d) => d[0]
)[1]
.filter((d) => d["PM2.5"] > 0) // remove the points with value -999
Insert cell
Insert cell
visibility().then(() => map(width))
Insert cell
// this is a function because we want to show the map at the top of the page.
map = (width) =>
Plot.plot({
width,
projection: "albers",
color: { ...color, legend: true },
marks: [
// this creates a path to clip the contour mark.
Plot.geo(nation, {
render: (i, s, v, d, c, next) => {
const g = next(i, s, v, d, c).children[0];
return svg`<clipPath id=nation>${g}`;
}
}),

Plot.contour(recent, {
x: "lon",
y: "lat",
fill: "PM2.5",
interpolate: "random-walk",
blur: 3,
thresholds: [0, ...color.domain],
stroke: "currentColor",
render: (i, s, v, d, c, next) => {
const g = next(i, s, v, d, c);
g.setAttribute("clip-path", "url(#nation)"); // add clip
return g;
}
}),

Plot.geo(states, { stroke: "grey" }),

Plot.dot(recent, {
x: "lon",
y: "lat",
fill: "PM2.5",
stroke: "currentColor",
strokeOpacity: 0.8,
strokeWidth: 0.75,
tip: true
}),
Plot.text([d1], {
frameAnchor: "top-right",
fontSize: 16,
fontVariant: "tabular-nums"
})
]
})
Insert cell
Insert cell
Insert cell
us = FileAttachment("us-counties-10m.json").json()
Insert cell
nation = topojson.feature(us, us.objects.nation)
Insert cell
states = topojson.feature(us, us.objects.states)
Insert cell
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