Public
Edited
Jan 18, 2024
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
viewof button2 = button({ value: "REFRESH DATA" })
Insert cell
current_day = {
var cd = {};
return (cd = {
day: new Date(lct).toLocaleString(undefined, { day: "numeric" }),
hour: new Date(lct).toLocaleString(undefined, {
hour: "numeric",
minute: "numeric"
//timeZone: city.timezone
//second: "numeric"
}),
weekday: new Date(lct).toLocaleString(undefined, { weekday: "short" }),
month: new Date(lct).toLocaleString(undefined, { month: "short" })
});
}
Insert cell
lct = {
return new Date(
data.current.time +
("" + data.utc_offset_seconds / 3600).slice(0, 1) +
"0" +
("" + data.utc_offset_seconds / 3600).slice(1) +
":00"
).toLocaleString(undefined, {
//hour: "numeric",
//minute: "numeric",
timeZone: city.timezone
//second: "numeric"
});
}
Insert cell
cti = hourly_time.indexOf(lct.slice(0, -8) + "00" + lct.slice(-6))
Insert cell
current_dp = data.hourly.dew_point_2m[cti]
Insert cell
dpToClass(current_dp)
Insert cell
test = new Date("2024-01-05T03:28-05:00")
Insert cell
new Date()
Insert cell
now = new Date(lct)
Insert cell
lcdf(new Date(lct))
Insert cell
parse2 = d3.utcParse("%d %b %Y %H:%M UT")
Insert cell
lcdf = (date, tz) =>
(
date
.toLocaleString("en-GB", {
day: "2-digit",
month: "short",
hour: "numeric",
year: "numeric",
//minute: "numeric",
//second: "numeric",
timeZone: tz
})
.split(":")
.join("") + ":00 UT"
)
.replace(",", "")
.replace("pt", "p")
Insert cell
test.toLocaleString("en-US", { timeZone: city.timezone })
Insert cell
locale_date = parseDate(test)
Insert cell
function parseDate(str_date) {
return new Date(Date.parse(str_date));
}
Insert cell
"2024-01-05T03:28" +
("" + data.utc_offset_seconds / 3600).slice(0, 1) +
"0" +
("" + data.utc_offset_seconds / 3600).slice(1) +
":00"
Insert cell
function genDayHeader(idx) {
const dt = new Date(data.daily.time[idx]);
const o = {
day: dt.toLocaleString(undefined, { day: "numeric" }),
weekday: dt.toLocaleString(undefined, { weekday: "short" }),
month: dt.toLocaleString(undefined, { month: "short" }),
max: ((data.daily.temperature_2m_max[idx] - 32) / 1.8).toFixed(0),
min: ((data.daily.temperature_2m_min[idx] - 32) / 1.8).toFixed(0),
sunrise: new Date(
data.daily.sunrise[idx] +
("" + data.utc_offset_seconds / 3600).slice(0, 1) +
"0" +
("" + data.utc_offset_seconds / 3600).slice(1) +
":00"
).toLocaleString(undefined, {
hour: "numeric",
minute: "numeric",
timeZone: city.timezone
//second: "numeric"
}),
sunset: new Date(
data.daily.sunset[idx] +
("" + data.utc_offset_seconds / 3600).slice(0, 1) +
"0" +
("" + data.utc_offset_seconds / 3600).slice(1) +
":00"
).toLocaleString(undefined, {
hour: "numeric",
minute: "numeric",
timeZone: city.timezone
//second: "numeric"
})
};
return `<div class="day-header">
<h6 class="day-title">${o.weekday}, ${o.month} ${o.day}</h6>
<p class="time">&nbsp&nbsp🌡️ ${o.max}° / ${o.min}°&nbsp&nbsp</p>
<p class="time"> 🌅 ${o.sunrise} / ${o.sunset}</p>
</div>`;
}
Insert cell
function genDayTableV2(dayIdx) {
let entries = "";
let degrees = "";
for (let hi = 0; hi < 24; hi++) {
const d = getHourlyData(dayIdx, hi);
degrees = d.winDir;
const rainDrop = d.rainProbability > minRainProb ? rainDropSvg : "";
const display =
radios === "Temperature (°C)"
? `
<div class="${dpToClass(d.dp)} ${d.isCurrent ? "current-hour" : ""}">
<p class="time">${d.hour}</p>
<p class="dew-point">${d.dt} ${rainDrop}</p>
</div>
`
: radios === "Dew Point (°C)"
? `
<div class="${dpToClass(d.dp)} ${d.isCurrent ? "current-hour" : ""}">
<p class="time">${d.hour}</p>
<p class="dew-point">${d.dp2} ${rainDrop}</p>
</div>
`
: `
<div class="${dpToClass(d.dp)} ${d.isCurrent ? "current-hour" : ""}">
<p class="time">${d.hour}</p>
<div style="color: deeppink;
font-size: 10px;
text-size-adjust: auto;
transform: rotate(${degrees}deg);">🢁</div>
<p class="dew-point">${d.winSpeed}</p>
</div>

`;
entries += display;
}
return `<div class="dew-point-table">${entries}</div>`;
}
Insert cell
minRainProb = 30
Insert cell
function getHourlyData(dayIdx, hourlyIdx) {
const now = new Date(lct);
const idxStart = dayIdx * 24;
const currHour = data.hourly.time[idxStart + hourlyIdx];
const dt = new Date(currHour);
const isCurrent =
`${dt.getDate()}-${dt.getHours()}` == `${now.getDate()}-${now.getHours()}`;
return {
hour: dt.toLocaleTimeString(undefined, {
hour: "numeric"
//timeZone: city.timezone
}),
dp: data.hourly.dew_point_2m[idxStart + hourlyIdx].toFixed(0),
dp2: ((data.hourly.dew_point_2m[idxStart + hourlyIdx] - 32) / 1.8).toFixed(
0
),
dt: ((data.hourly.temperature_2m[idxStart + hourlyIdx] - 32) / 1.8).toFixed(
0
),
isCurrent,
winSpeed: data.hourly.wind_speed_10m[idxStart + hourlyIdx].toFixed(0),
winDir: data.hourly.wind_direction_10m[idxStart + hourlyIdx],
rainProbability: data.hourly.precipitation_probability[idxStart + hourlyIdx]
};
}
Insert cell
function winDirToarrow(winDir) {
// dry comfortable alright uncomfortable miserable danger
if (winDir < 10) return arrow("n");
if (winDir < 80) return arrow("ne");
if (winDir < 100) return arrow("w");
if (winDir < 170) return arrow("se");
if (winDir < 190) return arrow("s");
if (winDir < 260) return arrow("sw");
if (winDir < 280) return arrow("e");
if (winDir < 350) return arrow("nw");
if (winDir <= 360) return arrow("n");
}
Insert cell
md`${winDirToarrow(6)}`
Insert cell
function dpToClass(dp) {
// dry comfortable alright uncomfortable miserable danger
if (dp < 55) return "Pleasant-Dry";
if (dp < 60) return "Comfortable";
if (dp < 65) return "Sticky-Humid";
if (dp < 70) return "Uncomfortable";
if (dp < 75) return "Oppressive";
return "Miserable";
}
Insert cell
Insert cell
lct.slice(0, -8) + "00" + lct.slice(-6)
Insert cell
lct
Insert cell
hourly_time = data.hourly.time.map((d) =>
new Date(
d //+
//("" + data.utc_offset_seconds / 3600).slice(0, 1) +
//"0" +
//("" + data.utc_offset_seconds / 3600).slice(1) +
//":00"
).toLocaleString(undefined, {
//hour: "numeric",
//minute: "numeric",
//timeZone: city.timezone
//second: "numeric"
})
)
Insert cell
Insert cell
url = `https://api.open-meteo.com/v1/forecast?latitude=32.7766&longitude=-79.9309&current=temperature_2m,relative_humidity_2m,is_day,precipitation,rain&hourly=temperature_2m,dew_point_2m,precipitation_probability,wind_speed_10m,wind_direction_10m&daily=sunrise,sunset,daylight_duration&timezone=America%2FNew_York`
Insert cell
urlF = "https://api.open-meteo.com/v1/forecast?latitude=32.7766&longitude=-79.9309&current=temperature_2m,relative_humidity_2m,is_day,precipitation,rain&hourly=temperature_2m,dew_point_2m,precipitation_probability,wind_speed_10m,wind_direction_10m&daily=temperature_2m_max,temperature_2m_min,sunrise,sunset&temperature_unit=fahrenheit&precipitation_unit=inch&timezone=America%2FNew_York"
Insert cell
Insert cell
mutable degrees = 0
Insert cell
Insert cell
import {
openMeteoSearchCity,
openMeteoGetData
} from "@drio/open-meteo-search-for-city"
Insert cell
Insert cell
Insert cell
md`## References

1. See Mike's [post](https://observablehq.com/@mbostock/date-formatting) on date formatting.
2. Inspiration from [Stefan](https://twitter.com/stefanbfritz): https://mydewpoint.com/.
`
Insert cell
dpImage = {
return FileAttachment("ref-dp.png").image();
}
Insert cell
import { button, time } from "@jashkenas/inputs"
Insert cell
import { arrow } from "@kannankumar/inline-charts-for-markdown"
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