diff --git a/explorer.py b/explorer.py index 4b30368..00cc37a 100644 --- a/explorer.py +++ b/explorer.py @@ -1777,6 +1777,11 @@ def build_trajectories_tab(db_path: str, window_size: str) -> None: # If no party-level centroids were computed, fall back to per-MP trajectories # so the user still sees a plot even when the party_map is missing or empty. if not centroids: + # Fallback: plot individual MP trajectories + st.info( + "Partijcentroiden niet beschikbaar — tonen individuele MP-trajecten als fallback." + ) + # Build per-MP time series from positions_by_window mp_positions: Dict[str, Dict[str, Tuple[float, float]]] = {} for wid in windows: @@ -1790,20 +1795,22 @@ def build_trajectories_tab(db_path: str, window_size: str) -> None: continue mp_positions.setdefault(mp_name, {})[wid] = (x, y) + # Filter to MPs with at least 2 windows and not all NaN + mp_positions = { + mp: pos + for mp, pos in mp_positions.items() + if len(pos) >= 2 + and not all(np.isnan(x) and np.isnan(y) for x, y in pos.values()) + } + if not mp_positions: - try: - _last_trajectories_diagnostics.update( - { - "stage": "no_mp_positions", - "mp_positions_count": len(mp_positions), - } - ) - except Exception: - pass - try: - st.info("Geen positiedata beschikbaar voor trajectplotten.") - except Exception: - pass + st.warning("Geen positiedata beschikbaar voor trajectplotten.") + _last_trajectories_diagnostics.update( + { + "stage": "no_mp_positions", + "mp_positions_count": 0, + } + ) # show diagnostics when debug enabled try: if get_debug_trajectories_enabled(): @@ -1819,6 +1826,9 @@ def build_trajectories_tab(db_path: str, window_size: str) -> None: pass return + # Store for later use + st.session_state["_trajectory_mp_positions"] = mp_positions + mp_list = sorted(mp_positions.keys()) default_mps = mp_list[:6] selected_mps = st.multiselect( @@ -2170,24 +2180,41 @@ def choose_trajectory_title(axis_def: dict, axis: str, threshold: float = 0.65) "sample_size": len(sample_mps), } if trace_count == 0: - try: - st.info( - "Geen trajecten getekend: geen geselecteerde partijen met voldoende data. Controleer de partijselectie en de 'Min. Kamerleden per partij' instelling." + st.info("📊 **Geen trajecten getekend**") + + # Show diagnostic information + with st.expander("🔍 Diagnostische informatie"): + st.write("**Data status:**") + st.write( + f"- Positie vensters: {len(positions_by_window) if positions_by_window else 0}" ) - except Exception: - pass - if debug_enabled: - try: - st.text_area( - "Trajectories diagnostics", - json.dumps(_last_trajectories_diagnostics, default=str), - height=240, + st.write(f"- Party mappings: {len(party_map) if party_map else 0}") + st.write( + f"- Geselecteerde partijen: {len(selected_parties) if selected_parties else 0}" + ) + + if "centroid_diagnostics" in locals(): + st.write("**Centroid berekening:**") + st.write( + f"- Partijen met posities: {len(centroid_diagnostics.get('parties_with_positions', []))}" ) - except Exception: - try: - st.json(_last_trajectories_diagnostics) - except Exception: - pass + st.write( + f"- Partijen met alleen NaN: {len(centroid_diagnostics.get('parties_all_nan', []))}" + ) + + st.write("\n**Mogelijke oorzaken:**") + st.write("1. Geen SVD vectoren berekend voor de geselecteerde vensters") + st.write("2. MP namen in posities komen niet overeen met party_map") + st.write("3. Alle geselecteerde partijen hebben te weinig MPs (< 5)") + + # Add a button to run diagnostics + if st.button("🔧 Database diagnostiek uitvoeren"): + with st.spinner("Bezig met diagnostiek..."): + # Import and run diagnostics + from scripts.diagnose_trajectories_cli import diagnose_trajectories + + results = diagnose_trajectories(db_path) + st.json(results) else: # DEBUG: show trace_count and figure data size before rendering try: