diff --git a/.gitignore b/.gitignore
index 30b0f86..f39627c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -103,3 +103,6 @@ node_modules/
*.iws
.idea/
/AGENTS.md
+
+# Manim animation sources
+_manim_animations/
diff --git a/docs/assets/images/tutorials/advanced_temporal_setup/UnevenWavesPadding.avif b/docs/assets/images/tutorials/advanced_temporal_setup/UnevenWavesPadding.avif
new file mode 100644
index 0000000..5f81305
Binary files /dev/null and b/docs/assets/images/tutorials/advanced_temporal_setup/UnevenWavesPadding.avif differ
diff --git a/docs/assets/images/tutorials/advanced_temporal_setup/UnevenWavesPaddingDark.avif b/docs/assets/images/tutorials/advanced_temporal_setup/UnevenWavesPaddingDark.avif
new file mode 100644
index 0000000..c0c727a
Binary files /dev/null and b/docs/assets/images/tutorials/advanced_temporal_setup/UnevenWavesPaddingDark.avif differ
diff --git a/docs/assets/images/tutorials/binary_vs_multiclass/BinaryVsMulticlass.avif b/docs/assets/images/tutorials/binary_vs_multiclass/BinaryVsMulticlass.avif
new file mode 100644
index 0000000..e374192
Binary files /dev/null and b/docs/assets/images/tutorials/binary_vs_multiclass/BinaryVsMulticlass.avif differ
diff --git a/docs/assets/images/tutorials/binary_vs_multiclass/BinaryVsMulticlassDark.avif b/docs/assets/images/tutorials/binary_vs_multiclass/BinaryVsMulticlassDark.avif
new file mode 100644
index 0000000..410c810
Binary files /dev/null and b/docs/assets/images/tutorials/binary_vs_multiclass/BinaryVsMulticlassDark.avif differ
diff --git a/docs/assets/images/tutorials/long_wide_reshape/LongToWide.avif b/docs/assets/images/tutorials/long_wide_reshape/LongToWide.avif
new file mode 100644
index 0000000..603fbae
Binary files /dev/null and b/docs/assets/images/tutorials/long_wide_reshape/LongToWide.avif differ
diff --git a/docs/assets/images/tutorials/long_wide_reshape/LongToWide.gif b/docs/assets/images/tutorials/long_wide_reshape/LongToWide.gif
deleted file mode 100644
index abacd2f..0000000
Binary files a/docs/assets/images/tutorials/long_wide_reshape/LongToWide.gif and /dev/null differ
diff --git a/docs/assets/images/tutorials/long_wide_reshape/LongToWideDark.avif b/docs/assets/images/tutorials/long_wide_reshape/LongToWideDark.avif
new file mode 100644
index 0000000..2712589
Binary files /dev/null and b/docs/assets/images/tutorials/long_wide_reshape/LongToWideDark.avif differ
diff --git a/docs/assets/images/tutorials/long_wide_reshape/WideToLong.avif b/docs/assets/images/tutorials/long_wide_reshape/WideToLong.avif
new file mode 100644
index 0000000..4c8b083
Binary files /dev/null and b/docs/assets/images/tutorials/long_wide_reshape/WideToLong.avif differ
diff --git a/docs/assets/images/tutorials/long_wide_reshape/WideToLong.gif b/docs/assets/images/tutorials/long_wide_reshape/WideToLong.gif
deleted file mode 100644
index 126645d..0000000
Binary files a/docs/assets/images/tutorials/long_wide_reshape/WideToLong.gif and /dev/null differ
diff --git a/docs/assets/images/tutorials/long_wide_reshape/WideToLongDark.avif b/docs/assets/images/tutorials/long_wide_reshape/WideToLongDark.avif
new file mode 100644
index 0000000..49ff781
Binary files /dev/null and b/docs/assets/images/tutorials/long_wide_reshape/WideToLongDark.avif differ
diff --git a/docs/assets/images/tutorials/sklong_data_preparation_first_exploration/AggrFuncFlatten.avif b/docs/assets/images/tutorials/sklong_data_preparation_first_exploration/AggrFuncFlatten.avif
new file mode 100644
index 0000000..6b23e5e
Binary files /dev/null and b/docs/assets/images/tutorials/sklong_data_preparation_first_exploration/AggrFuncFlatten.avif differ
diff --git a/docs/assets/images/tutorials/sklong_data_preparation_first_exploration/AggrFuncFlattenDark.avif b/docs/assets/images/tutorials/sklong_data_preparation_first_exploration/AggrFuncFlattenDark.avif
new file mode 100644
index 0000000..4fb565b
Binary files /dev/null and b/docs/assets/images/tutorials/sklong_data_preparation_first_exploration/AggrFuncFlattenDark.avif differ
diff --git a/docs/assets/images/tutorials/sklong_explore_your_first_estimator/LexicoRecency.avif b/docs/assets/images/tutorials/sklong_explore_your_first_estimator/LexicoRecency.avif
new file mode 100644
index 0000000..f48d370
Binary files /dev/null and b/docs/assets/images/tutorials/sklong_explore_your_first_estimator/LexicoRecency.avif differ
diff --git a/docs/assets/images/tutorials/sklong_explore_your_first_estimator/LexicoRecencyDark.avif b/docs/assets/images/tutorials/sklong_explore_your_first_estimator/LexicoRecencyDark.avif
new file mode 100644
index 0000000..df17cb8
Binary files /dev/null and b/docs/assets/images/tutorials/sklong_explore_your_first_estimator/LexicoRecencyDark.avif differ
diff --git a/docs/assets/images/tutorials/sklong_explore_your_first_pipeline/PipelineChain.avif b/docs/assets/images/tutorials/sklong_explore_your_first_pipeline/PipelineChain.avif
new file mode 100644
index 0000000..11751c7
Binary files /dev/null and b/docs/assets/images/tutorials/sklong_explore_your_first_pipeline/PipelineChain.avif differ
diff --git a/docs/assets/images/tutorials/sklong_explore_your_first_pipeline/PipelineChainDark.avif b/docs/assets/images/tutorials/sklong_explore_your_first_pipeline/PipelineChainDark.avif
new file mode 100644
index 0000000..250dcf8
Binary files /dev/null and b/docs/assets/images/tutorials/sklong_explore_your_first_pipeline/PipelineChainDark.avif differ
diff --git a/docs/assets/images/tutorials/sklong_hyperparameter_tuning/GridVsRandom.avif b/docs/assets/images/tutorials/sklong_hyperparameter_tuning/GridVsRandom.avif
new file mode 100644
index 0000000..9be294b
Binary files /dev/null and b/docs/assets/images/tutorials/sklong_hyperparameter_tuning/GridVsRandom.avif differ
diff --git a/docs/assets/images/tutorials/sklong_hyperparameter_tuning/GridVsRandomDark.avif b/docs/assets/images/tutorials/sklong_hyperparameter_tuning/GridVsRandomDark.avif
new file mode 100644
index 0000000..ffa5bb1
Binary files /dev/null and b/docs/assets/images/tutorials/sklong_hyperparameter_tuning/GridVsRandomDark.avif differ
diff --git a/docs/assets/images/tutorials/sklong_longitudinal_data_format/WideVsLongLeakage.avif b/docs/assets/images/tutorials/sklong_longitudinal_data_format/WideVsLongLeakage.avif
new file mode 100644
index 0000000..1361390
Binary files /dev/null and b/docs/assets/images/tutorials/sklong_longitudinal_data_format/WideVsLongLeakage.avif differ
diff --git a/docs/assets/images/tutorials/sklong_longitudinal_data_format/WideVsLongLeakageDark.avif b/docs/assets/images/tutorials/sklong_longitudinal_data_format/WideVsLongLeakageDark.avif
new file mode 100644
index 0000000..a3bcc66
Binary files /dev/null and b/docs/assets/images/tutorials/sklong_longitudinal_data_format/WideVsLongLeakageDark.avif differ
diff --git a/docs/assets/images/tutorials/temporal_dependency/FeaturesGroupBuilder.avif b/docs/assets/images/tutorials/temporal_dependency/FeaturesGroupBuilder.avif
new file mode 100644
index 0000000..4f42af7
Binary files /dev/null and b/docs/assets/images/tutorials/temporal_dependency/FeaturesGroupBuilder.avif differ
diff --git a/docs/assets/images/tutorials/temporal_dependency/FeaturesGroupBuilderDark.avif b/docs/assets/images/tutorials/temporal_dependency/FeaturesGroupBuilderDark.avif
new file mode 100644
index 0000000..f1bc4a4
Binary files /dev/null and b/docs/assets/images/tutorials/temporal_dependency/FeaturesGroupBuilderDark.avif differ
diff --git a/docs/tutorials/advanced_temporal_setup.md b/docs/tutorials/advanced_temporal_setup.md
index 61287b4..b3826b8 100644
--- a/docs/tutorials/advanced_temporal_setup.md
+++ b/docs/tutorials/advanced_temporal_setup.md
@@ -14,6 +14,14 @@ others have 4). In `Sklong`, the recommended approach is:
This tutorial shows how to do that in practice.
+The animation below summarises the end state you are aiming for: NaN cells for visits that did not take place, and `-1` padding inside `features_group` only when an entire wave column is absent from the schedule.
+
+
+ [{ width="100%" loading="lazy" }](../assets/images/tutorials/advanced_temporal_setup/UnevenWavesPadding.avif){ .expandable-media__trigger }
+ [{ width="100%" loading="lazy" }](../assets/images/tutorials/advanced_temporal_setup/UnevenWavesPaddingDark.avif){ .expandable-media__trigger }
+ Click the image to expand it.
+
+
## Step 1: Start from a long table (uneven observations) —— Optional
A long-format dataset makes it easy to describe variable visit counts, but it is not what `Sklong` consumes directly.
diff --git a/docs/tutorials/binary_vs_multiclass.md b/docs/tutorials/binary_vs_multiclass.md
index ed8e33e..8d49719 100644
--- a/docs/tutorials/binary_vs_multiclass.md
+++ b/docs/tutorials/binary_vs_multiclass.md
@@ -25,6 +25,14 @@ The estimators below support both binary and multiclass targets:
- `NestedTreesClassifier`
- `SepWav` with voting or stacking
+The animation below summarises what actually changes between the two settings: the fitting workflow is identical, `classes_` simply lists every observed label, and `predict_proba` grows one extra column per added class.
+
+
+ [{ width="100%" loading="lazy" }](../assets/images/tutorials/binary_vs_multiclass/BinaryVsMulticlass.avif){ .expandable-media__trigger }
+ [{ width="100%" loading="lazy" }](../assets/images/tutorials/binary_vs_multiclass/BinaryVsMulticlassDark.avif){ .expandable-media__trigger }
+ Click the image to expand it.
+
+
## Step 1: Binary classification
This first example uses the original `stroke_w2` target from the tutorial dataset.
diff --git a/docs/tutorials/long_wide_reshape.md b/docs/tutorials/long_wide_reshape.md
index eeb460f..c595c74 100644
--- a/docs/tutorials/long_wide_reshape.md
+++ b/docs/tutorials/long_wide_reshape.md
@@ -41,7 +41,8 @@ long_df = pd.DataFrame({
The animation below walks through every long-format row and shows where each value lands in the wide matrix.
- [{ width="100%" loading="lazy" }](../assets/images/tutorials/long_wide_reshape/LongToWide.gif){ .expandable-media__trigger }
+ [{ width="100%" loading="lazy" }](../assets/images/tutorials/long_wide_reshape/LongToWide.avif){ .expandable-media__trigger }
+ [{ width="100%" loading="lazy" }](../assets/images/tutorials/long_wide_reshape/LongToWideDark.avif){ .expandable-media__trigger }
Click the image to expand it.
@@ -99,7 +100,8 @@ A few things to notice:
The other direction, displays as follows:
- [{ width="100%" loading="lazy" }](../assets/images/tutorials/long_wide_reshape/WideToLong.gif){ .expandable-media__trigger }
+ [{ width="100%" loading="lazy" }](../assets/images/tutorials/long_wide_reshape/WideToLong.avif){ .expandable-media__trigger }
+ [{ width="100%" loading="lazy" }](../assets/images/tutorials/long_wide_reshape/WideToLongDark.avif){ .expandable-media__trigger }
Click the image to expand it.
diff --git a/docs/tutorials/overview.md b/docs/tutorials/overview.md
index c10302c..3eddd94 100644
--- a/docs/tutorials/overview.md
+++ b/docs/tutorials/overview.md
@@ -28,14 +28,6 @@ In order to visualise what the library delivers, the figure below shows the high
[Read the tutorial](temporal_dependency.md)
-- __Advanced Feature Group (Temporal) Setup__
-
- ---
-
- Handle uneven numbers of observations per subject, including missing waves and padded feature groups.
-
- [Read the tutorial](advanced_temporal_setup.md)
-
- __Longitudinal Data Format__
---
@@ -52,6 +44,14 @@ In order to visualise what the library delivers, the figure below shows the high
[Read the tutorial](long_wide_reshape.md)
+- __Advanced Feature Group (Temporal) Setup__
+
+ ---
+
+ Handle uneven numbers of observations per subject, including missing waves and padded feature groups.
+
+ [Read the tutorial](advanced_temporal_setup.md)
+
- __Data Preparation: Flatten Temporal Dependency for Scikit-Learn Estimators__
---
diff --git a/docs/tutorials/sklong_data_preparation_first_exploration.md b/docs/tutorials/sklong_data_preparation_first_exploration.md
index 8959164..a3be69e 100644
--- a/docs/tutorials/sklong_data_preparation_first_exploration.md
+++ b/docs/tutorials/sklong_data_preparation_first_exploration.md
@@ -9,6 +9,14 @@ icon: lucide/database-zap
Data-preparation workflows flatten longitudinal structure so you can plug the output into standard `scikit-learn` estimators. Follow this step-by-step path with [`AggrFunc`](../API/data_preparation/aggregation_function.md) (mean aggregation) and `LogisticRegression`—no longitudinal-specific pipeline required.
+The animation below shows the intuition: each longitudinal group (e.g. all `smoke_*` columns) collapses into a single static column, so the output is a plain tabular matrix ready for any scikit-learn estimator.
+
+
+ [{ width="100%" loading="lazy" }](../assets/images/tutorials/sklong_data_preparation_first_exploration/AggrFuncFlatten.avif){ .expandable-media__trigger }
+ [{ width="100%" loading="lazy" }](../assets/images/tutorials/sklong_data_preparation_first_exploration/AggrFuncFlattenDark.avif){ .expandable-media__trigger }
+ Click the image to expand it.
+
+
## Step 1: Load data and define temporal dependencies
```python
diff --git a/docs/tutorials/sklong_explore_your_first_estimator.md b/docs/tutorials/sklong_explore_your_first_estimator.md
index 06c96fa..30a1e91 100644
--- a/docs/tutorials/sklong_explore_your_first_estimator.md
+++ b/docs/tutorials/sklong_explore_your_first_estimator.md
@@ -9,6 +9,14 @@ icon: lucide/activity
Algorithm-adaptation workflows keep temporal structure intact. This walkthrough uses [`LexicoDecisionTreeClassifier`](../API/estimators/trees/lexico_decision_tree_classifier.md), which prioritises recent waves while respecting the full sequence.
+The animation below gives the intuition behind the split rule: when several candidate waves of the same attribute yield near-identical information gains (within `threshold_gain`), the lexicographic tree picks the **most recent** one rather than the classical "largest gain wins" tie-break.
+
+
+ [{ width="100%" loading="lazy" }](../assets/images/tutorials/sklong_explore_your_first_estimator/LexicoRecency.avif){ .expandable-media__trigger }
+ [{ width="100%" loading="lazy" }](../assets/images/tutorials/sklong_explore_your_first_estimator/LexicoRecencyDark.avif){ .expandable-media__trigger }
+ Click the image to expand it.
+
+
## Step 1: Load and prepare data
```python
diff --git a/docs/tutorials/sklong_explore_your_first_pipeline.md b/docs/tutorials/sklong_explore_your_first_pipeline.md
index 0519735..c1c872d 100644
--- a/docs/tutorials/sklong_explore_your_first_pipeline.md
+++ b/docs/tutorials/sklong_explore_your_first_pipeline.md
@@ -9,6 +9,14 @@ icon: lucide/workflow
Pipelines let you chain longitudinal transformations, preprocessing, and estimation in one interface.
+The animation below illustrates the key contract that makes this work: `features_group` travels alongside `X` through every step, and `update_feature_groups_callback` rewrites those indices whenever a step reshapes the matrix — so the final estimator still sees a coherent temporal structure.
+
+
+ [{ width="100%" loading="lazy" }](../assets/images/tutorials/sklong_explore_your_first_pipeline/PipelineChain.avif){ .expandable-media__trigger }
+ [{ width="100%" loading="lazy" }](../assets/images/tutorials/sklong_explore_your_first_pipeline/PipelineChainDark.avif){ .expandable-media__trigger }
+ Click the image to expand it.
+
+
## Load and prepare the dataset
Using `extended_stroke_longitudinal.csv`:
diff --git a/docs/tutorials/sklong_hyperparameter_tuning.md b/docs/tutorials/sklong_hyperparameter_tuning.md
index 069e6d0..dd45035 100644
--- a/docs/tutorials/sklong_hyperparameter_tuning.md
+++ b/docs/tutorials/sklong_hyperparameter_tuning.md
@@ -9,6 +9,14 @@ icon: lucide/sliders-horizontal
Tune longitudinal-aware models to squeeze out extra performance. This guide compares grid search and random search for `LexicoRandomForestClassifier`, focusing on `threshold_gain` plus common random-forest hyperparameters.
+The animation below summarises the contrast: grid search sweeps a regular lattice of hyperparameter combinations (thorough but expensive), while random search scatters samples across the same plane and, in practice, often lands inside high-performing regions that a coarse grid would miss.
+
+
+ [{ width="100%" loading="lazy" }](../assets/images/tutorials/sklong_hyperparameter_tuning/GridVsRandom.avif){ .expandable-media__trigger }
+ [{ width="100%" loading="lazy" }](../assets/images/tutorials/sklong_hyperparameter_tuning/GridVsRandomDark.avif){ .expandable-media__trigger }
+ Click the image to expand it.
+
+
## Step 1: Load data and define temporal dependencies
```python
diff --git a/docs/tutorials/sklong_longitudinal_data_format.md b/docs/tutorials/sklong_longitudinal_data_format.md
index b65e479..bcbc52a 100644
--- a/docs/tutorials/sklong_longitudinal_data_format.md
+++ b/docs/tutorials/sklong_longitudinal_data_format.md
@@ -11,6 +11,14 @@ This tutorial introduces the data formats supported by Scikit-Longitudinal (`Skl
## Wide vs. Long Format
+The animation below contrasts the two layouts at split time: a long-format split can cut through a single subject's rows and leak wave-level information across train/test, while a wide-format split always keeps one subject on one side.
+
+
+ [{ width="100%" loading="lazy" }](../assets/images/tutorials/sklong_longitudinal_data_format/WideVsLongLeakage.avif){ .expandable-media__trigger }
+ [{ width="100%" loading="lazy" }](../assets/images/tutorials/sklong_longitudinal_data_format/WideVsLongLeakageDark.avif){ .expandable-media__trigger }
+ Click the image to expand it.
+
+
Longitudinal data can be represented in two main formats:
- **Long Format**: Each observation for a subject is in a separate row, with a time indicator column. This can lead to data leakage during splitting if rows for the same subject are separated.
@@ -19,9 +27,6 @@ Longitudinal data can be represented in two main formats:
`Sklong` focuses on wide format for safety and simplicity in machine learning workflows.
-!!! tip "Converting Formats"
- If your data is in long format, pivot it to wide using pandas: `df.pivot(index='subject_id', columns='time', values='feature')`. Open an issue if you need built-in support.
-
## Synthetic Dataset Example
The dataset used is synthetic, mimicking health data for illustration.
@@ -45,3 +50,6 @@ print(dataset.data.head())
```
This wide format ensures safe splitting and temporal integrity.
+
+!!! tip "Need to convert from long to wide?"
+ See the dedicated [Long ⇄ Wide Reshape](long_wide_reshape.md) tutorial for a step-by-step walkthrough — including the recommended pandas pivot, handling uneven waves, and going back the other way.
diff --git a/docs/tutorials/temporal_dependency.md b/docs/tutorials/temporal_dependency.md
index ca34dc3..4cbc031 100644
--- a/docs/tutorials/temporal_dependency.md
+++ b/docs/tutorials/temporal_dependency.md
@@ -50,6 +50,14 @@ without worrying about temporal dependencies. The primitives will handle this ba
## Understanding `features_group`
+Before the formal definition, here is the same idea in one pass: a wide-format table, with each longitudinal attribute's columns collapsed into one inner list of indices (oldest → most recent), and static covariates kept aside in `non_longitudinal_features`.
+
+
+ [{ width="100%" loading="lazy" }](../assets/images/tutorials/temporal_dependency/FeaturesGroupBuilder.avif){ .expandable-media__trigger }
+ [{ width="100%" loading="lazy" }](../assets/images/tutorials/temporal_dependency/FeaturesGroupBuilderDark.avif){ .expandable-media__trigger }
+ Click the image to expand it.
+
+
`features_group` is a list of lists of integers, with each inner list representing a group of features for a specific
longitudinal variable. The inner lists' indices are ordered by wave/time-point sequence, capturing the
temporal dependencies required for longitudinal data algorithms.
diff --git a/zensical.toml b/zensical.toml
index 2e48c8b..708915d 100644
--- a/zensical.toml
+++ b/zensical.toml
@@ -23,9 +23,9 @@ nav = [
{ "Tutorials" = [
{ "Overview" = "tutorials/overview.md" },
{ "Temporal Dependency" = "tutorials/temporal_dependency.md" },
- { "Uneven Temporal Setup" = "tutorials/advanced_temporal_setup.md" },
{ "Data Format" = "tutorials/sklong_longitudinal_data_format.md" },
{ "Long ⇄ Wide Reshape" = "tutorials/long_wide_reshape.md" },
+ { "Uneven Temporal Setup" = "tutorials/advanced_temporal_setup.md" },
{ "Data Preparation" = "tutorials/sklong_data_preparation_first_exploration.md" },
{ "Algorithm Adaptation" = "tutorials/sklong_explore_your_first_estimator.md" },
{ "Binary & Multiclass" = "tutorials/binary_vs_multiclass.md" },