Reproducing the Method Animations

All 31 registered method entries have a numerical teaching animation and an English explanation in the complete method gallery. Each animation follows four stages, uses 32 frames by default, and places four plots in a 1280 × 820 frame. The coverage includes eight classical entries, seven adaptive or time-frequency entries, and sixteen experimental block entries. Aliases remain separate registry entries; this count does not imply 31 independent algorithms.

The inputs are deterministic synthetic signals chosen to make an operation visible. The plots show calculations such as constructing a trajectory matrix, averaging seasonal phases, updating a mode, or applying a frequency mask. These teaching traces are separate from the project's real-data tutorials and benchmark results.

Files and recorded evidence

The generated files live in docs/assets/generated/method-animations/. Every method has a looping GIF, a static PNG, a compressed NumPy archive (.npz), and JSON metadata. The complete manifest assembles the per-method records and reports registry coverage.

Record What it contains
GIF and PNG The animated computation and a still frame suitable for reading without playback.
NPZ archive The actual inputs, intermediate arrays, and outputs used by that method's trace.
Per-method JSON Four explanations, parameter effects, references, trace scope, example configuration, numerical checks, array names and shapes, artifact hashes, and render provenance.
Manifest All method records, their source hashes, and the Python/dependency environments captured during rendering.

The source baseline for this addition is c209d81fc9f9624fddf04c922c091bc86c820b60. The per-render SHA-256 hashes identify the actual implementation and generator files used to produce an asset; the baseline identifies the starting revision.

Install the generation environment

Run these commands from the repository root, using Python 3.10 or later:

python -m venv .venv
source .venv/bin/activate
python -m pip install ".[dev,docs,emd,multivar,vmd]"

In Windows Command Prompt, activate with .venv\Scripts\activate.bat instead. The optional extras supply the EMD, VMD, and multivariate backends used by the traces. The generator imports the current checkout's source, so run it from the repository whose files you intend to publish. Exact versions used for an existing artifact are recorded in its render_provenance.

Generation runs on CPU with small signals. It does not train a neural model and does not require a GPU, Torch, or a learned Gabor codebook. Allow roughly five minutes for a complete run as a planning estimate; the measured time depends on the machine, dependencies, and rendering settings. These timings describe documentation generation.

Regenerate and assemble

Rebuild every method

python scripts/generate_method_animations.py

This computes all traces, renders the assets, writes per-method metadata, assembles the manifest, and updates the generated explanation sections in the gallery and the existing Methods index. The default is 32 frames; use --frames 32 to state it explicitly. Keep source files stable during a run: the renderer checks that their hashes have not changed before writing the completed metadata.

Rebuild selected methods

python scripts/generate_method_animations.py --methods SSA STL
python scripts/generate_method_animations.py --group classical

--methods accepts registry names. --group accepts classical, adaptive, or neural. Selection controls the assets that are written; trace specifications are built together by group, so the group's optional dependencies must still be available. In a directory with a complete set of per-method metadata, the command also attempts final assembly.

The source hashes determine how much to regenerate. Editing scripts/method_animations/classical.py, for example, invalidates all eight classical assets because they share that source file. Editing the common renderer or a shared implementation file can invalidate all methods. Use the errors reported by --check to identify the affected records, then regenerate that group or the complete set.

For an isolated preview without updating the gallery:

python scripts/generate_method_animations.py --methods SSA --output-dir /tmp/detime-animation-preview --no-docs

A directory containing only selected methods remains a partial render until every registered entry has metadata.

Assemble existing, current artifacts

python scripts/generate_method_animations.py --assemble

Assembly rebuilds the manifest and generated Markdown from existing per-method JSON files. It does not recompute numerical traces or render images. Every registered method must have metadata, and each record must contain captured render provenance whose source hashes match the current checkout. A stale record causes assembly to fail with the affected method and source path.

