API Reference

Ballot

class votekit.ballot.RankBallot(*, ranking: Sequence[Iterable[str]] | None = None, scores: dict[str, int | float] | None = None, weight: float | int = 1.0, voter_set: set[str] | frozenset[str] = frozenset({}))

Class to handle ballots with rankings. Strips whitespace from candidate names.

Parameters:
  • ranking (RankingLike) – Ranking of candidates, defaults to None.

  • weight (Union[int, float]) – Weight of the ballot, defaults to 1.0.

  • voter_set (Union[set[str], frozenset[str]]) – Voter set of the ballot, defaults to frozenset().

ranking

Ranking of candidates.

Type:

RankingLike

weight

Weight of the ballot.

Type:

float

voter_set

Voter set of the ballot.

Type:

frozenset[str]

Raises:
  • ValueError – Candidate ‘~’ found in ballot ranking.

  • ValueError – Ballot weight cannot be negative.

class votekit.ballot.ScoreBallot(*, ranking: Sequence[Iterable[str]] | None = None, scores: dict[str, int | float] | None = None, weight: float | int = 1.0, voter_set: set[str] | frozenset[str] = frozenset({}))

Class to handle ballots with scores. Strips whitespace from candidate names.

Parameters:
  • scores (Optional[dict[str, Union[int, float]]]) – Scores of candidates, defaults to None.

  • weight (Union[int, float]) – Weight of the ballot, defaults to 1.0.

  • voter_set (Union[set[str], frozenset[str]]) – Voter set of the ballot, defaults to frozenset().

scores

Scores of candidates.

Type:

Optional[dict[str, float]]

weight

Weight of the ballot.

Type:

float

voter_set

Voter set of the ballot.

Type:

frozenset[str]

Raises:
  • ValueError – Candidate ‘~’ found in ballot scores.

  • ValueError – Ballot weight cannot be negative.

  • TypeError – Score values must be numeric.

Preference Profiles

class votekit.pref_profile.RankProfile(*, ballots: ~typing.Sequence[~votekit.Ballot] = (), candidates: ~typing.Sequence[str] = (), max_ranking_length: int = 0, df: ~pandas.DataFrame = Empty DataFrame Columns: [] Index: [], **kwargs)
property ballots: tuple[RankBallot, ...]

Compute the ballot tuple as a cached property.

classmethod from_csv(fpath: str | PathLike | Path) PreferenceProfile[source]

Creates a PreferenceProfile from a csv, formatted from the to_csv method.

Parameters:

fpath (Union[str, PathLike, Path]) – Path to csv.

Raises:
  • ValueError – If csv is improperly formatted for VoteKit.

  • ProfileError – If read profile has no rankings or scores.

group_ballots() RankProfile[source]

Groups ballots by rankings and updates weights. Retains voter sets, but loses ballot indices.

Returns:

A RankProfile object with grouped ballot list.

Return type:

RankProfile

property max_candidates_ranked: int

The maximum number of candidates ranked on any ballot in the profile.

Can be longer than max_ranking_length if a ballot has ties. E.g., a ballot that ranks two candidates tied for first and ranks no other candidates has length 1, but ranks 2 candidates in total.

to_csv(fpath: str | PathLike | Path | None = None, include_voter_set: bool = False, weight_precision: int = 2) str | None[source]

Saves PreferenceProfile to a custom CSV format.

Parameters:
  • fpath (str | PathLike | Path | None, optional) – Path to the saved csv. If None, returns the CSV content as a string instead of writing to disk. Defaults to None.

  • include_voter_set (bool, optional) – Whether or not to include the voter set of each ballot. Defaults to False.

  • weight_precision (int) – Number of decimals to round float weights to. Defaults to 2.

Returns:

The CSV content as a string when fpath is None, otherwise None.

Return type:

str | None

Raises:
  • ProfileError – Cannot write a profile with no ballots to a csv.

  • ValueError – File path must be provided.

class votekit.pref_profile.ScoreProfile(*, ballots: ~typing.Sequence[~votekit.Ballot] = (), candidates: ~typing.Sequence[str] = (), max_ranking_length: int = 0, df: ~pandas.DataFrame = Empty DataFrame Columns: [] Index: [], **kwargs)
property ballots: tuple[ScoreBallot, ...]

Compute the ballot tuple as a cached property.

classmethod from_csv(fpath: str | PathLike | Path) PreferenceProfile[source]

Creates a PreferenceProfile from a csv, formatted from the to_csv method.

Parameters:

fpath (str) – Path to csv.

Raises:
  • ValueError – If csv is improperly formatted for VoteKit.

  • ProfileError – If read profile has no rankings or scores.

group_ballots() ScoreProfile[source]

Groups ballots by scores and updates weights. Retains voter sets, but loses ballot ids.

Returns:

A ScoreProfile object with grouped ballot list.

Return type:

ScoreProfile

to_csv(fpath: str | PathLike | Path | None = None, include_voter_set: bool = False, weight_precision: int = 2) str | None[source]

Saves PreferenceProfile to a custom CSV format.

Parameters:
  • fpath (str | PathLike | Path | None, optional) – Path to the saved csv. If None, returns the CSV content as a string instead of writing to disk. Defaults to None.

  • include_voter_set (bool, optional) – Whether or not to include the voter set of each ballot. Defaults to False.

  • weight_precision (int) – Number of decimals to round float weights to. Defaults to 2.

Returns:

The CSV content as a string when fpath is None, otherwise None.

Return type:

str | None

Raises:
  • ProfileError – Cannot write a profile with no ballots to a csv.

  • ValueError – File path must be provided.

class votekit.pref_profile.CleanedRankProfile(*args, **kwargs)

CleanedRankProfile class, which is used to keep track of how ballots are altered from the original profile. In addition to a custom __str__ method, this class implements a collection of sets that track the indices of the ballot dataframe, and how they are changed by different cleaning rules. It also retains the parent profile of the CleanedRankProfile, allowing for full recovery of the cleaning steps.

Parameters:
  • ballots (tuple[Ballot], optional) – Tuple of Ballot objects. Defaults to empty tuple.

  • candidates (tuple[str], optional) – Tuple of candidate strings. Defaults to empty tuple. If empty, computes this from any candidate listed on a ballot with positive weight.

  • max_ranking_length (int, optional) – The length of the longest allowable ballot, i.e., how many candidates are allowed to be ranked in an election. Defaults to longest observed ballot.

  • parent_profile (PreferenceProfile | CleanedProfile) – The profile that was altered. If you apply multiple cleaning functions, the parent is always the profile immediately before cleaning, so you need to recurse to get the original, uncleaned profile.

  • df_index_column (list[int]) – The indices of the ballots in the df from the parent profile.

  • no_wt_altr_idxs (set[int], optional) – Set of indices of ballots that have 0 weight as a result of cleaning. Indices are with respect to parent_profile.df.

  • no_rank_altr_idxs (set[int], optional) – Set of indices of ballots that have no ranking as a result of cleaning. Indices are with respect to parent_profile.df.

  • nonempty_altr_idxs (set[int], optional) – Set of indices of ballots that have been altered but still have weight and (ranking or score) as a result of cleaning. Indices are with respect to parent_profile.df.

  • unaltr_idxs (set[int], optional) – Set of indices of ballots that have been unaltered by cleaning. Indices are with respect to parent_profile.df.

class votekit.pref_profile.CleanedScoreProfile(*args, **kwargs)

CleanedScoreProfile class, which is used to keep track of how ballots are altered from the original profile. In addition to a custom __str__ method, this class implements a collection of sets that track the indices of the ballot dataframe, and how they are changed by different cleaning rules. It also retains the parent profile of the CleanedScoreProfile, allowing for full recovery of the cleaning steps.

Parameters:
  • ballots (tuple[Ballot], optional) – Tuple of Ballot objects. Defaults to empty tuple.

  • candidates (tuple[str], optional) – Tuple of candidate strings. Defaults to empty tuple. If empty, computes this from any candidate listed on a ballot with positive weight.

  • parent_profile (ScoreProfile | CleanedScoreProfile) – The profile that was altered. If you apply multiple cleaning functions, the parent is always the profile immediately before cleaning, so you need to recurse to get the original, uncleaned profile.

  • df_index_column (list[int]) – The indices of the ballots in the df from the parent profile.

  • no_wt_altr_idxs (set[int], optional) – Set of indices of ballots that have 0 weight as a result of cleaning. Indices are with respect to parent_profile.df.

  • no_scores_altr_idxs (set[int], optional) – Set of indices of ballots that have no scores as a result of cleaning. Indices are with respect to parent_profile.df.

  • nonempty_altr_idxs (set[int], optional) – Set of indices of ballots that have been altered but still have weight and (ranking or score) as a result of cleaning. Indices are with respect to parent_profile.df.

  • unaltr_idxs (set[int], optional) – Set of indices of ballots that have been unaltered by cleaning. Indices are with respect to parent_profile.df.

votekit.pref_profile.rank_profile_to_ballot_dict(rank_profile: RankProfile, standardize: bool = False) dict[RankBallot, float]

Converts profile to dictionary with keys = ballots and values = corresponding total weights.

Parameters:
  • rank_profile (RankProfile) – Profile to convert.

  • standardize (bool, optional) – If True, divides the weight of each ballot by the total weight. Defaults to False.

Returns:

A dictionary with ballots (keys) and corresponding total weights (values).

Return type:

dict[Ballot, float]

votekit.pref_profile.score_profile_to_ballot_dict(score_profile: ScoreProfile, standardize: bool = False) dict[ScoreBallot, float]

Converts profile to dictionary with keys = ballots and values = corresponding total weights.

Parameters:
  • score_profile (ScoreProfile) – Profile to convert.

  • standardize (bool, optional) – If True, divides the weight of each ballot by the total weight. Defaults to False.

Returns:

A dictionary with ballots (keys) and corresponding total weights (values).

Return type:

dict[Ballot, float]

votekit.pref_profile.rank_profile_to_ranking_dict(rank_profile: RankProfile, standardize: bool = False) dict[tuple[frozenset[str], ...], float]

Converts profile to dictionary with keys = rankings and values = corresponding total weights.

Parameters:
  • rank_profile (RankProfile) – Profile to convert.

  • standardize (bool, optional) – If True, divides the weight of each ballot by the total weight. Defaults to False.

Returns:

A dictionary with rankings (keys) and corresponding total weights (values).

Return type:

dict[tuple[frozenset[str],…], float]

Raises:

TypeError – Profile must be a RankProfile.

votekit.pref_profile.score_profile_to_scores_dict(score_profile: ScoreProfile, standardize: bool = False) dict[tuple[tuple[str, float], ...] | None, float]

Converts profile to dictionary with keys = scores and values = corresponding total weights.

Parameters:
  • score_profile (ScoreProfile) – Profile to convert.

  • standardize (bool, optional) – If True, divides the weight of each ballot by the total weight. Defaults to False.

Returns:

A dictionary with scores (keys) and corresponding total weights (values).

Return type:

dict[tuple[tuple[str, float], …] | None, float]

Raises:

TypeError – Profile must be a ScoreProfile.

votekit.pref_profile.profile_df_head(profile: PreferenceProfile, n: int, sort_by_weight: bool | None = True, percents: bool | None = False, totals: bool | None = False, n_decimals: int = 1) pd.DataFrame

Returns a pd.DataFrame with the top-n ballots in profile.

Parameters:
  • n (int) – Number of ballots to view.

  • sort_by_weight (bool, optional) – If True, rank ballot from most to least votes. If sorting by weight, index resets. Defaults to True.

  • percents (bool, optional) – If True, show voter share for a given ballot. Defaults to False.

  • totals (bool, optional) – If True, show total values for Percent and Weight. Defaults to False.

  • n_decimals (int, optional) – Number of decimals to round to. Defaults to 1.

Returns:

A dataframe with top-n ballots.

Return type:

pandas.DataFrame

Raises:

ZeroDivisionError – Profile has 0 total ballot weight; cannot show percentages.

votekit.pref_profile.profile_df_tail(profile: PreferenceProfile, n: int, sort_by_weight: bool | None = True, percents: bool | None = False, totals: bool | None = False, n_decimals: int = 1) pd.DataFrame

Returns a pd.DataFrame with the bottom-n ballots in profile.

Parameters:
  • n (int) – Number of ballots to view.

  • sort_by_weight (bool, optional) – If True, rank ballot from least to most votes. Defaults to True.

  • percents (bool, optional) – If True, show voter share for a given ballot. Defaults to False.

  • totals (bool, optional) – If True, show total values for Percent and Weight. Defaults to False.

  • n_decimals (int, optional) – Number of decimals to round to. Defaults to 1.

Returns:

A data frame with bottom-n ballots.

Return type:

pandas.DataFrame

Raises:

ZeroDivisionError – Profile has 0 total ballot weight; cannot show percentages.

votekit.pref_profile.convert_row_to_rank_ballot(row: Series, max_ranking_length: int = 0) RankBallot

Convert a row of a properly formatted profile.df to a Ballot.

Parameters:
  • row (pd.Series) – Row of a profile.df.

  • max_ranking_length (int, optional) – The maximum length of a ranking. Defaults to 0, which is used for ballots with no ranking.

Returns:

Ballot corresponding to the row of the df.

Return type:

RankBallot

votekit.pref_profile.convert_rank_profile_to_score_profile_via_score_vector(rank_profile: RankProfile, score_vector: Sequence[float]) ScoreProfile

Convert a rank profile to a score profile using a score vector. Ballots must not contain ties. Score vector should be non-increasing and non-negative.

Parameters:
  • rank_profile (RankProfile) – Rank profile to convert.

  • score_vector (Sequence[float]) – Score vector to use.

Returns:

Score profile.

Return type:

ScoreProfile

Raises:
  • ValueError – Ballots must not contain ties.

  • ValueError – Score vector must be non-increasing and non-negative.

Preference Intervals

class votekit.pref_interval.PreferenceInterval(interval: dict, *, allow_zero_support: bool = False)

PreferenceInterval class, contains preference for individual candidates stored as relative share of the interval [0,1].

interval

A dictionary representing the given PreferenceInterval. The keys are candidate names, and the values are floats representing that candidates share of the interval. Does not have to sum to one, the init method will renormalize.

Type:

dict

candidates

A frozenset of candidates.

Type:

frozenset

Raises:

ValueError – If support values cannot be normalized (sum to <= 0).

Initializes a PreferenceInterval object.

Parameters:
  • interval (dict) – A dictionary representing the given PreferenceInterval. The keys are candidate names, and the values are floats representing that candidates share of the interval. Does not have to sum to one, the init method will renormalize.

  • allow_zero_support (bool) – If True, candidates with zero support are allowed. If False, all candidates must have strictly positive support.

classmethod from_dirichlet(candidates: list[str], alpha: float, *, allow_zero_support: bool = False)[source]

Samples a PreferenceInterval from the Dirichlet distribution on the candidate simplex. Alpha tends to 0 is strong support, alpha tends to infinity is uniform support, alpha = 1 is all bets are off.

Parameters:
  • candidates (list) – List of candidate strings.

  • alpha (float) – Alpha parameter for Dirichlet distribution.

  • allow_zero_support (bool) – If True, candidates with zero support are allowed. If False, all candidates must have strictly positive support.

Returns:

PreferenceInterval

Ballot Generators

class votekit.ballot_generator.BallotGenerator(**kwargs)

Bases: object

Base class for ballot generation models that use the candidate simplex (e.g. Plackett-Luce, Bradley-Terry, etc.).

Parameters:

**kwargs – Arbitrary keyword arguments needed for different models.

static ballot_pool_to_profile(ballot_pool, candidates) PreferenceProfile[source]

Given a list of ballots and candidates, convert them into a PreferenceProfile.

Parameters:
  • ballot_pool (list) – A list of ballots, where each ballot is a tuple of candidates indicating their ranking from top to bottom.

  • candidates (list) – A list of candidate strings.

Returns:

A PreferenceProfile representing the ballots in the election.

Return type:

PreferenceProfile

classmethod from_params(slate_to_candidates: dict, bloc_voter_prop: dict, cohesion_parameters: dict, alphas: dict, **data)[source]

Initializes a BallotGenerator by constructing preference intervals from parameters.

Parameters:
  • slate_to_candidates (dict) – Dictionary whose keys are bloc names and whose values are lists of candidate strings that make up the slate.

  • bloc_voter_prop (dict) – Dictionary whose keys are bloc strings and values are floats denoting population share.

  • cohesion_parameters (dict) – Dictionary mapping of bloc string to dictionary whose keys are bloc strings and values are cohesion parameters.

  • alphas (dict) – Dictionary mapping of bloc string to dictionary whose keys are bloc strings and values are alphas for Dirichlet distributions.

  • **data – kwargs to be passed to the init method.

Raises:
  • ValueError – If the voter proportion for blocs don’t sum to 1.

  • ValueError – Blocs are not the same.

Returns:

Initialized ballot generator.

Return type:

BallotGenerator

abstractmethod generate_profile(number_of_ballots: int, by_bloc: bool = False) PreferenceProfile | Tuple | dict[source]

Generates a PreferenceProfile.

Parameters:
  • number_of_ballots (int) – Number of ballots to generate.

  • by_bloc (bool) – True if you want the generated profiles returned as a tuple (pp_by_bloc, pp), where pp_by_bloc is a dictionary with keys = bloc strings and values = PreferenceProfile and pp is the aggregated profile. False if you only want the aggregated profile. Defaults to False.

Returns:

Union[PreferenceProfile, Tuple]

class votekit.ballot_generator.BlocSlateConfig(*, n_voters: int, slate_to_candidates: Mapping[str, Sequence[str]] | None = None, bloc_proportions: Mapping[str, int | float] | Series | None = None, preference_mapping: Mapping[str, Mapping[str, Mapping[str, float | int] | PreferenceInterval]] | DataFrame | None = None, cohesion_mapping: Mapping[str, Mapping[str, float] | Series] | DataFrame | None = None, allow_zero_support_candidates: bool = False, silent: bool = False)

Bases: object

Configuration object for BlocSlateGenerator that holds all the parameters needed to generate a set of ballots using one of our ballot generation algorithms involving both voter blocs and slates of candidates.

Parameters:
  • n_voters (int) – The total number of voters to simulate. Must be > 0.

  • slate_to_candidates (Optional[Mapping[str, Sequence[str]]]) – A mapping of slate names to sequences of candidate names. Each slate must have a non-empty list of candidates, and no candidate may appear in more than one slate. If None, defaults to an empty mapping.

  • bloc_proportions (Optional[BlocProportionMapping]) – A mapping of voter bloc names to their proportions in the electorate. The proportions must be non-negative and sum to 1. If None, defaults to an empty mapping.

  • preference_mapping (Optional[PreferenceMapping]) – A nested mapping of voter bloc names to slate names to either PreferenceInterval or Mapping[str, float|int] representing the preference scores for each candidate in the slate. Each bloc must have a mapping for every slate defined in slate_to_candidates, and no candidate may appear in more than one slate. The scores for each bloc and slate must be non-negative and sum to 1. If None, defaults to an empty mapping.

  • cohesion_mapping (Optional[CohesionMapping]) – A mapping of voter bloc names to mappings of slate names to their cohesion parameters. The cohesion parameters must be non-negative and sum to 1 for each bloc. If None, defaults to an empty mapping.

  • allow_zero_support_candidates (bool) – If True, permits candidates to have zero support in preference intervals. If False, every candidate support value must be strictly positive. Defaults to False.

  • silent (bool) – If True, suppresses warnings about configuration issues. Defaults to False.

n_voters

The total number of voters to simulate.

Type:

int

slate_to_candidates

A mapping of slate names to sequences of names. Behaves like a MutableMapping[str, Sequence[str]] (think dictionary).

Type:

SlateCandMap

bloc_proportions

A mapping of voter bloc names to their proportions in the electorate. Behaves like a MutableMapping[str, float] (think dictionary).

Type:

BlocProportions

preference_df

A DataFrame with blocs as the index and candidates as columns, containing the preference scores for each candidate in each bloc.

Type:

pd.DataFrame

cohesion_df

A DataFrame with blocs as the index and slates as columns, containing the cohesion parameters for each slate in each bloc.

Type:

pd.DataFrame

allow_zero_support_candidates

Whether zero support candidates are allowed in preference intervals.

Type:

bool

silent

If True, suppresses warnings about configuration issues.

Type:

bool

Warns:

ConfigurationWarning – If there is anything in the configuration that, when passed to a ballot generator, would cause an error.

Raises:
  • TypeError – On invalid types for any of the arguments or assignments (e.g., non-string keys, non-mapping shapes).

  • ValueError – On invalid values (e.g., empty candidate lists, duplicate keys, non-finite numbers, negative proportions/scores).

add_slate(slate: str, slate_candidate_list: Sequence[str]) None[source]

Add a new slate with the given candidates to the configuration.

Note: Also modifies the preference_df and cohesion_df to add dummy values for the new slate and candidates.

Parameters:
  • slate (str) – Name of the new slate to add.

  • slate_candidate_list (Sequence[str]) – List of candidate names for the new slate.

Raises:
  • ValueError – If the slate already exists

  • ValueError – If any candidate in the slate_candidate_list already exists in the configuration.

  • ValueError – If the slate_candidate_list is empty.

  • TypeError – If slate is not a str or any candidate in the slate_candidate_list is not a str.

property blocs: list[str]

A list of all voter blocs.

