Public
Edited
Jul 2, 2024
2 forks
4 stars
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
legend = () => {
const wrapper = d3.create("div")
.style("font-family", franklinLight);

wrapper.append("div")
.style("font-weight", "bold")
.text("How many days out is the temperature forecast accurate within 3°F");

const text = ["No more than 2 days", "3 to 4 days", "5 to 6 days", "At least 7 days"];
const swatch = wrapper.selectAll(".swatch")
.data(palette)
.join("div")
.attr("class", "swatch")
.style("display", "inline-block")
.style("margin-right", "16px");

swatch.append("div")
.style("background", d => d)
.style("display", "inline-block")
.style("height", "12px")
.style("margin-right", "4px")
.style("width", "12px");

swatch.append("div")
.style("display", "inline-block")
.text((d, i) => text[i]);

return wrapper.node();
}
Insert cell
map = function*() {
const wrapper = d3.create("div")
.style("height", `${height}px`);
const canvas = wrapper.append("canvas")
.style("position", "absolute")
.attr("width", width)
.attr("height", height);

// Faux clipping
path.context(null)
const svg = wrapper.append("svg")
.style("position", "absolute")
.attr("width", width)
.attr("height", height);

const mask = svg.append("mask")
.attr("id", "hole");

mask.append("rect")
.attr("width", width)
.attr("height", height)
.attr("opacity", 1)
.attr("fill", "white");

mask.append("path")
.datum(conusOuter)
.attr("d", path)
.attr("fill", "black")
.attr("stroke-linejoin", "round");
svg.append("rect")
.attr("mask", "url(#hole)")
.attr("fill", "white")
.attr("width", width)
.attr("height", height);
const context = canvas.node().getContext("2d");
path.context(context);
// Iterate through raster data
let i = 0;
for (let row = 0; row < rasters.height; row++) {
for (let col = 0; col < rasters.width; col++) {
const lon = originX + col * pixelWidth;
const lat = originY + row * pixelHeight;
const value = values[row * rasters.width + col];

if (value === null_value) continue;
const w = lon - pixelWidth;
const e = lon + pixelWidth;
const n = lat - pixelHeight;
const s = lat + pixelHeight;

context.beginPath();
path({
type: "Feature",
geometry: {
type: "Polygon",
coordinates: [
[[w, n], [e, n], [e, s], [w, s], [w, n]]
]
}
});

const c = color(value);
context.fillStyle = c;
context.fill();
context.strokeStyle = c;
context.stroke();
if (i++ % 1e4 === 0) {
yield wrapper.node();
}
}
}

context.fillStyle = "none";
context.lineWidth = 1;
context.beginPath();
path(conusInner);
context.strokeStyle = "#494949"
context.stroke();
context.beginPath();
path(conusOuter);
context.strokeStyle = "#2a2a2a"
context.stroke();
return wrapper.node();
}
Insert cell
Insert cell
palette = ["#faf4c8", "#96d1b1", "#2da6b8", "#3870ab"]
Insert cell
color = v => {
if (v <= 2) {
return palette[0];
}
if (v <= 4) {
return palette[1];
}
if (v <= 6) {
return palette[2];
}
return palette[3];
}

Insert cell
Insert cell
height = width * 0.631
Insert cell
Insert cell
projection = d3.geoAlbers().fitSize([width, height], conusOuter)
Insert cell
path = d3.geoPath(projection)
Insert cell
conusTopo = FileAttachment("conus.topo.json").json()
Insert cell
conusOuter = topojson.mesh(conusTopo, conusTopo.objects.conus, (a, b) => a === b)
Insert cell
conusInner = topojson.mesh(conusTopo, conusTopo.objects.conus, (a, b) => a !== b)
Insert cell
Insert cell
// Not very helpfully named, but this file contains the GeoTIFF of our analysis of the gridded verification data
zip = FileAttachment("test.tif.zip").zip()
Insert cell
file = (await zip.file("test.tif"))
Insert cell
tiff = file
.arrayBuffer()
.then((buffer) => GeoTIFF.fromArrayBuffer(buffer));
Insert cell
image = tiff.getImage()
Insert cell
tiePoint = image.getTiePoints()[0]
Insert cell
originX = tiePoint.x
Insert cell
originY = tiePoint.y
Insert cell
pixelScale = image.getFileDirectory().ModelPixelScale
Insert cell
pixelWidth = pixelScale[0]
Insert cell
pixelHeight = -pixelScale[1]
Insert cell
rasters = image.readRasters()
Insert cell
values = rasters[0]
Insert cell
null_value = -3.4028234663852886e+38;
Insert cell
Insert cell
GeoTIFF = require("geotiff@2.1.3/dist-browser/geotiff.js")
Insert cell
import { franklinLight } from "@climatelab/fonts@46"
Insert cell
import { toc } from "@climatelab/toc@45"
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