diff --git a/explorer.py b/explorer.py index 96ec740..4e49275 100644 --- a/explorer.py +++ b/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", )