What does ‘the same day’ mean?¶
PRISM and gridMET can publish the same calendar labels while describing different physical observation windows. This live-data lesson keeps the code short and makes that difference inspectable before any cross-source interpretation.
Data: maximum temperature and precipitation, South Dakota, 1–31 July 2024. Network required: noun loaders require observed provider data and never substitute synthetic values.
import matplotlib.pyplot as plt
import cubedynamics as cd
from cubedynamics import data, pipe, verbs as v
bbox = [-101.2, 43.7, -100.4, 44.3]
dates = dict(start="2024-07-01", end="2024-07-31")
One label, two source conventions¶
Load the same noun, place, statistic, and labels. Source identity, units, grids, methods, and observation support remain distinct.
prism_temperature = data.temperature(
source="prism", statistic="maximum", bbox=bbox, **dates
)
gridmet_temperature = data.temperature(
source="gridmet", statistic="maximum", bbox=bbox, **dates
)
comparison = cd.compare_temporal_support(
prism_temperature, gridmet_temperature
)
comparison.as_dict()
prism_bounds = data.observation_intervals(prism_temperature)
gridmet_bounds = data.observation_intervals(gridmet_temperature)
fig, ax = plt.subplots(figsize=(9, 2.8))
for y, label, bounds, color in [
(1, "PRISM", prism_bounds, "#386cb0"),
(0, "gridMET", gridmet_bounds, "#f26b38"),
]:
start = bounds.observation_start.values[12]
end = bounds.observation_end.values[12]
ax.plot([start, end], [y, y], lw=10, solid_capstyle="butt", color=color, label=label)
ax.set(yticks=[0, 1], yticklabels=["gridMET", "PRISM"], title="Physical support of the label 13 July 2024")
ax.grid(axis="x", alpha=.25)
plt.show()
Make the label choice explicit¶
mode="labels" records that we are pairing unchanged labels. It does not make the observation windows equal. Source-specific thresholds preserve each product's native units.
prism_hot = (
pipe(prism_temperature)
| v.threshold_state(threshold=30, direction="above", name="hot")
).unwrap()
gridmet_hot = (
pipe(gridmet_temperature)
| v.threshold_state(threshold=303.15, direction="above", name="hot")
).unwrap()
checked = pipe(prism_hot) | v.align_time(gridmet_hot, mode="labels")
print(checked.explain())
print(checked.validate())
fig, ax = plt.subplots(figsize=(9, 4))
prism_hot.state.mean(("y", "x")).plot(ax=ax, label="PRISM · >30 °C")
gridmet_hot.state.mean(("y", "x")).plot(ax=ax, label="gridMET · >303.15 K")
ax.set(title="Hot-area fraction by published date label", ylabel="Fraction of cells")
ax.legend()
plt.show()
Precipitation makes interval meaning especially visible¶
Daily totals accumulate over a window. Equal labels do not guarantee equal accumulation windows. Differences below must not be attributed only to timing: the products also differ in inputs, grids, methods, and revisions, and gridMET uses PRISM information in its lineage.
prism_precip = data.precipitation(source="prism", bbox=bbox, **dates)
gridmet_precip = data.precipitation(source="gridmet", bbox=bbox, **dates)
fig, ax = plt.subplots(figsize=(9, 4))
prism_precip.mean(("y", "x")).plot(ax=ax, label="PRISM")
gridmet_precip.mean(("y", "x")).plot(ax=ax, label="gridMET")
ax.set(title="AOI-mean daily precipitation by published label", ylabel="mm")
ax.legend()
plt.show()
Interpretation¶
The two time axes can be coordinate-compatible without being support-compatible. align_time(..., mode="labels") documents an intentional label comparison; it does not claim equivalent observations. Event starts and lags are a third decision made after states are defined.