|
|
|
|
@ -203,6 +203,73 @@ def load_party_map(db_path: str) -> Dict[str, str]: |
|
|
|
|
return {} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _render_party_axis_chart( |
|
|
|
|
party_scores: Dict[str, List[float]], comp_sel: int |
|
|
|
|
) -> None: |
|
|
|
|
"""Render a 1D horizontal Plotly scatter of party positions on SVD axis `comp_sel`. |
|
|
|
|
|
|
|
|
|
Each party is plotted at its score on a single horizontal axis (y=0). |
|
|
|
|
""" |
|
|
|
|
if not party_scores: |
|
|
|
|
st.caption("_Partijdata niet beschikbaar voor deze as._") |
|
|
|
|
return |
|
|
|
|
|
|
|
|
|
axis_idx = comp_sel - 1 # 0-based index into the 50-dim vector |
|
|
|
|
data: list[dict] = [] |
|
|
|
|
for party, vec in party_scores.items(): |
|
|
|
|
if axis_idx < len(vec): |
|
|
|
|
data.append({"party": party, "score": vec[axis_idx]}) |
|
|
|
|
|
|
|
|
|
if not data: |
|
|
|
|
st.caption("_Geen partijscores voor deze as._") |
|
|
|
|
return |
|
|
|
|
|
|
|
|
|
scores = [d["score"] for d in data] |
|
|
|
|
parties = [d["party"] for d in data] |
|
|
|
|
colours = [PARTY_COLOURS.get(p, "#9E9E9E") for p in parties] |
|
|
|
|
hover = [f"{p}: {s:.3f}" for p, s in zip(parties, scores)] |
|
|
|
|
|
|
|
|
|
fig = go.Figure() |
|
|
|
|
# Baseline |
|
|
|
|
x_min, x_max = min(scores) * 1.15, max(scores) * 1.15 |
|
|
|
|
fig.add_trace( |
|
|
|
|
go.Scatter( |
|
|
|
|
x=[x_min, x_max], |
|
|
|
|
y=[0, 0], |
|
|
|
|
mode="lines", |
|
|
|
|
line={"color": "#cccccc", "width": 1}, |
|
|
|
|
hoverinfo="skip", |
|
|
|
|
showlegend=False, |
|
|
|
|
) |
|
|
|
|
) |
|
|
|
|
# Party markers |
|
|
|
|
fig.add_trace( |
|
|
|
|
go.Scatter( |
|
|
|
|
x=scores, |
|
|
|
|
y=[0] * len(scores), |
|
|
|
|
mode="markers+text", |
|
|
|
|
text=parties, |
|
|
|
|
textposition="top center", |
|
|
|
|
marker={"size": 12, "color": colours}, |
|
|
|
|
hovertext=hover, |
|
|
|
|
hoverinfo="text", |
|
|
|
|
showlegend=False, |
|
|
|
|
) |
|
|
|
|
) |
|
|
|
|
fig.update_layout( |
|
|
|
|
height=160, |
|
|
|
|
margin={"l": 10, "r": 10, "t": 10, "b": 30}, |
|
|
|
|
xaxis={ |
|
|
|
|
"title": "← Negatieve pool | Positieve pool →", |
|
|
|
|
"zeroline": True, |
|
|
|
|
"zerolinecolor": "#aaaaaa", |
|
|
|
|
}, |
|
|
|
|
yaxis={"visible": False, "range": [-1, 2]}, |
|
|
|
|
plot_bgcolor="white", |
|
|
|
|
) |
|
|
|
|
st.plotly_chart(fig, use_container_width=True) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@st.cache_data(show_spinner="Moties laden…") |
|
|
|
|
def load_motions_df(db_path: str) -> pd.DataFrame: |
|
|
|
|
"""Load the full motions table as a pandas DataFrame (read-only).""" |
|
|
|
|
|