Display order of election in count report
This commit is contained in:
parent
7afd8d7bfd
commit
7ee56f97f8
@ -361,6 +361,32 @@ async function clickCount() {
|
||||
elVRE.appendChild(elTd);
|
||||
}
|
||||
}
|
||||
|
||||
if (evt.data.type === 'done') {
|
||||
let result = evt.data.result;
|
||||
|
||||
// Display results
|
||||
|
||||
for (let [candidate, countCard] of result.candidates) {
|
||||
[elTr1, elTr2] = candMap[candidate];
|
||||
elTd = document.createElement('td');
|
||||
elTd.setAttribute('rowspan', '2');
|
||||
if (countCard.state === py.pyRCV2.model.CandidateState.WITHDRAWN) {
|
||||
elTd.classList.add('excluded');
|
||||
elTd.innerHTML = 'Withdrawn';
|
||||
} else if (countCard.state === py.pyRCV2.model.CandidateState.EXCLUDED || countCard.state === py.pyRCV2.model.CandidateState.EXCLUDING) {
|
||||
elTd.classList.add('excluded');
|
||||
elTd.innerHTML = 'Excluded ' + (-countCard.order_elected);
|
||||
} else if (countCard.state === py.pyRCV2.model.CandidateState.ELECTED || countCard.state === py.pyRCV2.model.CandidateState.PROVISIONALLY_ELECTED || countCard.state === py.pyRCV2.model.CandidateState.DISTRIBUTING_SURPLUS) {
|
||||
elTd.classList.add('elected');
|
||||
elTd.innerHTML = 'ELECTED ' + countCard.order_elected;
|
||||
}
|
||||
elTd.style.borderTop = '1px solid black';
|
||||
elTr1.appendChild(elTd);
|
||||
}
|
||||
|
||||
elTd.style.borderBottom = '1px solid black';
|
||||
}
|
||||
}
|
||||
|
||||
worker.onerror = function(evt) {
|
||||
|
@ -65,26 +65,7 @@ onmessage = function(evt) {
|
||||
stage = 1;
|
||||
result = counter.reset();
|
||||
|
||||
postMessage({'type': 'result', 'result': {
|
||||
'stage': stage,
|
||||
'comment': result.comment,
|
||||
'candidates': result.candidates.py_items().map(([c, cc]) => [c.py_name, {
|
||||
'transfers': cc.transfers.pp(ppDP),
|
||||
'votes': cc.votes.pp(ppDP),
|
||||
'state': cc.state
|
||||
}]),
|
||||
'exhausted': {
|
||||
'transfers': result.exhausted.transfers.pp(ppDP),
|
||||
'votes': result.exhausted.votes.pp(ppDP)
|
||||
},
|
||||
'loss_fraction': {
|
||||
'transfers': result.loss_fraction.transfers.pp(ppDP),
|
||||
'votes': result.loss_fraction.votes.pp(ppDP)
|
||||
},
|
||||
'total': result.total.pp(ppDP),
|
||||
'quota': result.quota.pp(ppDP),
|
||||
'vote_required_election': result.vote_required_election === null ? null : result.vote_required_election.pp(ppDP),
|
||||
}});
|
||||
postMessage({'type': 'result', 'result': resultToJS(result)});
|
||||
|
||||
stepElection();
|
||||
} else if (evt.data.type === 'require_input') {
|
||||
@ -115,16 +96,23 @@ function stepElection() {
|
||||
}
|
||||
|
||||
if (py.isinstance(result, py.pyRCV2.model.CountCompleted)) {
|
||||
postMessage({'type': 'done'});
|
||||
postMessage({'type': 'done', 'result': resultToJS(result)});
|
||||
break;
|
||||
} else {
|
||||
postMessage({'type': 'result', 'result': {
|
||||
postMessage({'type': 'result', 'result': resultToJS(result)});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function resultToJS(result) {
|
||||
return {
|
||||
'stage': stage,
|
||||
'comment': result.comment,
|
||||
'candidates': result.candidates.py_items().map(([c, cc]) => [c.py_name, {
|
||||
'transfers': cc.transfers.pp(ppDP),
|
||||
'votes': cc.votes.pp(ppDP),
|
||||
'state': cc.state
|
||||
'state': cc.state,
|
||||
'order_elected': cc.order_elected,
|
||||
}]),
|
||||
'exhausted': {
|
||||
'transfers': result.exhausted.transfers.pp(ppDP),
|
||||
@ -137,7 +125,5 @@ function stepElection() {
|
||||
'total': result.total.pp(ppDP),
|
||||
'quota': result.quota.pp(ppDP),
|
||||
'vote_required_election': result.vote_required_election === null ? null : result.vote_required_election.pp(ppDP),
|
||||
}});
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -60,9 +60,9 @@ def print_step(args, stage, result):
|
||||
for candidate, count_card in results:
|
||||
state = None
|
||||
if count_card.state == pyRCV2.model.CandidateState.ELECTED or count_card.state == pyRCV2.model.CandidateState.PROVISIONALLY_ELECTED or count_card.state == pyRCV2.model.CandidateState.DISTRIBUTING_SURPLUS:
|
||||
state = 'ELECTED'
|
||||
state = 'ELECTED {}'.format(count_card.order_elected)
|
||||
elif count_card.state == pyRCV2.model.CandidateState.EXCLUDED or count_card.state == pyRCV2.model.CandidateState.EXCLUDING:
|
||||
state = 'Excluded'
|
||||
state = 'Excluded {}'.format(-count_card.order_elected)
|
||||
elif count_card.state == pyRCV2.model.CandidateState.WITHDRAWN:
|
||||
state = 'Withdrawn'
|
||||
|
||||
|
@ -89,6 +89,7 @@ class BaseSTVCounter:
|
||||
self.total_orig = sum((b.value for b in self.election.ballots), Num('0'))
|
||||
|
||||
self.num_elected = 0
|
||||
self.num_excluded = 0
|
||||
|
||||
# Withdraw candidates
|
||||
for candidate in self.election.withdrawn:
|
||||
@ -196,17 +197,28 @@ class BaseSTVCounter:
|
||||
|
||||
# Have sufficient candidates been elected?
|
||||
if self.num_elected >= self.election.seats:
|
||||
return CountCompleted()
|
||||
__pragma__('opov')
|
||||
return CountCompleted(
|
||||
'Count complete',
|
||||
self.candidates,
|
||||
self.exhausted,
|
||||
self.loss_fraction,
|
||||
self.total + self.exhausted.votes + self.loss_fraction.votes,
|
||||
self.quota,
|
||||
self.vote_required_election,
|
||||
)
|
||||
__pragma__('noopov')
|
||||
|
||||
# Are there just enough candidates to fill all the seats?
|
||||
if self.options['bulk_elect']:
|
||||
if self.num_elected + sum(1 for c, cc in self.candidates.items() if cc.state == CandidateState.HOPEFUL or cc.state == CandidateState.EXCLUDING) <= self.election.seats:
|
||||
# Include EXCLUDING to avoid interrupting an exclusion
|
||||
if len(self.election.candidates) - self.num_excluded + sum(1 for c, cc in self.candidates.items() if cc.state == CandidateState.EXCLUDING) <= self.election.seats:
|
||||
# Declare elected all remaining candidates
|
||||
for candidate, count_card in self.candidates.items():
|
||||
if count_card.state == CandidateState.HOPEFUL:
|
||||
count_card.state = CandidateState.PROVISIONALLY_ELECTED
|
||||
count_card.order_elected = self.num_elected
|
||||
self.num_elected += 1
|
||||
count_card.order_elected = self.num_elected
|
||||
|
||||
__pragma__('opov')
|
||||
result = CountStepResult(
|
||||
@ -338,15 +350,15 @@ class BaseSTVCounter:
|
||||
|
||||
# If we did not perform bulk election in before_surpluses: Are there just enough candidates to fill all the seats?
|
||||
if not self.options['bulk_elect']:
|
||||
if self.num_elected + sum(1 for c, cc in self.candidates.items() if cc.state == CandidateState.HOPEFUL) <= self.election.seats:
|
||||
if len(self.election.candidates) - self.num_excluded <= self.election.seats:
|
||||
# Declare elected one remaining candidate at a time
|
||||
hopefuls = [(c, cc) for c, cc in self.candidates.items() if cc.state == CandidateState.HOPEFUL]
|
||||
hopefuls.sort(key=lambda x: x[1].votes, reverse=True)
|
||||
candidate_elected, count_card = self.choose_highest(hopefuls)
|
||||
|
||||
count_card.state = CandidateState.PROVISIONALLY_ELECTED
|
||||
count_card.order_elected = self.num_elected
|
||||
self.num_elected += 1
|
||||
count_card.order_elected = self.num_elected
|
||||
|
||||
__pragma__('opov')
|
||||
result = CountStepResult(
|
||||
@ -370,7 +382,10 @@ class BaseSTVCounter:
|
||||
|
||||
candidates_excluded = self.candidates_to_exclude()
|
||||
for candidate, count_card in candidates_excluded:
|
||||
if count_card.state != CandidateState.EXCLUDING:
|
||||
count_card.state = CandidateState.EXCLUDING
|
||||
self.num_excluded += 1
|
||||
count_card.order_elected = -self.num_excluded
|
||||
|
||||
# Handle Wright STV
|
||||
if self.options['exclusion'] == 'wright':
|
||||
@ -433,7 +448,7 @@ class BaseSTVCounter:
|
||||
Returns List[Tuple[Candidate, CountCard]]
|
||||
"""
|
||||
|
||||
remaining_candidates = self.num_elected + sum(1 for c, cc in self.candidates.items() if cc.state == CandidateState.HOPEFUL)
|
||||
remaining_candidates = len(self.election.candidates) - self.num_excluded
|
||||
__pragma__('opov')
|
||||
total_surpluses = sum((cc.votes - self.quota for c, cc in self.candidates.items() if cc.votes > self.quota), Num(0))
|
||||
__pragma__('noopov')
|
||||
@ -574,8 +589,8 @@ class BaseSTVCounter:
|
||||
candidate, count_card = x[0], x[1]
|
||||
|
||||
count_card.state = CandidateState.PROVISIONALLY_ELECTED
|
||||
count_card.order_elected = self.num_elected
|
||||
self.num_elected += 1
|
||||
count_card.order_elected = self.num_elected
|
||||
|
||||
meets_quota.remove(x)
|
||||
|
||||
|
@ -65,7 +65,7 @@ class CountCard:
|
||||
self.orig_votes = Num('0')
|
||||
self.transfers = Num('0')
|
||||
self.state = CandidateState.HOPEFUL
|
||||
self.order_elected = None
|
||||
self.order_elected = None # Negative for order of exclusion
|
||||
|
||||
# self.parcels = List[Parcel]
|
||||
# Parcel = List[Tuple[Ballot, Num]]
|
||||
@ -94,9 +94,6 @@ class CountCard:
|
||||
result.order_elected = self.order_elected
|
||||
return result
|
||||
|
||||
class CountCompleted:
|
||||
pass
|
||||
|
||||
class CountStepResult:
|
||||
def __init__(self, comment, candidates, exhausted, loss_fraction, total, quota, vote_required_election):
|
||||
self.comment = comment
|
||||
@ -119,3 +116,6 @@ class CountStepResult:
|
||||
__pragma__('noopov')
|
||||
|
||||
return CountStepResult(self.comment, candidates, self.exhausted.clone(), self.loss_fraction.clone(), self.total, self.quota)
|
||||
|
||||
class CountCompleted(CountStepResult):
|
||||
pass
|
||||
|
Reference in New Issue
Block a user