import pandas as pd
import plotly.express as px
from hh.io import read_parquet
from hh.viz import style, CATEGORICAL, BLUE, SEQUENTIAL_BLUE, INK, MUTED
households = read_parquet("processed", "households_summary.parquet")
regs = read_parquet("processed", "registrations_enriched.parquet")
# headline figures (computed, not hardcoded)
_order = ["[0, 1)", "[1, 5)", "[5, 10)", "[10, 20)", "[20, ∞)"]
_d = (
households[households["is_donor"]]
.groupby("distance_band", observed=True)["total_donations"]
.sum()
.reindex(_order)
.fillna(0)
)
_c = _d.cumsum() / _d.sum()
within5, within10, within20 = (
f"{_c.loc[b]:.0%}" for b in ("[1, 5)", "[5, 10)", "[10, 20)")
)
n_hh = f"{len(households):,}"
n_donors = f"{int(households['is_donor'].sum()):,}"
n_patrons = f"{int(households['is_patron'].sum()):,}"
n_class = f"{int(households['is_class_taker'].sum()):,}"
n_donor_class = f"{int((households['is_donor'] & households['is_class_taker']).sum()):,}"
n_all3 = f"{int((households['is_donor'] & households['is_patron'] & households['is_class_taker']).sum()):,}"
from hh.analytics.productions import is_excluded, count_succeeded_attendees
_near = ["[0, 1)", "[1, 5)", "[5, 10)"]
_cl = regs[regs["event_majorcat"] == "class"].dropna(subset=["distance_band"])
class_w10 = f"{_cl['distance_band'].isin(_near).mean():.0%}"
_th = regs[regs["event_minorcat"] == "theater"].dropna(subset=["distance_band"])
theater_w10 = f"{_th['distance_band'].isin(_near).mean():.0%}"
_perf = regs[(regs["event_majorcat"] == "performance") & ~regs["event_name"].map(is_excluded)].copy()
_perf["attendees"] = _perf["tickets"].map(count_succeeded_attendees)
_don = _perf.merge(households[["id", "is_donor"]], on="id", how="left")
donor_att_share = f"{_don.loc[_don['is_donor'].fillna(False), 'attendees'].sum() / _don['attendees'].sum():.0%}"
# donor concentration & persistence (new donor chapters)
from hh.clean.accounts import clean_accounts
from hh.clean.donations import clean_donations
from hh.analytics.donors import annual_gifts, donor_retention
_dt = households.loc[households["is_donor"], "total_donations"]
large_donor_share = f"{(_dt >= 1000).mean():.0%}"
large_dollar_share = f"{_dt[_dt >= 1000].sum() / _dt.sum():.0%}"
_ag = annual_gifts(clean_donations(accounts=clean_accounts()))
_max_year = int(_ag["year"].max())
_ret = donor_retention(_ag)
_ret = _ret[_ret["year"] < _max_year - 1] # drop the row whose next year is the partial current year
_ret_year = int(_ret["year"].iloc[-1])
_recent_ret = f"{_ret['retention'].iloc[-1]:.0%}"