Derived from the keys of bloc_proportions.

Type:

Computed property

property candidates: list[str]

A flat list of all candidates in all slate.

Derived from the values of slate_to_candidates.

Type:

Computed property

clear_dirichlet_alphas() None[source]

Remove the Dirichlet alphas from the configuration.

copy() BlocSlateConfig[source]

Create a deep copy of the current configuration.

Returns:

A deep copy of the current configuration.

Return type:

BlocSlateConfig

get_combined_preference_intervals_by_bloc() dict[str, PreferenceInterval][source]

Get the combined preference intervals for each bloc across all slates.

The combined preference interval for a bloc is computed by combining the preference intervals for each slate, weighted by the bloc’s cohesion parameters for each slate.

Returns:

A mapping of bloc names to their combined

preference intervals.

Return type:

dict[str, PreferenceInterval]

get_preference_interval_for_bloc_and_slate(bloc_name: str, slate_name: str) PreferenceInterval[source]

Get the preference interval for a given bloc and slate.

Parameters:
  • bloc (str) – The name of the voter bloc.

  • slate (str) – The name of the slate.

Returns:

The preference interval for the given bloc and slate.

Return type:

PreferenceInterval

get_preference_intervals_for_bloc(block_name) dict[str, PreferenceInterval][source]

Get the preference intervals for each bloc and slate.

Returns:

A nested mapping of bloc names to

slate names to their preference intervals.

Return type:

dict[str, dict[str, PreferenceInterval]]

is_valid(*, raise_errors: bool = False, raise_warnings: bool = True) bool[source]

Check if the current configuration is valid and can be passed to a ballot generator.

Parameters:
  • raise_errors (bool) – If True, raises the first error encountered instead of returning False. Defaults to False.

  • raise_warnings (bool) – If True, raises warnings for non-fatal issues (e.g., bloc proportions not summing to 1). Defaults to True.

Returns:

True if the configuration is valid, False otherwise.

Return type:

bool

normalize_cohesion_df() None[source]

Normalize each bloc’s cohesion parameters so that they sum to 1.

Note: Will set all uninitialized slates (value -1.0) to 0.0 before normalizing.

normalize_preference_intervals() None[source]

Normalize each bloc’s preference interval so that it sums to 1.

Note: Will set all uninitialized candidates (value -1.0) to 0.0 before normalizing.

read_dirichlet_alphas() DataFrame | None[source]

Get a copy of the current Dirichlet alphas.

Returns:

A DataFrame with blocs as the index and slates as columns, containing the Dirichlet alpha values for each slate in each bloc, or None if Dirichlet alphas have not been set.

Return type:

Optional[pd.DataFrame]

remove_candidates(candidates: str | Sequence[str]) None[source]

Remove candidates from the configuration.

Note: Also modifies the preference_df and cohesion_df to remove any slates that contained the removed candidates if the slate becomes empty.

Parameters:

candidates (Union[str, Sequence[str]]) – Candidate name or list of candidate names to remove.

remove_slate(slate: str) None[source]

Remove a slate and its candidates from the configuration.

Note: Also modifies the preference_df and cohesion_df to remove the slate and its candidates.

Parameters:

slate (str) – Name of the slate to remove.

rename_candidates(candidate_mapping: Mapping[str, str]) None[source]

Rename candidates in the configuration in place.

Parameters:

candidate_mapping (Mapping[str, str]) – A mapping of old candidate names to new candidate names.

Raises:
  • ValueError – If any old candidate name does not exist in the configuration.

  • TypeError – If any key or value in candidate_mapping is not a str.

resample_preference_intervals_from_dirichlet_alphas() None[source]

Resample the preference intervals for each bloc from the current Dirichlet alphas.

Note: This will overwrite any existing preference intervals in the configuration.

set_dirichlet_alphas(alphas: Mapping[str, Mapping[str, float | int]] | DataFrame) None[source]

Set the Dirichlet alphas for the configuration and resample the preference intervals.

Parameters:

alphas (Union[Mapping[str, Mapping[str, Union[float, int]]], pd.DataFrame]) – A mapping of bloc names to mappings of slate names to their Dirichlet alpha values. Each bloc must have a mapping for every slate defined in slate_to_candidates. All alpha values must be positive finite reals.

Raises:

ConfigurationWarning – If preference intervals have already been set without setting the Dirichlet alphas. Setting the Dirichlet alphas will overwrite the existing preference intervals

property slates: list[str]

A list of all slates. Derived from the keys of slate_to_candidates.

Type:

Computed property

unset_candidate_preferences(candidates: str | Sequence[str]) None[source]

Unset the preferences for the given candidates by setting their values to -1.0.

Parameters:

candidates (Union[str, Sequence[str]]) – Candidate name or list of candidate names to unset.

votekit.ballot_generator.cambridge_profile_generator(config: BlocSlateConfig, *, majority_bloc: str | None = None, minority_bloc: str | None = None, group_ballots: bool = True) RankProfile

Generates a RankProfile using historical RCV elections occurring in Cambridge, MA. The Cambridge data labels candidates with ‘W’ and ‘C’ which correspond to the majority and minority slates, respectively. This model only works with two blocs and two slates, which must have corresponding names.

Based on cohesion parameters, decides if a voter casts their top choice within a slate. Then uses historical data; given their first choice, choose a ballot type from the historical distribution.

Parameters:

config (BlocSlateConfig) – Configuration object containing all necessary parameters for working with a bloc-slate ballot generator.

Kwargs:
majority_bloc (str): Name of the group in the config corresponding to the historical

majority group. Defaults to None, in which case the majority group is determined by the bloc proportions.

minority_bloc (str): Name of the group in the config corresponding to the historical

minority group. Defaults to None, in which case the minority group is determined by the bloc proportions.

group_ballots (bool): If True, groups identical ballots in the resulting profiles.

Defaults to True.

Returns:

A RankProfile object representing the aggregated generated preference profiles.

Return type:

RankProfile

votekit.ballot_generator.cambridge_profiles_by_bloc_generator(config: BlocSlateConfig, *, majority_bloc: str | None = None, minority_bloc: str | None = None, group_ballots: bool = True) dict[str, RankProfile]

Generates a dictionary mapping bloc names to RankProfiles using historical RCV elections occurring in Cambridge, MA. The Cambridge data labels candidates with ‘W’ and ‘C’ which correspond to the majority and minority slates, respectively. This model only works with two blocs and two slates, which must have corresponding names.

Based on cohesion parameters, decides if a voter casts their top choice within a slate. Then uses historical data; given their first choice, choose a ballot type from the historical distribution.

Parameters:

config (BlocSlateConfig) – Configuration object containing all necessary parameters for working with a bloc-slate ballot generator.

Kwargs:
majority_bloc (Optional[str]): Name of the group in the config corresponding to the

historical majority group. Defaults to None, in which case the majority group is determined by the bloc proportions.

minority_bloc (Optional[str]): Name of the group in the config corresponding to the

historical minority group. Defaults to None, in which case the minority group is determined by the bloc proportions.

group_ballots (bool): If True, groups identical ballots in the resulting profiles.

Defaults to True.

Returns:

A dictionary whose keys are bloc strings and values are

RankProfile objects representing the generated preference profiles for each bloc.

Return type:

dict[str, RankProfile]

votekit.ballot_generator.clustered_spacial_profile_and_positions_generator(number_of_ballots: dict[str, int], candidates: list[str], voter_dist: ~typing.Callable[[...], ~numpy.ndarray] = <bound method RandomState.normal of RandomState(MT19937)>, voter_dist_kwargs: ~typing.Dict[str, ~typing.Any] | None = None, candidate_dist: ~typing.Callable[[...], ~numpy.ndarray] = <bound method RandomState.uniform of RandomState(MT19937)>, candidate_dist_kwargs: ~typing.Dict[str, ~typing.Any] | None = None, distance: ~typing.Callable[[~numpy.ndarray, ~numpy.ndarray], float] = <function euclidean_dist>) Tuple[RankProfile, dict[str, ndarray], ndarray]

Generate a clustered spatial rank profile and sampled positions.

Samples candidate positions first, then samples each voter around the candidate they are assigned to in number_of_ballots.

Example

profile, cand_pos, voter_pos = clustered_spacial_profile_and_positions_generator(

number_of_ballots={“A”: 40, “B”: 35, “C”: 25}, candidates=[“A”, “B”, “C”], voter_dist=np.random.normal, voter_dist_kwargs={“loc”: 0.0, “scale”: 0.5, “size”: 2}, candidate_dist=np.random.uniform, candidate_dist_kwargs={“low”: -1.0, “high”: 1.0, “size”: 2},

)

