feat(explorer): restructure SVD tab — pole-split motions, party axis chart, inline expanders with voting

main
Sven Geboers 1 month ago
parent 1515661929
commit 6b8ec93fe0
  1. 118
      explorer.py

@ -929,62 +929,90 @@ def build_svd_components_tab(db_path: str) -> None:
)
comp_sel = comp_options[comp_sel_idx]
# Show theme explanation + poles
# Show theme explanation
theme = SVD_THEMES.get(comp_sel, {})
if theme:
st.info(f"**{theme['label']}** — {theme['explanation']}")
pos = theme.get("positive_pole", "")
neg = theme.get("negative_pole", "")
if pos or neg:
pcol, ncol = st.columns(2)
with pcol:
st.success(f"▲ **Positieve pool:** {pos}")
with ncol:
st.error(f"▼ **Negatieve pool:** {neg}")
motions = comp_map.get(comp_sel, [])
col1, col2 = st.columns([1, 2])
with col1:
st.markdown("**Top-moties (titels)**")
for m in motions:
mid = m.get("motion_id")
score = m.get("score", 0.0)
title = m.get("title") or f"Motie #{mid}"
sign = "" if score >= 0 else ""
if st.button(f"{sign} {mid}: {title[:72]}", key=f"btn_{comp_sel}_{mid}"):
st.session_state["svd_selected_mid"] = mid
# Party axis chart
party_scores = load_party_axis_scores(db_path)
_render_party_axis_chart(party_scores, comp_sel)
with col2:
sel_mid = st.session_state.get("svd_selected_mid")
if not sel_mid and motions:
sel_mid = motions[0].get("motion_id")
if sel_mid:
# fetch motion metadata from DB for completeness
# Batch-fetch motion details (title, date, policy_area, url, body_text, voting_results)
motion_ids = [m.get("motion_id") for m in motions if m.get("motion_id") is not None]
motion_details: Dict[int, tuple] = {}
if motion_ids:
try:
placeholders = ", ".join("?" for _ in motion_ids)
con = duckdb.connect(database=db_path, read_only=True)
row = con.execute(
"SELECT id, title, date, policy_area, url, body_text FROM motions WHERE id=?",
[int(sel_mid)],
).fetchone()
db_rows = con.execute(
f"SELECT id, title, date, policy_area, url, body_text, voting_results "
f"FROM motions WHERE id IN ({placeholders})",
[int(mid) for mid in motion_ids],
).fetchall()
con.close()
motion_details = {r[0]: r for r in db_rows}
except Exception:
row = None
if row:
st.markdown(f"### {row[1] or f'Motie #{row[0]}'}")
try:
date_str = str(row[2])[:10]
except Exception:
date_str = "?"
st.caption(f"📅 {date_str} | {row[3]}")
if row[4] and str(row[4]).startswith("http"):
st.markdown(f"[🔗 Bekijk op Tweede Kamer]({row[4]})")
if row[5]:
with st.expander("Toon volledige tekst"):
st.write(row[5])
else:
st.info(f"Metadata not found in DB for motion {sel_mid}")
logger.exception("Failed to batch-fetch motion details")
# Split motions by pole sign
pos_motions = [m for m in motions if float(m.get("score", 0.0)) >= 0]
neg_motions = [m for m in motions if float(m.get("score", 0.0)) < 0]
pos_pole = (
theme.get("positive_pole", "Positieve pool") if theme else "Positieve pool"
)
neg_pole = (
theme.get("negative_pole", "Negatieve pool") if theme else "Negatieve pool"
)
pcol, ncol = st.columns(2)
with pcol:
st.success(f"▲ **Positieve pool:** {pos_pole}")
for m in pos_motions:
mid = m.get("motion_id")
raw_title = m.get("title") or f"Motie #{mid}"
with st.expander(f"{raw_title[:80]}"):
row = motion_details.get(int(mid)) if mid is not None else None
if row:
try:
date_str = str(row[2])[:10]
except Exception:
date_str = "?"
st.caption(f"📅 {date_str} | {row[3] or ''}")
if row[4] and str(row[4]).startswith("http"):
st.markdown(f"[🔗 Bekijk op Tweede Kamer]({row[4]})")
if row[5]:
with st.expander("Toon volledige tekst"):
st.write(row[5])
_render_voting_results(row[6])
else:
st.caption("_Geen metadata beschikbaar_")
with ncol:
st.error(f"▼ **Negatieve pool:** {neg_pole}")
for m in neg_motions:
mid = m.get("motion_id")
raw_title = m.get("title") or f"Motie #{mid}"
with st.expander(f"{raw_title[:80]}"):
row = motion_details.get(int(mid)) if mid is not None else None
if row:
try:
date_str = str(row[2])[:10]
except Exception:
date_str = "?"
st.caption(f"📅 {date_str} | {row[3] or ''}")
if row[4] and str(row[4]).startswith("http"):
st.markdown(f"[🔗 Bekijk op Tweede Kamer]({row[4]})")
if row[5]:
with st.expander("Toon volledige tekst"):
st.write(row[5])
_render_voting_results(row[6])
else:
st.caption("_Geen metadata beschikbaar_")
def build_mp_quiz_tab(db_path: str) -> None:

Loading…
Cancel
Save