Public
Edited
Apr 12, 2023
Insert cell
Insert cell
Insert cell
chart = html`<svg
viewBox="0 0 ${width} ${height}"
style="display: block;">
<g>
${data.filter(d => d.temp !== "na").map(d => {
const icon = svgIcon(d.desc, hourScale.bandwidth() + 1, yearScale.bandwidth(), tempColor(d.temp));
return svg`<g transform="translate(${hourScale_(d.hour)},${yearScale(d.year)})">
<rect width="${hourScale.bandwidth()}" height="${yearScale.bandwidth()}" fill="transparent" />
${icon}
<title>${d.time}, ${d.temp}°C / ${Math.round(9*d.temp/5+32)}°F, ${d.desc}</title>
</g>`;
})}
</g>
${d3.select(svg`<g transform="translate(${margin.left},0)">`)
.call(d3.axisLeft(yearScale))
.call(g => g.select(".domain").remove())
.node()}
</svg>`
Insert cell
legend2 = html`<div style="display: flex; gap: 3em;">
<div>
${legend({color: tempColor, title: "Temperature →", tickFormat: d => `${d}°C`})}
</div>
${legend({color: tempColor, title: "Temperature →", tickFormat: d => `${Math.round(9*d/5+32)}°F`})}
</div>`
Insert cell
chart2 = html`<svg
viewBox="0 0 ${width} ${height2+20}"
style="display: block;">
<g>
${data.filter(d => d.year === 2023).map(d => {
const icon = svgIcon(d.desc, hourScale.bandwidth() + 1, height2, tempColor(d.temp), 4);
return svg`<g transform="translate(${hourScale_(d.hour)}, 0)">
<rect width="${hourScale.bandwidth()}" height="${yearScale.bandwidth()}" fill="transparent" />
${icon}
<title>${d.time}, ${d.temp}°C / ${Math.round(9*d.temp/5+32)}°F, ${d.desc}</title>
</g>`;
})}
</g>
${[0,1,2,3].map(i => d3.select(svg`<g transform="translate(${margin.left + i*(width - margin.left)/4},${height2})">`)
.call(leg())
.node())}
</svg>`
Insert cell
leg = () => {
let scale = d3.scaleBand().domain(d3.range(0,24)).range([0, (width - margin.left - 3*hourPadding)/4]);
let axis = d3.axisBottom(scale);
axis.tickValues([0,6,12,18]).tickFormat(z => `${String(z).padStart(2, "0")}:00`).tickSizeOuter(0);
return axis;
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
tempColor = d3.scaleSequential()
.domain([-5, 30])
.interpolator(d3.interpolateViridis);
Insert cell
yearScale = d3.scaleBand()
.domain(data.map(d => d.year))
.range([margin.top, height - margin.bottom])
Insert cell
hourPadding = 4
Insert cell
hourScale = d3.scaleBand()
.domain(d3.range(0, 96))
.range([margin.left, width - margin.right - 3*hourPadding])
Insert cell
hourScale_ = h => hourScale(h) + Math.floor(h / 24)*hourPadding
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
svgIcon = (i, w, h, f, t=3) => {
const wrap = child => svg`
<g transform="scale(${w/10}, ${h/10})" fill="${f}">
${child}
</g>`;
if (["clear", "cloud", "fog"].some(w => i.includes(w))) {
return wrap(svg`
<rect x="0" y="${(10-t)/2}" width="10" height="${t}"/>
`);
}
return wrap(svg`
<rect x="0" y="1" width="10" height="8"/>
`);
}
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