Recent Releases of VoteKit
VoteKit - v3.2.1
What's Changed
- removed the PreferenceProfile warning raised when
max_ranking_length>0but no rankings provided. We have decided an empty profile can still have positive max ranking length. - fixed an error raised by an empty ranking of ~ symbols being passed to
utils.ballots_by_first_cand.
Scientific Software - Peer-reviewed
- Python
Published by cdonnay 8 months ago
VoteKit - v3.2.0
[3.2.0] - 2025-06-13
Added
- created a
PreferenceProfile.dfattribute that is a pandasDataFramerepresentation of the profile. The df is in bijection with the profile, and using the df allows for great speed improvements throughout the codebase. - a new tutorial notebook replicating the Portland, OR election case study.
- added a
to_pickleandfrom_picklemethod toPreferenceProfile.
Changed
- separated the computation of the pairwise comparison dictionary from the pairwise comparison graph.
- renamed
dominating_tiersmethod of pairwise comparison graph toget_dominating_tiers. - renamed
cleaning.deduplicate_profiletocleaning.remove_repeated_candidates. - moved
remove_candfromutilstocleaning, and removed the older functionremove_noncands. - renamed
PreferenceProfile.condense_ballots()toPreferenceProfile.group_ballots(). - removed
Ballot.idattribute. - rewrote many cleaning functions and utilities to use the underlying dataframe of
PreferenceProfilefor speed improvements. - removed the use of
Fractionand use floats instead for speed improvement. - altered the various plotting functions for profiles, now in the
plots.profilesmodule.
Fixed
PreferenceProfile.group_ballots()now also groups thevoter_setattribute of ballots.
Scientific Software - Peer-reviewed
- Python
Published by cdonnay 9 months ago
VoteKit - v3.1.0
This is a minor update to VoteKit that includes some new election analysis tools, some refactored visualization code for bar plots, and a minor tweak to how scores are computed from ranked ballots to allow for different averaging conventions for ties.
Added
- added support for three types of averaging conventions within
score_profile_from_rankings: average, low, and high. - r-representation scores: compute how "satisfied" voters are with a given winners set.
- matrices: create three kinds of matrices based on profiles: boost, mentions, and average distance. Accompanying heatmap code that plots them.
- support for Python 3.12, 3.13
- contributing guidelines and community resources to our docs.
Changed
- changed the default Borda scoring to use low averaging, where tied rankings receive the lowest possible points
- changed the sampling method for
boosted_random_dictatorandrandom_dictatorto more clearly use the first place votes distribution - changed the structure of
plot_summary_stats. Is now split into many functions, all calledprofile_STAT_plotormulti_profile_STAT_plot, whereSTATcan befpv,borda,mentions, andballot_lengths. Built on top of more generalbar_plotandmulti_bar_plotfunctions. - removed support for Python 3.9.
New Contributors
- @wkirby made their first contribution in https://github.com/mggg/VoteKit/pull/153
Full Changelog: https://github.com/mggg/VoteKit/compare/v3.0.0...v3.1.0
Scientific Software - Peer-reviewed
- Python
Published by cdonnay 12 months ago
VoteKit - v3.0.0
This is a major update to VoteKit that includes some breaking changes for the API and a major refactoring of the code base to make it more organized, maintainable, and (hopefully) easier to contribute to in the future.
Added
- The election methods thanks to @kevin-q2. The newest election methods are
PluralityVeto,RandomDictator, andBoostedRandomDictator. - More comprehensive tests for the
Ballotclass. - More comprehensive tests for all of the election types.
- More comprehensive tests for the
PreferenceProfileclass. - Tests for potential errors in the
BallotGeneratorclasses.
Changed
Moved the following election methods to sorted folders in
src/votekit/elections/election_types:approvalApprovalBlockPlurality
rankingRankingElectionAlaskaBoostedRandomDictatorBordaCondoBordaDominatingSetsPluralityVetoPluralitySNTVRandomDictator
scoresGeneralRatingLimitedRatingCumulative
Updated / added the following methods to
src/votekit/utils.py:ballots_by_first_candremove_candadd_missing_candsvalidate_score_vectorscore_profilefirst_place_votesmentionsborda_scorestie_broken_rankingscore_dict_to_rankingelect_cands_from_set_rankingexpand_tied_ballotresolve_profile_ties
Changed the way that the
ElectionStateclass operates. It now operates as a dataclass storing the following data:round_number: The round number of the election.remaining: The remaining candidates in the election that have not been elected.elected: The set of candidates that have been elected.eliminated: The set of candidates that have been eliminated.tiebreak_winners: The set of candidates that were elected due to a tiebreak within a round.scores: The scores for each candidate in the election.
The
PreferenceProfileclass is now a frozen dataclass with the idea being that, once the ballots and candidates for an election have been set, they should not be changed.- Several validators have also been added to the
PreferenceProfileclass to ensure that the ballots and candidates are valid.
- Several validators have also been added to the
Updated all documentation to reflect major changes in the API of the package.
New Contributors
- @kevin-q2 made their first contribution in https://github.com/mggg/VoteKit/pull/130
- @peterrrock2 made their first contribution in https://github.com/mggg/VoteKit/pull/151
Full Changelog: https://github.com/mggg/VoteKit/compare/v2.0.1...v3.0.0
Scientific Software - Peer-reviewed
- Python
Published by peterrrock2 over 1 year ago
VoteKit - v2.0.1
This is a minor patch of votekit. It fixes minor bugs in the slate methods, adapts to the new csv format in the scot-elex repo, and updates some plotting functions.
Added
- Created a read the docs page.
- Add
scaleparameter toballot_graph.draw()to allow for easier reading of text labels. - Allow users to choose which bloc is W/C in historical Cambridge data for CambridgeSampler.
Changed
- Updated tutorial notebooks; larger focus on slate models, updated notebooks to match current codebase.
- Removed the seq-RCV transfer rule since it is a dummy function, replaced with lambda function.
- Update plot MDS to have aspect ratio 1, remove axes labels since they are meaningless in MDS.
- Update all BLT files in scot-elex repo to be true CSV files, updated
load_scottishaccordingly. #123 #129
Fixed
- Fixed bug by which slate-PlackettLuce could not generate ballots when some candidate had 0 support. #131
- Updated various functions in the ballot generator module to only generate ballots for non-zero candidates.
- Fixed one bloc s-BT pdf, which was incorrectly giving 0 weight to all ballot types.
Full Changelog: https://github.com/mggg/VoteKit/compare/v2.0.0...v2.0.1
Scientific Software - Peer-reviewed
- Python
Published by cdonnay over 1 year ago
VoteKit - v2.0.0
This update will break some of the backwards compatibility, so we have incremented the major version number.
Added
- A
PreferenceIntervalclass. - MCMC sampling for both
BradleyTerryballot generators. - Add print statement to
BallotGraphso that when you draw the graph without labels, it prints a dictionary of candidate labels for you. - Add an IRV election class, which is just a wrapper for STV with 1 seat.
- Add default option to Borda election class, so users do not have to input a score vector if they want to use the traditional Borda vector.
- Add several methods to
PairwiseComparisonGraph. Added two boolean methods that return True if there is a condorcet winner or if there is a condorcet cycle. Added two get methods that return the winner or the cycles. Cached the results ofdominating_tiersandget_condorcet_cycles. - Added optional tofloat method to `firstplacevotes
if users want to see them as floats instead of Fractions. -Added abyblocparameter togenerate_profile`. If True, this returns a tuple, the first entry of which is a dictionary of PreferenceProfiles by bloc. The second entry is the aggregated profile. This is very helpful for analyzing the behavior of a single bloc of voters. Defaults to False for backwards compatibility. - Created a
Cumulativeballot generator class. TheCumulativeclass works like PL, but samples with replacement instead of without. The ranking order does not matter here, simply that candidates are listed on the ballot with multiplicity. - Created a
HighestScoreelection class. This takes in a profile and a score vector, and returns the candidates with highest scores. There is a lot of flexibility in the score vector, so this class can run things like Borda, cumulative, etc. - Created a
Cumulativeelection class which is just a subclass ofHighestScorewith the score vector set to all 1s. Thus anyone appearing on the ballot gets one point for each time they appear. - Wrote an
__add__method forPreferenceProfilethat combines the ballot lists of two profiles. - Created utility functions to compute the winners of a profile given a score vector, as well as to validate a score vector (non-negative and non-increasing).
- Created a
shortPlackettLuceclass which allows you to generate ballots of arbitrary length in the style of PL. - Added tests for
__add__method ofPreferenceProfile. - Added
SlatePreferencemodel and tests.
Changed
Change the way the
condense_ballots()method works in profiles. Rather than altering the original profile, it returns a new profile. This gives users the option to preserve the original profile.Alter
STVclass so that the remaining candidates are always listed in order of current first place votes.Made
PlackettLucea subclass ofshortPlackettLuce.Change
PlackettLuce,BradleyTerry, andCumulativeballot generators to havename_prefix. This is in contrast to theslate_models we have introduced.Speed improvements for various ballot generators.
pref_interval_by_blocis nowpref_intervals_by_blocin all ballot generators. This is now a dictionary of dictionaries, where the both sets of keys are the blocs, and the values of the sub-dictionaries are PreferenceInterval objects. The slate models require that we sample from the uncombined PreferenceInterval objects, while the name models require that we combine the PreferenceInterval objects using cohesion parameters.MDS plot functionality, splitting it into
compute_MDSwhich computes the coordinates, andplot_MDSwhich plots them. Made because the computation is the most time intensive.
Fixed
- Fixed an error in the
PreferenceProfiletail method. - Errors in bloc labeling in
CambridgeSampler.
Deprecations
- Deprecated PL and BT to namePL and nameBT
Full Changelog: https://github.com/mggg/VoteKit/compare/v1.1.1...v2.0.0
Scientific Software - Peer-reviewed
- Python
Published by peterrrock2 almost 2 years ago
VoteKit - v1.1.1
VoteKit 1.1.1 is a patch update aimed primarily at extending the functionality of VoteKit. More specifically, this release implements score-based voting systems, and does so without editing the ballot class. To use a score-based system, you have to decide how many points to assign to each position of the ranking. This is flexible enough to handle things like cumulative and approval voting.
This update also includes some additional functionality that was included after creating and running some tutorials on usage of the software. For recordings and copies of some of these notebooks, please see the main website for VoteKit.
Key Changes
- Change the way the
condense_ballots()method works in profiles. Rather than altering the original profile, it returns a new profile. - Altered
STVclass so that the remaining candidates are always listed in order of current first place votes. - Added print statement to
BallotGraphso that when you draw the graph without labels, it prints a dictionary of candidate labels for you.
Additions
- Added a
by_blocparameter togenerate_profile. If True, this returns a dictionary ofPreferenceProfileobjects by bloc. Defaults to False for backwards compatibility. - Created a
Cumulativeballot generator class. TheCumulativeclass works like PL, but samples with replacement instead of without. The ranking order does not matter here, simply that candidates are listed on the ballot with multiplicity. - Created a
HighestScoreelection class. This takes in a profile and a score vector, and returns the $m$ candidates with highest scores. - Created a
Cumulativeelection class which is just a subclass ofHighestScorewith the score vector set to all 1s. - Wrote an
__add__method forPreferenceProfilethat combines the ballot lists of two profiles. - Created utility functions to compute the winners of a profile given a score vector, as well as to validate a score vector (non-negative and non-increasing).
- Add an
IRVelection class, which is just a wrapper forSTVwith 1 seat. - Add default option to
Bordaelection class, so users do not have to input a score vector. Add several methods toPairwiseComparisonGraph.- Added two boolean methods that return True if there is a condorcet winner or if there is a condorcet cycle.
- Added two get methods that return the winner or the cycles. Cached the results of
dominating_tiersandget_condorcet_cycles.
- Added optional
to_floatmethod tofirst_place_votesif users want to see them as floats instead of Fractions.
Bug Fixes
- Fixed an error in the
PreferenceProfiletail method.
Full Changelog: v1.1.0..v1.1.1
Scientific Software - Peer-reviewed
- Python
Published by peterrrock2 about 2 years ago
VoteKit - v1.1.0
Votekit 1.1.0 features a number of important functional and syntactical changes to the core Ballot, PreferenceProfile, and ElectionState objects. It also includes changes to ballot generation methods to output the correct number of ballots and allow for user-defined block names in the CambridgeSampler class. This release marks an overhaul to the library's documentation, and the addition of section explaining the social choice theory that underpins Votekit's functionality.
Key Changes
- Method names for
ElectionStatemethods - Caches for the results of
run_election() Ballotobjects made immutable, using Pydantic dataclass- Parameter names for
CambridgeSampler BallotGraphnow always displays vote totals for a ballotElectionStatenow prints the current round whenever printingload_bltbecameload_scottishplot_summary_statsalways displays candidates in order inputtedPreferenceProfiledata frame now has Percent column, removed the Weight Share columnBallotobject can take floats and integers as weightsBallotattributevoterchanged tovoter_set
Additions
- Added
to_dict(),to_json()functions forElectionState - Scores attribute to
ElectionState _rename_blocsmethod toCambridgeSamplerto rename blocs to historical names.- Added
resetandrun_to_stepmethods toElectionclass sort_by_weightparameter toheadandtailmethods ofPreferenceProfilereceived_votesparameter toget_candidatesmethod ofPreferenceProfile__str__method forBallot
Bug Fixes
- Multiple winners correctly ordered based off previous round's vote totals
CambridgeSamplercorrectly computes the frequency of opposing bloc ballotsPreferenceProfileno longer rounds all weights to integer when printing
Special thanks to Chris Donnay (@cdonnay) who made significant contributions to this release and is responsible for the improved tutorials and social choice theory sections of the documentation!
Scientific Software - Peer-reviewed
- Python
Published by jgibson517 about 2 years ago
VoteKit - v1.0.0
Version 1.0 - User determined options for breaking ties - Ballot Simplex object, refactored construction for ballot generator classes - IC/IAC with generalized arguments - Fixed package imports - Improved handling of tied rankings within ballots - Optimization for election helper functions
Scientific Software - Peer-reviewed
- Python
Published by jgibson517 over 2 years ago