fix: resolve SVD axis label alignment and score mismatch in tijdtraject view

Two related bugs fixed:

1. Label alignment: Removed static left_pole/right_pole from SVD_THEMES
   entries. These labels assumed a fixed flip direction but could mismatch
   with runtime flip computation, causing right-wing parties to appear on
   the wrong side. Labels are now always derived from positive_pole,
   negative_pole, and the runtime flip direction.

2. Score mismatch: Changed tijdtraject view for components 3-10 from
   load_party_scores_all_windows_aligned() to load_party_scores_all_windows().
   Procrustes alignment rotates the full 50-dim vector space to align
   components 1-2, but this also transforms components 3-10, making their
   scores incomparable with the single-window view. Per-window flip
   computation already handles orientation alignment for these components.

Also updated svd_labels.py to prefer analysis.config as the canonical
source for SVD_THEMES, falling back to explorer only when config is
unavailable.
This commit is contained in:
2026-04-12 21:02:28 +02:00
parent 54489b6a30
commit 823df6f9ee
4 changed files with 33 additions and 47 deletions
+3 -10
View File
@@ -201,9 +201,8 @@ def check_theme_consistency(
) -> List[Dict]:
"""Check that theme pole labels are consistent with actual party positions.
Note: left_pole/right_pole describe the SEMANTIC left/right after flip,
not the political left/right spectrum. This check verifies that the
parties mentioned in each pole are actually on the expected side.
Note: positive_pole/negative_pole describe the SVD axis orientation.
Labels are derived at runtime from flip direction.
Returns list of divergence reports.
"""
@@ -276,13 +275,7 @@ def main() -> int:
print(f" Diff (post-flip R - L): {d['diff']:.4f}")
print(f" Right scores: {d['right_scores']}")
print(f" Left scores: {d['left_scores']}")
elif d["issue"] == "theme_pole_mismatch":
print(f" Label: {d.get('label', '')}")
print(f" Left pole: {d['left_pole']}")
print(f" Right pole: {d['right_pole']}")
print(f" Left mean: {d['left_mean']:.4f} ({d['left_parties']})")
print(f" Right mean: {d['right_mean']:.4f} ({d['right_parties']})")
print(f" Diff (left - right): {d['diff']:.4f}")
elif d["issue"] == "missing_canonical_party_data":
print(f" Expected right: {canonical_right}")
print(f" Expected left: {canonical_left}")