Partisan Bias & Responsiveness
You can compute a full complement of partisan analytics for a set of districts all at once, described next, or you can compute individual metrics, described in the subsequent sections.
Partisan Analytics for a Set of Districts
To calculate all partisan analytics for a statewide two-party vote share and two-party vote shares by district:
def calc_partisan_metrics(Vf: float, Vf_array: list[float]) -> dict:
where “Vf” is the statewide two-party vote share, and “Vf_array” is a list of two-party vote shares by district.
Examples can be found in the “partisanship” section of the profiles in the testdata/CD116 directory.
This returns a dictionary of results:
results: dict = {
"bias": bias_measurements,
"responsiveness": responsiveness_measurements,
"dSVpoints": dSVpoints,
"rSVpoints": rSVpoints,
"averageDVf": averageDVf,
"averageRVf": averageRVf,
}
# where:
bias_measurements: dict = {
"bestS": bestS,
"estS": estS,
"deviation": deviation,
"tOf": TOf,
"fptpS": fptpS,
"bS50": Bs50f,
"bV50": Bv50f,
"decl": decl,
"rvPoints": rvPoints,
"eG": EG,
"eGFPTP": EG_FPTP,
"bSV": BsGf,
"prop": prop,
"mMs": mMs,
"mMd": mMd,
"lO": LO,
}
responsiveness_measurements: dict = {
"cSimple": Cn,
"cD": cD,
"bigR": bigR,
"littleR": littleR,
"mIR": MIR,
"rD": rD,
"rDf": rDf,
"averageMargin": average_margin,
}
The dictionary key names here match those in the relevant sections of the Map Analytics Format.
Measures of Bias
The bias measures above are described in Advanced Measures of Bias & Responsiveness. They may be calculated individually.
In the functions below:
- Vf - is generally the statewide two-party vote share, but sometimes it’s the two-party vote share for one district
- Sf - is the two-party seat share
- N - the number of districts
- Vf_array - is a list of two-party vote shares by district
def calc_best_seats(N: int, Vf: float) -> int:
def calc_disproportionality_from_best(est_Sf: float, best_Sf: float) -> float:
def calc_disproportionality(Vf: float, Sf: float) -> float:
def calc_efficiency_gap(Vf: float, Sf: float) -> float:
def calc_efficiency_gap_wasted_votes(dem_votes_by_district: List[int], rep_votes_by_district: List[int]) -> float
def calc_gamma(Vf: float, Sf: float, r: float) -> float:
def est_seats_bias(sv_curve_pts: list[tuple[float, float]], N: int) -> float:
def est_votes_bias(sv_curve_pts: list[tuple[float, float]], N: int) -> float:
def est_geometric_seats_bias(
Vf: float,
d_sv_pts: list[tuple[float, float]],
r_sv_pts: list[tuple[float, float]],
) -> float:
def calc_global_symmetry(
d_sv_pts: list[tuple[float, float]],
r_sv_pts: list[tuple[float, float]],
S50V: float,
) -> float:
def calc_declination(Vf_array: list[float]) -> Optional[float]:
Note: This function supports both median difference using average district vote share and median difference using statewide vote share, if provided.
def calc_mean_median_difference(
Vf_array: list[float], Vf: Optional[float] = None
) -> float:
def calc_turnout_bias(Vf: float, Vf_array: list[float]) -> float:
def calc_lopsided_outcomes(Vf_array: list[float]) -> Optional[float]:
Measures of Responsiveness
Similarly, you can compute the responsiveness measures individually. These responsiveness measures are also described in Advanced Measures of Bias & Responsiveness.
def count_competitive_districts(Vf_array: list[float]) -> int:
def est_competitive_districts(Vf_array: list[float]) -> float:
def est_district_competitiveness(Vf: float) -> float:
def est_responsiveness(
Vf: float, sv_curve_pts: list[tuple[float, float]], N: int
) -> float:
def calc_big_R(Vf: float, Sf: float) -> Optional[float]:
def calc_minimal_inverse_responsiveness(Vf: float, r: float) -> Optional[float]:
def est_responsive_districts(Vf_array: list[float]) -> float:
def calc_average_margin(Vf_array: List[float]) -> float:
Nagle’s Method
Finally, several functions expose John Nagle’s method for estimating fractional seat probabilities and district responsiveness and inferring seats-votes curves.
To estimate the fractional probability of a seat win for district, given a two-party vote share:
def est_seat_probability(Vf: float) -> float:
Similarly, to estimate the responsiveness of a district, given a two-party vote share:
def est_district_responsiveness(Vf: float) -> float:
To estimate the fractional # of seats for a set of two-party vote shares, using seat probabilities:
def est_seats(Vf_array: list[float]) -> float:
To estimate the fractional # of seats for a set of two-party vote shares, using first past the post accounting:
def est_fptp_seats(Vf_array: list[float]) -> int:
To infer the points of an seats-votes curve from a set of two-party vote shares by district, using either proportional or uniform shifts in statewide vote share:
def infer_sv_points(Vf: float, Vf_array: list[float], proportional=True) -> list[tuple]:
Finally, to infer the points of an inverse points from a set of inferred seats-votes curve points:
def infer_inverse_sv_points(sv_pts: list[tuple], N: int) -> list[tuple[float, float]]: