poli-sci-kit is a Python package for political science appointment and election analysis. The goal is to provide a comprehensive tool for all methods needed to analyze and simulate election results. See the documentation for a full outline of the package including algorithms and visualization techniques.
poli-sci-kit can be downloaded from PyPI via pip or sourced directly from this repository:
pip install poli-sci-kit
git clone https://github.com/andrewtavis/poli-sci-kit.git cd poli-sci-kit python setup.py install
appointment.methods includes functions to allocate parliamentary seats based on population or vote shares. Included methods are:
Largest Remainder: Hare, Droop, Hagenbach–Bischoff (incl Hamilton, Vinton, Hare–Niemeyer)
Highest Average: Jefferson, Webster, Huntington-Hill
Arguments to allow allocation thresholds, minimum allocations per group, tie break conditions, and other election features are also provided. Along with deriving results for visualization and reporting, these functions allow the user to analyze outcomes given systematic or situational changes. The appointment.metrics module further provides diagnostics to analyze the results of elections, apportionments, and other political science scenarios.
A basic example of political appointment using poli-sci-kit is:
from poli_sci_kit import appointment vote_counts = [2700, 900, 3300, 1300, 2150, 500] seats_to_allocate = 50 # Huntington-Hill is the method used to allocate House of Representatives seats to US states ha_allocations = appointment.methods.highest_average( averaging_style="Huntington-Hill", shares=vote_counts, total_alloc=seats_to_allocate, alloc_threshold=None, min_alloc=1, tie_break="majority", majority_bonus=False, modifier=None, ) ha_allocations # [26, 9, 37, 12, 23, 5] # The Gallagher method is a measure of absolute difference similar to summing square residuals disproportionality = appointment.metrics.dispr_index( shares=vote_counts, allocations=ha_allocations, metric_type='Gallagher' ) disproportionality # 0.01002
We can also check that the allocations pass the quota condition:
passes_qc = appointment.checks.quota_condition( shares=vote_counts, seats=ha_allocations ) passes_qc # True
poli-sci-kit provides Python only implementations of common electoral plots.
Visualizing the above results:
import matplotlib.pyplot as plt import poli_sci_kit # German political parties parties = ['CDU/CSU', 'FDP', 'Greens', 'Die Linke', 'SPD', 'AfD'] party_colors = ['#000000', '#ffed00', '#64a12d', '#be3075', '#eb001f', '#009ee0']
poli_sci_kit provides implementations of both rectangular and semicircle parliament plots:
fig, (ax1, ax2) = plt.subplots(nrows=1, ncols=2) ax1 = poli_sci_kit.plot.parliament( allocations=seat_allocations, labels=parties, colors=party_colors, style="rectangle", num_rows=4, marker_size=300, speaker=True, axis=ax1, ) ax2 = poli_sci_kit.plot.parliament( allocations=seat_allocations, labels=parties, colors=party_colors, style="semicircle", num_rows=4, marker_size=175, speaker=False, axis=ax2, ) plt.show()
Disproportionality Bar Plot
A novel addition to social science analysis is the disproportionality bar plot, which graphically depicts the disproportionality between expected and realized results. Bar widths are the proportion of shares (ex: votes received), and heights are the difference or relative difference between shares and allocations (ex: parliament seats received).
An example follows:
import pltviz ax = poli_sci_kit.plot.dispr_bar( shares=votes, allocations=ha_allocations, labels=parties, colors=party_colors, total_shares=None, total_alloc=None, percent=True, axis=None, ) handles, labels = pltviz.plot.legend.gen_elements( counts=[round(v / sum(votes), 4) for v in votes], labels=parties, colors=party_colors, size=11, marker="o", padding_indexes=None, order=None, ) ax.legend( handles=handles, labels=labels, title="Vote Percents (bar widths)", title_fontsize=15, fontsize=11, ncol=2, loc="upper left", bbox_to_anchor=(0, 1), frameon=True, facecolor="#FFFFFF", framealpha=1, ) ax.axes.set_title('Seat to Vote Share Disproportionality', fontsize=30) ax.set_xlabel('Parties', fontsize=20) ax.set_ylabel('Percent Shift', fontsize=20) plt.show()
Examples in poli-sci-kit use publicly available Wikidata statistics sourced via the Python package wikirepo. Current examples include:
- Allocates seats to a version of the US House of Representatives that includes all US territories and Washington DC given census data, with this further being used to derive relative vote strengths of state citizens in the US presidential election
- Analyzes the allocation of seats in a hypothetical global parliament given the prevalence of certain countries and organizations, the distribution of seats based on Freedom House indexes, as well as disproportionality metrics