Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

STV should use first-round total for vote percent #509

Merged
merged 2 commits into from
Sep 30, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 10 additions & 3 deletions static/bargraph/barchart.js
Original file line number Diff line number Diff line change
Expand Up @@ -326,14 +326,20 @@
}
else
{
return startText + votesAndPctToText(d.data["candidate"], d[1], totalVotesPerRound[d.round], false, false);
const percentDenominator = calculatePercentDenominator(lastRoundNumWinners, totalVotesPerRound[0], totalVotesPerRound[d.round])
return startText + votesAndPctToText(d.data["candidate"], d[1], percentDenominator, false, false);
}
};
function secondaryDataLabelTextFn(d) {
if(isEliminatedThisRound(d) || !isVertical) {
return "";
}
return percentToText(d.data["candidate"], d[1], totalVotesPerRound[d.round]);
if (lastRoundNumWinners > 1) {
percentDenominator = totalVotesPerRound[0];
Fixed Show fixed Hide fixed
} else {
percentDenominator = totalVotesPerRound[d.round];
}
return percentToText(d.data["candidate"], d[1], percentDenominator);
};
function rightRoundedRect(x, y, width, height, radius) {
return "M" + x + "," + y
Expand Down Expand Up @@ -428,7 +434,8 @@
// Hover text helper
function barTextFn(d) {
const text = !isEliminatedThisRound(d) ? "On Round " + (d.round+1) + ", has " : "Eliminated on Round " + (d.round+1) + " with ";
return text + votesAndPctToText(d.data["candidate"], d[1], totalVotesPerRound[d.round], true, false);
const percentDenominator = calculatePercentDenominator(lastRoundNumWinners, totalVotesPerRound[0], totalVotesPerRound[d.round])
return text + votesAndPctToText(d.data["candidate"], d[1], percentDenominator, true, false);
};

function addMetadataToEachBar() {
Expand Down
5 changes: 3 additions & 2 deletions static/sankey/sankey-wrapper.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
function makeSankey(graph, numRounds, numCandidates, longestLabelApxWidth, totalVotesPerRound, colorThemeIndex) {
function makeSankey(graph, numRounds, numCandidates, numWinners, longestLabelApxWidth, totalVotesPerRound, colorThemeIndex) {
// Below are crazy heuristics to try to get the graph to look good
// on a variety of sizes.
const units = "Votes";
Expand Down Expand Up @@ -75,7 +75,8 @@ function makeSankey(graph, numRounds, numCandidates, longestLabelApxWidth, total
return textForNode(d)
}
function getNodePercentText(d) {
return percentToText(d.name, d.value, totalVotesPerRound[d.round])
const percentDenominator = calculatePercentDenominator(numWinners, totalVotesPerRound[0], totalVotesPerRound[d.round])
return percentToText(d.name, d.value, percentDenominator)
}

function makeViewboxSizeString(size0, size1) {
Expand Down
13 changes: 11 additions & 2 deletions static/visualizer/visualize-common.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,15 @@ function votesToText(numVotes, includeWordVotes, doSimplifyNumber)
return fmt(numVotes) + " " + (includeWordVotes ? "votes" : "");
}

function calculatePercentDenominator(numWinners, firstRoundVoteTotal, currRoundVoteTotal)
{
if (numWinners <= 1) {
return currRoundVoteTotal;
} else {
return firstRoundVoteTotal;
}
}

function percentToText(candidateName, numVotes, totalVotes)
{
// Inactive ballots should not show %
Expand All @@ -50,9 +59,9 @@ function percentToText(candidateName, numVotes, totalVotes)
return "(" + percentVotes + "%)";
}

function votesAndPctToText(candidateName, numVotes, totalVotes, includeWordVotes, doSimplifyNumber)
function votesAndPctToText(candidateName, numVotes, percentDenominator, includeWordVotes, doSimplifyNumber)
{
return votesToText(numVotes, includeWordVotes, doSimplifyNumber) + " " + percentToText(candidateName, numVotes, totalVotes);
return votesToText(numVotes, includeWordVotes, doSimplifyNumber) + " " + percentToText(candidateName, numVotes, percentDenominator);
}

function classNameForDescriptionVerb(verb) {
Expand Down
2 changes: 1 addition & 1 deletion templates/sankey/sankey-nonblocking.html
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
if (numRounds > 1)
{
loadFunctions();
makeSankey(graph, numRounds, numCandidates, longestLabelApxWidth, totalVotesPerRound, config.colorTheme);
makeSankey(graph, numRounds, numCandidates, numWinners, longestLabelApxWidth, totalVotesPerRound, config.colorTheme);
}
else
{
Expand Down
9 changes: 9 additions & 0 deletions visualizer/graph/graphSummary.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,15 @@ def __init__(self, graph):
self.numWinners = len(self.winnerNames)
self.numEliminated = sum(len(r.eliminatedNames) for r in rounds)

# percentDenominator is either the current round total in IRV,
# and the first round total in STV
def percentDenominator(self, roundNum):
if self.numWinners <= 1:
return self.rounds[roundNum].totalActiveVotes
else:
return self.rounds[0].totalActiveVotes



class RoundInfo:
""" Summarizes a single round, with functions to build the round """
Expand Down
1 change: 1 addition & 0 deletions visualizer/sankey/graphToD3.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ def __init__(self, graph):
js = ''
js += f'numRounds = {graph.numRounds};\n'
js += f'numCandidates = {len(graph.nodesPerRound[0])} ;\n'
js += f'numWinners = {len(graph.nodesPerRound[0])} ;\n'
js += f'longestLabelApxWidth = {longestLabelApxWidth};\n'
js += f'totalVotesPerRound = {totalVotesPerRound};\n'
js += 'graph = {"nodes" : [], "links" : []};\n'
Expand Down
33 changes: 15 additions & 18 deletions visualizer/tabular/tabular.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
from visualizer.descriptors import textForWinnerUtils as TextForWinner


def makePrimarySecondaryLabels(numVotes, allVotes, item):
def makePrimarySecondaryLabels(numVotes, denominator, item):
if item.isActive:
primaryLabel = percentify(numVotes, allVotes)
primaryLabel = percentify(numVotes, denominator)
secondaryLabel = votify(numVotes)
else:
primaryLabel = intify(numVotes)
Expand Down Expand Up @@ -60,9 +60,9 @@ def __init__(self, graph, config):
d['change'] = changify(votesAddedThisRound)

myNumVotes = cinfo.totalVotesPerRound[roundNum]
allVotes = roundData.totalActiveVotes
percentDenominator = summary.percentDenominator(roundNum)
d['primaryLabel'], d['secondaryLabel'] = makePrimarySecondaryLabels(
myNumVotes, allVotes, item)
myNumVotes, percentDenominator, item)
d['name'] = cinfo.name
d['wonThisRound'] = cinfo.name in roundData.winnerNames
d['eliminatedThisRound'] = isEliminatedThisRound
Expand Down Expand Up @@ -117,11 +117,9 @@ def __init__(self, graph, item):
self.rounds = range(numRounds)
for i, myNumVotes in enumerate(candidateInfo.totalVotesPerRound):
thisRoundSummary = summary.rounds[i]
self.eachRound.append(
OneCandidateOneRound(
thisRoundSummary,
myNumVotes,
item))
percentDenominator = summary.percentDenominator(i)
self.eachRound.append(OneCandidateOneRound(
thisRoundSummary, myNumVotes, percentDenominator, item))

# We want all rounds filled out - pad the remaining rounds
numRoundsThisCandidate = len(candidateInfo.totalVotesPerRound)
Expand All @@ -138,14 +136,12 @@ class OneCandidateOneRound:
numVotes: str
pctVotes: str

def __init__(self, thisRoundSummary, myNumVotes, item):
allVotes = thisRoundSummary.totalActiveVotes

def __init__(self, thisRoundSummary, myNumVotes, percentDenominator, item):
self.primaryLabel, self.secondaryLabel = makePrimarySecondaryLabels(
myNumVotes, allVotes, item)
myNumVotes, percentDenominator, item)

self.numVotes = intify(myNumVotes)
self.pctVotes = percentify(myNumVotes, allVotes)
self.pctVotes = percentify(myNumVotes, percentDenominator)

self.isWinner = item.name in thisRoundSummary.winnerNames
self.isEliminated = item.name in thisRoundSummary.eliminatedNames
Expand Down Expand Up @@ -189,7 +185,7 @@ def __init__(self, graph, config, item):

self.rounds.append(
RoundTabulation(config, node.count, i,
item, summary.rounds, linksForThisNode))
item, summary, linksForThisNode))


class RoundTabulation:
Expand All @@ -199,14 +195,15 @@ class RoundTabulation:
# secondaryLabel:str
# round_i:int, 1-indexed

def __init__(self, config, totalActiveVotes, round_i, item, roundInfos, linksForThisNode):
def __init__(self, config, totalActiveVotes, round_i, item, summary, linksForThisNode):
self.round_i = round_i + 1

myNumVotes = float(totalActiveVotes)
allVotes = roundInfos[round_i].totalActiveVotes
percentDenominator = summary.percentDenominator(round_i)
self.primaryLabel, self.secondaryLabel = makePrimarySecondaryLabels(
myNumVotes, allVotes, item)
myNumVotes, percentDenominator, item)

roundInfos = summary.rounds
thisRoundWinners = roundInfos[round_i].winnerNames
if round_i < len(roundInfos) - 1:
thisRoundEliminations = roundInfos[round_i + 1].eliminatedNames
Expand Down
Loading