refactor: use svd_labels for fallback labels in explorer and axis_classifier (Task 4)

main
Sven Geboers 4 weeks ago
parent 36b58ad50d
commit 5b3cf23d36
  1. 27
      analysis/axis_classifier.py
  2. 9
      explorer.py
  3. 52
      tests/test_axis_label_fallback.py

@ -13,7 +13,7 @@ import numpy as np
import re
import json
from analysis.svd_labels import get_svd_label
from analysis.svd_labels import get_svd_label, get_fallback_labels
_logger = logging.getLogger(__name__)
@ -44,16 +44,21 @@ _LABELS = {
def display_label_for_modal(modal_label: Optional[str], axis: str) -> str:
"""Return a user-facing axis label for a modal/internal label.
Keeps existing behavior: map numeric fallback names 'As 1' / 'Stempatroon As 1'
to the conventional semantic defaults used in the UI. Any other label is
returned unchanged; None is treated as the semantic fallback for the axis.
Maps numeric fallback names 'As 1' / 'Stempatroon As 1' to the
semantic labels from SVD_THEMES. Any other label is returned unchanged.
None is treated as the semantic fallback for the axis.
"""
if modal_label is None:
return "Links\u2013Rechts" if axis == "x" else "Progressief\u2013Conservatief"
# Fallback to component 1 (x) or 2 (y)
comp = 1 if axis == "x" else 2
return get_svd_label(comp)
# Map "As 1" / "As 2" to semantic labels
if axis == "x" and modal_label in ("As 1", "Stempatroon As 1"):
return "Links\u2013Rechts"
return get_svd_label(1)
if axis == "y" and modal_label in ("As 2", "Stempatroon As 2"):
return "Progressief\u2013Conservatief"
return get_svd_label(2)
return modal_label
@ -430,7 +435,8 @@ def _assign_label(
Returns (label, interpretation_string, quality_score).
"""
orientation = "horizontale" if axis == "x" else "verticale"
fallback_label = _LABELS["fallback_x"] if axis == "x" else _LABELS["fallback_y"]
_x_fallback, _y_fallback = get_fallback_labels()
fallback_label = _x_fallback if axis == "x" else _y_fallback
quality = max(abs(r_lr), abs(r_co), abs(r_pc))
if abs(r_lr) >= _THRESHOLD:
@ -608,13 +614,14 @@ def classify_axes(
# ── Final label resolution ────────────────────────────────────────────
# If both motion and ideology paths produced nothing, use generic fallback.
_x_fallback, _y_fallback = get_fallback_labels()
if x_lbl is None:
x_lbl = _LABELS["fallback_x"]
x_lbl = _x_fallback
x_int = _INTERPRETATION_TEMPLATES["fallback"].format(
orientation="horizontale"
)
if y_lbl is None:
y_lbl = _LABELS["fallback_y"]
y_lbl = _y_fallback
y_int = _INTERPRETATION_TEMPLATES["fallback"].format(
orientation="verticale"
)

@ -1612,15 +1612,18 @@ def build_compass_tab(db_path: str, window_size: str) -> None:
# Use the classifier helper to map internal/modal labels (e.g. "As 1") to
# user-facing labels. Import at function-time to avoid module import cycles
# and keep explorer lightweight. If the helper is unavailable fall back to
# conventional semantic defaults so the UI remains readable.
# labels from the unified svd_labels module.
try:
from analysis.axis_classifier import display_label_for_modal
_x_label = display_label_for_modal(_raw_x, "x")
_y_label = display_label_for_modal(_raw_y, "y")
except Exception:
_x_label = _raw_x or "EU-integratie–Nationalisme"
_y_label = _raw_y or "Populistisch–Institutioneel"
from analysis.svd_labels import get_fallback_labels
_x_fallback, _y_fallback = get_fallback_labels()
_x_label = _raw_x or _x_fallback
_y_label = _raw_y or _y_fallback
if level == "Partijen":
# Aggregate to party centroids

@ -4,21 +4,34 @@ from analysis import axis_classifier
def test_display_label_for_modal():
assert axis_classifier.display_label_for_modal("As 1", "x") == "Links\u2013Rechts"
assert (
axis_classifier.display_label_for_modal("Stempatroon As 1", "x")
== "Links\u2013Rechts"
)
assert (
axis_classifier.display_label_for_modal("As 2", "y")
== "Conservatief\u2013Progressief"
)
assert (
axis_classifier.display_label_for_modal("Stempatroon As 2", "y")
== "Conservatief\u2013Progressief"
)
# None maps to conventional fallback
assert axis_classifier.display_label_for_modal(None, "x") == "Links\u2013Rechts"
"""Test that display_label_for_modal uses SVD_THEMES for fallback labels."""
# None should return fallback from SVD_THEMES
x_label = axis_classifier.display_label_for_modal(None, "x")
y_label = axis_classifier.display_label_for_modal(None, "y")
# Should return component 1 and 2 labels from SVD_THEMES
assert "EU-integratie" in x_label or "Nationalisme" in x_label
assert "Populistisch" in y_label or "Institutioneel" in y_label
def test_display_label_for_modal_maps_as_labels():
"""Test that 'As 1' and 'As 2' are mapped to semantic labels."""
x_label = axis_classifier.display_label_for_modal("As 1", "x")
y_label = axis_classifier.display_label_for_modal("As 2", "y")
# Should return component 1 and 2 labels
assert "EU-integratie" in x_label or "Nationalisme" in x_label
assert "Populistisch" in y_label or "Institutioneel" in y_label
def test_display_label_for_modal_stempatroon():
"""Test that 'Stempatroon As N' are mapped to semantic labels."""
x_label = axis_classifier.display_label_for_modal("Stempatroon As 1", "x")
y_label = axis_classifier.display_label_for_modal("Stempatroon As 2", "y")
# Should return component 1 and 2 labels
assert "EU-integratie" in x_label or "Nationalisme" in x_label
assert "Populistisch" in y_label or "Institutioneel" in y_label
def test_classify_axes_modal_fallback(monkeypatch, tmp_path):
@ -69,5 +82,10 @@ def test_classify_axes_modal_fallback(monkeypatch, tmp_path):
if not enriched or not isinstance(enriched, dict):
pytest.skip("classify_axes returned no enrichment in this environment")
assert enriched["x_label"] == "Links\u2013Rechts"
assert enriched["y_label"] == "Progressief\u2013Conservatief"
# Should now return SVD component labels instead of hardcoded values
assert (
"EU-integratie" in enriched["x_label"] or "Nationalisme" in enriched["x_label"]
)
assert (
"Populistisch" in enriched["y_label"] or "Institutioneel" in enriched["y_label"]
)

Loading…
Cancel
Save