feat: use dynamic axis labels in compass and trajectories UI

Replace hardcoded 'Links-Rechts' / 'Progressief-Conservatief' axis labels
with values from classify_axes(). Add per-year interpretation caption when
axis quality score is below the 0.65 correlation threshold.
main
Sven Geboers 1 month ago
parent 5ec1f7af75
commit 34c08a40fa
  1. 39
      explorer.py

@ -199,6 +199,17 @@ def load_positions(
normalize_vectors=True,
)
try:
from analysis.axis_classifier import classify_axes
axis_def = classify_axes(positions_by_window, axis_def, db_path)
except Exception:
import logging
logging.getLogger(__name__).exception(
"classify_axes failed; using generic axis labels"
)
# Filter displayed windows by window_size AFTER PCA computation.
if window_size == "annual":
annual_keys = set(w for w in all_available if "-Q" not in w)
@ -831,6 +842,7 @@ def build_compass_tab(db_path: str, window_size: str) -> None:
# Motion counts per year — sparse years get a warning label.
_SPARSE_YEARS = {"2016", "2017", "2018"}
_THRESHOLD = 0.65
def _window_label(w: str) -> str:
if w == "current_parliament":
@ -904,6 +916,9 @@ def build_compass_tab(db_path: str, window_size: str) -> None:
st.info("Geen partijen met genoeg Kamerleden voor dit venster.")
return
_x_label = axis_def.get("x_label", "Links\u2013Rechts")
_y_label = axis_def.get("y_label", "Progressief\u2013Conservatief")
if level == "Partijen":
# Aggregate to party centroids
df_party = df_pos.groupby("party", as_index=False).agg(
@ -924,8 +939,8 @@ def build_compass_tab(db_path: str, window_size: str) -> None:
color_discrete_map=colour_map,
title=f"Politiek Kompas — {_window_label(window_idx)} (partijen)",
labels={
"x": "Links ← → Rechts",
"y": "Progressief / Conservatief",
"x": _x_label,
"y": _y_label,
"n": "Kamerleden",
},
)
@ -943,7 +958,7 @@ def build_compass_tab(db_path: str, window_size: str) -> None:
hover_data={"party": True, "x": ":.3f", "y": ":.3f"},
color_discrete_map=colour_map,
title=f"Politiek Kompas — {_window_label(window_idx)}",
labels={"x": "Links ← → Rechts", "y": "Progressief / Conservatief"},
labels={"x": _x_label, "y": _y_label},
)
fig.update_layout(
@ -956,6 +971,18 @@ def build_compass_tab(db_path: str, window_size: str) -> None:
with col1:
st.plotly_chart(fig, use_container_width=True)
_x_interp = axis_def.get("x_interpretation", {}).get(window_idx, "")
_y_interp = axis_def.get("y_interpretation", {}).get(window_idx, "")
if (
_x_interp
and axis_def.get("x_quality", {}).get(window_idx, 1.0) < _THRESHOLD
):
st.caption(_x_interp)
if (
_y_interp
and axis_def.get("y_quality", {}).get(window_idx, 1.0) < _THRESHOLD
):
st.caption(_y_interp)
# --- Voting discipline section ---
_MIN_MOTIONS_FOR_DISCIPLINE = 5
@ -1047,7 +1074,7 @@ def build_trajectories_tab(db_path: str, window_size: str) -> None:
st.subheader("Partij Trajectories")
st.markdown("Hoe bewegen partijen over de tijdsvensters heen?")
positions_by_window, _ = load_positions(db_path, window_size)
positions_by_window, axis_def = load_positions(db_path, window_size)
if not positions_by_window:
st.warning("Geen positiedata beschikbaar.")
return
@ -1117,8 +1144,8 @@ def build_trajectories_tab(db_path: str, window_size: str) -> None:
fig.update_layout(
title="Partij trajectories",
xaxis_title="Links ← → Rechts",
yaxis_title="Progressief / Conservatief",
xaxis_title=axis_def.get("x_label", "Links\u2013Rechts"),
yaxis_title=axis_def.get("y_label", "Progressief\u2013Conservatief"),
height=600,
legend_title_text="Partij",
)

Loading…
Cancel
Save