@ -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 \u2013 Rechts " )
_y_label = axis_def . get ( " y_label " , " Progressief \u2013 Conservatief " )
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 \u2013 Rechts " ) ,
yaxis_title = axis_def . get ( " y_label " , " Progressief \u2013 Conservatief" ) ,
height = 600 ,
legend_title_text = " Partij " ,
)