Regenerate an affected trace before assembling. Assembly preserves the Python version and dependency versions captured when each asset was rendered; it does not substitute the current environment or relabel older assets with new source hashes.

Audit and build the website

python scripts/generate_method_animations.py --check
python -m pytest tests/docs/test_method_animations.py -q
python -m mkdocs build --strict

--check audits existing files without running optional algorithm backends. It checks exact registry coverage, source provenance, agreement between per-method metadata and the manifest, artifact hashes, GIF dimensions and frame availability, the 3 MiB per-GIF budget, finite source arrays with matching names and shapes, and current English explanation sections.

The documentation tests also verify that plot content changes across stages and that alias and untrained-model explanations remain available in static Markdown. During rendering, every encoded GIF frame is decoded and compared with the planned palette frame, so the compact GIF encoding is checked for visual consistency.

Numerical checks are method-specific values in the metadata. Some compare an instrumented trace with the public implementation; others check a basis formula, reconstruction identity, or an upstream checkpoint. Read the record's trace_note and checks together: an additive identity alone does not establish useful component recovery or forecasting performance.

Inspect the source arrays

Use NumPy with allow_pickle=False. This example lists every stored SSA array, checks its shape against the metadata, and inspects the additive identity:

import json
from pathlib import Path

import numpy as np

assets = Path("docs/assets/generated/method-animations")
metadata = json.loads((assets / "ssa.json").read_text())
print(metadata["trace_kind"])
print(metadata["trace_note"])
print(metadata["checks"])

with np.load(assets / "ssa.npz", allow_pickle=False) as arrays:
    print(sorted(arrays.files))
    for name in sorted(arrays.files):
        values = arrays[name]
        assert list(values.shape) == metadata["source_arrays"][name]
        print(name, values.shape, values.dtype)

    reconstructed = arrays["trend"] + arrays["season"] + arrays["residual"]
    error = np.max(np.abs(arrays["observed"] - reconstructed))
    print("Maximum additive reconstruction error:", float(error))

The SSA archive contains t, observed, trajectory, singular_values, rank_one_matrices, reconstructed_modes, dominant_frequencies, trend_indices, season_indices, trend, season, and residual. Other methods have different inventories: STL stores fit checkpoints, STDR stores cycle normalization and phase counts, and Gabor stores complex Fourier coefficients and codebook assignments. Use each JSON record's source_arrays rather than assuming that every archive has SSA's keys or array dimensions.

Understand the kind of trace

Example What is computed
SSA, MSSA, STD/STDR, moving-average baseline Source-level operations and final components, with numerical comparisons against the configured implementation.
STL and robust STL Actual statsmodels iteration checkpoints. STL's separate local-regression panel illustrates LOESS and identifies the internal details it omits.
MSTL The alternating upstream STL procedure, including separate seasonal estimates before DeTime aggregates them.
Experimental blocks and aliases The operator implemented in this repository. The explanation identifies its relationship to the named architecture and any shared implementation.
NBEATS_INTERPRETABLE Polynomial/Fourier bases with explicitly chosen, untrained teaching coefficients and separate backcast/output bookkeeping.
GABOR_CLUSTER Repository windowing, Fourier features, nearest-centroid assignment, and masked overlap-add reconstruction using a fixed teaching codebook.

For N-BEATS, the generator saves the basis arrays and all chosen coefficients. It does not execute the optional Torch fitting path. Running the public method configuration on that page starts a separate fitting experiment and will not reproduce the illustration's selected coefficients.

For Gabor clustering, the archive includes feature_mean, feature_scale, standardized_demo_centroids, the window, and numeric window/hop/FFT settings. These specify the fixed codebook and normalization used in the trace, so they can be used to construct a GaborClusterModel. The public decomposition call requires that model object or a model archive written by its save() method. The trace's NPZ is an inspection archive, with a different schema from a saved model. Its centroids are teaching constants; no codebook training is performed. See the Gabor explanation and the model implementation for the matching fields.

