style: humanize reports and translate Streamlit UI to English
Streamlit tabs: translated all Dutch text to English in overton.py, compass.py (Overton expander + voting discipline), trajectories.py. Humanization (all 3 report surfaces): - Removed 60+ em dashes, replaced with periods/commas/colons - Removed AI vocabulary (crucial, pivotal, underscores, landscape) - Removed excessive boldface, rule-of-three, -ing padding - Replaced 'serves as'/'stands as' with 'is' - Preserved all data, numbers, tables, code blocks exactly
This commit is contained in:
+21
-21
@@ -185,28 +185,28 @@ def build_compass_tab(db_path: str, window_size: str) -> None:
|
||||
|
||||
with st.expander("Overton Window Context"):
|
||||
st.markdown(
|
||||
"Het SVD-kompas visualiseert de dynamiek achter de "
|
||||
"**verbreding van het Overton-venster** in de Tweede Kamer.\n\n"
|
||||
"Centristische steun voor rechtse moties steeg van 25% naar 51% na 2024, "
|
||||
"terwijl steun voor linkse moties gelijk bleef. Het venster verschoof — "
|
||||
"meer rechtse standpunten werden acceptabel.\n\n"
|
||||
"Maar: **centristische partijen** (D66, CDA, CU, NSC) zijn op **beide assen naar"
|
||||
" links** verschoven, terwijl rechtse partijen stabiel bleven. Dit patroon"
|
||||
' van "acceptatie zonder conversie" betekent dat rechtse partijen mildere'
|
||||
" moties gingen indienen, en centristen daardoor vaker konden meestemmen — "
|
||||
"zonder dat ze ideologisch naar rechts opschoven.\n\n"
|
||||
"[Lees de volledige analyse](../reports/overton_window/overton_window.qmd)\n\n"
|
||||
"Probeer de **Stemwijzer-quiz** om te zien welke MP bij jouw standpunten past."
|
||||
"The SVD compass visualizes the dynamics behind the "
|
||||
"**widening of the Overton window** in the Dutch parliament.\n\n"
|
||||
"Centrist support for right-wing motions rose from 25% to 51% after 2024, "
|
||||
"while support for left-wing motions stayed flat. The window widened: "
|
||||
"more right-wing positions became acceptable.\n\n"
|
||||
"But **centrist parties** (D66, CDA, CU, NSC) moved **left on both axes** "
|
||||
"while right-wing parties stayed put. This pattern of "
|
||||
'"acceptance without conversion" means right-wing parties filed milder '
|
||||
"motions, and centrists could vote along more often, "
|
||||
"without shifting ideologically to the right.\n\n"
|
||||
"[Read the full analysis](../reports/overton_window/overton_window.qmd)\n\n"
|
||||
"Try the **Stemwijzer quiz** to see which MP matches your positions."
|
||||
)
|
||||
st.markdown("---")
|
||||
st.markdown(
|
||||
"**Stemdiscipline analyse:** De Rice-index meet hoe eensgezind partijen stemmen "
|
||||
"tijdens hoofdelijke stemmingen. Een score van 100% betekent dat alle MPs van "
|
||||
"een partij hetzelfde stemden; 50% wijst op een gelijke splitsing binnen de partij. "
|
||||
"Partijen met hoge discipline (>95%) zoals PVV en SGP stemmen als een blok, wat "
|
||||
"wijst op sterke partijdiscipline en homogene membership. Lagere discipline (<85%) "
|
||||
"bij partijen als PvdA of SP kan duiden op interne factiestrijd, gewetensvragen "
|
||||
"bij ethische thema's, of een brede ideologische koers die ruimte laat voor "
|
||||
"afwijkende meningen. De discipline varieert ook per onderwerp — ethische kwesties "
|
||||
"tonen vaak meer interne verschillen dan economische thema's."
|
||||
"**Voting discipline analysis:** The Rice index measures how united parties vote "
|
||||
"during roll-call votes. A score of 100% means all MPs of a party voted the "
|
||||
"same way; 50% indicates an even split within the party. "
|
||||
"High-discipline parties (>95%) like PVV and SGP vote as a bloc, indicating "
|
||||
"strong party discipline and homogeneous membership. Lower discipline (<85%) "
|
||||
"in parties like PvdA or SP may indicate internal factional struggles, conscience "
|
||||
"votes on ethical issues, or a broad ideological course that leaves room for "
|
||||
"dissenting opinions. Discipline also varies by topic: ethical issues "
|
||||
"tend to show more internal division than economic topics."
|
||||
)
|
||||
|
||||
+33
-33
@@ -15,18 +15,18 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
def build_overton_tab(db_path: str) -> None:
|
||||
"""Build the Overton Window tab."""
|
||||
st.subheader("Overton Window Analyse")
|
||||
st.subheader("Overton Window Analysis")
|
||||
st.markdown(
|
||||
"Het Overton-venster **verbreedde** na 2024: centristische steun voor rechtse "
|
||||
"moties steeg van 25% naar 51%, terwijl steun voor linkse moties gelijk bleef. "
|
||||
"Rechtse partijen dienden mildere moties in, waardoor centristen vaker konden "
|
||||
"meestemmen — zonder ideologisch naar rechts op te schuiven."
|
||||
"The Overton window **widened** after 2024: centrist support for right-wing "
|
||||
"motions rose from 25% to 51%, while support for left-wing motions stayed flat. "
|
||||
"Right-wing parties filed milder motions, allowing centrists to vote along "
|
||||
"without shifting ideologically."
|
||||
)
|
||||
|
||||
try:
|
||||
con = duckdb.connect(db_path, read_only=True)
|
||||
except Exception:
|
||||
st.warning("Kan geen verbinding maken met de database.")
|
||||
st.warning("Cannot connect to the database.")
|
||||
return
|
||||
|
||||
try:
|
||||
@@ -35,12 +35,12 @@ def build_overton_tab(db_path: str) -> None:
|
||||
).fetchall()
|
||||
if not tables:
|
||||
st.info(
|
||||
"De right_wing_motions tabel is nog niet beschikbaar. "
|
||||
"Draai de pipeline om deze te genereren."
|
||||
"The right_wing_motions table is not yet available. "
|
||||
"Run the pipeline to generate it."
|
||||
)
|
||||
return
|
||||
except Exception:
|
||||
st.info("De right_wing_motions tabel is niet beschikbaar.")
|
||||
st.info("The right_wing_motions table is not available.")
|
||||
return
|
||||
|
||||
try:
|
||||
@@ -50,7 +50,7 @@ def build_overton_tab(db_path: str) -> None:
|
||||
_render_motion_browser(con)
|
||||
_render_explore_further()
|
||||
except Exception as e:
|
||||
st.error(f"Fout bij laden van Overton data: {e}")
|
||||
st.error(f"Error loading Overton data: {e}")
|
||||
logger.exception("Overton tab error")
|
||||
finally:
|
||||
con.close()
|
||||
@@ -65,7 +65,7 @@ def _render_centrist_support_chart(con: duckdb.DuckDBPyConnection) -> None:
|
||||
""").fetchdf()
|
||||
|
||||
if df.empty:
|
||||
st.info("Geen centrist support data beschikbaar.")
|
||||
st.info("No centrist support data available.")
|
||||
return
|
||||
|
||||
fig = go.Figure()
|
||||
@@ -82,7 +82,7 @@ def _render_centrist_support_chart(con: duckdb.DuckDBPyConnection) -> None:
|
||||
fig.add_trace(go.Bar(
|
||||
x=df["year"],
|
||||
y=df["n_motions"],
|
||||
name="Aantal moties",
|
||||
name="Motion count",
|
||||
yaxis="y2",
|
||||
marker_color="#90CAF9",
|
||||
opacity=0.5,
|
||||
@@ -99,10 +99,10 @@ def _render_centrist_support_chart(con: duckdb.DuckDBPyConnection) -> None:
|
||||
)
|
||||
|
||||
fig.update_layout(
|
||||
title="Centrist Support voor Rechtse Moties",
|
||||
xaxis=dict(title="Jaar", dtick=1),
|
||||
title="Centrist Support for Right-Wing Motions",
|
||||
xaxis=dict(title="Year", dtick=1),
|
||||
yaxis=dict(title="Centrist Support", range=[0, 1]),
|
||||
yaxis2=dict(title="Aantal moties", overlaying="y", side="right"),
|
||||
yaxis2=dict(title="Motion count", overlaying="y", side="right"),
|
||||
height=400,
|
||||
legend=dict(orientation="h", y=1.1),
|
||||
hovermode="x unified",
|
||||
@@ -112,7 +112,7 @@ def _render_centrist_support_chart(con: duckdb.DuckDBPyConnection) -> None:
|
||||
|
||||
|
||||
def _render_summary_stats(con: duckdb.DuckDBPyConnection) -> None:
|
||||
st.subheader("Samenvatting")
|
||||
st.subheader("Summary")
|
||||
|
||||
result = con.execute("""
|
||||
SELECT
|
||||
@@ -139,10 +139,10 @@ def _render_summary_stats(con: duckdb.DuckDBPyConnection) -> None:
|
||||
|
||||
|
||||
def _render_migration_gateway(con: duckdb.DuckDBPyConnection) -> None:
|
||||
st.subheader("Migratie: de gateway-domein")
|
||||
st.subheader("Migration: the gateway domain")
|
||||
st.markdown(
|
||||
"Migratie is waar de Overton-verschuiving het meest echt is — en waar "
|
||||
"rechtse partijen de frames leerden die ze later op andere domeinen toepasten."
|
||||
"Migration is where the Overton shift is most genuine, and where "
|
||||
"right-wing parties learned the frames they later applied to other domains."
|
||||
)
|
||||
|
||||
df = con.execute("""
|
||||
@@ -165,21 +165,21 @@ def _render_migration_gateway(con: duckdb.DuckDBPyConnection) -> None:
|
||||
post = df[df["period"] == "Post-2024"].iloc[0]
|
||||
|
||||
col1, col2, col3, col4 = st.columns(4)
|
||||
col1.metric("Pre-2024 CS (migratie)", f"{pre['cs_strict']:.3f}")
|
||||
col2.metric("Post-2024 CS (migratie)", f"{post['cs_strict']:.3f}")
|
||||
col1.metric("Pre-2024 CS (migration)", f"{pre['cs_strict']:.3f}")
|
||||
col2.metric("Post-2024 CS (migration)", f"{post['cs_strict']:.3f}")
|
||||
col3.metric("Shift", f"{post['cs_strict'] - pre['cs_strict']:+.3f}")
|
||||
col4.metric("Moties", f"{int(pre['n_motions'] + post['n_motions'])}")
|
||||
col4.metric("Motions", f"{int(pre['n_motions'] + post['n_motions'])}")
|
||||
|
||||
st.caption(
|
||||
"Ter vergelijking: niet-migratie moties gingen van 0.276 naar 0.481 (+0.205). "
|
||||
"Migratie steeg meer dan twee keer zo hard (+0.216), terwijl de materiële impact "
|
||||
"nauwelijks daalde. CDA en ChristenUnie verdubbelden hun migratie-steun "
|
||||
"(18%→40%, 10%→30%)."
|
||||
"For comparison: non-migration motions went from 0.276 to 0.481 (+0.205). "
|
||||
"Migration rose more than twice as fast (+0.216), while material impact "
|
||||
"barely declined. CDA and ChristenUnie doubled their migration support "
|
||||
"(18% to 40%, 10% to 30%)."
|
||||
)
|
||||
|
||||
|
||||
def _render_motion_browser(con: duckdb.DuckDBPyConnection) -> None:
|
||||
st.subheader("Rechtse Moties Browser")
|
||||
st.subheader("Right-Wing Motions Browser")
|
||||
|
||||
df = con.execute("""
|
||||
SELECT r.year, r.title, m.text, r.centrist_support_strict, r.category
|
||||
@@ -191,21 +191,21 @@ def _render_motion_browser(con: duckdb.DuckDBPyConnection) -> None:
|
||||
""").fetchdf()
|
||||
|
||||
if df.empty:
|
||||
st.info("Geen rechtse moties gevonden.")
|
||||
st.info("No right-wing motions found.")
|
||||
return
|
||||
|
||||
df = df.rename(columns={
|
||||
"year": "Jaar",
|
||||
"title": "Titel",
|
||||
"text": "Motietekst",
|
||||
"year": "Year",
|
||||
"title": "Title",
|
||||
"text": "Motion text",
|
||||
"centrist_support_strict": "Centrist Support",
|
||||
"category": "Categorie",
|
||||
"category": "Category",
|
||||
})
|
||||
st.dataframe(df, use_container_width=True, height=600)
|
||||
|
||||
|
||||
def _render_explore_further() -> None:
|
||||
st.subheader("Verder verkennen")
|
||||
st.subheader("Explore further")
|
||||
st.markdown(
|
||||
"- See party positions → Kompas tab\n"
|
||||
"- See party drift over time → Trajectories tab\n"
|
||||
|
||||
@@ -667,10 +667,10 @@ def build_trajectories_tab(db_path: str, window_size: str) -> None:
|
||||
try:
|
||||
st.plotly_chart(fig, use_container_width=True)
|
||||
st.info(
|
||||
"**Overton-venster verbreed:** na PVV's verkiezingsoverwinning (nov 2023) "
|
||||
"steeg centristische steun voor rechtse moties van 25% naar 51%, "
|
||||
"terwijl steun voor linkse moties gelijk bleef. "
|
||||
"Rechtse partijen matigden hun moties, centristen stemden vaker voor."
|
||||
"**Overton window widened:** after PVV's election victory (Nov 2023), "
|
||||
"centrist support for right-wing motions rose from 25% to 51%, "
|
||||
"while support for left-wing motions stayed flat. "
|
||||
"Right-wing parties moderated their motions; centrists voted along more often."
|
||||
)
|
||||
except Exception as e:
|
||||
st.error(f"Trajectories rendering failed: {e}")
|
||||
|
||||
Reference in New Issue
Block a user