feat(overton): coalition coding fix + regenerate breakpoint analysis
This commit is contained in:
@@ -16,6 +16,7 @@ Output:
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import datetime
|
||||
import json
|
||||
import logging
|
||||
import random
|
||||
@@ -24,6 +25,9 @@ import sys
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
ROOT = Path(__file__).parent.parent.parent.resolve()
|
||||
sys.path.insert(0, str(ROOT))
|
||||
|
||||
import duckdb
|
||||
import matplotlib
|
||||
import numpy as np
|
||||
@@ -58,6 +62,9 @@ def _extremity_bucket(score: float) -> str:
|
||||
CANONICAL_LEFT_SET = set(CANONICAL_LEFT)
|
||||
CANONICAL_RIGHT_SET = set(CANONICAL_RIGHT)
|
||||
|
||||
RUTTE_IV_COALITION: set[str] = {"VVD", "D66", "CDA", "CU"}
|
||||
SCHOOF_COALITION: set[str] = {"PVV", "VVD", "NSC", "BBB"}
|
||||
|
||||
COALITION: dict[int, set[str]] = {
|
||||
2016: {"VVD", "PvdA"},
|
||||
2017: {"VVD", "PvdA"},
|
||||
@@ -67,18 +74,21 @@ COALITION: dict[int, set[str]] = {
|
||||
2021: {"VVD", "CDA", "D66", "CU"},
|
||||
2022: {"VVD", "D66", "CDA", "CU"},
|
||||
2023: {"VVD", "D66", "CDA", "CU"},
|
||||
2024: {"PVV", "VVD", "NSC", "BBB"},
|
||||
2025: {"PVV", "VVD", "NSC", "BBB"},
|
||||
2026: {"PVV", "VVD", "NSC", "BBB"},
|
||||
2024: SCHOOF_COALITION,
|
||||
2025: SCHOOF_COALITION,
|
||||
2026: SCHOOF_COALITION,
|
||||
}
|
||||
|
||||
SCHOOF_START_DATE = "2024-07-01"
|
||||
|
||||
COALITION_NOTE = (
|
||||
"2016-2017: Rutte II (VVD/PvdA). "
|
||||
"2018-2021: Rutte III (VVD/CDA/D66/CU). "
|
||||
"2022-2023: Rutte IV (VVD/D66/CDA/CU). "
|
||||
"2024-2026: Schoof (PVV/VVD/NSC/BBB). "
|
||||
"2024 ambiguous: Schoof cabinet started July 2024; all 2024 motions are coded "
|
||||
"to the Schoof coalition. Coalition effect may be overestimated for early 2024."
|
||||
"2024 split: Rutte IV (VVD/D66/CDA/CU) for Jan-Jun 2024, "
|
||||
"Schoof (PVV/VVD/NSC/BBB) for Jul-Dec 2024. "
|
||||
"2025-2026: Schoof (PVV/VVD/NSC/BBB). "
|
||||
"Period detection uses motion date, not just year."
|
||||
)
|
||||
|
||||
YEAR_MIN, YEAR_MAX = 2016, 2026
|
||||
@@ -114,7 +124,8 @@ def compute_yearly_rw_metrics(con: duckdb.DuckDBPyConnection) -> dict[int, dict]
|
||||
r.category,
|
||||
e.text_score AS extremity_score,
|
||||
m.voting_results,
|
||||
m.winning_margin
|
||||
m.winning_margin,
|
||||
m.date
|
||||
FROM right_wing_motions r
|
||||
JOIN extremity_scores e ON r.motion_id = e.motion_id
|
||||
JOIN motions m ON r.motion_id = m.id
|
||||
@@ -135,9 +146,10 @@ def compute_yearly_rw_metrics(con: duckdb.DuckDBPyConnection) -> dict[int, dict]
|
||||
"categories": [],
|
||||
"titles": [],
|
||||
"motion_ids": [],
|
||||
"dates": [],
|
||||
}
|
||||
|
||||
for mid, year, title, cst, crs, rs, lo, cat, ext, vr_json, wm in rows:
|
||||
for mid, year, title, cst, crs, rs, lo, cat, ext, vr_json, wm, motion_date in rows:
|
||||
if year is None or year < YEAR_MIN or year > YEAR_MAX:
|
||||
continue
|
||||
yearly[year]["centrist_support_strict"].append(cst if cst is not None else np.nan)
|
||||
@@ -148,6 +160,7 @@ def compute_yearly_rw_metrics(con: duckdb.DuckDBPyConnection) -> dict[int, dict]
|
||||
yearly[year]["categories"].append(cat or "other")
|
||||
yearly[year]["titles"].append(title or "")
|
||||
yearly[year]["motion_ids"].append(mid)
|
||||
yearly[year]["dates"].append(motion_date)
|
||||
|
||||
if vr_json is not None:
|
||||
voting = json.loads(vr_json) if isinstance(vr_json, str) else vr_json
|
||||
@@ -299,9 +312,9 @@ def compute_opposition_metrics(
|
||||
}
|
||||
|
||||
coalition = COALITION
|
||||
schoof_cutoff = datetime.date(2024, 7, 1)
|
||||
|
||||
for year, d in yearly_raw.items():
|
||||
coal = coalition.get(year, set())
|
||||
for idx in range(len(d["titles"])):
|
||||
title = d["titles"][idx]
|
||||
submitter_name, submitter_party = parse_lead_submitter(title, name_party_map)
|
||||
@@ -309,6 +322,13 @@ def compute_opposition_metrics(
|
||||
if submitter_party is None:
|
||||
continue
|
||||
|
||||
motion_date = d["dates"][idx] if idx < len(d.get("dates", [])) else None
|
||||
|
||||
if year == 2024 and motion_date is not None:
|
||||
coal = RUTTE_IV_COALITION if motion_date < schoof_cutoff else SCHOOF_COALITION
|
||||
else:
|
||||
coal = coalition.get(year, set())
|
||||
|
||||
if submitter_party in coal:
|
||||
continue
|
||||
|
||||
|
||||
Reference in New Issue
Block a user