MVMD input-layout correction

Tracing MVMD exposed a wrapper issue with the optional PySDKit backend. DeTime accepts multivariate input as (time, channels), while PySDKit's MVMD implementation reads its input as (channels, time) and returns modes as (modes, time, channels). The wrapper now transposes the input before its selected backend call and keeps DeTime's public output layout.

This matters because a backend can accept both shapes while performing its temporal operations along the wrong axis. Transposing a returned array cannot repair such a fit. The corrected wrapper also propagates a solver error from the selected entry point instead of retrying with another orientation or interface.

Six regression cases cover two- and four-channel permissive backends, callable dispatch, unchanged solver-error propagation, and direct numerical comparisons with real PySDKit for both channel counts:

python -m pytest tests/wrappers/test_mvmd_orientation.py -q

The real-backend comparisons require the multivar extra installed above. The wrapper-focused validation run passed 37 tests, including these six regressions. The regression source records the bounded solver settings used for the comparisons.

Website behavior

The existing MkDocs navigation groups and gallery URLs are retained. Gallery now includes a complete index and all 31 method entries. The homepage links directly to this index; the Methods page also links to all entries, including the experimental blocks. Generated sections are enclosed by marker comments so that regeneration updates the explanations within the existing pages.

Each page initially displays a static frame. Play animation loads the GIF; Show still frame returns to the PNG. The control is a keyboard accessible button with a playback-state label. Direct image links and the surrounding explanation work without JavaScript, including when viewed on GitHub. Playback is opt-in, and enabling a reduced-motion preference during playback returns the figure to its still frame.

If a GIF fails to load, the control restores the static preview and reports the failure. If the preview also fails, the four written steps and direct image links remain available, and Play can retry the GIF. The complete Gallery menu scrolls on short screens and uses a single column on mobile.

The documentation CI runs real Chromium at a 1440 × 1000 desktop viewport and a 390 × 844 viewport with touch emulation. Every method must load its PNG, play its GIF, stop, and fit the viewport. Additional tests exercise navigation, Tab/Enter/Space, reduced motion, failed requests, retry, and JavaScript-disabled links. For SSA, MVMD, and N-BEATS, screenshot comparisons verify changing plotted data while excluding headings and progress bars. These checks cover mobile emulation; they do not claim physical-device or Safari testing. See the browser test instructions.

The Pages workflow checks the published manifest and all method pages, then runs the same browser tests against the public deployment URL. Its de-time-public-browser-acceptance artifact records screenshots and test results. Public checks cannot fall back to local HTML. The source site also passes a local-link and HTML-fragment audit before deployment.

Local integrity checks cover the generated assets, static image links, explanation sections, and changing plot content. After deployment, record the live browser playback and keyboard-control checks on the deployment pull request.

Original PR verification record (29 October 2026)

Check Recorded result
Registry coverage 31 method entries, four stages and 32 frames per animation.
GIF size Approximately 13.34 MiB across the complete GIF set; each file is below the 3 MiB budget.
Focused wrapper/backend tests 37 passed, including six MVMD input-layout regression cases.
Strict documentation build Passed with 103 documentation pages.
Animation integrity tests 3 passed; generated assets, changing plot content, explanations, and stale-provenance rejection are covered.
Final full test suite 193 passed, 1 skipped (optional Torch), and 3 warnings in 62.40 seconds.
Source-distribution build Passed with isolated build dependencies; distribution-content checks passed, including all animation assets and generation sources.

The manifest and per-method metadata contain the detailed array inventories, numerical checks, dependency versions, and artifact hashes for this record.

The delivery revision corrects STDR's remainder terminology, documents the actual parameter defaults, and labels notebook output as Reconstruction RMSE over all samples and channels. All 31 animations were recomputed after the source documentation changes. The renderer now checks the exact 1280 × 820 pixel canvas for every frame, including on Matplotlib versions whose floating-point size conversion can otherwise lose one pixel.