feat: persist and load explained variance for scree plots

- compute_svd_for_window now computes explained variance ratio (s²/sum(s²))
  and appends it as a metadata row (entity_type='metadata',
  entity_id='explained_variance') to motion_rows
- load_scree_data reads this metadata row from svd_vectors instead of
  querying the non-existent sv_metadata column
- run_svd_for_window counts only entity_type='motion' rows in stored_motion
  so metadata rows don't inflate the count
- Added 5 TDD tests covering load, compute, store, and round-trip

All 227 tests pass.
This commit is contained in:
2026-05-01 10:34:31 +02:00
parent 121c32ae8a
commit 6e36fa2604
3 changed files with 267 additions and 8 deletions
+8 -1
View File
@@ -409,11 +409,16 @@ def compute_svd_for_window(
for j, mid in enumerate(motion_ids)
]
# Persist explained variance ratio as a metadata row for scree plots
evr = (s ** 2 / np.sum(s ** 2)).tolist()
motion_rows.append(("metadata", "explained_variance", evr, None))
return {
"window_id": window_id,
"k_used": k_used,
"mp_rows": mp_rows,
"motion_rows": motion_rows,
"explained_variance": evr,
}
except Exception:
@@ -438,8 +443,10 @@ def run_svd_for_window(
rows = result["mp_rows"] + result["motion_rows"]
stored = db.batch_store_svd_vectors(window_id, rows)
# motion_rows may include metadata rows (e.g. explained_variance)
motion_entity_rows = [r for r in result["motion_rows"] if r[0] == "motion"]
return {
"k_used": result["k_used"],
"stored_mp": len(result["mp_rows"]),
"stored_motion": len(result["motion_rows"]),
"stored_motion": len(motion_entity_rows),
}