|
|
|
|
@ -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: |
|
|
|
|
|