Parameters:
  • number_of_ballots (dict[str, int]) – The number of voters attributed to each candidate {candidate string: # voters}.

  • candidates (list[str]) – Candidate names used when building rankings.

  • voter_dist (Callable[..., np.ndarray], optional) – Distribution sampler used to draw voter positions centered at each candidate location. Defaults to np.random.normal.

  • voter_dist_kwargs (Optional[Dict[str, Any]], optional) – Keyword arguments passed to voter_dist while generating voter positions. If None, uses {"loc": 0, "std": np.array(1.0), "size": np.array(2.0)} for np.random.normal and {} for other supported distributions.

  • candidate_dist (Callable[..., np.ndarray], optional) – Distribution sampler used to draw each candidate position. Defaults to np.random.uniform.

  • candidate_dist_kwargs (Optional[Dict[str, Any]], optional) – Keyword arguments passed to candidate_dist for each sample. If None, uses {"low": 0.0, "high": 1.0, "size": 2.0} for np.random.uniform and {} for other distributions.

  • distance (Callable[[np.ndarray, np.ndarray], float], optional) – Distance function used to compare voter and candidate positions. Defaults to euclidean_dist.

Returns:

A tuple containing the preference profile object, a dictionary with each candidate’s position in the metric space, and a matrix where each row is a single voter’s position in the metric space.

Return type:

Tuple[RankProfile, dict[str, numpy.ndarray], numpy.ndarray]

votekit.ballot_generator.convert_bloc_proportion_map_to_series(bloc_prop_mapping: Mapping[str, int | float] | Series) Series

Convert a dictionary of bloc proportions to a Series.

Parameters:

bloc_prop_mapping (BlocProportionMapping) – The bloc proportion mapping to convert.

Returns:

A pandas Series with bloc names as the index and proportions as values.

Return type:

pd.Series

Raises:
  • TypeError – If bloc_prop is not a Mapping[str, float] or pd.Series with string index and numeric dtype.

  • ValueError – If bloc_prop contains non-finite values, negative values, or does not sum to 1.

votekit.ballot_generator.convert_cohesion_map_to_cohesion_df(cohesion_mapping: Mapping[str, Mapping[str, float] | Series] | DataFrame) DataFrame

Convert a dictionary of cohesion parameters to a DataFrame to pass to BlocSlateConfig.

Parameters:

cohesion_mapping (CohesionMapping) – The cohesion mapping to convert.

Returns:

A pandas DataFrame with blocs as the index and slates as columns.

Return type:

pd.DataFrame

Raises:
  • TypeError – If cohesion_map is not a Mapping[str, Mapping[str, float]] or pd.DataFrame with string index and float dtypes.

  • ValueError – If cohesion_map contains non-finite values.

  • ValueError – If cohesion_map contains duplicate blocs or slates.

votekit.ballot_generator.convert_preference_map_to_preference_df(preference_mapping: Mapping[str, Mapping[str, Mapping[str, float | int] | PreferenceInterval]] | DataFrame) DataFrame

Convert a dictionary of preference mappings to a DataFrame to pass to BlocSlateConfig.

Parameters:

preference_mapping (PreferenceMapping) – The preference mapping to convert.

Returns:

A pandas DataFrame with blocs as the index and candidates as columns.

Return type:

pd.DataFrame

Raises:
  • TypeError – If preference_map is not a Mapping[str, Mapping[str, PreferenceIntervalLike]] or pd.DataFrame with string index and numeric dtypes. Note that PreferenceIntervalLike is either a Mapping[str, float|int] or PreferenceInterval.

  • ValueError – If preference_map contains non-finite values.

  • ValueError – If preference_map contains duplicate blocs or candidates.

votekit.ballot_generator.iac_profile_generator(candidates: Sequence[str], number_of_ballots: int, max_ballot_length: int | None = None) RankProfile

Generate a profile according to the Impartial Anonymous Culture (IAC) model where each profile is equally likely.

Parameters:
  • candidates (Sequence[str]) – List of candidate strings.

  • number_of_ballots (int) – Number of ballots to generate.

  • max_ballot_length (Optional[int]) – Maximum length of each ballot. If None, defaults to the number of candidates.

Returns:

Generated rank profile

Return type:

RankProfile

votekit.ballot_generator.ic_profile_generator(candidates: Sequence[str], number_of_ballots: int, max_ballot_length: int | None = None, allow_short_ballots: bool = False) RankProfile

Impartial Culture model where each ballot is equally likely. Equivalent to the ballot simplex with an alpha value of infinity.

Parameters:
  • candidates (Sequence[str]) – The list of candidates in the election.

  • number_of_ballots (int) – The number of ballots to generate for the profile.

  • max_ballot_length (Optional[int]) – Maximum length of each ballot. If None, defaults to the number of candidates.

  • allow_short_ballots (bool, optional) – Whether to allow short ballots. Defaults to False.

Returns:

The generated preference profile

Return type:

RankProfile

votekit.ballot_generator.name_bt_profile_generator(config: BlocSlateConfig, *, group_ballots=True) RankProfile

Generate a preference profile using the name-BradleyTerry model.

The probability of sampling the ranking \(X>Y>Z\) is proportional to \(P(X>Y)*P(X>Z)*P(Y>Z)\). These individual probabilities are based on the preference interval: :math: P(X>Y) = x/(x+y).

Parameters:
  • config (BlocSlateConfig) – Configuration object containing all necessary parameters for working with a bloc-slate ballot generator.

  • group_ballots (bool) – If True, group identical ballots in the returned profile and set the weight accordingly. Defaults to True.

Returns:

Generated preference profile.

Return type:

RankProfile

votekit.ballot_generator.name_bt_profile_generator_using_mcmc(config: BlocSlateConfig, *, group_ballots=True, verbose: bool = False, burn_in_time: int = 0, chain_length: int | None = None) RankProfile

Generate a preference profile using MCMC sampling from the name-BradleyTerry model.

Parameters:

config (BlocSlateConfig) – Configuration object containing all necessary parameters for working with a bloc-slate ballot generator.

Kwargs:
group_ballots (bool): If True, group identical ballots in the returned profile and

set the weight accordingly. Defaults to True.

verbose (bool): If True, print the acceptance ratio of the chain. Defaults to False. burn_in_time (int): the number of ballots discarded in the beginning of the chain.

Defaults to 0.

chain_length (Optional[int]): the length of the Markov Chain. Ballots are subsampled every

chain_length//n_ballots steps from the chain until the desired number of ballots is reached. Defaults to None which sets the chain_length to the number of ballots in the config.

Returns:

Generated preference profile.

Return type:

RankProfile

votekit.ballot_generator.name_bt_profiles_by_bloc_generator(config: BlocSlateConfig, *, group_ballots=True) dict[str, RankProfile]

Generate preference profiles by bloc using the name-BradleyTerry model.

The probability of sampling the ranking \(X>Y>Z\) is proportional to \(P(X>Y)*P(X>Z)*P(Y>Z)\). These individual probabilities are based on the preference interval: :math: P(X>Y) = x/(x+y).

Parameters:
  • config (BlocSlateConfig) – Configuration object containing all necessary parameters for working with a bloc-slate ballot generator.

  • group_ballots (bool) – If True, group identical ballots in the returned profile and set the weight accordingly. Defaults to True.

Returns:

Generated preference profiles by bloc.

Return type:

dict[str, RankProfile]

votekit.ballot_generator.name_bt_profiles_by_bloc_generator_using_mcmc(config: BlocSlateConfig, *, group_ballots=True, verbose: bool = False, burn_in_time: int = 0, chain_length: int | None = None) dict[str, RankProfile]

Generate a preference profile dictionary by bloc using MCMC sampling from the name-BradleyTerry model.

Parameters:

config (BlocSlateConfig) – Configuration object containing all necessary parameters for working with a bloc-slate ballot generator.

Kwargs:
group_ballots (bool): If True, group identical ballots in the returned profile and

set the weight accordingly. Defaults to True.

verbose (bool): If True, print the acceptance ratio of the chain. Defaults to False. burn_in_time (int): the number of ballots discarded in the beginning of the chain.

Defaults to 0.

chain_length (Optional[int]): the length of the Markov Chain. Ballots are subsampled every

chain_length//n_ballots steps from the chain until the desired number of ballots is reached. Defaults to None which sets the chain_length to the number of ballots in the config.

Returns:

Generated preference profiles by bloc.

Return type:

dict[str, RankProfile]

votekit.ballot_generator.name_cumulative_ballot_generator_by_bloc(config: BlocSlateConfig, *, total_points: int | None = None, group_ballots: bool = True) dict[str, ScoreProfile]

Generates a dictionary mapping bloc names to ScoreProfiles using the name-Cumulative model.

This model samples with replacement from a combined preference interval and counts candidates with multiplicity.

Parameters:

config (BlocSlateConfig) – Configuration object containing all necessary parameters for working with a bloc-slate ballot generator.

Kwargs:
total_points (Optional[int]): The total number of points to distribute among candidates.

If None, defaults to the number of candidates in the configuration. Defaults to None.

group_ballots (bool): If True, groups identical ballots in the resulting profile.

Defaults to True.

Returns:

A dictionary whose keys are bloc strings and values are

ScoreProfile objects representing the generated ballots for each bloc.

Return type:

dict[str, ScoreProfile]

votekit.ballot_generator.name_cumulative_profile_generator(config: BlocSlateConfig, *, total_points: int | None = None, group_ballots: bool = True) ScoreProfile

Generates a ScoreProfile using the name-Cumulative.

This model samples with replacement from a combined preference interval and counts candidates with multiplicity.

Parameters:

config (BlocSlateConfig) – Configuration object containing all necessary parameters for working with a bloc-slate ballot generator.

Kwargs:
total_points (Optional[int]): The total number of points to distribute among candidates.

If None, defaults to the number of candidates in the configuration. Defaults to None.

group_ballots (bool): If True, groups identical ballots in the resulting profile.

Defaults to True.

Returns:

A ScoreProfile object representing the generated ballots.

Return type:

ScoreProfile

votekit.ballot_generator.name_pl_profile_generator(config: BlocSlateConfig, *, group_ballots: bool = True) RankProfile

Generates a merged preference profile using the name-Plackett-Luce model.

The Plackett-Luce model samples without replacement from each preference interval for each bloc of voters. These profiles are then merged into a single profile.

Parameters:
  • config (BlocSlateConfig) – Configuration object containing all necessary parameters for working with a bloc-slate ballot generator.

  • group_ballots (bool) – If True, group identical ballots in the returned profile and set the weight accordingly. Defaults to True.

Returns:

Merged RankProfile object generated by the model.

Return type:

RankProfile

votekit.ballot_generator.name_pl_profiles_by_bloc_generator(config: BlocSlateConfig, *, group_ballots: bool = True) dict[str, RankProfile]

Generates a dictionary mapping bloc names to preference profiles by bloc using the name-Plackett-Luce model.

The Plackett-Luce model samples without replacement from each preference interval for each bloc of voters.

Parameters:
  • config (BlocSlateConfig) – Configuration object containing all necessary parameters for working with a bloc-slate ballot generator.

  • group_ballots (bool) – If True, group identical ballots in the returned profile and set the weight accordingly. Defaults to True.

Returns:

Dictionary whose keys are bloc strings and values are

RankProfile objects generated by the model for each bloc.

Return type:

dict[str, RankProfile]

votekit.ballot_generator.onedim_spacial_profile_generator(candidates: Sequence[str], number_of_ballots: int) RankProfile

Generate a 1D spatial rank profile.

Voters and candidates are sampled from normal distributions on a line. Each ballot ranks candidates by absolute distance from the voter.

Parameters:
  • candidates (Sequence[str]) – Candidate names used in each generated ballot.

  • number_of_ballots (int) – The number of ballots to generate.

Returns:

A ranked preference profile object.

Return type:

RankProfile

votekit.ballot_generator.slate_bt_profile_generator(config: BlocSlateConfig, *, group_ballots=True) RankProfile

Generate a preference profile using the name-BradleyTerry model.

This model first samples a ballot type (e.g. AABABB) according the the Bradley-Terry model using the cohesion parameters for each slate and the candidate counts of those slates (so the utilities of each of the candidates in a slate are assumed to be uniform in this stage).

Once the ballot type is sampled, the candidate names for each of the positions is filled out by sampling without replacement within each slate according to the preference interval of that slate in the given bloc (i.e. according to the name-Plackett-Luce model).

Slates with zero cohesion for the given bloc are randomly permuted at the end of the ballot. Candidates with zero support are randomly permuted at the end of the candidate ordering.

Parameters:
  • config (BlocSlateConfig) – Configuration object containing all necessary parameters for working with a bloc-slate ballot generator.

  • group_ballots (bool) – If True, group identical ballots in the returned profile and set the weight accordingly. Defaults to True.

Returns:

Generated preference profile.

Return type:

RankProfile

votekit.ballot_generator.slate_bt_profile_generator_using_mcmc(config: BlocSlateConfig, *, group_ballots=True) RankProfile

Generate a ranked preference profile using the slate-BradleyTerry model.

This model is mainly useful when then number of possible ballot types is too large to compute the full probability distribution on the present hardware (e.g. more than 12! possible ballot types).

The MCMC version of this model uses a Markov Chain Monte Carlo method to sample ballot types according to the slate-BradleyTerry model. After selecting a seed ballot, the model proposes swaps of adjacent slates in the ballot type and accepts or rejects the swap according to the ratio of the cohesion parameters of the two slates being swapped within a given block.

Once the ballot type is sampled, the candidate names for each of the positions is filled out by sampling without replacement within each slate according to the preference interval of that slate in the given bloc (i.e. according to the name-Plackett-Luce model).

Slates with zero cohesion for the given bloc are randomly permuted at the end of the ballot. Candidates with zero support are randomly permuted at the end of the candidate ordering.

Parameters:
  • config (BlocSlateConfig) – Configuration object containing all necessary parameters for working with a bloc-slate ballot generator.

  • group_ballots (bool) – If True, group identical ballots in the returned profile and set the weight accordingly. Defaults to True.

Returns:

Generated preference profile.

Return type:

RankProfile

votekit.ballot_generator.slate_bt_profiles_by_bloc_generator(config: BlocSlateConfig, *, group_ballots=True) dict[str, RankProfile]

Generate a dictionary mapping bloc names to ranked preference profiles using the slate-BradleyTerry model.

This model first samples a ballot type (e.g. AABABB) according the the Bradley-Terry model using the cohesion parameters for each slate and the candidate counts of those slates (so the utilities of each of the candidates in a slate are assumed to be uniform in this stage).

Once the ballot type is sampled, the candidate names for each of the positions is filled out by sampling without replacement within each slate according to the preference interval of that slate in the given bloc (i.e. according to the name-Plackett-Luce model).

Slates with zero cohesion for the given bloc are randomly permuted at the end of the ballot. Candidates with zero support are randomly permuted at the end of the candidate ordering.

Parameters:
  • config (BlocSlateConfig) – Configuration object containing all necessary parameters for working with a bloc-slate ballot generator.

  • group_ballots (bool) – If True, group identical ballots in the returned profile and set the weight accordingly. Defaults to True.

Returns:

Generated preference profiles by bloc.

Return type:

dict[str, RankProfile]

votekit.ballot_generator.slate_bt_profiles_by_bloc_generator_using_mcmc(config: BlocSlateConfig, *, group_ballots=True) dict[str, RankProfile]

Generate a dictionary mapping bloc names to ranked preference profiles using the slate-BradleyTerry model.

This model is mainly useful when then number of possible ballot types is too large to compute the full probability distribution on the present hardware (e.g. more than 12! possible ballot types).

The MCMC version of this model uses a Markov Chain Monte Carlo method to sample ballot types according to the slate-BradleyTerry model. After selecting a seed ballot, the model proposes swaps of adjacent slates in the ballot type and accepts or rejects the swap according to the ratio of the cohesion parameters of the two slates being swapped within a given block.

Once the ballot type is sampled, the candidate names for each of the positions is filled out by sampling without replacement within each slate according to the preference interval of that slate in the given bloc (i.e. according to the name-Plackett-Luce model).

Slates with zero cohesion for the given bloc are randomly permuted at the end of the ballot. Candidates with zero support are randomly permuted at the end of the candidate ordering.

Parameters:
  • config (BlocSlateConfig) – Configuration object containing all necessary parameters for working with a bloc-slate ballot generator.

  • group_ballots (bool) – If True, group identical ballots in the returned profile and set the weight accordingly. Defaults to True.

Returns:

Generated preference profiles by bloc.

Return type:

dict[str, RankProfile]

votekit.ballot_generator.slate_pl_profile_generator(config: BlocSlateConfig, *, group_ballots: bool = True) RankProfile

Generates a merged preference profile using the slate-Plackett-Luce model.

This model first samples a ballot type by flipping a cohesion parameter weighted coin. It then fills out the ballot type via sampling without replacement from the preference interval (i.e. according to the name-Plackett-Luce model).

Slates with zero cohesion for the given bloc are randomly permuted at the end of the ballot. Candidates with zero support are randomly permuted at the end of the candidate ordering.

Parameters:
  • config (BlocSlateConfig) – Configuration object containing all necessary parameters for working with a bloc-slate ballot generator.

  • group_ballots (bool) – If True, group identical ballots in the returned profile and set the weight accordingly. Defaults to True.

Returns:

Merged RankProfile object generated by the model.

Return type:

RankProfile

votekit.ballot_generator.slate_pl_profiles_by_bloc_generator(config: BlocSlateConfig, *, group_ballots: bool = True) dict[str, RankProfile]

Generates a dictionary mapping bloc names to preference profiles using the slate-Plackett-Luce model.

This model first samples a ballot type by flipping a cohesion parameter weighted coin. It then fills out the ballot type via sampling without replacement from the preference interval (i.e. according to the name-Plackett-Luce model).

Slates with zero cohesion for the given bloc are randomly permuted at the end of the ballot. Candidates with zero support are randomly permuted at the end of the candidate ordering.

Parameters:
  • config (BlocSlateConfig) – Configuration object containing all necessary parameters for working with a bloc-slate ballot generator.

  • group_ballots (bool) – If True, group identical ballots in the returned profile and set the weight accordingly. Defaults to True.

Returns:

Dictionary whose keys are bloc strings and values are

RankProfile objects generated by the model for each bloc.

Return type:

dict[str, RankProfile]

votekit.ballot_generator.spacial_profile_and_positions_generator(number_of_ballots: int, candidates: list[str], voter_dist: ~typing.Callable[[...], ~numpy.ndarray] = <bound method RandomState.uniform of RandomState(MT19937)>, voter_dist_kwargs: ~typing.Dict[str, ~typing.Any] | None = None, candidate_dist: ~typing.Callable[[...], ~numpy.ndarray] = <bound method RandomState.uniform of RandomState(MT19937)>, candidate_dist_kwargs: ~typing.Dict[str, ~typing.Any] | None = None, distance: ~typing.Callable[[~numpy.ndarray, ~numpy.ndarray], float] = <function euclidean_dist>) Tuple[RankProfile, dict[str, ndarray], ndarray]

Generate a spatial rank profile and sampled positions.

Samples voter and candidate positions in a metric space, then ranks each ballot by candidate distance from the sampled voter position.

Example

profile, cand_pos, voter_pos = spacial_profile_and_positions_generator(

number_of_ballots=100, candidates=[“A”, “B”, “C”], voter_dist=np.random.normal, voter_dist_kwargs={“loc”: 0.0, “scale”: 1.0, “size”: 2}, candidate_dist=np.random.uniform, candidate_dist_kwargs={“low”: -1.0, “high”: 1.0, “size”: 2},

)

Parameters:
  • number_of_ballots (int) – The number of ballots to generate.

  • candidates (list[str]) – Candidate names used when building rankings.

  • voter_dist (Callable[..., np.ndarray], optional) – Distribution sampler used to draw each voter position. Defaults to np.random.uniform.

  • voter_dist_kwargs (Optional[Dict[str, Any]], optional) – Keyword arguments passed to voter_dist for each sample. If None, uses {"low": 0.0, "high": 1.0, "size": 2.0} for np.random.uniform and {} for other distributions.

  • candidate_dist (Callable[..., np.ndarray], optional) – Distribution sampler used to draw each candidate position. Defaults to np.random.uniform.

  • candidate_dist_kwargs (Optional[Dict[str, Any]], optional) – Keyword arguments passed to candidate_dist for each sample. If None, uses {"low": 0.0, "high": 1.0, "size": 2.0} for np.random.uniform and {} for other distributions.

  • distance (Callable[[np.ndarray, np.ndarray], float], optional) – Distance function used to compare voter and candidate positions. Defaults to euclidean_dist.

Returns:

A tuple containing the preference profile object, a dictionary with each candidate’s position in the metric space, and a matrix where each row is a single voter’s position in the metric space.

Return type:

Tuple[RankProfile, dict[str, numpy.ndarray], numpy.ndarray]

Cleaning

votekit.cleaning.clean_rank_profile(profile: RankProfile, clean_ranking_func: Callable[[tuple], tuple], remove_empty_ballots: bool = True, remove_zero_weight_ballots: bool = True, retain_original_candidate_list: bool = True) CleanedRankProfile

Allows user-defined cleaning rules for RankProfile. Input function that applies modification to ranking portion of the df, not weight or voterset.

Parameters:
  • profile (RankProfile) – A RankProfile to clean.

  • clean_ranking_func (Callable[[tuple], tuple]) – Function that takes the ranking portion of a row of the profile df and returns an altered ranking.

  • remove_empty_ballots (bool, optional) – Whether or not to remove ballots that have no ranking and no scores as a result of the cleaning. Defaults to True.

  • remove_zero_weight_ballots (bool, optional) – Whether or not to remove ballots that have no weight as a result of the cleaning. Defaults to True.

  • retain_original_candidate_list (bool, optional) – Whether or not to use the candidate list from the original profile in the new profile. If False, uses only candidates who receive votes. Defaults to True.

Returns:

A cleaned RankProfile.

Return type:

CleanedRankProfile

Raises:

ProfileError – Profile must only contain ranked ballots.

votekit.cleaning.clean_score_profile(profile: ScoreProfile, clean_score_func: Callable[[tuple], tuple], remove_empty_ballots: bool = True, remove_zero_weight_ballots: bool = True, retain_original_candidate_list: bool = True) CleanedScoreProfile

Allows user-defined cleaning rules for ScoreProfile. Cleaning function can only be applied to the score section of the dataframe, not the weight or voter set.

Parameters:
  • profile (ScoreProfile) – A ScoreProfile to clean.

  • clean_score_func (Callable[[tuple], tuple]) – Function that takes the score portion of a row of the profile df and returns an altered score.

  • remove_empty_ballots (bool, optional) – Whether or not to remove ballots that have no no scores as a result of the cleaning. Defaults to True.

  • remove_zero_weight_ballots (bool, optional) – Whether or not to remove ballots that have no weight as a result of the cleaning. Defaults to True.

  • retain_original_candidate_list (bool, optional) – Whether or not to use the candidate list from the original profile in the new profile. If False, uses only candidates who receive votes. Defaults to True.

Returns:

A cleaned ScoreProfile.

Return type:

CleanedScoreProfile

Raises:

ProfileError – Profile must only contain ranked ballots.

votekit.cleaning.condense_rank_ballot(ballot: RankBallot) RankBallot

Given a ballot, removes any empty ranking positions and moves up any lower ranked candidates.

Parameters:

ballot (RankBallot) – Ballot to condense.

Returns:

Condensed ballot.

Return type:

RankBallot

votekit.cleaning.condense_rank_profile(profile: RankProfile, remove_empty_ballots: bool = True, remove_zero_weight_ballots: bool = True, retain_original_candidate_list: bool = True) CleanedRankProfile

Given a ranked profile, removes any empty frozensets from the rankings and condenses the resulting ranking. If a ranking only has trailing empty positions, the condensed ranking is considered equivalent. For example, (A,B,{},{}) is mapped to (A,B) but considered unaltered since the ranking did not change.

Wrapper for clean_rank_profile that does some extra processing to ensure condensed ranking equivalence is handled correctly.

Parameters:
  • profile (RankProfile) – Profile to remove repeated candidates from.

  • remove_empty_ballots (bool, optional) – Whether or not to remove ballots that have no ranking or scores as a result of cleaning. Defaults to True.

  • remove_zero_weight_ballots (bool, optional) – Whether or not to remove ballots that have no weight as a result of cleaning. Defaults to True.

  • retain_original_candidate_list (bool, optional) – Whether or not to use the candidate list from the original profile in the new profile. If False, uses only candidates who receive votes. Defaults to True.

Returns:

A cleaned RankProfile.

Return type:

CleanedRankProfile

votekit.cleaning.remove_and_condense_rank_profile(removed: str | list, profile: RankProfile, remove_empty_ballots: bool = True, remove_zero_weight_ballots: bool = True, retain_original_candidate_list: bool = False) CleanedRankProfile

Given a ranked profile, remove the given candidate(s) and condense the resulting rankings. If a ranking only has trailing empty positions, the condensed ranking is considered equivalent. For example, (A,B,{},{}) is mapped to (A,B) but considered unaltered since the ranking did not change.

This function is intended to save computational time in election methods, where removing and condensing happen frequently. Researches interested in the difference between removing and condensing should use remove_cand and condense_profile in series.

Wrapper for clean_rank_profile that does some extra processing to ensure the candidate list is handled correctly, and that ballot equivalence is checked.

Parameters:
  • removed (Union[str, list]) – Candidate or list of candidates to be removed.

  • profile (RankProfile) – Profile to remove repeated candidates from.

  • remove_empty_ballots (bool, optional) – Whether or not to remove ballots that have no ranking or scores as a result of cleaning. Defaults to True.

  • remove_zero_weight_ballots (bool, optional) – Whether or not to remove ballots that have no weight as a result of cleaning. Defaults to True.

  • retain_original_candidate_list (bool, optional) – Whether or not to use the candidate list from the orginal profile in the new profile. If False, takes the original candidate list and removes the candidate(s) given in removed, but preserves all others. Defaults to False.

Returns:

A cleaned RankProfile.

Return type:

CleanedRankProfile

votekit.cleaning.remove_cand_rank_ballot(removed: str | list, ballot: RankBallot) RankBallot

Removes specified candidate(s) from ballot. Does not condense the resulting ballot.

Parameters:
  • removed (Union[str, list]) – Candidate or list of candidates to be removed.

  • ballot (RankBallot) – Ballot to remove candidates from.

Returns:

Ballot with candidate(s) removed.

Return type:

RankBallot

votekit.cleaning.remove_cand_rank_profile(removed: str | list, profile: RankProfile, remove_empty_ballots: bool = True, remove_zero_weight_ballots: bool = True, retain_original_candidate_list: bool = False) CleanedRankProfile

Given a ranked profile, remove the given candidate(s) from the ballots. Does not condense the resulting ballots.

Wrapper for clean_rank_profile that does some extra processing to ensure the candidate list is handled correctly.

Parameters:
  • removed (Union[str, list]) – Candidate or list of candidates to be removed.

  • profile (RankProfile) – Profile to remove candidates from.

  • remove_empty_ballots (bool, optional) – Whether or not to remove ballots that have no ranking or scores as a result of cleaning. Defaults to True.

  • remove_zero_weight_ballots (bool, optional) – Whether or not to remove ballots that have no weight as a result of cleaning. Defaults to True.

  • retain_original_candidate_list (bool, optional) – Whether or not to use the candidate list from the orginal profile in the new profile. If False, takes the original candidate list and removes the candidate(s) given in removed, but preserves all others. Defaults to False.

Returns:

A cleaned RankProfile.

Return type:

CleanedRankProfile

Raises:

ProfileError – Profile must only contain ranked ballots.

votekit.cleaning.remove_cand_score_ballot(removed: str | list, ballot: ScoreBallot) ScoreBallot

Removes specified candidate(s) from ballot.

Parameters:
  • removed (Union[str, list]) – Candidate or list of candidates to be removed.

  • ballot (ScoreBallot) – Ballot to remove candidates from.

Returns:

Ballot with candidate(s) removed.

Return type:

ScoreBallot

votekit.cleaning.remove_cand_score_profile(removed: str | list, profile: ScoreProfile, remove_empty_ballots: bool = True, remove_zero_weight_ballots: bool = True, retain_original_candidate_list: bool = False) CleanedScoreProfile

Given a score profile, remove the given candidate(s) from the ballots.

Wrapper for clean_score_profile that does some extra processing to ensure the candidate list is handled correctly.

Not as fast as removing the candidate columns directly, but tracks more information about which ballots were adjusted.

Parameters:
  • removed (Union[str, list]) – Candidate or list of candidates to be removed.

  • profile (ScoreProfile) – Profile to remove candidates from.

  • remove_empty_ballots (bool, optional) – Whether or not to remove ballots that have no ranking or scores as a result of cleaning. Defaults to True.

  • remove_zero_weight_ballots (bool, optional) – Whether or not to remove ballots that have no weight as a result of cleaning. Defaults to True.

  • retain_original_candidate_list (bool, optional) – Whether or not to use the candidate list from the orginal profile in the new profile. If False, takes the original candidate list and removes the candidate(s) given in removed, but preserves all others. Defaults to False.

Returns:

A cleaned ScoreProfile.

Return type:

CleanedScoreProfile

Raises:

ProfileError – Profile must only contain score ballots.

votekit.cleaning.remove_repeat_cands_rank_ballot(ballot: RankBallot) RankBallot

Given a ballot, if a candidate appears multiple times on a ballot, keep the first instance, and remove any further instances. Does not condense the ballot. Only works on ranking ballots, not score ballots.

Parameters:

ballot (RankBallot) – Ballot to remove repeated candidates from.

Returns:

Ballot with duplicate candidate(s) removed.

Return type:

RankBallot

Raises:
  • TypeError – Ballot must only have rankings, not scores.

  • TypeError – Ballot must have rankings.

votekit.cleaning.remove_repeat_cands_rank_profile(profile: RankProfile, remove_empty_ballots: bool = True, remove_zero_weight_ballots: bool = True, retain_original_candidate_list: bool = True) CleanedRankProfile

Given a profile, if a candidate appears multiple times on a ballot, keep the first instance and remove any further instances. Does not condense any empty rankings as as result. Only works on ranking ballots, not score ballots.

Wrapper for clean_rank_profile.

Parameters:
  • profile (RankProfile) – Profile to remove repeated candidates from.

  • remove_empty_ballots (bool, optional) – Whether or not to remove ballots that have no ranking or scores as a result of cleaning. Defaults to True.

  • remove_zero_weight_ballots (bool, optional) – Whether or not to remove ballots that have no weight as a result of cleaning. Defaults to True.

  • retain_original_candidate_list (bool, optional) – Whether or not to use the candidate list from the original profile in the new profile. If False, uses only candidates who receive votes. Defaults to True.

Returns:

A cleaned RankProfile.

Return type:

CleanedRankProfile

Raises:

ProfileError – Profile must only contain ranked ballots.

Elections

class votekit.elections.ElectionState(round_number: int = 0, remaining: tuple[frozenset[str], ...] = (frozenset({}),), elected: tuple[frozenset[str], ...] = (frozenset({}),), eliminated: tuple[frozenset[str], ...] = (frozenset({}),), tiebreaks: dict[frozenset[str], tuple[frozenset[str], ...]] = <factory>, scores: dict[str, float] = <factory>)

Class for storing information about a round of an election. Round 0 should be the initial state of the election. To save memory, the PreferenceProfile is not carried by the ElectionState class.

round_number

Round number, defaults to 0.

Type:

int, optional

remaining

Remaining candidates, ordered to indicate ranking, frozensets to indicate ties. Defaults to tuple with one empty set.

Type:

tuple[frozenset[str],…], optional

elected

Elected candidates, ordered to indicate ranking, frozensets to indicate ties. Defaults to tuple with one empty set.

Type:

tuple[frozenset[str],…], optional

eliminated

Eliminated candidates, ordered to indicate ranking, frozensets to indicate ties. Defaults to tuple with one empty set.

Type:

tuple[frozenset[str],…], optional

tiebreaks

Stores tiebreak resolutions. Keys are frozensets of tied candidates and values are resolutions of tiebreak. Defaults to empty dictionary.

Type:

dict[frozenset[str], tuple[frozenset[str],…]], optional

scores

Stores score information. Keys are candidates, values are scores. Only remaining candidates should be stored.

Type:

dict[str, float], optional

to_dict() dict[str, Any][source]

Convert the ElectionState to a dictionary representation.

class votekit.elections.Election(profile: P, score_function: Callable[[P], dict[str, float]] | None = None, sort_high_low: bool = True)

Abstract base class for election types.

Parameters:
  • profile (PreferenceProfile) – The initial profile of ballots.

  • score_function (Callable[[PreferenceProfile], dict[str, float]], optional) – A function that converts profiles to a score dictionary mapping candidates to their current score. Used in creating ElectionState objects and sorting candidates in Round 0. If None, no score dictionary is saved and all candidates are tied in Round 0. Defaults to None.

  • sort_high_low (bool, optional) – How to sort candidates based on score_function. True sorts from high to low. Defaults to True.

election_states

A list of election states, one for each round of the election. The list is 0 indexed, so the initial state is stored at index 0, round 1 at 1, etc.

Type:

list[ElectionState]

score_function

A function that converts profiles to a score dictionary mapping candidates to their current score. Used in creating ElectionState objects. Defaults to None.

Type:

Callable[[PreferenceProfile], dict[str, float]], optional

length

The number of rounds of the election.

Type:

int

get_elected(round_number: int = -1) tuple[frozenset[str], ...][source]

Fetch the elected candidates up to the given round number.

Parameters:

round_number (int, optional) – The round number. Supports negative indexing. Defaults to -1, which accesses the final profile.

Returns:

List of winning candidates in order of election. Candidates in the same set were elected simultaneously, i.e. in the final ranking they are tied.

Return type:

tuple[frozenset[str],…]

get_eliminated(round_number: int = -1) tuple[frozenset[str], ...][source]

Fetch the eliminated candidates up to the given round number.

Parameters:

round_number (int, optional) – The round number. Supports negative indexing. Defaults to -1, which accesses the final profile.

Returns:

Tuple of eliminated candidates in reverse order of elimination. Candidates in the same set were eliminated simultaneously, i.e. in the final ranking they are tied.

Return type:

tuple[frozenset[str],…]

get_profile(round_number: int = -1) P[source]

Fetch the PreferenceProfile of the given round number.

Parameters:

round_number (int, optional) – The round number. Supports negative indexing. Defaults to -1, which accesses the final profile.

Returns:

PreferenceProfile

get_ranking(round_number: int = -1) tuple[frozenset[str], ...][source]

Fetch the ranking of candidates after a given round.

Parameters:

round_number (int, optional) – The round number. Supports negative indexing. Defaults to -1, which accesses the final profile.

Returns:

Ranking of candidates.

Return type:

tuple[frozenset[str],…]

get_remaining(round_number: int = -1) tuple[frozenset[str], ...][source]

Fetch the remaining candidates after the given round.

Parameters:

round_number (int, optional) – The round number. Supports negative indexing. Defaults to -1, which accesses the final profile.

Returns:

Tuple of sets of remaining candidates. Ordering of tuple denotes ranking of remaining candidates, sets denote ties.

Return type:

tuple[frozenset[str],…]

get_status_df(round_number: int = -1) DataFrame[source]

Yield the status (elected, eliminated, remaining) of the candidates in the given round. DataFrame is sorted by current ranking.

Parameters:

round_number (int, optional) – The round number. Supports negative indexing. Defaults to -1, which accesses the final profile.

Returns:

Data frame displaying candidate, status (elected, eliminated, remaining), and the round their status updated.

Return type:

pd.DataFrame

get_step(round_number: int = -1) tuple[P, ElectionState][source]

Fetches the profile and ElectionState of the given round number.

Parameters:

round_number (int, optional) – The round number. Supports negative indexing. Defaults to -1, which accesses the final profile.

Returns:

tuple[PreferenceProfile, ElectionState]

Approval-based

class votekit.elections.Approval(profile: ScoreProfile, n_seats: int | None = None, tiebreak: str | None = None, **kwargs)

Bases: GeneralRating

Approval election. Standard approval voting lets voters choose any subset of candidates to approve. Winners are the \(n_ ext{seats}\) candidates who received the most approval votes.

Parameters:
  • profile (ScoreProfile) – Profile to conduct election on.

  • n_seats (int, optional) – Number of seats to elect. Defaults to 1.

  • tiebreak (str, optional) – Tiebreak method to use. Options are None and ‘random’. Defaults to None, in which case a tie raises a ValueError.

class votekit.elections.BlockPlurality(profile: RankProfile | ScoreProfile, n_seats: int | None = None, budget: int | None = None, tiebreak: str | None = None, scoring_tie_convention: Literal['high', 'average', 'low'] = 'low', **kwargs)

Bases: Election

Block plurality election. Supports both ranked and score profiles.

When given a RankProfile, the top budget ranked candidates each receive 1 point and all others receive 0. When given a ScoreProfile, voters may give at most 1 point to each of budget candidates.

Parameters:
  • profile (RankProfile | ScoreProfile) – Profile to conduct election on.

  • n_seats (int, optional) – Number of seats to elect. Defaults to 1.

  • budget (int, optional) – Number of positions or approvals that count. Defaults to None, which results in n_seats.

  • tiebreak (str, optional) – Tiebreak method to use. Options are None and ‘random’. Defaults to None, in which case a tie raises a ValueError.

  • scoring_tie_convention (Literal["high", "average", "low"], optional) – How to award points for tied rankings. Only used when profile is a RankProfile. Defaults to “low”.

Raises:

TypeError – If profile is not a RankProfile or ScoreProfile.

Ranking-based

class votekit.elections.RankingElection(profile: RankProfile, n_seats: int = 1, score_function: Callable[[RankProfile], dict[str, float]] | None = None, sort_high_low: bool = True)

Bases: Election[RankProfile]

Abstract class for ranking election types. Validates that profile contains ranked ballots.

Parameters:
  • profile (RankProfile) – The initial profile of ballots.

  • score_function (Callable[[RankProfile], dict[str, float]], optional) – A function that converts profiles to a score dictionary mapping candidates to their current score. Used in creating ElectionState objects and sorting candidates in Round 0. If None, no score dictionary is saved and all candidates are tied in Round 0. Defaults to None.

  • sort_high_low (bool, optional) – How to sort candidates based on score_function. True sorts from high to low. Defaults to True.

election_states

a list of election states, one for each round of the election. The list is 0 indexed, so the initial state is stored at index 0, round 1 at 1, etc.

Type:

list[ElectionState]

score_function

A function that converts profiles to a score dictionary mapping candidates to their current score. Used in creating ElectionState objects. Defaults to None.

Type:

Callable[[RankProfile], dict[str, float]], optional

length

the number of rounds of the election.

Type:

int

class votekit.elections.Alaska(profile: ~votekit.RankProfile, m_1: int = 2, m_2: int = 1, transfer: ~typing.Callable[[str, float, tuple[~votekit.RankBallot] | list[~votekit.RankBallot], int], tuple[~votekit.RankBallot, ...]] = <function fractional_transfer>, quota: ~typing.Literal['droop', 'hare'] | None = 'droop', simultaneous: bool = True, tiebreak: ~typing.Literal['borda', 'random', 'first_place'] | None = None, fpv_tie_convention: ~typing.Literal['high', 'low', 'average'] = 'average')

Bases: RankingElection

Alaska election. Election method that first runs a Plurality election to choose a user-specified number of final-round candidates, then runs STV to choose \(m\) winners.

Parameters:
  • profile (RankProfile) – Profile to conduct election on.

  • m_1 (int, optional) – Number of final round candidates, i.e. number of winners of Plurality round. Defaults to 2.

  • m_2 (int, optional) – Number of seats to elect in STV round, i.e. number of overall winners. Defaults to 1.

  • (Callable[[str (transfer) – tuple[Ballot,…]], optional): Transfer method. Defaults to fractional transfer. Function signature is elected candidate, their number of first-place votes, the list of ballots with them ranked first, and the threshold value. Returns the list of ballots after transfer.

  • float] – tuple[Ballot,…]], optional): Transfer method. Defaults to fractional transfer. Function signature is elected candidate, their number of first-place votes, the list of ballots with them ranked first, and the threshold value. Returns the list of ballots after transfer.

  • Union[tuple[Ballot] – tuple[Ballot,…]], optional): Transfer method. Defaults to fractional transfer. Function signature is elected candidate, their number of first-place votes, the list of ballots with them ranked first, and the threshold value. Returns the list of ballots after transfer.

  • list[Ballot]] – tuple[Ballot,…]], optional): Transfer method. Defaults to fractional transfer. Function signature is elected candidate, their number of first-place votes, the list of ballots with them ranked first, and the threshold value. Returns the list of ballots after transfer.

  • int] – tuple[Ballot,…]], optional): Transfer method. Defaults to fractional transfer. Function signature is elected candidate, their number of first-place votes, the list of ballots with them ranked first, and the threshold value. Returns the list of ballots after transfer.

