Public
Edited
Nov 26, 2023
Paused
1 fork
5 stars
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
groundhogs = {
const response = await fetch("https://groundhog-day.com/api/v1/groundhogs");
const json = await response.json();
const groundhogs = json.groundhogs;

return groundhogs
.map((groundhog) => ({
...groundhog,
lat: parseFloat(groundhog.coordinates?.split(", ")[0]),
lon: parseFloat(groundhog.coordinates?.split(",")[1])
}))
.map((groundhog) => ({
...groundhog,
predictions: groundhog.predictions.map((prediction) => {
// HERE BE DRAGONS: A lot of sparse data here, be careful with undefined and nulls causing problems
// can be undefined
const conclusion =
prediction.shadow === 1
? "❄️ longer winter"
: prediction.shadow === 0
? "🌼 early spring"
: undefined;

const year = new Date("2/2/" + prediction.year);

// can be undefined
const correspondingWeather = weather.find(
(w) => w.year?.getTime() === year.getTime()
);

// can be undefined
const correct =
correspondingWeather !== undefined &&
correspondingWeather.skew !== undefined &&
conclusion !== undefined
? correspondingWeather.skew === conclusion
: undefined;

return {
...groundhog,
...prediction,
year,
conclusion,
correct
};
})
}))
.map((groundhog) => ({
...groundhog,
accuracy: Number(
(
groundhog.predictions.filter((p) => p.correct === true).length /
// count number of true or false
groundhog.predictions.filter((p) => p.correct !== undefined).length
).toFixed(2)
)
}));
}
Insert cell
Insert cell
Insert cell
predictions = groundhogs.flatMap((groundhog) =>
groundhog.predictions
)
Insert cell
Insert cell
Insert cell
archive.csv
Type Table, then Shift-Enter. Ctrl-space for more options.

Insert cell
Insert cell
Insert cell
Insert cell
hadEarlySpring = (year) => {
const feb = year["February Average Temperature"];
const march = year["March Average Temperature"];

// ignore null or undefined
if (feb > 0 && march > 0) {
return feb > febuaryAverage || march > marchAverage;
}
}
Insert cell
weatherTill2016 = archive.map((year) => {
let skew;
let symbol;

// leave undefined if no data
if (hadEarlySpring(year) !== undefined) {
skew = hadEarlySpring(year) ? "🌼 early spring" : "❄️ longer winter";
symbol = hadEarlySpring(year) ? "🌼" : "❄️";
}

return {
...year,
year: new Date("2/2/" + year.Year),
skew,
symbol
};
})
Insert cell
Insert cell
Insert cell
Insert cell
weatherAfter2016
Type Table, then Shift-Enter. Ctrl-space for more options.

Insert cell
Insert cell
weather = [...weatherTill2016, ...weatherAfter2016]
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
function isDisplayedGroundhog(groundhog) {
if (filter === FILTER_TYPE.ALL) {
return true;
} else if (filter === FILTER_TYPE.GROUNDHOG_RESEMBLING) {
return groundhog.type.toLowerCase().includes("groundhog");
} else if (filter === FILTER_TYPE.ANY_GROUNDHOG) {
return (
groundhog.type.toLowerCase() === "groundhog" ||
groundhog.type.toLowerCase() === "taxidermied groundhog"
);
} else if (filter === FILTER_TYPE.ALIVE_GROUNDHOG) {
return groundhog.type.toLowerCase() === "groundhog";
}
}
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