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.
This commit is contained in:
+33
-6
@@ -199,6 +199,17 @@ def load_positions(
|
|||||||
normalize_vectors=True,
|
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.
|
# Filter displayed windows by window_size AFTER PCA computation.
|
||||||
if window_size == "annual":
|
if window_size == "annual":
|
||||||
annual_keys = set(w for w in all_available if "-Q" not in w)
|
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.
|
# Motion counts per year — sparse years get a warning label.
|
||||||
_SPARSE_YEARS = {"2016", "2017", "2018"}
|
_SPARSE_YEARS = {"2016", "2017", "2018"}
|
||||||
|
_THRESHOLD = 0.65
|
||||||
|
|
||||||
def _window_label(w: str) -> str:
|
def _window_label(w: str) -> str:
|
||||||
if w == "current_parliament":
|
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.")
|
st.info("Geen partijen met genoeg Kamerleden voor dit venster.")
|
||||||
return
|
return
|
||||||
|
|
||||||
|
_x_label = axis_def.get("x_label", "Links\u2013Rechts")
|
||||||
|
_y_label = axis_def.get("y_label", "Progressief\u2013Conservatief")
|
||||||
|
|
||||||
if level == "Partijen":
|
if level == "Partijen":
|
||||||
# Aggregate to party centroids
|
# Aggregate to party centroids
|
||||||
df_party = df_pos.groupby("party", as_index=False).agg(
|
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,
|
color_discrete_map=colour_map,
|
||||||
title=f"Politiek Kompas — {_window_label(window_idx)} (partijen)",
|
title=f"Politiek Kompas — {_window_label(window_idx)} (partijen)",
|
||||||
labels={
|
labels={
|
||||||
"x": "Links ← → Rechts",
|
"x": _x_label,
|
||||||
"y": "Progressief / Conservatief",
|
"y": _y_label,
|
||||||
"n": "Kamerleden",
|
"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"},
|
hover_data={"party": True, "x": ":.3f", "y": ":.3f"},
|
||||||
color_discrete_map=colour_map,
|
color_discrete_map=colour_map,
|
||||||
title=f"Politiek Kompas — {_window_label(window_idx)}",
|
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(
|
fig.update_layout(
|
||||||
@@ -956,6 +971,18 @@ def build_compass_tab(db_path: str, window_size: str) -> None:
|
|||||||
|
|
||||||
with col1:
|
with col1:
|
||||||
st.plotly_chart(fig, use_container_width=True)
|
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 ---
|
# --- Voting discipline section ---
|
||||||
_MIN_MOTIONS_FOR_DISCIPLINE = 5
|
_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.subheader("Partij Trajectories")
|
||||||
st.markdown("Hoe bewegen partijen over de tijdsvensters heen?")
|
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:
|
if not positions_by_window:
|
||||||
st.warning("Geen positiedata beschikbaar.")
|
st.warning("Geen positiedata beschikbaar.")
|
||||||
return
|
return
|
||||||
@@ -1117,8 +1144,8 @@ def build_trajectories_tab(db_path: str, window_size: str) -> None:
|
|||||||
|
|
||||||
fig.update_layout(
|
fig.update_layout(
|
||||||
title="Partij trajectories",
|
title="Partij trajectories",
|
||||||
xaxis_title="Links ← → Rechts",
|
xaxis_title=axis_def.get("x_label", "Links\u2013Rechts"),
|
||||||
yaxis_title="Progressief / Conservatief",
|
yaxis_title=axis_def.get("y_label", "Progressief\u2013Conservatief"),
|
||||||
height=600,
|
height=600,
|
||||||
legend_title_text="Partij",
|
legend_title_text="Partij",
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user