#!/usr/bin/env python3 """Generate self-contained HTML dashboard for Massie 119th Congress voting analysis.""" import json from collections import Counter, defaultdict votes = json.load(open("/home/user/polisci/votes.json")) # Aggregate align_counts = Counter(v["alignment"] for v in votes) massie_counts = Counter(v["massie"] for v in votes) blocked_counts = Counter(v["blocked"] for v in votes if v["blocked"]) # Monthly alignment trend month_align = defaultdict(lambda: Counter()) MONTHS = ["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"] def month_key(v): # date like "3-Jan-2025" try: d, m, y = v["date"].split("-") return f"{y}-{MONTHS.index(m)+1:02d}" except Exception: return None for v in votes: mk = month_key(v) if mk: month_align[mk][v["alignment"]] += 1 months_sorted = sorted(month_align.keys()) align_labels = ["Helped Republicans", "Helped Democrats", "Helped Both", "Helped Neither"] monthly_series = {lab: [month_align[m].get(lab, 0) for m in months_sorted] for lab in align_labels} # Blocked measures - list for table blocked_dem = [v for v in votes if v["blocked"] == "Democrat"] blocked_rep = [v for v in votes if v["blocked"] == "Republican"] # All vote rows (compact) for filterable table def row(v): return { "y": v["year"], "r": v["roll"], "d": v["date"], "ln": v["legis_num"], "q": v["question"], "ds": v["desc"][:90], "rs": v["result"], "m": v["massie"], "ry": v["R"]["yea"], "rn": v["R"]["nay"], "dy": v["D"]["yea"], "dn": v["D"]["nay"], "a": v["alignment"], "b": v["blocked"] or "", } rows = [row(v) for v in votes] # Summary stats total = len(votes) voting = sum(1 for v in votes if v["massie"] in ("Yea","Nay","Aye","No")) yeas = sum(1 for v in votes if v["massie"] in ("Yea","Aye")) nays = sum(1 for v in votes if v["massie"] in ("Nay","No")) nv = sum(1 for v in votes if v["massie"] == "Not Voting") present = sum(1 for v in votes if v["massie"] == "Present") # Lone-wolf: cases where Massie was on the losing side with very few co-defectors of his own party lone_wolf = 0 for v in votes: if v["massie"] not in ("Yea","Nay","Aye","No"): continue m_norm = "Yea" if v["massie"] in ("Yea","Aye") else "Nay" r_pos = "Yea" if v["R"]["yea"] > v["R"]["nay"] else ("Nay" if v["R"]["nay"] > v["R"]["yea"] else "Split") if r_pos != "Split" and m_norm != r_pos: # how many Republicans defected with him? defectors = v["R"]["nay"] if r_pos == "Yea" else v["R"]["yea"] if defectors <= 5: lone_wolf += 1 voted_against_gop = 0 voted_against_dem = 0 voted_with_gop = 0 voted_with_dem = 0 for v in votes: if v["massie"] not in ("Yea","Nay","Aye","No"): continue m_norm = "Yea" if v["massie"] in ("Yea","Aye") else "Nay" r_pos = "Yea" if v["R"]["yea"] > v["R"]["nay"] else ("Nay" if v["R"]["nay"] > v["R"]["yea"] else "Split") d_pos = "Yea" if v["D"]["yea"] > v["D"]["nay"] else ("Nay" if v["D"]["nay"] > v["D"]["yea"] else "Split") if r_pos != "Split": if m_norm == r_pos: voted_with_gop += 1 else: voted_against_gop += 1 if d_pos != "Split": if m_norm == d_pos: voted_with_dem += 1 else: voted_against_dem += 1 data = { "total": total, "voting": voting, "yeas": yeas, "nays": nays, "nv": nv, "present": present, "alignment": dict(align_counts), "massie": dict(massie_counts), "blocked": dict(blocked_counts), "months": months_sorted, "monthly": monthly_series, "rows": rows, "blocked_dem_count": len(blocked_dem), "blocked_rep_count": len(blocked_rep), "lone_wolf": lone_wolf, "voted_against_gop": voted_against_gop, "voted_against_dem": voted_against_dem, "voted_with_gop": voted_with_gop, "voted_with_dem": voted_with_dem, } # Write to template HTML = """
| Yr | # | Date | Bill | Question | Description | Result | Massie | R Yea | R Nay | D Yea | D Nay | Alignment | Blocked |
|---|