:paramtuple[Ballot,…]], optional):

Transfer method. Defaults to fractional transfer. Function signature is elected candidate, their number of first-place votes, the list of ballots with them ranked first, and the threshold value. Returns the list of ballots after transfer.

Parameters:
  • quota (str, optional) – Formula to calculate quota. Accepts “droop” or “hare”. Defaults to “droop”.

  • simultaneous (bool, optional) – True if all candidates who cross threshold in a round are elected simultaneously, False if only the candidate with highest first-place votes who crosses the threshold is elected in a round. Defaults to True.

  • tiebreak (TiebreakType | None, optional) – Tiebreak method to use. Options are None, ‘random’, and ‘borda’. Defaults to None, in which case a tie raises a ValueError.

  • fpv_tie_convention (Literal["high", "average", "low"], optional) – How to award points for tied first place votes. Defaults to “average”, where if n candidates are tied for first, each receives 1/n points. “high” would award them each one point, and “low” 0. Only used by score_function parameter.

get_profile(round_number: int = -1) RankProfile[source]

Fetch the RankProfile of the given round number.

Parameters:

round_number (int, optional) – The round number. Supports negative indexing. Defaults to -1, which accesses the final profile.

Returns:

RankProfile

class votekit.elections.Borda(profile: RankProfile, n_seats: int | None = None, score_vector: Sequence[float] | None = None, tiebreak: str | None = None, scoring_tie_convention: Literal['high', 'average', 'low'] = 'low', **kwargs)

Bases: RankingElection

Borda election. Positional voting system that assigns a decreasing number of points to candidates based on their ordering. The conventional score vector is \((n, n-1, \dots, 1)\) where \(n\) is the max_ranking_length of the profile. Candidates with the highest scores are elected. This class uses the utils.score_dict_from_score_vector() to handle ballots with ties.

Parameters:
  • profile (RankProfile) – Profile to conduct election on.

  • n_seats (int, optional) – Number of seats to elect. Defaults to 1.

  • score_vector (Sequence[float], optional) – Score vector. Should be non-increasing and non-negative. Vector should be as long as the number of candidates. If it is shorter, we add 0s. Defaults to None, which is the conventional Borda vector.

  • tiebreak (str, optional) – Tiebreak method to use. Options are None, ‘random’, and ‘first_place’. Defaults to None, in which case a tie raises a ValueError.

  • scoring_tie_convention (Literal["high", "average", "low"], optional) – How to award points for tied rankings. Defaults to “low”, where any candidates tied receive the lowest possible points for their position, eg three people tied for 3rd would each receive the points for 5th. “high” awards the highest possible points, so in the previous example, they would each receive the points for 3rd. “average” averages the points, so they would each receive the points for 4th place.

class votekit.elections.BoostedRandomDictator(profile: RankProfile, n_seats: int | None = None, fpv_tie_convention: Literal['high', 'average', 'low'] = 'average', **kwargs)

Bases: RankingElection

Modified random dictator where with probability (1 - 1/(n_candidates - 1)) choose a winner randomly from the distribution of first place votes. With probability 1/(n_candidates - 1), choose a winner via a proportional to squares rule.

For multi-winner elections repeat this process for every winner, removing that candidate from every voter’s ballot once they have been elected.

Parameters:
  • profile (RankProfile) – RankProfile to run election on.

  • n_seats (int) – Number of seats to elect.

  • fpv_tie_convention (Literal["high", "average", "low"], optional) – How to award points for tied first place votes. Defaults to “average”, where if n candidates are tied for first, each receives 1/n points. “high” would award them each one point, and “low” 0.

class votekit.elections.CondoBorda(profile: RankProfile, n_seats: int | None = None, **kwargs)

Bases: RankingElection

Just like DominatingSets (Smith method), but user gets to choose the number of winners, \(n_ ext{seats}\). Ties are broken with Borda scores.

Parameters:
  • profile (RankProfile) – Profile to conduct election on.

  • n_seats (int, optional) – Number of seats to elect. Defaults to 1.

class votekit.elections.DominatingSets(profile: RankProfile)

Bases: RankingElection

A “dominating set” is any set S of candidates such that everyone in S beats everyone outside of S head-to-head. The top tier (which is well defined) is often called the “Smith set,” and if it is just one person, they are called the “Condorcet candidate.” The Smith method of election declares the Smith set to be the winners, which means that users do not get to specify the number of winners.

Parameters:

profile (RankProfile) – Profile to conduct election on.

class votekit.elections.Plurality(profile: RankProfile, n_seats: int | None = None, tiebreak: str | None = None, fpv_tie_convention: Literal['high', 'low', 'average'] = 'average', **kwargs)

Bases: RankingElection

Plurality election. Winners are the n_seats candidates with the most first-place votes.

Parameters:
  • profile (RankProfile) – Profile to conduct election on.

  • n_seats (int, optional) – Number of seats to elect. Defaults to 1.

  • tiebreak (str, optional) – Tiebreak method to use. Options are None, ‘random’, and ‘borda’. Defaults to None, in which case a tie raises a ValueError.

  • fpv_tie_convention (Literal["high", "average", "low"], optional) – How to award points for tied first place votes. Defaults to “average”, where if n candidates are tied for first, each receives 1/n points. “high” would award them each one point, and “low” 0. Only used by score_function parameter.

class votekit.elections.SNTV(profile: RankProfile, n_seats: int | None = None, tiebreak: str | None = None, **kwargs)

Bases: Plurality

Wrapper for Plurality election. Winners are the n_seats candidates with the most first-place votes.

Parameters:
  • profile (RankProfile) – Profile to conduct election on.

  • n_seats (int, optional) – Number of seats to elect. Defaults to 1.

  • tiebreak (str, optional) – Tiebreak method to use. Options are None, ‘random’, and ‘borda’. Defaults to None, in which case a tie raises a ValueError.

class votekit.elections.PluralityVeto(profile: RankProfile, n_seats: int | None = None, tiebreak: Literal['first_place', 'borda', 'random', 'lex'] = 'first_place', scoring_tie_convention: Literal['high', 'low', 'average'] = 'average', **kwargs)

Bases: _IterativeVetoBase

PluralityVeto election.

Scores each candidate by their number of first place (plurality) votes, then in a randomized order it lets each voter decrement the score of their least favorite remaining candidate. Candidates are eliminated immediately when their score reaches zero. The last m candidates remaining are the winners.

Partial ballots are handled by assuming that unranked candidates tie for last place.

Parameters:
  • profile (RankProfile) – RankProfile to run election on. All ballots must have integer weights.

  • n_seats (int, optional) – Number of seats to elect. Defaults to 1.

  • tiebreak (str, optional) – Tiebreak method. Can be ‘first_place’, ‘random’, or ‘borda’. Used to determine veto when multiple candidates are tied for last place on a ballot. Defaults to ‘first_place’. If tiebreak is not ‘random’, tiebreak order is calculated in advance, using the initial profile. Thus, for ‘borda’ tiebreak, Borda scores are not recalculated as candidates are eliminated.

  • scoring_tie_convention (str, optional) – How to award points for tied first-place votes. Defaults to ‘average’: if n candidates are tied for first, each receives 1/n points. ‘high’ would award them each one point, and ‘low’ 0. Used by score_function parameter. Also used to define tiebreak_order if tiebreak is ‘first_place’ or ‘borda’.

n_seats

The number of seats to be filled in the election.

Type:

int

candidates

The set of candidates in the election.

Type:

frozenset[str]

tiebreak_order

The candidate ordering used to break last-place ties when processing vetoes. None if tiebreak = ‘random’.

Type:

Optional[tuple[frozenset[str]]]

Raises:

ValueError – If any of the following: - n_seats is less than or equal to 0 - n_seats exceeds the number of candidates in the profile who received votes, - a ballot has no ranking, - a ballot has non-integer weight.

class votekit.elections.SerialVeto(profile: RankProfile, n_seats: int | None = None, tiebreak: Literal['first_place', 'borda', 'random', 'lex'] = 'first_place', scoring_tie_convention: Literal['high', 'low', 'average'] = 'average', **kwargs)

Bases: _IterativeVetoBase

SerialVeto election.

Scores each candidate by their number of first place (plurality) votes, then in a randomized order it lets each voter decrement the score of their least favorite remaining candidate. Candidates with zero score are only eliminated when a voter attempts to veto them, which does not use up that voter’s veto. The last n_seats candidates remaining are the winners.

Partial ballots are handled by assuming that unranked candidates tie for last place.

Parameters:
  • profile (RankProfile) – RankProfile to run election on. All ballots must have integer weights.

  • n_seats (int, optional) – Number of seats to elect. Defaults to 1.

  • tiebreak (str, optional) – Tiebreak method. Can be ‘first_place’, ‘random’, or ‘borda’.

  • ballot. (Used to determine veto when multiple candidates are tied for last place on a) – Defaults to ‘first_place’. If tiebreak is not ‘random’, tiebreak order is calculated in advance, using the initial profile. Thus, for ‘borda’ tiebreak, Borda scores are not recalculated as candidates are eliminated.

  • scoring_tie_convention (str, optional) – How to award points for tied first-place votes. Defaults to ‘average’: if n candidates are tied for first, each receives 1/n points. ‘high’ would award them each one point, and ‘low’ 0. Used by score_function parameter. Also used to define tiebreak_order if tiebreak is ‘first_place’ or ‘borda’.

n_seats

The number of seats to be filled in the election.

Type:

int

candidates

The set of candidates in the election.

Type:

frozenset[str]

tiebreak_order

The candidate ordering used to break last-place ties when processing vetoes. None if tiebreak = ‘random’.

Type:

Optional[tuple[frozenset[str]]]

Raises:

ValueError – If any of the following: - n_seats is less than or equal to 0, - n_seats exceeds the number of candidates in the profile who received votes, - a ballot has no ranking, or - a ballot has non-integer weight.

class votekit.elections.SimultaneousVeto(profile: RankProfile, n_seats: int | None = None, candidate_weights: Literal['first_place', 'uniform', 'borda', 'harmonic'] | dict[str, float] | int = 'first_place', tiebreak: Literal['first_place', 'random', 'borda', 'remaining_score', 'veto_pressure', 'lex'] = 'first_place', scoring_tie_convention: Literal['high', 'average', 'low'] = 'average', return_all_tied_winners: bool = False, **kwargs)

Bases: RankingElection

An anonymous version of PluralityVeto.

Each candidate begins with a score, then, all at the same time, voters remove score from their least favorite candidates at a constant rate. As candidates’ scores reach zero, they are eliminated, and voters that were vetoing them transfer to their next least-favorite candidate. With plurality scores (first-place votes), this voting rule achieves optimal metric distortion. See Kizilkaya & Kempe’s 2023 paper: “Generalized Veto Core and a Practical Voting Rule with Optimal Metric Distortion” (https://arxiv.org/pdf/2305.19632).

Partial ballots are treated by assuming that all unranked candidates tie for last place. Voters with ties in their ranking will spread their veto evenly across the tied candidates.

Parameters:
  • profile (RankProfile) – Profile to run election on.

  • n_seats (int, optional) – Number of seats to elect. Defaults to 1.

  • (Literal['first_place' (tiebreak) –

    int, optional): Initial candidate scores. ‘first_place’ means candidates begin with

    their first-place vote count. ‘uniform’ means all candidates begin with the same score. ‘borda’ means candidates begin with their Borda scores. If a dictionary, keys are candidates and values are initial scores; a score must be provided for every candidate. If an integer k, candidates begin with their top-k vote count. Defaults to “first_place”.

  • 'uniform'

    int, optional): Initial candidate scores. ‘first_place’ means candidates begin with

    their first-place vote count. ‘uniform’ means all candidates begin with the same score. ‘borda’ means candidates begin with their Borda scores. If a dictionary, keys are candidates and values are initial scores; a score must be provided for every candidate. If an integer k, candidates begin with their top-k vote count. Defaults to “first_place”.

  • 'borda'

    int, optional): Initial candidate scores. ‘first_place’ means candidates begin with

    their first-place vote count. ‘uniform’ means all candidates begin with the same score. ‘borda’ means candidates begin with their Borda scores. If a dictionary, keys are candidates and values are initial scores; a score must be provided for every candidate. If an integer k, candidates begin with their top-k vote count. Defaults to “first_place”.

  • dict[str ('harmonic'] |) –

    int, optional): Initial candidate scores. ‘first_place’ means candidates begin with

    their first-place vote count. ‘uniform’ means all candidates begin with the same score. ‘borda’ means candidates begin with their Borda scores. If a dictionary, keys are candidates and values are initial scores; a score must be provided for every candidate. If an integer k, candidates begin with their top-k vote count. Defaults to “first_place”.

  • float]

    int, optional): Initial candidate scores. ‘first_place’ means candidates begin with

    their first-place vote count. ‘uniform’ means all candidates begin with the same score. ‘borda’ means candidates begin with their Borda scores. If a dictionary, keys are candidates and values are initial scores; a score must be provided for every candidate. If an integer k, candidates begin with their top-k vote count. Defaults to “first_place”.

  • (Literal['first_place' – ‘lex’], optional): Method for breaking ties when multiple candidates are eliminated simultaneously. Defaults to “first_place”. Backup tiebreak is lexicographic/alphabetical.

  • 'random' – ‘lex’], optional): Method for breaking ties when multiple candidates are eliminated simultaneously. Defaults to “first_place”. Backup tiebreak is lexicographic/alphabetical.

  • 'borda' – ‘lex’], optional): Method for breaking ties when multiple candidates are eliminated simultaneously. Defaults to “first_place”. Backup tiebreak is lexicographic/alphabetical.

  • 'remaining_score' – ‘lex’], optional): Method for breaking ties when multiple candidates are eliminated simultaneously. Defaults to “first_place”. Backup tiebreak is lexicographic/alphabetical.

  • 'veto_pressure' – ‘lex’], optional): Method for breaking ties when multiple candidates are eliminated simultaneously. Defaults to “first_place”. Backup tiebreak is lexicographic/alphabetical.

:param‘lex’], optional): Method for breaking ties when multiple candidates

are eliminated simultaneously. Defaults to “first_place”. Backup tiebreak is lexicographic/alphabetical.

Parameters:
  • scoring_tie_convention (Literal['high', 'average', 'low'], optional) – How to award points for ties in rankings when candidate_weights is ‘first_place’ or ‘borda’. Defaults to “average”.

  • return_all_tied_winners (bool) – If True, election returns a winner set of all tied winners, even if it is larger than n_seats. Defaults to False.

