feat: add voting discipline section below political compass
This commit is contained in:
@@ -237,3 +237,131 @@ def test_pca_axis_orientation(monkeypatch):
|
||||
assert prog_y > cons_y, (
|
||||
f"Expected progressive parties (y={prog_y:.3f}) > conservative parties (y={cons_y:.3f}) on Y-axis"
|
||||
)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Tests for compute_party_discipline
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
def _make_mp_votes_db():
|
||||
"""Create an in-memory DuckDB with mp_votes fixture data.
|
||||
|
||||
6 motions, 2 parties (SP, VVD), each with 4 MPs.
|
||||
SP is perfectly disciplined (all 4 vote the same each time).
|
||||
VVD has 1 dissident on 2 of 6 motions → Rice index = (4+4+4+4+3+3)/6/4 ≈ 0.917.
|
||||
Dates span 2023-01-01 to 2023-12-31.
|
||||
"""
|
||||
import duckdb
|
||||
|
||||
conn = duckdb.connect(":memory:")
|
||||
conn.execute("""
|
||||
CREATE TABLE mp_votes (
|
||||
id INTEGER,
|
||||
motion_id VARCHAR,
|
||||
mp_name VARCHAR,
|
||||
party VARCHAR,
|
||||
vote VARCHAR,
|
||||
date DATE,
|
||||
created_at TIMESTAMP
|
||||
)
|
||||
""")
|
||||
rows = []
|
||||
dates = [
|
||||
"2023-01-10",
|
||||
"2023-03-15",
|
||||
"2023-05-20",
|
||||
"2023-07-25",
|
||||
"2023-09-30",
|
||||
"2023-11-05",
|
||||
]
|
||||
sp_mps = ["Janssen, A.", "Pietersen, B.", "Willemsen, C.", "Hendriksen, D."]
|
||||
vvd_mps = ["Adams, E.", "Bakker, F.", "Claassen, G.", "Dekker, H."]
|
||||
for i, date in enumerate(dates, start=1):
|
||||
m_id = f"M{i:03d}"
|
||||
for mp in sp_mps:
|
||||
rows.append((i * 10 + 1, m_id, mp, "SP", "voor", date, "2023-01-01"))
|
||||
if i <= 4:
|
||||
for mp in vvd_mps:
|
||||
rows.append((i * 10 + 2, m_id, mp, "VVD", "voor", date, "2023-01-01"))
|
||||
else:
|
||||
for mp in vvd_mps[:3]:
|
||||
rows.append((i * 10 + 2, m_id, mp, "VVD", "voor", date, "2023-01-01"))
|
||||
rows.append(
|
||||
(i * 10 + 3, m_id, vvd_mps[3], "VVD", "tegen", date, "2023-01-01")
|
||||
)
|
||||
conn.executemany("INSERT INTO mp_votes VALUES (?, ?, ?, ?, ?, ?, ?)", rows)
|
||||
return conn
|
||||
|
||||
|
||||
def test_compute_party_discipline_basic(monkeypatch):
|
||||
"""compute_party_discipline returns correct Rice index for fixture data."""
|
||||
import duckdb as _duckdb
|
||||
|
||||
fixture_conn = _make_mp_votes_db()
|
||||
|
||||
monkeypatch.setattr(_duckdb, "connect", lambda path, **kw: fixture_conn)
|
||||
|
||||
import importlib
|
||||
import sys
|
||||
|
||||
if "streamlit" not in sys.modules:
|
||||
import types
|
||||
|
||||
st_stub = types.ModuleType("streamlit")
|
||||
st_stub.cache_data = lambda **kw: lambda f: f
|
||||
sys.modules["streamlit"] = st_stub
|
||||
|
||||
import explorer as _explorer
|
||||
|
||||
importlib.reload(_explorer)
|
||||
|
||||
df = _explorer.compute_party_discipline(
|
||||
db_path="dummy",
|
||||
start_date="2023-01-01",
|
||||
end_date="2023-12-31",
|
||||
)
|
||||
|
||||
assert not df.empty
|
||||
assert set(df.columns) >= {"party", "n_motions", "discipline"}
|
||||
|
||||
sp_row = df[df["party"] == "SP"].iloc[0]
|
||||
vvd_row = df[df["party"] == "VVD"].iloc[0]
|
||||
|
||||
assert sp_row["n_motions"] == 6
|
||||
assert sp_row["discipline"] == pytest.approx(1.0, abs=1e-6)
|
||||
|
||||
assert vvd_row["n_motions"] == 6
|
||||
expected_vvd = (4 * 1.0 + 2 * 0.75) / 6
|
||||
assert vvd_row["discipline"] == pytest.approx(expected_vvd, abs=1e-4)
|
||||
|
||||
assert (df["discipline"] >= 0).all() and (df["discipline"] <= 1).all()
|
||||
|
||||
|
||||
def test_compute_party_discipline_empty_range(monkeypatch):
|
||||
"""Returns empty DataFrame when no motions fall in the date range."""
|
||||
import duckdb as _duckdb
|
||||
|
||||
fixture_conn = _make_mp_votes_db()
|
||||
monkeypatch.setattr(_duckdb, "connect", lambda path, **kw: fixture_conn)
|
||||
|
||||
import importlib, sys
|
||||
|
||||
if "streamlit" not in sys.modules:
|
||||
import types
|
||||
|
||||
st_stub = types.ModuleType("streamlit")
|
||||
st_stub.cache_data = lambda **kw: lambda f: f
|
||||
sys.modules["streamlit"] = st_stub
|
||||
|
||||
import explorer as _explorer
|
||||
|
||||
importlib.reload(_explorer)
|
||||
|
||||
df = _explorer.compute_party_discipline(
|
||||
db_path="dummy",
|
||||
start_date="2000-01-01",
|
||||
end_date="2000-12-31",
|
||||
)
|
||||
|
||||
assert df.empty
|
||||
|
||||
Reference in New Issue
Block a user