Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Patching — temporal + spatiotemporal composition

Temporal patching + spatiotemporal composition

Mirror of 01_intro, but walking through the temporal axes and the SpatioTemporalPatcher composition. The window-math sections run on a 1-D synthetic series (the math is the lesson — real data would not change it). The spatiotemporal composition runs on a real Sentinel-2 time stack over Lake Tahoe — eight cloud-free acquisitions across June–July 2024 from MPC.

TemporalWindow.weights(geometry, length) returns a 1-D weight array whose length matches the temporal window. Recency, periodicity, and spectral-leakage tapers all live here.

              CausalBoxcar: weights.shape: (16,)
     ExponentialDecay(τ=2): weights.shape: (16,)
     ExponentialDecay(τ=6): weights.shape: (16,)
       TaperedTukey(α=0.3): weights.shape: (16,)
       TaperedTukey(α=0.7): weights.shape: (16,)
        Periodic(period=8): weights.shape: (16,)
<Figure size 800x350 with 1 Axes>

2. Lookback windows along a 1-D NDVI-style series

A 100-step synthetic NDVI series (sinusoidal seasonality + drift) stands in for any per-pixel temporal trace.

series.shape: (100,)
len(patches): 9
patches[0].data.shape: (10,)
<Figure size 900x300 with 1 Axes>

3. TemporalFold — stateful, RNN-like reduction

Patches are folded sequentially with caller-supplied state. The canonical use case is per-pixel rolling statistics (running mean, running max, exponentially-smoothed forecast, …).

running sum at end: 495.000
np.sum(series)    : 495.000

4. Forecasting with TemporalLookbackHorizon

Each patch carries lookback + horizon. The TemporalForecast aggregation keeps only the horizon block per anchor.

len(patches_lh): 13
patches_lh[1].data.shape: (8,)
len(aligned): 12
  anchor=8: horizon.shape=(3,)
  anchor=16: horizon.shape=(3,)
  anchor=24: horizon.shape=(3,)

5. SpatioTemporalPatcher over a real S2 time stack

Pull eight cloud-free Sentinel-2 acquisitions over Lake Tahoe (June–July 2024) — load_s2_timestack returns a (T, C, H, W) uint16 array plus a date list. We compose a SpatialPatcher (256×256 chips) with a TemporalPatcher (4-date causal lookback) under the product coupling — every spatial patch is paired with every temporal patch.

stack shape: (8, 2, 3935, 1599)  dates: ['2024-06-02', '2024-06-04', '2024-06-07', '2024-06-09', '2024-06-12', '2024-06-14', '2024-06-17', '2024-06-19']
nir_stack shape: (8, 512, 512)
product coupling: 8 space×time patches
  first.data.shape: (1, 256, 256)
  first.(space, time): ((0, 0), 0)
<Figure size 700x400 with 2 Axes>

6. Coupled coupling — event-triggered patching

coupling="coupled" lets you specify explicit (space, time) pairs — useful for event-triggered analysis (e.g. “look at chip X only after acquisition Y”). Three events on the Lake Tahoe stack:

coupled events: 3
  space=(0, 0) time=1  data.shape=(2, 256, 256)
  space=(0, 256) time=3  data.shape=(2, 256, 256)
  space=(256, 0) time=5  data.shape=(2, 256, 256)

Recap

Same four-axis machinery as the spatial case, applied along the time axis (geometry, sampler, window, aggregation) — plus a SpatioTemporalPatcher that composes the two. Three coupling modes:

CouplingMeaningExample
productevery space × every timeDense space-time inference.
alignedone-to-one along the iteration axisWalking a single trajectory through space-time.
coupledexplicit (space, time) pairsEvent-triggered analysis.

For the applied version of this — running NDVI per chip across a real time stack and stitching back into a global animation — see ../05_patching_grids and the geocatalog.load_raster_timeseries walk in ../catalog/01_intro.