candidates

Candidates in the initial profile.

Type:

frozenset[str]

initial_scores

Initial scores of each candidate before veto process.

Type:

dict[str, float]

Raises:
  • ValueError – If any of the following: - n_seats is not positive or exceeds the number of candidates. - any ballot lacks a ranking. - candidate_weights is a dict missing candidates as keys. - candidate_weights is an unrecognized string. - candidate_weights is an int not in [1, number of candidates]

  • TypeError – If candidate_weights is not a string, dict, or int.

class votekit.elections.RandomDictator(profile: RankProfile, n_seats: int | None = None, fpv_tie_convention: Literal['high', 'average', 'low'] = 'average', **kwargs)

Bases: RankingElection

Choose a winner randomly from the distribution of first place votes. For multi-winner elections repeat this process for every winner, removing that candidate from every voter’s ballot once they have been elected.

Parameters:
  • profile (RankProfile) – RankProfile to run election on.

  • n_seats (int) – Number of seats to elect.

  • fpv_tie_convention (Literal["high", "average", "low"], optional) – How to award points for tied first place votes. Defaults to “average”, where if n candidates are tied for first, each receives 1/n points. “high” would award them each one point, and “low” 0.

class votekit.elections.RankedPairs(profile: RankProfile, tiebreak: str = 'lexicographic', n_seats: int | None = None, **kwargs)

Bases: RankingElection

See Ranked Pairs for more details. Any ambiguity is resolved lexicographically, so that the candidate with the first name alphabetically is preferred in the case of a tie.

The idea of the Ranked Pairs election is to take the head-to-head results of the candidates and then sort them by the margin of victory. We then lock this order in and construct a directed graph from the head-to-head results by traversing the locked order and skipping any edges that would create a cycle in the directed graph. The final ranking of the election is then determined by the dominating tiers of the directed graph with ties broken lexicographically.

Parameters:
  • profile (RankProfile) – Profile to conduct election on.

  • n_seats (int, optional) – Number of seats to elect. Defaults to 1.

class votekit.elections.Schulze(profile: RankProfile, tiebreak: str = 'lexicographic', n_seats: int | None = None, **kwargs)

Bases: RankingElection

See <https://link.springer.com/article/10.1007/s00355-010-0475-4> and <https://arxiv.org/pdf/1804.02973>

The Schulze method uses the widest path algorithm to determine winners. For each pair of candidates, it computes the strength of the strongest path (where the strength of a path is the strength of its weakest link). For example, if Alice beats Bob by 2 votes, Bob beats Charlie by 4 votes, then the beatpath strength from Alice to Bob is 2. Candidate A is preferred to candidate B if the strongest path from A to B is stronger than the strongest path from B to A.

The Schulze method computes the strongest paths between all pairs of candidates: 1. Initialize p[i,j] = d[i,j] - d[j,i] (margin of victory) 2. For each intermediate candidate k, update p[i,j] = max(p[i,j], min(p[i,k], p[k,j])) 3. Candidate i beats j if p[i,j] > p[j,i]

Parameters:
  • profile (RankProfile) – Profile to conduct election on.

  • n_seats (int, optional) – Number of seats to elect. Defaults to 1.

  • tiebreak (str, optional) – Method for breaking ties. Defaults to “lexicographic”.

class votekit.elections.STV(profile: ~votekit.RankProfile, n_seats: int | None = None, transfer: ~typing.Callable[[str, float, tuple[~votekit.RankBallot] | list[~votekit.RankBallot], int], tuple[~votekit.RankBallot, ...]] = <function fractional_transfer>, quota: ~typing.Literal['droop', 'hare'] | None = 'droop', simultaneous: bool = True, tiebreak: ~typing.Literal['borda', 'random', 'first_place'] | None = None, **kwargs)

Bases: RankingElection

STV elections. All ballots must have no ties.

get_threshold(total_ballot_wt: float) int[source]

Calculates threshold required for election.

Parameters:

total_ballot_wt (float) – Total weight of ballots to compute threshold.

Returns:

Value of the threshold.

Return type:

int

class votekit.elections.FastSTV(profile: RankProfile, n_seats: int | None = None, transfer: Literal['fractional', 'fractional_random', 'cambridge_random', 'random'] = 'fractional', quota: Literal['droop', 'hare'] | None = 'droop', simultaneous: bool = True, tiebreak: Literal['borda', 'random', 'first_place'] | None = None, **kwargs)

Bases: NumpyInnerSTV

STV elections. Must be given a RankProfile.

Initialize a fast STV election.

Parameters:
  • profile (RankProfile) – RankProfile to run election on.

  • n_seats (int, optional) – Number of seats to be elected. Defaults to 1.

  • transfer (TransferType, optional) – Transfer method to be used. Accepts “fractional”, “random”, “fractional_random”, and “cambridge_random”. Defaults to “fractional”.

  • quota (QuotaType, optional) – Formula to calculate quota. Accepts “droop” or “hare”. Defaults to “droop”.

  • simultaneous (bool, optional) – True if all candidates who cross threshold in a round are elected simultaneously. False if only the candidate with highest first-place votes who crosses the threshold is elected in a round. Defaults to True.

  • tiebreak (TiebreakType | None, optional) – Method to be used if a tiebreak is needed. Accepts “borda”, “random”, and “cambridge_random”. Defaults to None, in which case a ValueError is raised if a tiebreak is needed.

class votekit.elections.IRV(profile: RankProfile, quota: Literal['droop', 'hare'] | None = 'droop', tiebreak: Literal['borda', 'random', 'first_place'] | None = None)

Bases: STV

Elect exactly 1 seat using IRV (Instant-runoff voting).

All ballots must have no ties. Equivalent to STV for n_seats = 1.

Initialize an IRV election.

Parameters:
  • profile (RankProfile) – RankProfile to run election on.

  • quota (QuotaType, optional) – Formula to calculate quota. Accepts “droop” or “hare”. Defaults to “droop”.

  • tiebreak (TiebreakType | None, optional) – Method to be used if a tiebreak is needed. Accepts “borda” and “random”. Defaults to None, in which case a ValueError is raised if a tiebreak is needed.

class votekit.elections.SequentialRCV(profile: RankProfile, n_seats: int | None = None, quota: Literal['droop', 'hare'] | None = 'droop', simultaneous: bool = True, tiebreak: Literal['borda', 'random', 'first_place'] | None = None, **kwargs)

Bases: STV

STV election in which votes are not transferred from elected candidates.

This system just runs a series of IRV elections until the desired number of candidates are elected.

Notes

  • Used in parts of Utah.

Initialize a sequential RCV election.

Parameters:
  • profile (RankProfile) – RankProfile to run election on.

  • n_seats (int, optional) – Number of seats to be elected. Defaults to 1.

  • quota (QuotaType, optional) – Formula to calculate quota. Accepts “droop” or “hare”. Defaults to “droop”.

  • simultaneous (bool, optional) – True if all candidates who cross threshold in a round are elected simultaneously. False if only the candidate with highest first-place votes who crosses the threshold is elected in a round. Defaults to True.

  • tiebreak (TiebreakType | None, optional) – Method to be used if a tiebreak is needed. Accepts “borda” and “random”. Defaults to None, in which case a ValueError is raised if a tiebreak is needed.

class votekit.elections.TopTwo(profile: RankProfile, tiebreak: str | None = None, fpv_tie_convention: Literal['high', 'low', 'average'] = 'average')

Bases: RankingElection

Eliminates all but the top two plurality vote-getters, and then conducts a runoff between them, reallocating other ballots.

Parameters:
  • profile (RankProfile) – Profile to conduct election on.

  • tiebreak (str, optional) – Tiebreak method to use. Options are None, ‘random’, and ‘borda’. Defaults to None, in which case a tie raises a ValueError.

  • fpv_tie_convention (Literal["high", "average", "low"], optional) – How to award points for tied first place votes. Defaults to “average”, where if n candidates are tied for first, each receives 1/n points. “high” would award them each one point, and “low” 0. Only used by score_function parameter.

Score-based

class votekit.elections.GeneralRating(profile: ScoreProfile, n_seats: int | None = None, per_candidate_limit: float | None = None, budget: float | None = None, tiebreak: str | None = None, **kwargs)

Bases: Election[ScoreProfile]

General rating election. To fill \(n_ ext{seats}\) seats, voters score each candidate from \(0\) to per_candidate_limit. There is also a total budget of budget points per voter. The \(n_ ext{seats}\) winners are those with the highest total score.

Parameters:
  • profile (ScoreProfile) – Profile to conduct election on.

  • n_seats (int, optional) – Number of seats to elect. Defaults to 1.

  • per_candidate_limit (float, optional) – Rating per candidate limit. Defaults to 1.

  • budget (float, optional) – Budget per ballot limit. Defaults to None, in which case voters can score each candidate independently.

  • tiebreak (str, optional) – Tiebreak method to use. Options are None and ‘random’. Defaults to None, in which case a tie raises a ValueError.

class votekit.elections.Rating(profile: ScoreProfile, n_seats: int | None = None, per_candidate_limit: float | None = None, tiebreak: str | None = None, **kwargs)

Bases: GeneralRating

Rating election. To fill \(n_ ext{seats}\) seats, voters score each candidate independently from \(0\) to per_candidate_limit. The \(n_ ext{seats}\) winners are those with the highest total score.

Parameters:
  • profile (ScoreProfile) – Profile to conduct election on.

  • n_seats (int, optional) – Number of seats to elect. Defaults to 1.

  • per_candidate_limit (float, optional) – Rating per candidate limit. Defaults to 1.

  • tiebreak (str, optional) – Tiebreak method to use. Options are None and ‘random’. Defaults to None, in which case a tie raises a ValueError.

class votekit.elections.Cumulative(profile: ScoreProfile, n_seats: int | None = None, tiebreak: str | None = None, **kwargs)

Bases: Limited

Scoring election where voters distribute up to n_seats points total.

Voters can score each candidate, but have a total budget of \(n_ ext{seats}\) points. Winners are those with the highest total score.

Parameters:
  • profile (ScoreProfile) – Profile to conduct election on.

  • n_seats (int, optional) – Number of seats to elect. Defaults to 1.

  • tiebreak (str, optional) – Tiebreak method to use. Options are None and ‘random’. Defaults to None, in which case a tie raises a ValueError.

class votekit.elections.Limited(profile: ScoreProfile, n_seats: int | None = None, budget: float | None = None, tiebreak: str | None = None, **kwargs)

Bases: GeneralRating

A scoring election with a per-voter budget constraint.

Voters can score each candidate, but have a total budget of \(\text{budget} \le n_\text{seats}\) points. Winners are those with the highest total score.

Parameters:
  • profile (ScoreProfile) – Profile to conduct election on.

  • n_seats (int, optional) – Number of seats to elect. Defaults to 1.

  • budget (float, optional) – Total points allowed per voter. Defaults to 1.

  • tiebreak (str, optional) – Tiebreak method to use. Options are None and ‘random’. Defaults to None, in which case a tie raises a ValueError.

Raises:

ValueError – If budget exceeds n_seats.

Graphs and Viz.

class votekit.graphs.BallotGraph(source: RankProfile | int | list, allow_partial: bool | None = True, fix_short: bool | None = True)

Class to build ballot graphs.

Parameters:
  • source (Union[RankProfile, int, list]) – data to create graph from, either RankProfile object, number of candidates, or list of candidates.

  • allow_partial (bool, optional) – If True, builds graph using all possible ballots, If False, only uses total linear ordered ballots. Defaults to True.

  • fix_short (bool, optional) – If True, auto completes ballots of length \(n-1\) to \(n\). Ballots of length less than \(n-1\) are preserved. Defaults to True.

profile

Profile used to create graph, None if not provided.

Type:

RankProfile

candidates

Tuple of candidates, None if not provided.

Type:

tuple[str]

num_cands

Number of candidates.

Type:

int

num_voters

Sum of weights of profile if provided.

Type:

float

allow_partial

If True, builds graph using all possible ballots, If False, only uses total linear ordered ballots.

Type:

bool, optional

graph

underlying networkx graph.

Type:

networkx.Graph

build_graph(n: int) Graph[source]

Builds graph of all possible ballots given a number of candiates.

Parameters:

n (int) – Number of candidates in an election.

Returns:

A networkx graph.

Return type:

networkx.Graph

draw(to_display: ~typing.Callable = <function all_nodes>, neighborhoods: list[tuple] | None = [], show_cast: bool | None = False, labels: bool | None = False, scale: float = 1.0)[source]

Visualize the graph.

Parameters:
  • to_display (Callable, optional) – A boolean function that takes the graph and a node as input, returns True if you want that node displayed. Defaults to showing all nodes.

  • neighborhoods (list[tuple], optional) – A list of neighborhoods to display, given as tuple (node, radius). eg. (n,1) gives all nodes within one step of n. Defaults to empty list which shows all nodes.

  • show_cast (bool, optional) – If True, show only nodes with “cast” attribute = True. If False, show all nodes. Defaults to False.

  • labels (bool, optional) – If True, labels nodes with candidate names and vote totals. Defaults to False.

  • scale (float, optional) – How much to scale the base graph by. Defaults to 1.0.

fix_short_ballot(ballot: list, candidates: list) list[source]

Adds missing candidates to a short ballot.

Parameters:
  • ballot (list) – A list of candidates on the ballot.

  • candidates (list) – A list of all candidates.

Returns:

A new list with the missing candidates added to the end of the ballot.

Return type:

list

from_profile(profile: RankProfile, fix_short: bool | None = True) Graph[source]

Updates existing graph based on cast ballots from a RankProfile, or creates graph based on RankProfile.

Parameters:
  • profile (RankProfile) – RankProfile assigned to graph.

  • fix_short (bool, optional) – If True, complete short ballots. Defaults to True.

Returns:

Graph based on RankProfile, ‘cast’ node attribute indicates ballots cast in RankProfile.

Return type:

networkx.Graph

label_cands(candidates, to_display: ~typing.Callable = <function all_nodes>)[source]

Assigns candidate labels to ballot graph for plotting.

Parameters:
  • candidates (list) – A list of candidates.

  • to_display (Callable, optional) – A Boolean callable that takes in a graph and node, returns True if node should be displayed. Defaults to showing all nodes.

label_weights(to_display: ~typing.Callable = <function all_nodes>)[source]

Assigns weight labels to ballot graph for plotting. Only shows weight if non-zero.

Parameters:

to_display (Callable, optional) – A Boolean callable that takes in a graph and node, returns True if node should be displayed. Defaults to showing all nodes.

class votekit.graphs.PairwiseComparisonGraph(*args, backend=None, **kwargs)

Bases: DiGraph

Class to construct the pairwise comparison graph where nodes are candidates and edges are pairwise preferences.

Parameters:
  • profile (RankProfile) – RankProfile to construct graph from.

  • sort_candidate_pairs (bool) – If True, candidate pairs in the pairwise comparison dictionary will be sorted lexicographically. Defaults to True.

profile

RankProfile to construct graph from.

Type:

RankProfile

candidates

List of candidates.

Type:

list

pairwise_dict

Dictionary constructed from pairwise_dict. The pairwise dictionary is a dictionary whose keys are candidate pairs (A,B) and whose values are lists [a,b] where ‘a’ denotes the number of times A beats B head to head, and ‘b’ is the number of times B beats A head to head.

Type:

dict[tuple[str, str], tuple[float, float]]

pairwise_graph

Underlying graph.

Type:

networkx.DiGraph

draw(ax: matplotlib.axes.Axes | None = None, candidate_list: list[str] | None = None) matplotlib.axes.Axes[source]

Draws pairwise comparison graph.

Parameters:
  • ax (Axes, optional) – Matplotlib axes to plot on. Defaults to None, in which case an axes is generated.

  • candidate_list (list[str], optional) – List of candidates to plot. Defaults to None, in which case all candidates are used.

Returns:

Matplotlib axes of pairwise comparison graph.

Return type:

Axes

get_condorcet_cycles(strict: bool = False) list[set[str]][source]

Returns a list of condorcet cycles in the graph.

A cycle is defined as any cycle of length greater than 2.

Parameters:

strict (bool, optional) – If True, only considers strict wins (weight > 0). If False, includes ties (weak condorcet cycles). Defaults to False.

Returns:

List of condorcet cycles sorted by length.

Return type:

list[set[str]]

get_condorcet_winner() str[source]

Returns the condorcet winner. Raises a ValueError if no condorcet winner.

Returns:

The condorcet winner.

Return type:

str

Raises:

ValueError – There is no condorcet winner.

get_dominating_tiers() list[set[str]][source]

Compute the dominating tiers of the pairwise comparison graph. Candidates in a tier beat all other candidates in lower tiers in head to head comparisons.

Returns:

Dominating tiers, where the first entry of the list is the highest tier.

Return type:

list[set[str]]

has_condorcet_cycles() bool[source]

Checks if graph has any condorcet cycles, which we define as any cycle of length greater than 2 in the graph.

Returns:

True if condorcet cycles exists, False otherwise.

Return type:

bool

has_condorcet_winner() bool[source]

Checks if graph has a condorcet winner.

Returns:

True if condorcet winner exists, False otherwise.

Return type:

bool

ties_or_beats(candidate: str) set[str][source]

Returns the predecessors of x, which are all of the nodes m that have a directed path from m to x. In the pairwise comparison graph, these are the candidates that tie or beat the given candidate.

Parameters:

candidate (str) – Candidate.

Returns:

Candidates that beat or tie given candidate head to head.

Return type:

set[str]

votekit.graphs.pairwise_dict(profile: RankProfile, *, sort_candidate_pairs: bool = True) dict[tuple[str, str], tuple[float, float]]

Computes a dictionary whose keys are candidate pairs (A,B) and whose values are lists [a,b] where ‘a’ denotes the number of times A beats B head to head, and ‘b’ is the reverse.

Parameters:
  • profile (RankProfile) – Profile to compute dict on.

  • sort_candidate_pairs (bool) – If True, candidate pairs in the pairwise comparison dictionary will be sorted lexicographically. Defaults to True.

Returns:

Pairwise comparison dictionary.

Return type:

dict[tuple[str, str], tuple[float, float]]

votekit.graphs.restrict_pairwise_dict_to_subset(cand_subset: list[str] | tuple[str] | set[str], pairwise_dict: dict[tuple[str, str], tuple[float, float]]) dict[tuple[str, str], tuple[float, float]]

Restricts the full pairwise dictionary to a subset of candidates. The pairwise dictionary is a dictionary whose keys are candidate pairs (A,B) and whose values are lists [a,b] where ‘a’ denotes the number of times A beats B head to head, and ‘b’ is the reverse.

