fix: use CANONICAL_LEFT/RIGHT in compass PCA for consistency with SVD components tab
Previously the compass (political_axis.py) used hardcoded party sets that excluded Volt and PvdD, while the SVD components tab (svd_labels.py) used CANONICAL_LEFT/RIGHT which includes them. This caused inconsistencies in axis orientation where Volt appeared most left on the compass but PvdD appeared most left in the SVD components visualization. Changes: - Import CANONICAL_LEFT/RIGHT from config in political_axis.py - Replace hardcoded party sets with CANONICAL_LEFT/RIGHT for axis orientation - Update tests to match new SVD_THEMES labels
This commit is contained in:
+14
-29
@@ -24,6 +24,13 @@ try:
|
|||||||
except Exception: # pragma: no cover - allow importing module in lightweight test envs
|
except Exception: # pragma: no cover - allow importing module in lightweight test envs
|
||||||
duckdb = None # type: ignore
|
duckdb = None # type: ignore
|
||||||
|
|
||||||
|
# Import canonical party sets from config for consistent orientation with SVD components tab
|
||||||
|
try:
|
||||||
|
from .config import CANONICAL_LEFT, CANONICAL_RIGHT
|
||||||
|
except Exception: # pragma: no cover - fallback for test environments
|
||||||
|
CANONICAL_LEFT: frozenset = frozenset()
|
||||||
|
CANONICAL_RIGHT: frozenset = frozenset()
|
||||||
|
|
||||||
_logger = logging.getLogger(__name__)
|
_logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
@@ -262,35 +269,13 @@ def compute_2d_axes(
|
|||||||
}
|
}
|
||||||
|
|
||||||
# Canonical party sets used for axis orientation (global and per-window).
|
# Canonical party sets used for axis orientation (global and per-window).
|
||||||
# Defined outside the try-block so they're always in scope.
|
# Use CANONICAL_LEFT/RIGHT from config for consistency with SVD components tab.
|
||||||
right_parties = {
|
# X-axis: CANONICAL_RIGHT (right) vs CANONICAL_LEFT (left)
|
||||||
"PVV",
|
# Y-axis: CANONICAL_LEFT (progressive) vs cons_parties (conservative)
|
||||||
"VVD",
|
right_parties = CANONICAL_RIGHT
|
||||||
"FVD",
|
left_parties = CANONICAL_LEFT
|
||||||
"BBB",
|
cons_parties = CANONICAL_RIGHT # Conservative = right-leaning parties
|
||||||
"JA21",
|
prog_parties = CANONICAL_LEFT # Progressive = left-leaning parties
|
||||||
"Nieuw Sociaal Contract",
|
|
||||||
}
|
|
||||||
left_parties = {"SP", "PvdA", "GL", "GroenLinks", "GroenLinks-PvdA", "DENK"}
|
|
||||||
cons_parties = {
|
|
||||||
"PVV",
|
|
||||||
"VVD",
|
|
||||||
"FVD",
|
|
||||||
"CDA",
|
|
||||||
"SGP",
|
|
||||||
"BBB",
|
|
||||||
"JA21",
|
|
||||||
"Nieuw Sociaal Contract",
|
|
||||||
}
|
|
||||||
prog_parties = {
|
|
||||||
"GL",
|
|
||||||
"GroenLinks",
|
|
||||||
"PvdA",
|
|
||||||
"PvdD",
|
|
||||||
"SP",
|
|
||||||
"GroenLinks-PvdA",
|
|
||||||
"DENK",
|
|
||||||
}
|
|
||||||
|
|
||||||
# Ensure consistent left/right and progressive/conservative orientation
|
# Ensure consistent left/right and progressive/conservative orientation
|
||||||
# by checking canonical party centroids and flipping axis signs if needed.
|
# by checking canonical party centroids and flipping axis signs if needed.
|
||||||
|
|||||||
@@ -10,8 +10,12 @@ def test_display_label_for_modal():
|
|||||||
y_label = axis_classifier.display_label_for_modal(None, "y")
|
y_label = axis_classifier.display_label_for_modal(None, "y")
|
||||||
|
|
||||||
# Should return component 1 and 2 labels from SVD_THEMES
|
# Should return component 1 and 2 labels from SVD_THEMES
|
||||||
assert "Rechts versus links" in x_label or "links" in x_label.lower()
|
# SVD_THEMES[0] = "Economische sectorbelangen versus sociale welvaart"
|
||||||
assert "Nationalistisch" in y_label or "kosmopolitisch" in y_label
|
# SVD_THEMES[1] = "Nationalistische versus multilateralistische oriëntatie"
|
||||||
|
assert (
|
||||||
|
"Economische sectorbelangen" in x_label or "sectorbelangen" in x_label.lower()
|
||||||
|
)
|
||||||
|
assert "Nationalistisch" in y_label or "nationalistisch" in y_label.lower()
|
||||||
|
|
||||||
|
|
||||||
def test_display_label_for_modal_maps_as_labels():
|
def test_display_label_for_modal_maps_as_labels():
|
||||||
@@ -19,9 +23,11 @@ def test_display_label_for_modal_maps_as_labels():
|
|||||||
x_label = axis_classifier.display_label_for_modal("As 1", "x")
|
x_label = axis_classifier.display_label_for_modal("As 1", "x")
|
||||||
y_label = axis_classifier.display_label_for_modal("As 2", "y")
|
y_label = axis_classifier.display_label_for_modal("As 2", "y")
|
||||||
|
|
||||||
# Should return component 1 and 2 labels
|
# Should return component 1 and 2 labels from SVD_THEMES
|
||||||
assert "Rechts versus links" in x_label or "links" in x_label.lower()
|
assert (
|
||||||
assert "Nationalistisch" in y_label or "kosmopolitisch" in y_label
|
"Economische sectorbelangen" in x_label or "sectorbelangen" in x_label.lower()
|
||||||
|
)
|
||||||
|
assert "Nationalistisch" in y_label or "nationalistisch" in y_label.lower()
|
||||||
|
|
||||||
|
|
||||||
def test_display_label_for_modal_stempatroon():
|
def test_display_label_for_modal_stempatroon():
|
||||||
@@ -29,9 +35,11 @@ def test_display_label_for_modal_stempatroon():
|
|||||||
x_label = axis_classifier.display_label_for_modal("Stempatroon As 1", "x")
|
x_label = axis_classifier.display_label_for_modal("Stempatroon As 1", "x")
|
||||||
y_label = axis_classifier.display_label_for_modal("Stempatroon As 2", "y")
|
y_label = axis_classifier.display_label_for_modal("Stempatroon As 2", "y")
|
||||||
|
|
||||||
# Should return component 1 and 2 labels
|
# Should return component 1 and 2 labels from SVD_THEMES
|
||||||
assert "Rechts versus links" in x_label or "links" in x_label.lower()
|
assert (
|
||||||
assert "Nationalistisch" in y_label or "kosmopolitisch" in y_label
|
"Economische sectorbelangen" in x_label or "sectorbelangen" in x_label.lower()
|
||||||
|
)
|
||||||
|
assert "Nationalistisch" in y_label or "nationalistisch" in y_label.lower()
|
||||||
|
|
||||||
|
|
||||||
def test_classify_axes_modal_fallback(monkeypatch, tmp_path):
|
def test_classify_axes_modal_fallback(monkeypatch, tmp_path):
|
||||||
@@ -82,12 +90,12 @@ def test_classify_axes_modal_fallback(monkeypatch, tmp_path):
|
|||||||
if not enriched or not isinstance(enriched, dict):
|
if not enriched or not isinstance(enriched, dict):
|
||||||
pytest.skip("classify_axes returned no enrichment in this environment")
|
pytest.skip("classify_axes returned no enrichment in this environment")
|
||||||
|
|
||||||
# Should now return SVD component labels instead of hardcoded values
|
# Should now return SVD component labels from SVD_THEMES
|
||||||
assert (
|
assert (
|
||||||
"Rechts versus links" in enriched["x_label"]
|
"Economische sectorbelangen" in enriched["x_label"]
|
||||||
or "links" in enriched["x_label"].lower()
|
or "sectorbelangen" in enriched["x_label"].lower()
|
||||||
)
|
)
|
||||||
assert (
|
assert (
|
||||||
"Nationalistisch" in enriched["y_label"]
|
"Nationalistisch" in enriched["y_label"]
|
||||||
or "kosmopolitisch" in enriched["y_label"]
|
or "nationalistisch" in enriched["y_label"].lower()
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -78,17 +78,17 @@ def test_get_svd_label_returns_correct_label():
|
|||||||
"""Test that get_svd_label returns the correct label for each component."""
|
"""Test that get_svd_label returns the correct label for each component."""
|
||||||
from analysis.svd_labels import get_svd_label
|
from analysis.svd_labels import get_svd_label
|
||||||
|
|
||||||
# Component 1 should return Rechts versus links label
|
# Component 1 should return "Economische sectorbelangen versus sociale welvaart"
|
||||||
label1 = get_svd_label(1)
|
label1 = get_svd_label(1)
|
||||||
assert "Rechts versus links" in label1 or "links" in label1.lower()
|
assert "Economische sectorbelangen" in label1 or "sectorbelangen" in label1.lower()
|
||||||
|
|
||||||
# Component 2 should return Nationalistisch versus kosmopolitisch label
|
# Component 2 should return "Nationalistische versus multilateralistische oriëntatie"
|
||||||
label2 = get_svd_label(2)
|
label2 = get_svd_label(2)
|
||||||
assert "Nationalistisch" in label2 or "kosmopolitisch" in label2
|
assert "Nationalistisch" in label2 or "nationalistisch" in label2.lower()
|
||||||
|
|
||||||
# Component 3 should return Verzorgingsstaat label
|
# Component 3 should return "Verzorgingsstaat versus defensie en nationale veiligheid"
|
||||||
label3 = get_svd_label(3)
|
label3 = get_svd_label(3)
|
||||||
assert "Verzorgingsstaat" in label3 or "Marktwerking" in label3
|
assert "Verzorgingsstaat" in label3 or "verzorgingsstaat" in label3.lower()
|
||||||
|
|
||||||
|
|
||||||
def test_compute_flip_direction_right_on_left():
|
def test_compute_flip_direction_right_on_left():
|
||||||
|
|||||||
Reference in New Issue
Block a user