Parameters:
  • cands (list[str] | tuple[str] | set[str]) – Candidate subset to restrict to.

  • pairwise_dict (dict[tuple[str, str], tuple[float, float]) – Full pairwise comparison dictionary.

Returns:

Pairwise dict restricted to the provided

candidates.

Return type:

dict[tuple[str, str], tuple[float, float]]

Raises:
  • ValueError – cand_subset must be at least length 2.

  • ValueError – cand_subset must be a subset of the candidates in the dictionary.

votekit.plots.compute_MDS(data: Dict[str, list[PreferenceProfile]], distance: Callable[[...], int], random_seed: int = 47, *args, **kwargs)

Computes the coordinates of an MDS plot. This is time intensive, so it is decoupled from plot_mds to allow users to flexibly use the coordinates.

Parameters:
  • data (Dict[str, list[PreferenceProfile]]) – Dictionary with key being a string label and value being list of PreferenceProfiles. eg. {'PL with alpha = 4': list[PreferenceProfile]}

  • distance (Callable[..., int]) – Distance function. See distance.py.

  • random_seed (int, optional) – An integer seed to allow for reproducible MDS plots. Defaults to 47.

  • *args – args to be passed to distance_matrix.

  • **kwargs – kwargs to be passed to distance_matrix.

Returns:

a dictionary whose keys match data and whose values are tuples of

numpy arrays (x_list, y_list) of coordinates for the MDS plot.

Return type:

coord_dict (dict)

votekit.plots.plot_MDS(coord_dict: dict, ax: matplotlib.axes.Axes | None = None, plot_kwarg_dict: dict | None = None, legend: bool = True, title: bool = True)

Creates an MDS plot from the output of compute_MDS with legend labels matching the keys of coord_dict.

Parameters:
  • coord_dict (dict) – Dictionary with key being a string label and value being tuple (x_list, y_list), coordinates for the MDS plot. Should be piped in from compute_MDS.

  • ax (axes, optional) – A matplolib axes object to plot the figure on. Defaults to None, in which case the function creates and returns a new axes.

  • plot_kwarg_dict (dict, optional) – Dictionary with keys matching coord_dict and values are kwarg dictionaries that will be passed to matplotlib scatter.

  • legend (bool, optional) – boolean for plotting the legend. Defaults to True.

  • title (bool, optional) – boolean for plotting the title. Defaults to True.

Returns:

a matplotlib Axes.

Return type:

Axes

votekit.plots.bar_plot(data: Mapping[str, float], *, data_set_label: str = 'Data set', normalize: bool = False, data_set_color: str = '#0099cd', bar_width: float | None = None, category_ordering: list[str] | None = None, x_axis_name: str | None = None, y_axis_name: str | None = None, title: str | None = None, show_data_set_legend: bool = False, categories_legend: Mapping[str, str | int] | None = None, threshold_values: list[float] | float | None = None, threshold_kwds: list[dict] | dict | None = None, legend_font_size: float | None = None, ax: matplotlib.axes.Axes | None = None) matplotlib.axes.Axes

Plots bar plot of a single categorical data set. Wrapper for multi_bar_plot.

Parameters:
  • data (dict[str, float]) – Categorical data set to be plotted. Keys are categories, and values are the height of the bars.

  • data_set_label (str, optional) – Label for data set. Defaults to “Data set”.

  • normalize (bool, optional) – Whether or not to normalize data. Defaults to False.

  • data_set_color (str, optional) – Color of data set. Defaults to the first color from COLOR_LIST from utils module.

  • bar_width (float, optional) – Width of bars. Defaults to None which computes the bar width as 0.7 divided by the number of data sets. Must be in the interval \((0,1]\).

  • category_ordering (list[str], optional) – Ordering of x-labels. Defaults to order retrieved from data dictionary.

  • x_axis_name (str, optional) – Name of x-axis. Defaults to None, which does not plot a name.

  • y_axis_name (str, optional) – Name of y-axis. Defaults to None, which does not plot a name.

  • title (str, optional) – Title for the figure. Defaults to None, which does not plot a title.

  • show_data_set_legend (bool, optional) – Whether or not to plot the data set legend. Defaults to False. Is automatically shown if any threshold lines have the keyword “label” passed through threshold_kwds.

  • categories_legend (dict[str, str], optional) – Dictionary mapping data categories to description. Defaults to None. If provided, generates a second legend for data categories.

  • threshold_values (Union[list[float], float], optional) – List of values to plot horizontal lines at. Can be provided as a list or a single float.

  • threshold_kwds (Union[list[dict], dict], optional) – List of plotting keywords for the horizontal lines. Can be a list or single dictionary. These will be passed to plt.axhline(). Common keywords include “linestyle”, “linewidth”, and “label”. If “label” is passed, automatically plots the data set legend with the labels.

  • legend_font_size (float, optional) – The font size to use for the legend. Defaults to 10.0 + the number of categories.

  • legend_loc (str, optional) – The location parameter to pass to Axes.legend(loc=). Defaults to “center left”.

  • legend_bbox_to_anchor (Tuple[float, float], otptional) – The bounding box to anchor the legend to. Defaults to (1, 0.5).

  • ax (Axes, optional) – A matplotlib axes object to plot the figure on. Defaults to None, in which case the function creates and returns a new axes. The figure height is 6 inches and the figure width is 3 inches times the number of categories.

Returns:

A matplotlib axes with a bar plot of the given data.

Return type:

Axes

votekit.plots.multi_bar_plot(data: Mapping[str, Mapping[str, float]], *, normalize: bool = False, data_set_colors: Mapping[str, str] | None = None, bar_width: float | None = None, category_ordering: list[str] | None = None, x_axis_name: str | None = None, y_axis_name: str | None = None, title: str | None = None, show_data_set_legend: bool = False, categories_legend: Mapping[str, str | int] | None = None, threshold_values: list[float] | float | None = None, threshold_kwds: list[dict] | dict | None = None, legend_font_size: float | None = None, ax: matplotlib.axes.Axes | None = None) matplotlib.axes.Axes

Plots bar plot of categorical data.

Parameters:
  • data (dict[str, dict[str, float]]) – Categorical data to be plotted. Top level keys are data set labels. Inner keys are categories, and inner values are the height of the bars.

  • normalize (bool, optional) – Whether or not to normalize data. Defaults to False.

  • data_set_colors (dict[str, str], optional) – Dictionary mapping data set labels to colors. Defaults to None, in which case we use a subset of COLOR_LIST from utils module. Dictionary keys can be a subset of the data sets.

  • bar_width (float, optional) – Width of bars. Defaults to None which computes the bar width as 0.7 divided by the number of data sets. Must be in the interval \((0,1]\).

  • category_ordering (list[str], optional) – Ordering of x-labels. Defaults to order retrieved from data dictionary.

  • x_axis_name (str, optional) – Name of x-axis. Defaults to None, which does not plot a name.

  • y_axis_name (str, optional) – Name of y-axis. Defaults to None, which does not plot a name.

  • title (str, optional) – Title for the figure. Defaults to None, which does not plot a title.

  • show_data_set_legend (bool, optional) – Whether or not to plot the data set legend. Defaults to False. Is automatically shown if any threshold lines have the keyword “label” passed through threshold_kwds.

  • categories_legend (dict[str, str], optional) – Dictionary mapping data categories to relabeling. Defaults to None. If provided, generates a second legend for data categories and relabels the x-axis accordingly. Can be a subset of the data keys.

  • threshold_values (Union[list[float], float], optional) – List of values to plot horizontal lines at. Can be provided as a list or a single float.

  • threshold_kwds (Union[list[dict], dict], optional) – List of plotting keywords for the horizontal lines. Can be a list or single dictionary. These will be passed to plt.axhline(). Common keywords include “linestyle”, “linewidth”, and “label”. If “label” is passed, automatically plots the data set legend with the labels.

  • legend_font_size (float, optional) – The font size to use for the legend. Defaults to 10.0 + the number of categories.

  • legend_loc (str, optional) – The location parameter to pass to Axes.legend(loc=). Defaults to “center left”.

  • legend_bbox_to_anchor (Tuple[float, float], otptional) – The bounding box to anchor the legend to. Defaults to (1, 0.5).

  • ax (Axes, optional) – A matplotlib axes object to plot the figure on. Defaults to None, in which case the function creates and returns a new axes. The figure height is 6 inches and the figure width is 3 inches times the number of categories.

Returns:

A matplotlib axes with a bar plot of the given data.

Return type:

Axes

votekit.plots.profile_bar_plot(profile: ProfileT, stat_function: Callable[[ProfileT], dict[str, float]], *, profile_label: str = 'Profile', normalize: bool = False, profile_color: str = '#0099cd', bar_width: float | None = None, category_ordering: list[str] | None = None, x_axis_name: str | None = None, y_axis_name: str | None = None, title: str | None = None, show_profile_legend: bool = False, categories_legend: Mapping[str, str | int] | None = None, threshold_values: list[float] | float | None = None, threshold_kwds: list[dict] | dict | None = None, legend_font_size: float | None = None, ax: matplotlib.axes.Axes | None = None) matplotlib.axes.Axes

Plots bar plot of a single profile.

Parameters:
  • profile (RankProfile) – Profile to plot statistics for.

  • stat_function (Callable[[RankProfile], dict[str, float]]) – Which stat to use for the bar plot. Must be a callable that takes a profile and returns a dict with str keys and float values.

  • profile_label (str, optional) – Label for profile. Defaults to “Profile”.

  • normalize (bool, optional) – Whether or not to normalize data. Defaults to False.

  • profile_color (str, optional) – Color to plot. Defaults to the first color from COLOR_LIST from utils module.

  • bar_width (float, optional) – Width of bars. Defaults to None which computes the bar width as 0.7 divided by the number of data sets. Must be in the interval \((0,1]\).

  • category_ordering (list[str], optional) – Ordering of x-labels. Defaults to order retrieved from data dictionary.

  • x_axis_name (str, optional) – Name of x-axis. Defaults to None, which does not plot a name.

  • y_axis_name (str, optional) – Name of y-axis. Defaults to None, which does not plot a name.

  • title (str, optional) – Title for the figure. Defaults to None, which does not plot a title.

  • show_profile_legend (bool, optional) – Whether or not to plot the profile legend. Defaults to False. Is automatically shown if any threshold lines have the keyword “label” passed through threshold_kwds.

  • categories_legend (dict[str, str], optional) – Dictionary mapping data categories to description. Defaults to None. If provided, generates a second legend for data categories.

  • threshold_values (Union[list[float], float], optional) – List of values to plot horizontal lines at. Can be provided as a list or a single float.

  • threshold_kwds (Union[list[dict], dict], optional) – List of plotting keywords for the horizontal lines. Can be a list or single dictionary. These will be passed to plt.axhline(). Common keywords include “linestyle”, “linewidth”, and “label”. If “label” is passed, automatically plots the data set legend with the labels.

  • legend_font_size (float, optional) – The font size to use for the legend. Defaults to 10.0 + the number of categories.

  • legend_loc (str, optional) – The location parameter to pass to Axes.legend(loc=). Defaults to “center left”.

  • legend_bbox_to_anchor (Tuple[float, float], otptional) – The bounding box to anchor the legend to. Defaults to (1, 0.5).

  • ax (Axes, optional) – A matplotlib axes object to plot the figure on. Defaults to None, in which case the function creates and returns a new axes. The figure height is 6 inches and the figure width is 3 inches times the number of categories.

Returns:

A matplotlib axes with a bar plot of the given data.

Return type:

Axes

votekit.plots.profile_borda_plot(profile: RankProfile, *, profile_label: str = 'Profile', borda_kwds: dict[str, Any] | None = None, normalize: bool = False, profile_color: str = '#0099cd', bar_width: float | None = None, candidate_ordering: list[str] | None = None, x_axis_name: str | None = None, y_axis_name: str | None = None, title: str | None = None, show_profile_legend: bool = False, candidate_legend: Mapping[str, str | int] | None = None, relabel_candidates_with_int: bool = False, threshold_values: list[float] | float | None = None, threshold_kwds: list[dict] | dict | None = None, legend_font_size: float | None = None, ax: matplotlib.axes.Axes | None = None) matplotlib.axes.Axes

Plots borda points of candidates in profile. Wrapper for profile_bar_plot.

Parameters:
  • profile (RankProfile) – Profile to plot statistics for.

  • profile_label (str, optional) – Label for profile. Defaults to “Profile”.

  • borda_kwds (dict[str, Any], optional) – Keyword arguments to pass to borda_scores. Defaults to None, in which case default values for borda_scores are used.

  • normalize (bool, optional) – Whether or not to normalize data. Defaults to False.

  • profile_color (str, optional) – Color to plot. Defaults to the first color from COLOR_LIST from utils module.

  • bar_width (float, optional) – Width of bars. Defaults to None which computes the bar width as 0.7 divided by the number of data sets. Must be in the interval \((0,1]\).

  • candidate_ordering (list[str], optional) – Ordering of x-labels. Defaults to decreasing order of Borda scores.

  • x_axis_name (str, optional) – Name of x-axis. Defaults to None, which does not plot a name.

  • y_axis_name (str, optional) – Name of y-axis. Defaults to None, which does not plot a name.

  • title (str, optional) – Title for the figure. Defaults to None, which does not plot a title.

  • show_profile_legend (bool, optional) – Whether or not to plot the profile legend. Defaults to False. Is automatically shown if any threshold lines have the keyword “label” passed through threshold_kwds.

  • candidate_legend (dict[str, str], optional) – Dictionary mapping candidates to alternate label. Defaults to None. If provided, generates a second legend.

  • relabel_candidates_with_int (bool, optional) – Relabel the candidates with integer labels. Defaults to False. If candidate_legend is passed, those labels supercede.

  • threshold_values (Union[list[float], float], optional) – List of values to plot horizontal lines at. Can be provided as a list or a single float.

  • threshold_kwds (Union[list[dict], dict], optional) – List of plotting keywords for the horizontal lines. Can be a list or single dictionary. These will be passed to plt.axhline(). Common keywords include “linestyle”, “linewidth”, and “label”. If “label” is passed, automatically plots the data set legend with the labels.

  • legend_font_size (float, optional) – The font size to use for the legend. Defaults to 10.0 + the number of categories.

  • legend_loc (str, optional) – The location parameter to pass to Axes.legend(loc=). Defaults to “center left”.

  • legend_bbox_to_anchor (Tuple[float, float], otptional) – The bounding box to anchor the legend to. Defaults to (1, 0.5).

  • ax (Axes, optional) – A matplotlib axes object to plot the figure on. Defaults to None, in which case the function creates and returns a new axes. The figure height is 6 inches and the figure width is 3 inches times the number of categories.

Returns:

A matplotlib axes with a bar plot of the given data.

Return type:

Axes

votekit.plots.profile_ballot_lengths_plot(profile: RankProfile, *, profile_label: str = 'Profile', ballot_lengths_kwds: dict[str, Any] | None = None, normalize: bool = False, profile_color: str = '#0099cd', bar_width: float | None = None, lengths_ordering: list[str | int] | None = None, x_axis_name: str | None = None, y_axis_name: str | None = None, title: str | None = None, show_profile_legend: bool = False, lengths_legend: Mapping[str | int, str | int] | None = None, threshold_values: list[float] | float | None = None, threshold_kwds: list[dict] | dict | None = None, legend_font_size: float | None = None, ax: matplotlib.axes.Axes | None = None) matplotlib.axes.Axes

Plots ballot lengths in profile. Wrapper for profile_bar_plot.

Parameters:
  • profile (RankProfile) – Profile to plot statistics for.

  • profile_label (str, optional) – Label for profile. Defaults to “Profile”.

  • ballot_lengths_kwds (dict[str, Any], optional) – Keyword arguments to pass to ballot_lengths. Defaults to None, in which case default values for ballot_lengths are used.

  • normalize (bool, optional) – Whether or not to normalize data. Defaults to False.

  • profile_color (str, optional) – Color to plot. Defaults to the first color from COLOR_LIST from utils module.

  • bar_width (float, optional) – Width of bars. Defaults to None which computes the bar width as 0.7 divided by the number of data sets. Must be in the interval \((0,1]\).

  • lengths_ordering (list[str], optional) – Ordering of x-labels. Defaults to increasing order of lengths.

  • x_axis_name (str, optional) – Name of x-axis. Defaults to None, which does not plot a name.

  • y_axis_name (str, optional) – Name of y-axis. Defaults to None, which does not plot a name.

  • title (str, optional) – Title for the figure. Defaults to None, which does not plot a title.

  • show_profile_legend (bool, optional) – Whether or not to plot the profile legend. Defaults to False. Is automatically shown if any threshold lines have the keyword “label” passed through threshold_kwds.

  • lengths_legend (dict[str, str], optional) – Dictionary mapping lengths to alternate label. Defaults to None. If provided, generates a second legend.

  • threshold_values (Union[list[float], float], optional) – List of values to plot horizontal lines at. Can be provided as a list or a single float.

  • threshold_kwds (Union[list[dict], dict], optional) – List of plotting keywords for the horizontal lines. Can be a list or single dictionary. These will be passed to plt.axhline(). Common keywords include “linestyle”, “linewidth”, and “label”. If “label” is passed, automatically plots the data set legend with the labels.

  • legend_font_size (float, optional) – The font size to use for the legend. Defaults to 10.0 + the number of categories.

  • legend_loc (str, optional) – The location parameter to pass to Axes.legend(loc=). Defaults to “center left”.

  • legend_bbox_to_anchor (Tuple[float, float], optional) – The bounding box to anchor the legend to. Defaults to (1, 0.5).

  • ax (Axes, optional) – A matplotlib axes object to plot the figure on. Defaults to None, in which case the function creates and returns a new axes. The figure height is 6 inches and the figure width is 3 inches times the number of categories.

Returns:

A matplotlib axes with a bar plot of the given data.

Return type:

Axes

votekit.plots.profile_fpv_plot(profile: RankProfile, *, profile_label: str = 'Profile', fpv_kwds: dict[str, Any] | None = None, normalize: bool = False, profile_color: str = '#0099cd', bar_width: float | None = None, candidate_ordering: list[str] | None = None, x_axis_name: str | None = None, y_axis_name: str | None = None, title: str | None = None, show_profile_legend: bool = False, candidate_legend: Mapping[str, str | int] | None = None, relabel_candidates_with_int: bool = False, threshold_values: list[float] | float | None = None, threshold_kwds: list[dict] | dict | None = None, legend_font_size: float | None = None, ax: matplotlib.axes.Axes | None = None) matplotlib.axes.Axes

Plots first place votes of candidates in profile. Wrapper for profile_bar_plot.

Parameters:
  • profile (RankProfile) – Profile to plot statistics for.

  • profile_label (str, optional) – Label for profile. Defaults to “Profile”.

  • fpv_kwds (dict[str, Any], optional) – Keyword arguments to pass to first_place_votes. Defaults to None, in which case default values for first_place_votes are used.

  • normalize (bool, optional) – Whether or not to normalize data. Defaults to False.

  • profile_color (str, optional) – Color to plot. Defaults to the first color from COLOR_LIST from utils module.

  • bar_width (float, optional) – Width of bars. Defaults to None which computes the bar width as 0.7 divided by the number of data sets. Must be in the interval \((0,1]\).

  • candidate_ordering (list[str], optional) – Ordering of x-labels. Defaults to decreasing order of first place votes.

  • x_axis_name (str, optional) – Name of x-axis. Defaults to None, which does not plot a name.

  • y_axis_name (str, optional) – Name of y-axis. Defaults to None, which does not plot a name.

  • title (str, optional) – Title for the figure. Defaults to None, which does not plot a title.

  • show_profile_legend (bool, optional) – Whether or not to plot the profile legend. Defaults to False. Is automatically shown if any threshold lines have the keyword “label” passed through threshold_kwds.

  • candidate_legend (dict[str, str], optional) – Dictionary mapping candidates to alternate label. Defaults to None. If provided, generates a second legend.

  • relabel_candidates_with_int (bool, optional) – Relabel the candidates with integer labels. Defaults to False. If candidate_legend is passed, those labels supercede.

  • threshold_values (Union[list[float], float], optional) – List of values to plot horizontal lines at. Can be provided as a list or a single float.

  • threshold_kwds (Union[list[dict], dict], optional) – List of plotting keywords for the horizontal lines. Can be a list or single dictionary. These will be passed to plt.axhline(). Common keywords include “linestyle”, “linewidth”, and “label”. If “label” is passed, automatically plots the data set legend with the labels.

  • legend_font_size (float, optional) – The font size to use for the legend. Defaults to 10.0 + the number of categories.

  • legend_loc (str, optional) – The location parameter to pass to Axes.legend(loc=). Defaults to “center left”.

  • legend_bbox_to_anchor (Tuple[float, float], otptional) – The bounding box to anchor the legend to. Defaults to (1, 0.5).

  • ax (Axes, optional) – A matplotlib axes object to plot the figure on. Defaults to None, in which case the function creates and returns a new axes. The figure height is 6 inches and the figure width is 3 inches times the number of categories.

Returns:

A matplotlib axes with a bar plot of the given data.

Return type:

Axes

votekit.plots.profile_mentions_plot(profile: RankProfile, *, profile_label: str = 'Profile', mentions_kwds: dict[str, Any] | None = None, normalize: bool = False, profile_color: str = '#0099cd', bar_width: float | None = None, candidate_ordering: list[str] | None = None, x_axis_name: str | None = None, y_axis_name: str | None = None, title: str | None = None, show_profile_legend: bool = False, candidate_legend: Mapping[str, str | int] | None = None, relabel_candidates_with_int: bool = False, threshold_values: list[float] | float | None = None, threshold_kwds: list[dict] | dict | None = None, legend_font_size: float | None = None, ax: matplotlib.axes.Axes | None = None) matplotlib.axes.Axes

Plots mentions of candidates in profile. Wrapper for profile_bar_plot.

Parameters:
  • profile (RankProfile) – Profile to plot statistics for.

  • profile_label (str, optional) – Label for profile. Defaults to “Profile”.

  • mentions_kwds (dict[str, Any], optional) – Keyword arguments to pass to mentions. Defaults to None, in which case default values for mentions are used.

  • normalize (bool, optional) – Whether or not to normalize data. Defaults to False.

  • profile_color (str, optional) – Color to plot. Defaults to the first color from COLOR_LIST from utils module.

  • bar_width (float, optional) – Width of bars. Defaults to None which computes the bar width as 0.7 divided by the number of data sets. Must be in the interval \((0,1]\).

  • candidate_ordering (list[str], optional) – Ordering of x-labels. Defaults to decreasing order of mentions.

  • x_axis_name (str, optional) – Name of x-axis. Defaults to None, which does not plot a name.

  • y_axis_name (str, optional) – Name of y-axis. Defaults to None, which does not plot a name.

  • title (str, optional) – Title for the figure. Defaults to None, which does not plot a title.

  • show_profile_legend (bool, optional) – Whether or not to plot the profile legend. Defaults to False. Is automatically shown if any threshold lines have the keyword “label” passed through threshold_kwds.

  • candidate_legend (dict[str, str], optional) – Dictionary mapping candidates to alternate label. Defaults to None. If provided, generates a second legend.

  • relabel_candidates_with_int (bool, optional) – Relabel the candidates with integer labels. Defaults to False. If candidate_legend is passed, those labels supercede.

  • threshold_values (Union[list[float], float], optional) – List of values to plot horizontal lines at. Can be provided as a list or a single float.

  • threshold_kwds (Union[list[dict], dict], optional) – List of plotting keywords for the horizontal lines. Can be a list or single dictionary. These will be passed to plt.axhline(). Common keywords include “linestyle”, “linewidth”, and “label”. If “label” is passed, automatically plots the data set legend with the labels.

  • legend_font_size (float, optional) – The font size to use for the legend. Defaults to 10.0 + the number of categories.

  • legend_loc (str, optional) – The location parameter to pass to Axes.legend(loc=). Defaults to “center left”.

  • legend_bbox_to_anchor (Tuple[float, float], otptional) – The bounding box to anchor the legend to. Defaults to (1, 0.5).

  • ax (Axes, optional) – A matplotlib axes object to plot the figure on. Defaults to None, in which case the function creates and returns a new axes. The figure height is 6 inches and the figure width is 3 inches times the number of categories.

Returns:

A matplotlib axes with a bar plot of the given data.

Return type:

Axes

votekit.plots.multi_profile_bar_plot(profile_dict: Mapping[str, ProfileT], stat_function: Callable[[ProfileT], dict[str, float]], normalize: bool = False, profile_colors: Mapping[str, str] | None = None, bar_width: float | None = None, category_ordering: list[str] | None = None, x_axis_name: str | None = None, y_axis_name: str | None = None, title: str | None = None, show_profile_legend: bool = False, categories_legend: Mapping[str, str | int] | None = None, threshold_values: list[float] | float | None = None, threshold_kwds: list[dict] | dict | None = None, legend_font_size: float | None = None, ax: matplotlib.axes.Axes | None = None) matplotlib.axes.Axes

Plot a multi bar plot over a set of preference profiles and some statistic about the profile, like ballot length, first place votes for candidate, etc.

Parameters:
  • profile_dict (dict[str, RankProfile | ScoreProfile]) – Keys are profile labels and values are profiles to plot statistics for.

  • stat_function (Callable[[RankProfile | ScoreProfile], dict[str, float]]) – Which stat to use for the bar plot. Must be a callable that takes a profile and returns a dict with str keys and float values.

  • normalize (bool, optional) – Whether or not to normalize data. Defaults to False.

  • profile_colors (dict[str, str], optional) – Dictionary mapping profile labels to colors. Defaults to None, in which case we use a subset of COLOR_LIST from utils module. Dictionary keys can be a subset of the profiles.

  • bar_width (float, optional) – Width of bars. Defaults to None which computes the bar width as 0.7 divided by the number of data sets. Must be in the interval \((0,1]\).

  • category_ordering (list[str], optional) – Ordering of x-labels. Defaults to order retrieved from data dictionary.

  • x_axis_name (str, optional) – Name of x-axis. Defaults to None, which does not plot a name.

  • y_axis_name (str, optional) – Name of y-axis. Defaults to None, which does not plot a name.

  • title (str, optional) – Title for the figure. Defaults to None, which does not plot a title.

  • show_profile_legend (bool, optional) – Whether or not to plot the profile legend. Defaults to False. Is automatically shown if any threshold lines have the keyword “label” passed through threshold_kwds.

  • categories_legend (dict[str, str], optional) – Dictionary mapping data categories to description. Defaults to None. If provided, generates a second legend for data categories.

  • threshold_values (Union[list[float], float], optional) – List of values to plot horizontal lines at. Can be provided as a list or a single float.

  • threshold_kwds (Union[list[dict], dict], optional) – List of plotting keywords for the horizontal lines. Can be a list or single dictionary. These will be passed to plt.axhline(). Common keywords include “linestyle”, “linewidth”, and “label”. If “label” is passed, automatically plots the data set legend with the labels.

  • legend_font_size (float, optional) – The font size to use for the legend. Defaults to 10.0 + the number of categories.

  • legend_loc (str, optional) – The location parameter to pass to Axes.legend(loc=). Defaults to “center left”.

  • legend_bbox_to_anchor (Tuple[float, float], otptional) – The bounding box to anchor the legend to. Defaults to (1, 0.5).

  • ax (Axes, optional) – A matplotlib axes object to plot the figure on. Defaults to None, in which case the function creates and returns a new axes. The figure height is 6 inches and the figure width is 3 inches times the number of categories.

Returns:

A matplotlib axes with a bar plot of the given data.

Return type:

Axes

votekit.plots.multi_profile_ballot_lengths_plot(profile_dict: Mapping[str, RankProfile], ballot_lengths_kwds: dict[str, Any] | None = None, normalize: bool = False, profile_colors: Mapping[str, str] | None = None, bar_width: float | None = None, lengths_ordering: list[str | int] | None = None, x_axis_name: str | None = None, y_axis_name: str | None = None, title: str | None = None, show_profile_legend: bool = False, lengths_legend: Mapping[str | int, str | int] | None = None, threshold_values: list[float] | float | None = None, threshold_kwds: list[dict] | dict | None = None, legend_font_size: float | None = None, ax: matplotlib.axes.Axes | None = None) matplotlib.axes.Axes

Plot the ballot lengths for a collection of profiles. Wrapper for multi_profile_bar_plot.

Parameters:
  • profile_dict (dict[str, RankProfile]) – Keys are profile labels and values are profiles to plot statistics for.

  • ballot_lengths_kwds (dict[str, Any], optional) – Keyword arguments to pass to ballot_lengths. Defaults to None, in which case default values for ballot_lengths are used.

  • normalize (bool, optional) – Whether or not to normalize data. Defaults to False.

  • profile_colors (dict[str, str], optional) – Dictionary mapping profile labels to colors. Defaults to None, in which case we use a subset of COLOR_LIST from utils module. Dictionary keys can be a subset of the profiles.

  • bar_width (float, optional) – Width of bars. Defaults to None which computes the bar width as 0.7 divided by the number of data sets. Must be in the interval \((0,1]\).

  • lengths_ordering (list[str], optional) – Ordering of x-labels. Defaults to order retrieved from score dictionary.

  • x_axis_name (str, optional) – Name of x-axis. Defaults to None, which does not plot a name.

  • y_axis_name (str, optional) – Name of y-axis. Defaults to None, which does not plot a name.

  • title (str, optional) – Title for the figure. Defaults to None, which does not plot a title.

  • show_profile_legend (bool, optional) – Whether or not to plot the profile legend. Defaults to False. Is automatically shown if any threshold lines have the keyword “label” passed through threshold_kwds.

  • lengths_legend (dict[str, str], optional) – Dictionary mapping lengths to relableing. Defaults to None. If provided, generates a second legend for data categories.

  • threshold_values (Union[list[float], float], optional) – List of values to plot horizontal lines at. Can be provided as a list or a single float.

  • threshold_kwds (Union[list[dict], dict], optional) – List of plotting keywords for the horizontal lines. Can be a list or single dictionary. These will be passed to plt.axhline(). Common keywords include “linestyle”, “linewidth”, and “label”. If “label” is passed, automatically plots the data set legend with the labels.

  • legend_font_size (float, optional) – The font size to use for the legend. Defaults to 10.0 + the number of categories.

  • legend_loc (str, optional) – The location parameter to pass to Axes.legend(loc=). Defaults to “center left”.

  • legend_bbox_to_anchor (Tuple[float, float], otptional) – The bounding box to anchor the legend to. Defaults to (1, 0.5).

  • ax (Axes, optional) – A matplotlib axes object to plot the figure on. Defaults to None, in which case the function creates and returns a new axes. The figure height is 6 inches and the figure width is 3 inches times the number of categories.

Returns:

A matplotlib axes with a bar plot of the given data.

Return type:

Axes

votekit.plots.multi_profile_borda_plot(profile_dict: Mapping[str, RankProfile], borda_kwds: dict[str, Any] | None = None, normalize: bool = False, profile_colors: Mapping[str, str] | None = None, bar_width: float | None = None, candidate_ordering: list[str] | None = None, x_axis_name: str | None = None, y_axis_name: str | None = None, title: str | None = None, show_profile_legend: bool = False, candidate_legend: Mapping[str, str | int] | None = None, relabel_candidates_with_int: bool = False, threshold_values: list[float] | float | None = None, threshold_kwds: list[dict] | dict | None = None, legend_font_size: float | None = None, ax: matplotlib.axes.Axes | None = None) matplotlib.axes.Axes

Plot the borda scores for a collection of profiles. Wrapper for multi_profile_bar_plot.

Parameters:
  • profile_dict (dict[str, RankProfile]) – Keys are profile labels and values are profiles to plot statistics for.

  • borda_kwds (dict[str, Any], optional) – Keyword arguments to pass to borda_scores. Defaults to None, in which case default values for borda_scores are used.

  • normalize (bool, optional) – Whether or not to normalize data. Defaults to False.

  • profile_colors (dict[str, str], optional) – Dictionary mapping profile labels to colors. Defaults to None, in which case we use a subset of COLOR_LIST from utils module. Dictionary keys can be a subset of the profiles.

  • bar_width (float, optional) – Width of bars. Defaults to None which computes the bar width as 0.7 divided by the number of data sets. Must be in the interval \((0,1]\).

  • candidate_ordering (list[str], optional) – Ordering of x-labels. Defaults to decreasing borda scores from the first profile.

  • x_axis_name (str, optional) – Name of x-axis. Defaults to None, which does not plot a name.

  • y_axis_name (str, optional) – Name of y-axis. Defaults to None, which does not plot a name.

  • title (str, optional) – Title for the figure. Defaults to None, which does not plot a title.

  • show_profile_legend (bool, optional) – Whether or not to plot the profile legend. Defaults to False. Is automatically shown if any threshold lines have the keyword “label” passed through threshold_kwds.

  • candidate_legend (dict[str, str], optional) – Dictionary mapping candidates to relableing. Defaults to None. If provided, generates a second legend for data categories.

  • relabel_candidates_with_int (bool, optional) – Relabel the candidates with integer labels. Defaults to False. If candidate_legend is passed, those labels supercede.

  • threshold_values (Union[list[float], float], optional) – List of values to plot horizontal lines at. Can be provided as a list or a single float.

  • threshold_kwds (Union[list[dict], dict], optional) – List of plotting keywords for the horizontal lines. Can be a list or single dictionary. These will be passed to plt.axhline(). Common keywords include “linestyle”, “linewidth”, and “label”. If “label” is passed, automatically plots the data set legend with the labels.

  • legend_font_size (float, optional) – The font size to use for the legend. Defaults to 10.0 + the number of categories.

  • legend_loc (str, optional) – The location parameter to pass to Axes.legend(loc=). Defaults to “center left”.

  • legend_bbox_to_anchor (Tuple[float, float], otptional) – The bounding box to anchor the legend to. Defaults to (1, 0.5).

  • ax (Axes, optional) – A matplotlib axes object to plot the figure on. Defaults to None, in which case the function creates and returns a new axes. The figure height is 6 inches and the figure width is 3 inches times the number of categories.

Returns:

A matplotlib axes with a bar plot of the given data.

Return type:

Axes

votekit.plots.multi_profile_fpv_plot(profile_dict: Mapping[str, RankProfile], fpv_kwds: dict[str, Any] | None = None, normalize: bool = False, profile_colors: Mapping[str, str] | None = None, bar_width: float | None = None, candidate_ordering: list[str] | None = None, x_axis_name: str | None = None, y_axis_name: str | None = None, title: str | None = None, show_profile_legend: bool = False, candidate_legend: Mapping[str, str | int] | None = None, relabel_candidates_with_int: bool = False, threshold_values: list[float] | float | None = None, threshold_kwds: list[dict] | dict | None = None, legend_font_size: float | None = None, ax: matplotlib.axes.Axes | None = None) matplotlib.axes.Axes

Plot the first place votes for a collection of profiles. Wrapper for multi_profile_bar_plot.

Parameters:
  • profile_dict (dict[str, RankProfile]) – Keys are profile labels and values are profiles to plot statistics for.

  • fpv_kwds (dict[str, Any], optional) – Keyword arguments to pass to first_place_votes. Defaults to None, in which case default values for first_place_votes are used.

  • normalize (bool, optional) – Whether or not to normalize data. Defaults to False.

  • profile_colors (dict[str, str], optional) – Dictionary mapping profile labels to colors. Defaults to None, in which case we use a subset of COLOR_LIST from utils module. Dictionary keys can be a subset of the profiles.

  • bar_width (float, optional) – Width of bars. Defaults to None which computes the bar width as 0.7 divided by the number of data sets. Must be in the interval \((0,1]\).

  • candidate_ordering (list[str], optional) – Ordering of x-labels. Defaults to order retrieved from score dictionary.

  • x_axis_name (str, optional) – Name of x-axis. Defaults to None, which does not plot a name.

  • y_axis_name (str, optional) – Name of y-axis. Defaults to None, which does not plot a name.

  • title (str, optional) – Title for the figure. Defaults to None, which does not plot a title.

  • show_profile_legend (bool, optional) – Whether or not to plot the profile legend. Defaults to False. Is automatically shown if any threshold lines have the keyword “label” passed through threshold_kwds.

  • candidate_legend (dict[str, str], optional) – Dictionary mapping candidates to relableing. Defaults to None. If provided, generates a second legend for data categories.

  • relabel_candidates_with_int (bool, optional) – Relabel the candidates with integer labels. Defaults to False. If candidate_legend is passed, those labels supercede.

  • threshold_values (Union[list[float], float], optional) – List of values to plot horizontal lines at. Can be provided as a list or a single float.

  • threshold_kwds (Union[list[dict], dict], optional) – List of plotting keywords for the horizontal lines. Can be a list or single dictionary. These will be passed to plt.axhline(). Common keywords include “linestyle”, “linewidth”, and “label”. If “label” is passed, automatically plots the data set legend with the labels.

  • legend_font_size (float, optional) – The font size to use for the legend. Defaults to 10.0 + the number of categories.

  • legend_loc (str, optional) – The location parameter to pass to Axes.legend(loc=). Defaults to “center left”.

  • legend_bbox_to_anchor (Tuple[float, float], otptional) – The bounding box to anchor the legend to. Defaults to (1, 0.5).

  • ax (Axes, optional) – A matplotlib axes object to plot the figure on. Defaults to None, in which case the function creates and returns a new axes. The figure height is 6 inches and the figure width is 3 inches times the number of categories.

Returns:

A matplotlib axes with a bar plot of the given data.

Return type:

Axes

votekit.plots.multi_profile_mentions_plot(profile_dict: Mapping[str, RankProfile], mentions_kwds: dict[str, Any] | None = None, normalize: bool = False, profile_colors: Mapping[str, str] | None = None, bar_width: float | None = None, candidate_ordering: list[str] | None = None, x_axis_name: str | None = None, y_axis_name: str | None = None, title: str | None = None, show_profile_legend: bool = False, candidate_legend: Mapping[str, str | int] | None = None, relabel_candidates_with_int: bool = False, threshold_values: list[float] | float | None = None, threshold_kwds: list[dict] | dict | None = None, legend_font_size: float | None = None, ax: matplotlib.axes.Axes | None = None) matplotlib.axes.Axes

Plot the mentions for a collection of profiles. Wrapper for multi_profile_bar_plot.

Parameters:
  • profile_dict (dict[str, RankProfile]) – Keys are profile labels and values are profiles to plot statistics for.

  • mentions_kwds (dict[str, Any], optional) – Keyword arguments to pass to mentions. Defaults to None, in which case default values for mentions are used.

  • normalize (bool, optional) – Whether or not to normalize data. Defaults to False.

  • profile_colors (dict[str, str], optional) – Dictionary mapping profile labels to colors. Defaults to None, in which case we use a subset of COLOR_LIST from utils module. Dictionary keys can be a subset of the profiles.

  • bar_width (float, optional) – Width of bars. Defaults to None which computes the bar width as 0.7 divided by the number of data sets. Must be in the interval \((0,1]\).

  • candidate_ordering (list[str], optional) – Ordering of x-labels. Defaults to order retrieved from score dictionary.

  • x_axis_name (str, optional) – Name of x-axis. Defaults to None, which does not plot a name.

  • y_axis_name (str, optional) – Name of y-axis. Defaults to None, which does not plot a name.

  • title (str, optional) – Title for the figure. Defaults to None, which does not plot a title.

  • show_profile_legend (bool, optional) – Whether or not to plot the profile legend. Defaults to False. Is automatically shown if any threshold lines have the keyword “label” passed through threshold_kwds.

  • candidate_legend (dict[str, str], optional) – Dictionary mapping candidates to relableing. Defaults to None. If provided, generates a second legend for data categories.

  • relabel_candidates_with_int (bool, optional) – Relabel the candidates with integer labels. Defaults to False. If candidate_legend is passed, those labels supercede.

  • threshold_values (Union[list[float], float], optional) – List of values to plot horizontal lines at. Can be provided as a list or a single float.

  • threshold_kwds (Union[list[dict], dict], optional) – List of plotting keywords for the horizontal lines. Can be a list or single dictionary. These will be passed to plt.axhline(). Common keywords include “linestyle”, “linewidth”, and “label”. If “label” is passed, automatically plots the data set legend with the labels.

  • legend_font_size (float, optional) – The font size to use for the legend. Defaults to 10.0 + the number of categories.

  • legend_loc (str, optional) – The location parameter to pass to Axes.legend(loc=). Defaults to “center left”.

  • legend_bbox_to_anchor (Tuple[float, float], otptional) – The bounding box to anchor the legend to. Defaults to (1, 0.5).

  • ax (Axes, optional) – A matplotlib axes object to plot the figure on. Defaults to None, in which case the function creates and returns a new axes. The figure height is 6 inches and the figure width is 3 inches times the number of categories.

Returns:

A matplotlib axes with a bar plot of the given data.

Return type:

Axes

Cast Vote Records

votekit.cvr_loaders.load_csv(path_or_url: str, rank_cols: list[int], *, weight_col: int | None = None, id_col: int | None = None, candidates: list[str] | None = None, delimiter: str = ',', header_row: int | None = None, print_profile: bool = True) RankProfile

Given a file path or url, loads ranked cast vote record (cvr) with ranks as columns and voters as rows.

Parameters:
  • path_or_url (str) – Path or url to cvr file.

  • rank_cols (list[int]) – List of column indices that contain rankings. Column indexing starts from 0, in order from top to bottom rank.

  • weight_col (Optional[int]) – The column position for ballot weights. Defaults to None, which implies each row has weight 1. Cannot be provided if id_col is also provided.

  • id_col (Optional[int]) – Index for the column with voter ids. Defaults to None. Cannot be provided if weight_col is also provided.

  • candidates (Optional[list[str]]) – List of candidate names. Defaults to None, in which case names are inferred from the CVR.

  • delimiter (Optional[str]) – The character that separates entries. Defaults to a comma.

  • header_row (Optional[int]) – The row containing the column names, below which the data begins. Defaults to None, in which case row 0 is considered to be the first ballot.

  • print_profile (bool) – Whether or not to print the loaded profile. Defaults to True. Useful for debugging.

Raises:
  • FileNotFoundError – CSV cannot be found. Raised by pandas.read_csv.

  • URLError – Invalid url. Raised by pandas.read_csv.

  • HTTPError – URL is valid but other failure occurs. Raised by pandas.read_csv.

  • ParserError – Pandas fails to read the csv. Raised by pandas.read_csv.

  • UnicodeDecodeError – Bad encoding. Raised by pandas.read_csv.

  • ValueError – Candidates provided but they do not exist in the CSV.

  • ValueError – Candidates provided but extra candidates are found in the CSV.

  • ValueError – Only one of weight_col or id_col can be provided.

  • ValueError – weight_col or id_col are not distinct from rank_cols.

  • ValueError – weight_col, id_col, and each entry of rank_cols must be non-negative and within the number of columns of the csv.

  • ValueError – If weight_col is provided, weights must be non-empty and convertible to float.

  • ValueError – Header must be non-negative.

Returns:

A RankProfile that represents all the ballots in the csv.

Return type:

RankProfile

votekit.cvr_loaders.load_ranking_csv(path_or_url: str | PathLike | Path, rank_cols: list[int], *, weight_col: int | None = None, id_col: int | None = None, candidates: list[str] | None = None, delimiter: str = ',', header_row: int | None = None, print_profile: bool = True) RankProfile

Given a file path or url, loads ranked cast vote record (cvr) with ranks as columns and voters as rows.

Parameters:
  • path_or_url (Union[str, os.PathLike, pathlib.Path]) – Path or url to cvr file.

  • rank_cols (list[int]) – List of column indices that contain rankings. Column indexing starts from 0, in order from top to bottom rank.

  • weight_col (Optional[int]) – The column position for ballot weights. Defaults to None, which implies each row has weight 1. Cannot be provided if id_col is also provided.

  • id_col (Optional[int]) – Index for the column with voter ids. Defaults to None. Cannot be provided if weight_col is also provided.

  • candidates (Optional[list[str]]) – List of candidate names. Defaults to None, in which case names are inferred from the CVR.

  • delimiter (Optional[str]) – The character that separates entries. Defaults to a comma.

  • header_row (Optional[int]) – The row containing the column names, below which the data begins. Defaults to None, in which case row 0 is considered to be the first ballot.

  • print_profile (bool) – Whether or not to print the loaded profile. Defaults to True. Useful for debugging.

Raises:
  • FileNotFoundError – CSV cannot be found. Raised by pandas.read_csv.

  • URLError – Invalid url. Raised by pandas.read_csv.

  • HTTPError – URL is valid but other failure occurs. Raised by pandas.read_csv.

  • ParserError – Pandas fails to read the csv. Raised by pandas.read_csv.

  • UnicodeDecodeError – Bad encoding. Raised by pandas.read_csv.

  • ValueError – Candidates provided but they do not exist in the CSV.

  • ValueError – Candidates provided but extra candidates are found in the CSV.

  • ValueError – Only one of weight_col or id_col can be provided.

  • ValueError – weight_col or id_col are not distinct from rank_cols.

  • ValueError – weight_col, id_col, and each entry of rank_cols must be non-negative and within the number of columns of the csv.

  • ValueError – If weight_col is provided, weights must be non-empty and convertible to float.

  • ValueError – Header must be non-negative.

Returns:

A RankProfile that represents all the ballots in the csv.

Return type:

RankProfile

votekit.cvr_loaders.load_scottish(fpath: str | PathLike | Path) tuple[RankProfile, int, list[str], dict[str, str], str]

Given a file path, loads cast vote record from format used for Scottish election data in (this repo)[https://github.com/mggg/scot-elex].

Parameters:

fpath (Union[str, os.PathLike, pathlib.Path]) – Path to Scottish election csv file. Can be a url.

Raises:
  • FileNotFoundError – If fpath is invalid.

  • EmptyDataError – If dataset is empty.

  • DataError – If there is missing or incorrect metadata or candidate data.

Returns:

A tuple (RankProfile, seats, cand_list, cand_to_party, ward) representing the election, the number of seats in the election, the candidate names, a dictionary mapping candidates to their party, and the ward. The candidate names are also stored in the PreferenceProfile object.

Return type:

tuple

Matrices

votekit.matrices.matrix_heatmap(matrix: ndarray, *, ax: matplotlib.axes.Axes | None = None, show_cell_values: bool = True, n_decimals_to_display: int = 2, row_labels: List[str] | None = None, row_label_rotation: float | None = None, row_legend: dict[str, str] | None = None, column_labels: List[str] | None = None, column_label_rotation: float | None = None, column_legend: dict[str, str] | None = None, cell_color_map: str | matplotlib.colors.Colormap | None = None, cell_font_size: int | None = None, cell_spacing: float = 0.5, cell_divider_color: str = 'white', show_colorbar: bool = False, legend_font_size: float = 10.0, legend_location: str = 'center left', legend_bbox_to_anchor: Tuple[float, float] = (1.03, 0.5)) matplotlib.axes.Axes

Basic function for plotting a matrix as a heatmap.

Parameters:
  • matrix (np.ndarray) – A 2D numpy array containing the data to be plotted.

  • ax (matplotlib.axes.Axes, optional) – The matplotlib axis to plot on. Defaults to None, in which case an axis is created.

  • show_cell_values (bool) – Whether to show the values of the cells in the heatmap. These values are shown in the center of each cell and are dynamically formatted to be human-readable. Defaults to True.

  • n_decimals_to_display (int) – The number of decimal places to display for the values in the heatmap. Defaults to 2.

  • row_labels (Optional(List[str])) – A list of strings containing the labels for the rows of the heatmap. Defaults to None.

  • row_label_rotation (Optional(float)) – The rotation to apply to the row labels. Defaults to None.

  • row_legend (Optional(Dict[str, str])) – A dictionary mapping row labels to legend descriptions. Defaults to None.

  • column_labels (Optional(List[str])) – A list of strings containing the labels for the columns of the heatmap. Defaults to None.

  • column_label_rotation (Optional(float)) – The rotation to apply to the column labels. Defaults to None.

  • column_legend (Optional(Dict[str, str])) – A dictionary mapping column labels to legend descriptions. Defaults to None.

  • cell_color_map (Optional(Union[str, matplotlib.colors.Colormap])) – The color map to use for the heatmap. Defaults to PRGn if the matrix contains negative values and Greens otherwise.

  • cell_font_size (Optional(int)) – The font size to use for the cell values. Defaults to None, which will then use dynamic font size based on the number of cells and the figure size.

  • cell_spacing (float) – The spacing between the cells in the heatmap. Defaults to 0.5.

  • cell_divider_color (str) – The color to use for the cell dividers for spacing cells. Defaults to “white”.

  • show_colorbar (bool) – Whether to show the colorbar for the heatmap. Defaults to False.

  • legend_font_size (float) – The font size to use for the legend. Defaults to 10.0.

  • legend_location (str) – The location to place the legend. Defaults to “center left”.

  • legend_bbox_to_anchor (Tuple[float, float]) – The bounding box to anchor the legend to. Defaults to (1.03, 0.5).

Returns:

The matplotlib axis containing the heatmap.

Return type:

matplotlib.axes.Axes

votekit.matrices.boost_prob(i: str, j: str, pref_profile: RankProfile) Tuple[float, float]

Takes candidates i,j and a preference profile and computes the conditional P(mention i | mention j) and P(mention i). If candidate j is never mentioned, or if the profile has 0 total ballot weight, it returns numpy.nan for the respective probability.

Parameters:
  • i (str) – Candidate.

  • j (str) – Candidate.

  • pref_profile (RankProfile) – Profile.

Returns:

P(mention i | mention j), P(mention i)

Return type:

tuple[float, float]

votekit.matrices.boost_matrix(pref_profile: RankProfile, candidates: list[str]) ndarray

Takes a profile and converts to a matrix where the i,j entry shows P(mention i | mention j) - P(mention i). Thus, the i,j entry shows the boost given to i by j. Computations use ballot weight. Non-symmetric matrix. Undefined entries are denoted with numpy.nan values.

Parameters:
  • pref_profile (RankProfile) – Profile.

  • candidates (list[str]) – List of candidates to use. Indexing of this list matches indexing of output array.

Returns:

Numpy array of boosts.

Return type:

np.ndarray

votekit.matrices.candidate_distance(i: str, j: str, ballot: RankBallot) float

Takes candidates i,j and returns distance r(j)-r(i) in ranking. Returns numpy.nan if a candidate is not on ballot. Note that this is non-symmetric, and that a positive value indicates that i is ranked higher than j.

Parameters:
  • i (str) – Candidate.

  • j (str) – Candidate.

  • ballot (RankBallot) – RankBallot.

Returns:

Distance r(j)-r(i) in ranking.

Return type:

float

votekit.matrices.candidate_distance_matrix(pref_profile: RankProfile, candidates: list[str]) ndarray

Takes a preference profile and converts to a matrix where the i,j entry shows the average distance between i and j when i >= j on the same ballot. Computations use ballot weight. Non-symmetric. Uses numpy.nan for undefined entries.

Parameters:
  • pref_profile (RankProfile) – Profile.

  • candidates (list[str]) – List of candidates to use. Indexing of this list matches indexing of output array.

Returns:

Numpy array of average distances.

Return type:

np.ndarray

votekit.matrices.comention(cands: str | list[str], ballot: RankBallot)

Takes cands and returns true if they all appear on the ballot in the ranking.

Parameters:
  • cands (Union[str, list[str]]) – Candidate name or list of candidate names.

  • ballot (RankBallot) – RankBallot.

Returns:

True if all candidates appear in ballot.

Return type:

bool

votekit.matrices.comention_above(i: str, j: str, ballot: RankBallot) bool

Takes candidates i,j and returns True if i >= j in the ranking. Requires that the ballot has a ranking.

Parameters:
  • i (str) – Candidate name.

  • j (str) – Candidate name.

  • ballot (RankBallot) – RankBallot.

Returns:

True if both i and j appear in ballot and i >= j.

Return type:

bool

votekit.matrices.comentions_matrix(pref_profile: RankProfile, candidates: list[str], symmetric: bool = False) ndarray

Takes a preference profile and converts to a matrix where the i,j entry shows the number of times candidates i,j were mentioned on the same ballot with i >= j. There is an option to make it symmetric so that the i,j entry is just the number of times candidates i and j were mentioned on the same ballot.

Parameters:
  • pref_profile (RankProfile) – Profile.

  • candidates (list[str]) – List of candidates to use. Indexing of this list matches indexing of output array.

  • symmetric (bool, optional) – Whether or not to make the matrix symmetric. Defaults to False in which case the i,j entry is comentions where i >= j. True means the i,j entry is comentions of i,j.

Returns:

Numpy array of comentions.

Return type:

np.ndarray

Misc.

votekit.elections.fractional_transfer(winner: str, fpv: float, ballots: tuple[RankBallot] | list[RankBallot], threshold: int) tuple[RankBallot, ...]

Calculates fractional transfer from winner, then removes winner from the list of ballots.

Parameters:
  • winner (str) – Candidate to transfer votes from.

  • fpv (float) – Number of first place votes for winning candidate.

  • ballots (Union[tuple[RankBallot], list[RankBallot]]) – List of Ballot objects.

  • threshold (int) – Value required to be elected, used to calculate transfer value.

Returns:

Modified ballots with transferred weights and the winning candidate removed.

Return type:

tuple[Ballot,…]

votekit.elections.random_transfer(winner: str, fpv: float, ballots: tuple[RankBallot] | list[RankBallot], threshold: int) tuple[RankBallot, ...]

Cambridge-style transfer where transfer ballots are selected randomly. All ballots must have integer weights.

Parameters:
  • winner (str) – Candidate to transfer votes from.

  • fpv (float) – Number of first place votes for winning candidate.

  • ballots (Union[tuple[RankBallot], list[RankBallot]]) – List of Ballot objects.

  • threshold (int) – Value required to be elected, used to calculate transfer value.

Returns:

Modified ballots with transferred weights and the winning candidate removed.

Return type:

tuple[RankBallot,…]

votekit.utils.add_missing_cands(profile: RankProfile) RankProfile[source]

Add any candidates from profile.candidates that are not listed on a ballot as tied in last place.

Parameters:

profile (RankProfile) – Input profile.

Returns:

RankProfile

votekit.utils.ballot_lengths(profile: RankProfile) dict[int, float][source]

Compute the frequency of ballot lengths in the profile. Includes all lengths from 1 to max_ranking_length as keys. Ballots must have rankings.

Parameters:

profile (RankProfile) – Profile to compute ballot lengths.

Returns:

Dictionary of ballot length frequency.

Return type:

dict[int, float]

Raises:

TypeError – All ballots must have rankings.

votekit.utils.ballots_by_first_cand(profile: RankProfile) dict[str, list[RankBallot]][source]

Partitions the profile by first place candidate. Assumes there are no ties within first place positions of ballots.

Parameters:

profile (RankProfile) – Profile to partititon.

Returns:

A dictionary whose keys are candidates and values are lists of ballots that have that candidate first.

Return type:

dict[str, list[RankBallot]]

votekit.utils.borda_scores(profile: RankProfile, borda_max: int | None = None, tie_convention: Literal['high', 'average', 'low'] = 'low') dict[str, float][source]

Calculates Borda scores for candidates_cast in a RankProfile. The Borda vector is \((n,n-1,\dots,1)\) where \(n\) is the ``borda_max`.

Parameters:
  • profile (RankProfile) – RankProfile of ballots.

  • borda_max (int, optional) – The maximum value of the Borda vector. Defaults to the length of the longest allowable ballot in the profile.

  • tie_convention (Literal["high", "average", "low"], optional) – How to award points for tied rankings. Defaults to “low”, where any candidates tied receive the lowest possible points for their position, eg three people tied for 3rd would each receive the points for 5th. “high” awards the highest possible points, so in the previous example, they would each receive the points for 3rd. “average” averages the points, so they would each receive the points for 4th place.

Returns:

Dictionary mapping candidates to Borda scores.

Return type:

dict[str, float]

votekit.utils.build_df_from_ballot_samples(ballots_freq_dict: dict[tuple[int, ...], int], candidates: Sequence[str])[source]

Helper function which creates a pandas df to instantiate a RankProfile :param ballots_freq_dict: dictionary mapping ballots to

sampled frequency. The keys should be in candidate id form

Parameters:

candidates – list of candidates in the profile

Returns:

pandas df

votekit.utils.elect_cands_from_set_ranking(ranking: Sequence[frozenset[str] | set[str]], n_seats: int, profile: RankProfile | None = None, tiebreak: str | None = None) tuple[tuple[frozenset[str], ...], tuple[frozenset[str], ...], tuple[frozenset[str], tuple[frozenset[str], ...]] | None][source]

Given a ranking, elect the top n_seats candidates in the ranking. If a tie set overlaps the desired number of seats, it breaks the tie with the provided method or raises a ValueError if tiebreak is set to None. Returns a tuple of elected candidates, remaining candidates, and a tuple whose first entry is a tie set and whose second entry is the resolution of the tie.

Parameters:
  • ranking (tuple[frozenset[str],...]) – A list-of-set ranking of candidates.

  • n_seats (int) – Number of seats to elect.

  • profile (RankProfile, optional) – Profile used to break ties in first-place votes or Borda setting. Defaults to None, which implies a random tiebreak.

  • tiebreak (str, optional) – Method of tiebreak, currently supports ‘random’, ‘borda’, ‘first_place’. Defaults to None, which does not break ties.

Returns:

tuple[tuple[frozenset[str]]], list[tuple[frozenset[str]],

Optional[tuple[frozenset[str], tuple[frozenset[str], …]]]: A list-of-sets of elected candidates, a list-of-sets of remaining candidates, and a tuple whose first entry is a tie set and whose second entry is the resolution of the tie. If no ties were broken, the tuple returns None.

votekit.utils.expand_tied_ballot(ballot: RankBallot) list[RankBallot][source]

Fix tie(s) in a ballot by returning all possible permutations of the tie(s), and divide the weight of the original ballot equally among the new ballots.

Parameters:

ballot (RankBallot) – Ballot to expand tie sets on.

Returns:

All possible permutations of the tie(s).

Return type:

list[v]

votekit.utils.first_place_votes(profile: RankProfile, tie_convention: Literal['high', 'average', 'low'] = 'average') dict[str, float][source]

Computes first place votes for all candidates_cast in a RankProfile.

Parameters:
  • profile (RankProfile) – The profile to compute first place votes for.

  • tie_convention (Literal["high", "average", "low"], optional) – How to award points for tied first place votes. Defaults to “average”, where if n candidates are tied for first, each receives 1/n points. “high” would award them each one point, and “low” 0.

Returns:

Dictionary mapping candidates to number of first place votes.

Return type:

dict[str, float]

votekit.utils.fixed_zero_index_lex_block_size(n_candidates: int, max_length: int) int[source]

Calculate the number of ballots in a single top-level branch of the lexicographic ballot tree.

That is, the number of ballots beginning with any fixed first candidate, with ballot lengths at most max_length.

Parameters:
  • n_candidates (int) – The number of candidates.

  • max_length (int) – The maximum ballot length.

Returns:

The number of ballots in a single top-level branch of the lexicographic ballot tree.

Return type:

int

votekit.utils.index_to_lexicographic_ballot(index: int, n_candidates: int, max_length: int) list[int][source]

Return the ballot at the given index in true lexicographic order, with ballot lengths at most max_length.

This matches the order produced by a depth-first lexicographic generator:

[0] [0, 1] [0, 1, 2] … [0, 2] … [1] …

Parameters:
  • index (int) – The index to convert.

  • n_candidates (int) – The number of candidates.

  • max_length (int) – The maximum ballot length.

Returns:

A list representing the ballot corresponding to the index.

Return type:

list[int]

votekit.utils.mentions(profile: RankProfile) dict[str, float][source]

Calculates total mentions for all candidates in a RankProfile.

Parameters:

profile (RankProfile) – RankProfile of ballots.

Returns:

Dictionary mapping candidates to mention totals (values).

Return type:

dict[str, float]

votekit.utils.resolve_profile_ties(profile: RankProfile) RankProfile[source]

Takes in a PeferenceProfile with potential ties in ballots. Replaces ballots with ties with fractionally weighted ballots corresponding to all permutations of the tied ranking.

Parameters:

profile (RankProfile) – Input profile with potentially tied rankings.

Returns:

A RankProfile with resolved ties.

Return type:

RankProfile

votekit.utils.score_dict_from_score_vector(profile: RankProfile, score_vector: Sequence[float], tie_convention: Literal['high', 'average', 'low'] = 'low') dict[str, float][source]

Score the candidates based on a score vector. For example, the vector (1,0,…) would return the first place votes for each candidate. Vectors should be non-increasing and non-negative. Vector should be as long as max_ranking_length in the profile. If it is shorter, we add 0s. Candidates who are not mentioned in any ranking do not appear in the dictionary.

We round to 10 decimal places to avoid floating point precision issues.

Parameters:
  • profile (RankProfile) – Profile to score.

  • score_vector (Sequence[float]) – Score vector. Should be non-increasing and non-negative. Vector should be as long as max_ranking_length in the profile. If it is shorter, we add 0s.

  • tie_convention (Literal["high", "average", "low"], optional) – How to award points for tied rankings. Defaults to “low”, where any candidates tied receive the lowest possible points for their position, eg three people tied for 3rd would each receive the points for 5th. “high” awards the highest possible points, so in the previous example, they would each receive the points for 3rd. “average” averages the points, so they would each receive the points for 4th place.

Returns:

Dictionary mapping candidates to scores.

Return type:

dict[str, float]

votekit.utils.score_dict_to_ranking(score_dict: dict[str, float], sort_high_low: bool = True) tuple[frozenset[str], ...][source]

Sorts candidates into a tuple of frozensets ranking based on a scoring dictionary.

Parameters:
  • score_dict (dict[str, float]) – Dictionary between candidates and their score.

  • sort_high_low (bool, optional) – How to sort candidates based on scores. True sorts from high to low. Defaults to True.

Returns:

Candidate rankings in a list-of-sets form.

Return type:

tuple[frozenset[str],…]

votekit.utils.score_profile_from_ballot_scores(profile: ScoreProfile) dict[str, float][source]

Score the candidates based on the scores parameter of the ballots. All ballots must have a scores parameter; note that a scores dictionary with no non-zero scores will raise the same error.

Parameters:

profile (ScoreProfile) – Profile to score.

Returns:

Dictionary mapping candidates to scores.

Return type:

dict[str, float]

votekit.utils.tiebreak_set(r_set: frozenset[str], profile: RankProfile | None = None, tiebreak: str = 'random', scoring_tie_convention: Literal['high', 'average', 'low'] = 'low', backup_tiebreak_convention: str | None = None) tuple[frozenset[str], ...][source]

Break a single set of candidates into multiple sets each with a single candidate according to a tiebreak rule. Rule 1: random. Rule 2: first-place votes; break the tie based on first-place votes in the profile. Rule 3: borda; break the tie based on Borda points in the profile. Rule 4: lex/lexicographic/alph/alphabetical; break the tie alphabetically.

Parameters:
  • r_set (frozenset[str]) – Set of candidates on which to break tie.

  • profile (RankProfile, optional) – Profile used to break ties in first-place votes or Borda setting. Defaults to None, which implies a random tiebreak.

  • tiebreak (str) – Tiebreak method to use. Options are “random”, “first_place”, and “borda”. Defaults to “random”.

  • scoring_tie_convention (Literal["high", "average", "low"]) – How to award points for tied rankings. Defaults to “low”, where any candidates tied receive the lowest possible points for their position, eg three people tied for 3rd would each receive the points for 5th. “high” awards the highest possible points, so in the previous example, they would each receive the points for 3rd. “average” averages the points, so they would each receive the points for 4th place.

  • backup_tiebreak_convention (str, optional) – If the initial tiebreak does not resolve all ties, this convention is used to break any remaining ties. Options are “random” and “lex/lexicographic/alph/alphabetical”. Defaults to None which sets the backup to “lex” if the initial tiebreak is alphabetical, and “random” otherwise.

Returns:

tiebroken ranking

Return type:

tuple[frozenset[str],…]

votekit.utils.tiebroken_ranking(ranking: tuple[frozenset[str], ...], profile: RankProfile | None = None, tiebreak: str = 'random') tuple[tuple[frozenset[str], ...], dict[frozenset[str], tuple[frozenset[str], ...]]][source]

Breaks ties in a list-of-sets ranking according to a given scheme.

Parameters:
  • ranking (list[set[str]]) – A list-of-set ranking of candidates.

  • profile (RankProfile, optional) – Profile used to break ties in first-place votes or Borda setting. Defaults to None, which implies a random tiebreak.

  • tiebreak (str, optional) – Method of tiebreak, currently supports ‘random’, ‘borda’, ‘first_place’. Defaults to random.

Returns:

The first entry of the tuple is a list-of-set ranking of candidates (broken down to one candidate sets). The second entry is a dictionary that maps tied sets to their resolution.

Return type:

tuple[tuple[frozenset[str], …], dict[frozenset[str], tuple[frozenset[str],…]]]

votekit.utils.validate_score_vector(score_vector: Sequence[float])[source]

Validator function for score vectors. Vectors should be non-increasing and non-negative.

Parameters:

score_vector (Sequence[float]) – Score vector.

Raises:
  • ValueError – If any score is negative.

  • ValueError – If score vector is increasing at any point.

votekit.metrics.earth_mover_dist(pp1: RankProfile, pp2: RankProfile) float

Computes the Earth Mover’s Distance (EMD) between two preference profiles. Assumes both elections share the same candidates.

Parameters:
Returns:

Earth Mover’s Distance between two profiles.

Return type:

float

votekit.metrics.lp_dist(pp1: RankProfile, pp2: RankProfile, p_value: int | str | None = 1) int

Computes the \(L_p\) distance between two profiles. Use ‘inf’ for infinity norm. Assumes both elections share the same candidates.

Parameters:
  • pp1 (RankProfile) – RankProfile for first profile.

  • pp2 (RankProfile) – RankProfile for second profile.

  • p_value (Union[int, str], optional) – \(L_p\) distance parameter. Use “inf” for \(\infty\).

Returns:

\(L_p\) distance between two profiles.

Return type:

int

votekit.metrics.euclidean_dist(point1: ndarray, point2: ndarray) float