Module:Sandbox/Julio974fr
Appearance
require('strict')
local p = {};
local political_party = require('Module:Political party')
local LANG = 'en'
local FALLBACK_LANGS = {'de', 'fr', 'it', 'rm'}
--[[ Properties shorthands ]]
local P_MEMBER_OF_PARTY = 'P102'
local P_FOLLOWS = 'P155'
local P_FOLLOWED_BY = 'P156'
local P_HAS_PARTS = 'P527'
local P_PART_OF = 'P361'
local P_COLOR = 'P465'
local P_POINT_IN_TIME = 'P585'
local P_CANDIDATE = 'P726'
local P_SUCCESSFUL_CANDIDATE = 'P991'
local P_VOTES_RECEIVED = 'P1111'
local P_REPLACED_BY = 'P1366'
local P_SEATS = 'P1410'
local P_TOTAL_VALID_VOTES = 'P1697'
local P_SHORT_NAME = 'P1813'
local P_ELIGIBLE_VOTERS = 'P1867'
local P_BALLOTS_CAST = 'P1868'
local P_NAME = 'P2561'
local P_SPOILT_VOTES = 'P5044'
local P_BLANK_VOTES = 'P5045'
--[[ Get a best ranking statement value from "item" with the property "property".
The value is returned through the function "typefunc". ]] -- Function copied from elsewhere
local function getStatementValue(item, property, typefunc)
local statements = mw.wikibase.getBestStatements(item, property)
if statements[1] and statements[1].mainsnak.snaktype == 'value' then
return typefunc(statements[1].mainsnak.datavalue.value)
end
end
local function getStatementQualifier(item, property, qualifier, typefunc)
local statements = mw.wikibase.getBestStatements(item, property)
if statements[1] and statements[1].qualifiers and statements[1].qualifiers[qualifier] and statements[1].qualifiers[qualifier][1] then
return typefunc(statements[1].qualifiers[qualifier][1].datavalue.value)
end
end
--[[ The "typefunc"s - A series of functions that extract the wanted information
from a statement value depending on the value type. ]]
local function getAmount(value) return tonumber(value.amount) end
local function getString(value) return value end
local function getItem(value) return value.id end
local function getTimestamp(value) return value.time end
-- Finds the text value of a given property in the given language
local function getValueFromLanguage(qid, property, lang)
local statement = mw.wikibase.getBestStatements(qid, property)
for i, v in ipairs(statement) do
if v.mainsnak.datavalue.value.language == lang then
return v.mainsnak.datavalue.value.text
end
end
for i, v in ipairs(statement) do
if v.mainsnak.datavalue.value.language == 'mul' then
return v.mainsnak.datavalue.value.text
end
end
end
local function getPartyColor(qid, articleTitle)
local color = getStatementValue(qid, P_COLOR, getString)
if color then
return '#'..color
end
if articleTitle == nil then
return '#ffffff'
end
color = political_party._fetch({articleTitle, 'color', error='#ffffff'})
color = mw.ustring.gsub(color, '&(#)35;', '%1')
return color
end
local function sortParties(listParties)
local function comparePartyByVotes(partyA, partyB)
if partyB.qid == 'Q86630688' then -- Q86630688 is 'Others'
return true
elseif partyA.qid == 'Q86630688' then
return false
elseif (partyA.votes1 or 0) > (partyB.votes1 or 0) then
return true
elseif (partyA.votes1 or 0) < (partyB.votes1 or 0) then
return false
else
return ((partyA.seats or 0) > (partyB.seats or 0))
end
end
table.sort(listParties, comparePartyByVotes)
end
local function formatWikilink_simple(link, displaytext)
return '[['..link..'|'..displaytext..']]'
end
local function getAndFormatInterlanguageLinks(qid)
local fallbackLinks = {}
for _, language in ipairs(FALLBACK_LANGS) do
local sitelink = mw.wikibase.getSitelink(qid, language..'wiki')
if sitelink then
fallbackLinks[#fallbackLinks+1] = formatWikilink_simple(':'..language..':'..sitelink, language)
end
end
if #fallbackLinks == 0 then return '' end
return ' <span style="font-size:85%">[​'..table.concat(fallbackLinks, '; ')..']</span>'
end
local function formatWikilink(link, displaytext, qid)
if link then
if displaytext then
return '[['..link..'|'..displaytext..']]'
else
return '[['..link..']]'
end
else
if displaytext then
return displaytext..getAndFormatInterlanguageLinks(qid)
else
return '[[wikidata:'..qid..']]'..getAndFormatInterlanguageLinks(qid)
end
end
end
local function fetchCandidacyData_party(partyQid)
local data = {}
data.candidacyType = 'party'
-- Get party qid
data.partyQid = partyQid
-- Get party article
local partyArticle, label
partyArticle = mw.wikibase.getSitelink(partyQid)
if not partyArticle then
label = mw.wikibase.getLabel(partyQid)
end
data.partyArticle = partyArticle
-- Get party name
data.partyName = getValueFromLanguage(partyQid, P_NAME, LANG) or label
return data
end
local function fetchCandidacyData_candidate(candidateQid)
local data = {}
data.candidacyType = 'candidate'
data.candidateQid = candidateQid
-- Get article name
local candidateArticle, label
data.candidateArticle = mw.wikibase.getSitelink(candidateQid)
data.candidateName = mw.wikibase.getLabel(candidateQid)
-- Get party
data.partyQid = getStatementValue(candidateQid, P_MEMBER_OF_PARTY, getItem)
if not data.partyQid then
return data
end
data.partyArticle = mw.wikibase.getSitelink(data.partyQid)
data.partyName = getValueFromLanguage(data.partyQid, P_SHORT_NAME, LANG)
mw.logObject({data.partyQid, P_SHORT_NAME, LANG})
mw.log(getValueFromLanguage, data.partyQid, P_SHORT_NAME, LANG)
mw.log(data.partyName)
return data
end
-- For a given candidacy: gets their name, article link, party shortlink, and color
local function fetchCandidacyData(qid, candidacyType)
if candidacyType == 'party' then
return fetchCandidacyData_party(qid)
elseif candidacyType == 'candidate' then
return fetchCandidacyData_candidate(qid)
else
error('candidacyType not specified')
end
end
-- Returns the candidacy qid from a candidacy statement
local function getCandidacyQidFromStatement(candidacyStatement, candidacyType, doGroupByParty)
if doGroupByParty then
if candidacyStatement.qualifiers[P_MEMBER_OF_PARTY] then
return candidacyStatement.qualifiers[P_MEMBER_OF_PARTY][1].datavalue.value.id
end
end
return candidacyStatement.mainsnak.datavalue.value.id
end
-- function internal to findCandidacyIndex
local function findCandidacyIndex_finder(listParties, partyQid)
local finalPartyIndex = nil
for curPartyindex, curParty in ipairs(listParties) do
if curParty.qid == partyQid then
finalPartyIndex = curPartyindex
break
end
end
return finalPartyIndex
end
-- Returns the index of a candidacy in a list given its qid. If it is not present and doCreate is true, creates an index for it
local function findCandidacyIndex(listCandidacies, candidacyQid, candidacyType, doCreate)
local candidacyIndex = findCandidacyIndex_finder(listCandidacies, candidacyQid)
if not doCreate then
return candidacyIndex
end
if not candidacyIndex then
if candidacyType == 'party' then
table.insert(listCandidacies, {qid=candidacyQid, votes1 = 0, seats = 0})
elseif candidacyType == 'candidate' then
table.insert(listCandidacies, {qid=candidacyQid, votes1 = 0})
else
error('candidacyType not specified')
end
candidacyIndex = #listCandidacies
end
return candidacyIndex
end
-- Returns a table with data from the candidacy's statement
local function addCandidacyDataFromStatement(candidacyData, statement, candidacyType, round, doPrevious, isWinning)
local roundKey
if round then roundKey = tostring(round)
else roundKey = '1' end
if doPrevious then
if not candidacyData.prevVotes then candidacyData.prevVotes = 0 end
if statement.qualifiers[P_VOTES_RECEIVED] then
candidacyData.prevVotes = candidacyData.prevVotes + getAmount(statement.qualifiers[P_VOTES_RECEIVED][1].datavalue.value)
end
if not candidacyData.prevSeats then candidacyData.prevSeats = 0 end
if statement.qualifiers[P_SEATS] then
candidacyData.prevSeats = candidacyData.prevSeats + getAmount(statement.qualifiers[P_SEATS][1].datavalue.value)
end
return candidacyData
end
if isWinning then
candidacyData.winning = round
end
if not statement.qualifiers then
return candidacyData
end
if statement.qualifiers[P_VOTES_RECEIVED] then
if not candidacyData['votes'..roundKey] then candidacyData['votes'..roundKey] = 0 end
candidacyData['votes'..roundKey] = candidacyData['votes'..roundKey] + getAmount(statement.qualifiers[P_VOTES_RECEIVED][1].datavalue.value)
end
if statement.qualifiers[P_SEATS] then
if not candidacyData.seats then candidacyData.seats = 0 end
candidacyData.seats = candidacyData.seats + getAmount(statement.qualifiers[P_SEATS][1].datavalue.value)
end
if statement.qualifiers[P_MEMBER_OF_PARTY] then
candidacyData.partyQid = getItem(statement.qualifiers[P_MEMBER_OF_PARTY][1].datavalue.value)
end
if statement.qualifiers[P_FOLLOWS] then
if not candidacyData.predecessors then candidacyData.predecessors = {} end
for _, predecessorStatement in ipairs(statement.qualifiers[P_FOLLOWS]) do
table.insert(candidacyData.predecessors, getItem(predecessorStatement.datavalue.value))
end
end
return candidacyData
end
local function findPartyPredecessorOverride(listParties, partyQid, partyIndex)
for tempIndex, tempParty in ipairs(listParties) do
if tempParty.predecessors then
for _, tempPredecessor in ipairs(tempParty.predecessors) do
if tempPredecessor == partyQid then
return tempIndex
end
end
end
end
return partyIndex
end
-- function internal to insertCandidacyInList
local function insertCandidacyInList_previous(listCandidacies, candidacyStatement, candidacyType, candidacyQid)
local candidacyIndex = findCandidacyIndex(listCandidacies, candidacyQid, candidacyType, false)
candidacyIndex = findPartyPredecessorOverride(listCandidacies, candidacyQid, candidacyIndex)
if not candidacyIndex then
candidacyIndex = findCandidacyIndex(listCandidacies, getStatementValue(candidacyQid, P_REPLACED_BY, getItem), candidacyType, false)
end
if candidacyIndex then
listCandidacies[candidacyIndex] = addCandidacyDataFromStatement(listCandidacies[candidacyIndex], candidacyStatement, candidacyType, 1, true)
end
return listCandidacies
end
-- Inserts a candidacy in the list of candidacies
local function insertCandidacyInList(listCandidacies, candidacyStatement, candidacyType, round, doPrevious, doGroupByParty, isWinning)
local candidacyQid = getCandidacyQidFromStatement(candidacyStatement, candidacyType, doGroupByParty)
if doPrevious then
return insertCandidacyInList_previous(listCandidacies, candidacyStatement, candidacyType, candidacyQid)
end
local candidacyIndex = findCandidacyIndex(listCandidacies, candidacyQid, candidacyType, true)
listCandidacies[candidacyIndex] = addCandidacyDataFromStatement(listCandidacies[candidacyIndex], candidacyStatement, candidacyType, round, false, isWinning)
return listCandidacies
end
local function addPartyPredecessorsByComponents(listParties)
for partyIndex, partyData in ipairs(listParties) do
local allParts = mw.wikibase.getAllStatements(partyData.qid, P_HAS_PARTS)
for _, predecessorStatement in ipairs(allParts) do
if not partyData.predecessors then partyData.predecessors = {} end
table.insert(partyData.predecessors, getItem(predecessorStatement.mainsnak.datavalue.value))
end
listParties[partyIndex] = partyData
end
return listParties
end
-- Retrieves the list of parties and sorts it by votes/seats
local function getCandidaciesDataFromElection(roundsQidsList, candidacyType, previousQid, doGroupByParty)
local listCandidacies = {}
-- For each round
for round, roundQid in ipairs(roundsQidsList) do
-- For each candidate
local allStatementsInElection = mw.wikibase.getAllStatements(roundQid, P_CANDIDATE)
for _, candidacyStatement in ipairs(allStatementsInElection) do
insertCandidacyInList(listCandidacies, candidacyStatement, candidacyType, round, false, doGroupByParty)
end
local allWinningStatementsInElection = mw.wikibase.getAllStatements(roundQid, P_SUCCESSFUL_CANDIDATE)
for _, winningStatement in ipairs(allWinningStatementsInElection) do
insertCandidacyInList(listCandidacies, winningStatement, candidacyType, round, false, false, true)
end
end
-- For each party in the previous election
if previousQid then
listCandidacies = addPartyPredecessorsByComponents(listCandidacies)
local allStatementsPrevElection = mw.wikibase.getAllStatements(previousQid, P_CANDIDATE)
for _, partyStatement in ipairs(allStatementsPrevElection) do
insertCandidacyInList(listCandidacies, partyStatement, 'party', 1, true, doGroupByParty)
end
end
sortParties(listCandidacies)
return listCandidacies
end
local function getAllCandidaciesData(roundsQidsList, candidacyType, previousQid, partyNameOverrides, doGroupByParty)
local candidaciesData = getCandidaciesDataFromElection(roundsQidsList, candidacyType, previousQid, doGroupByParty)
for candidacyIndex, candidacyData in ipairs(candidaciesData) do
local fetchedCandidacyData = fetchCandidacyData(candidacyData.qid, candidacyType)
candidacyData.partyQid = candidacyData.partyQid or fetchedCandidacyData.partyQid
candidacyData.partyName = candidacyData.partyName or fetchedCandidacyData.partyName
candidacyData.partyArticle = candidacyData.partyArticle or fetchedCandidacyData.partyArticle
candidacyData.candidateQid = candidacyData.candidateQid or fetchedCandidacyData.candidateQid
candidacyData.candidateName = candidacyData.candidateName or fetchedCandidacyData.candidateName
candidacyData.candidateArticle = candidacyData.candidateArticle or fetchedCandidacyData.candidateArticle
if candidacyData.partyQid then
candidacyData.partyWikilink = formatWikilink(candidacyData.partyArticle, candidacyData.partyName, candidacyData.partyQid)
end
if candidacyData.candidateQid then
candidacyData.candidateWikilink = formatWikilink(candidacyData.candidateArticle, candidacyData.candidateName, candidacyData.candidateQid)
end
if candidacyData.partyQid then
candidacyData.color = getPartyColor(candidacyData.partyQid, candidacyData.partyArticle)
end
if candidacyData.partyQid and partyNameOverrides['name_override_'..(candidacyData.partyQid)] then -- If name override specified
candidacyData.name = partyNameOverrides['name_override_'..(fetchedCandidacyData.partyQid)]
end
mw.logObject({candidacyData.partyQid, candidacyData.partyName, candidacyData.partyArticle, candidacyData.partyWikilink})
candidaciesData[candidacyIndex] = candidacyData
end
return candidaciesData
end
local function getElectionSitelink(qid)
local articleTitle
local supersetElectionQid = getStatementValue(qid, P_PART_OF, getItem)
while (not articleTitle) and supersetElectionQid do
qid = supersetElectionQid
supersetElectionQid = getStatementValue(qid, P_PART_OF, getItem)
articleTitle = mw.wikibase.getSitelink(qid)
end
return articleTitle
end
local function filterArgs(args, filter)
local matched = {}
for k, v in pairs(args) do
if string.match(k, filter) then
matched[k] = v
end
end
return matched
end
local function getYear(timestamp)
return tonumber(string.match(timestamp, '%+(%d%d%d%d)%-%d%d%-%d%dT%d%d:%d%d:%d%d'))
end
local function getReferences(electionQid)
local allReferences = {}
local function getReferenceIndex(allReferences, reference)
local url = reference.snaks.P854[1].datavalue.value
for i, curRef in ipairs(allReferences) do
if curRef.url == url then
return i
end
end
table.insert(allReferences, {url=url})
return #allReferences
end
local function addReference(allReferences, reference)
local refIndex = getReferenceIndex(allReferences, reference)
-- TODO: Add other reference attributes
-- allReferences[refIndex].url = uwu
end
for _, property in ipairs({P_CANDIDATE, P_ELIGIBLE_VOTERS, P_BALLOTS_CAST, P_SPOILT_VOTES, P_TOTAL_VALID_VOTES, P_BLANK_VOTES}) do
for _, statement in ipairs(mw.wikibase.getBestStatements(electionQid, property)) do
if statement.references then
for _, reference in ipairs(statement.references) do
addReference(allReferences, reference)
end
end
end
end
return allReferences
end
local function round(n)
local quotient, remainder = math.modf(n)
if remainder >= 0.5 then return quotient+1
else return quotient end
end
local function getElectionStatistics(qid, fallbackQid)
local statistics
if fallbackQid then -- fallbackQid is used to handle the fact data can be in the main item or in a separate "first round" item
statistics = getElectionStatistics(fallbackQid)
else
statistics = {}
end
if not qid then return {} end
statistics.eligibleVoters = getStatementValue(qid, P_ELIGIBLE_VOTERS, getAmount) or statistics.eligibleVoters
statistics.totalBallots = getStatementValue(qid, P_BALLOTS_CAST, getAmount) or statistics.totalBallots
statistics.invalidBallots = getStatementQualifier(qid, P_BALLOTS_CAST, P_SPOILT_VOTES, getAmount) or statistics.invalidBallots
statistics.blankBallots = getStatementQualifier(qid, P_BALLOTS_CAST, P_BLANK_VOTES, getAmount) or statistics.blankBallots
statistics.invalidVotes = getStatementValue(qid, P_SPOILT_VOTES, getAmount) or statistics.invalidVotes
statistics.blankVotes = getStatementValue(qid, P_BLANK_VOTES, getAmount) or statistics.blankVotes
statistics.validVotes = getStatementValue(qid, P_TOTAL_VALID_VOTES, getAmount) or statistics.validVotes
statistics.validBallots = (statistics.totalBallots or 0) - (statistics.invalidBallots or 0) - (statistics.blankBallots or 0)
statistics.totalVotes = (statistics.validVotes or 0) + (statistics.invalidVotes or 0) + (statistics.blankVotes or 0)
statistics.magnitude = round(statistics.totalVotes / statistics.validBallots)
return statistics
end
local function getRounds(electionQid)
local rounds = {}
for _,partStatement in ipairs(mw.wikibase.getAllStatements(electionQid, P_HAS_PARTS)) do
local roundQid = partStatement.mainsnak.datavalue.value.id
local roundNumber = partStatement.qualifiers.P1545[1].datavalue.value
rounds[tonumber(roundNumber)] = roundQid
end
if rounds == {} then return {electionQid} end
return rounds
end
-- Formatting functions (some copied from Module:Election_results)
local lang = mw.getContentLanguage()
local function fmt(n)
return n and tonumber(n) and lang:formatNum(tonumber(n)) or nil
end
local function pct(n, d)
n, d = tonumber(n), tonumber(d)
if n and d and d > 0 then
return string.format('%.2f', n / d * 100)
end
return '–'
end
local function formatMultiplier(n, d)
local n, d = tonumber(n), tonumber(d)
if (not n) or (not d) or d == 0 then return '–' end
local num = tostring(round(n/d))
return tostring(num)..'×'
end
local function diff(n, prevN)
if not n then
return '–'
elseif not prevN then
return "''New''"
end
n, prevN = tonumber(n), tonumber(prevN)
if n > prevN then
return '+'..tostring(n-prevN)
elseif prevN > n then
return '−'..tostring(prevN-n)
else
return '±0'
end
end
local function diffPct(n, d, prevN, prevD)
if not n or not d then
return '–'
elseif not prevN then
return "''New''"
end
n = tonumber(n) / tonumber(d)
prevN = tonumber(prevN) / tonumber(prevD)
if n > prevN then
return '+'..string.format('%.2f', (n - prevN) * 100)
elseif prevN > n then
return '−'..string.format('%.2f', (prevN - n) * 100)
else
return '±0.00'
end
end
--[[ Table-generating functions ]]
local function beginTable(classes, electionQid)
local root = mw.html.create('span')
root:attr('id', electionQid..'_resultsTable')
local tab = root:tag('table')
tab:addClass(classes)
local tableCaption = tab:tag('caption')
local caption = 'Results of the ' .. mw.wikibase.getLabel(electionQid)
local previousElectionQid = getStatementValue(electionQid, P_FOLLOWS, getItem)
local nextElectionQid = getStatementValue(electionQid, P_FOLLOWED_BY, getItem)
if previousElectionQid then
caption = '[['..getElectionSitelink(previousElectionQid)..'#'..previousElectionQid..'_resultsTable|←]] ' .. caption
end
if nextElectionQid then
caption = caption .. ' [['.. getElectionSitelink(nextElectionQid)..'#'..nextElectionQid..'_resultsTable|→]]'
end
tableCaption:wikitext(caption)
tableCaption:done()
tab:done()
return root, tab
end
local function addHeaderCell(row, wikitext, colspan, rowspan)
local cell = row:tag('th')
cell:wikitext(wikitext)
cell:attr('scope', 'col')
if colspan then cell:attr('colspan', tostring(colspan)) end
if rowspan then cell:attr('rowspan', tostring(rowspan)) end
cell:done()
end
local function addCell(row, wikitext, align, colspan, isBold)
local cell = row:tag('td')
if align then cell:css('text-align', align) end
if colspan then cell:attr('colspan', tostring(colspan)) end
if isBold then cell:css('font-weight', 'bold') end
cell:wikitext(wikitext)
cell:done()
end
local function addColorCell(row, color)
local cell = row:tag('td')
cell:css('width', '0px')
cell:css('background-color', color)
cell:done()
end
local function fillTopCell(topCell, wikitext, colspan)
topCell:wikitext(wikitext)
topCell:css('text-align', 'center')
topCell:css('background', '#F8F9FA')
topCell:attr('colspan', colspan)
topCell:done()
end
local function addStatRow(root, rowTitle, statisticsTables, statistic, fractionNumerator, fractionDenominator, doMakeBold, doUseMultiplier)
local isStatisticPresent
for _, roundStatistics in ipairs(statisticsTables) do -- Check if the statistic is even present
if roundStatistics[statistic] then
isStatisticPresent = true
break
end
end
if isStatisticPresent then
local row = root:tag('tr')
if doMakeBold then
row:css('font-weight', 'bold')
end
addCell(row, rowTitle, 'left', 3)
for _,roundStatistics in ipairs(statisticsTables) do
if roundStatistics[statistic] then
addCell(row, fmt(roundStatistics[statistic]), 'right')
if doUseMultiplier then
addCell(row, formatMultiplier(roundStatistics[fractionNumerator], roundStatistics[fractionDenominator] or 1), 'right')
else
addCell(row, pct(roundStatistics[fractionNumerator], roundStatistics[fractionDenominator]), 'right')
end
end
end
end
end
local function addReference(refsCell, ref)
local r = refsCell:wikitext(
mw.getCurrentFrame():extensionTag({
name = 'ref',
content = ref.url
})
)
return r
end
local function formatReferencesRow(root, references, electionQid, cols)
-- References and wikidata link row
local row = root:tag('tr')
row:css('font-size', '90%')
local refsCell = row:tag('td')
refsCell:wikitext('[[:wikidata:'..electionQid..'|See on Wikidata]]')
refsCell:attr('colspan', cols)
if references then
refsCell:wikitext(' - Sources')
for _, ref in ipairs(references) do
addReference(refsCell, ref)
end
end
end
--[[ Main functions ]]
function p._ch_proportional(args)
local electionQid = args.qid or args.election or args[1]
local previousElectionQid = getStatementValue(electionQid, P_FOLLOWS, getItem)
local doGroupByParty = args.groupByParty or false
local cols = 0
local year = getYear(getStatementValue(electionQid, P_POINT_IN_TIME, getTimestamp))
local totalVotes = getStatementValue(electionQid, P_TOTAL_VALID_VOTES, getAmount)
local statistics = getElectionStatistics(electionQid)
mw.logObject({statistics}, 'statistics')
local prevTotalVotes
if previousElectionQid then prevTotalVotes = getStatementValue(previousElectionQid, P_TOTAL_VALID_VOTES, getAmount) end
local references = getReferences(electionQid)
local rootSpan, root = beginTable('wikitable sortable', electionQid)
-- topCell (for the parliament diagram)
local topCell = nil
topCell = root:tag('th')
-- Table header
local headerRow = root:tag('tr')
addHeaderCell(headerRow, (args.partytitle or 'Party'), 2)
addHeaderCell(headerRow, 'Votes')
addHeaderCell(headerRow, '%')
if previousElectionQid then addHeaderCell(headerRow, '+/−') end
addHeaderCell(headerRow, 'Seats')
if previousElectionQid then addHeaderCell(headerRow, '+/−') end
cols = cols + 5
if previousElectionQid then cols = cols + 2 end
-- Fetch parties data
local partyNameOverrides = filterArgs(args, 'name_override_Q%d+')
local partiesData = getAllCandidaciesData({electionQid}, 'party', previousElectionQid, partyNameOverrides, doGroupByParty)
mw.logObject(partiesData)
if topCell then
fillTopCell(
topCell,
(args['image'] or require('Module:Sandbox/Julio974fr/parliament_diagram').makeParliamentDiagram(partiesData, year)),
cols
)
end
-- Get parties list and make the rows
for _, party in ipairs(partiesData) do
local row = root:tag('tr')
if party.qid == 'Q86630688' then --Others
addCell(row, 'Others', 'left', 2)
else
addColorCell(row, party.color)
addCell(row, party.partyWikilink)
end
addCell(row, fmt(party.votes1), 'right')
addCell(row, pct(party.votes1, totalVotes), 'right')
if previousElectionQid then addCell(row, diffPct(party.votes1, totalVotes, party.prevVotes, prevTotalVotes), 'right') end
addCell(row, party.seats, 'right')
if previousElectionQid then addCell(row, diff(party.seats, party.prevSeats), 'right') end
end
-- Footer separator
addStatRow(root, 'Total', {statistics}, 'validVotes', 'validVotes', 'totalVotes', true)
local row = root:tag('tr')
addHeaderCell(row, '', cols)
-- Footer rows (statistics & references)
if statistics.blankVotes or statistics.invalidVotes then
addStatRow(root, 'Blank votes', {statistics}, 'blankVotes', 'blankVotes', 'totalVotes')
addStatRow(root, 'Invalid votes', {statistics}, 'invalidVotes', 'invalidVotes', 'totalVotes')
addStatRow(root, 'Total votes', {statistics}, 'totalVotes', 'totalVotes', 'validBallots', true, true)
end
addStatRow(root, 'Blank ballots', {statistics}, 'blankBallots', 'blankBallots', 'ballotsCast')
addStatRow(root, 'Invalid ballots', {statistics}, 'invalidBallots', 'invalidBallots', 'ballotsCast')
addStatRow(root, 'Total ballots', {statistics}, 'ballotsCast', 'ballotsCast', 'ballotsCast', true)
addStatRow(root, 'Registered voters/Turnout', {statistics}, 'eligibleVoters', 'ballotsCast', 'eligibleVoters')
formatReferencesRow(root, references, electionQid, cols)
return rootSpan
end
function p._ch_majoritarian(args)
local electionQid = args.qid or args.election or args[1]
local cols = 0
local year = getYear(getStatementValue(electionQid, P_POINT_IN_TIME, getTimestamp))
local references = getReferences(electionQid)
local roundsQid = getRounds(electionQid)
local firstRoundQid = roundsQid[1] or electionQid
local secondRoundQid = roundsQid[2]
local hasSecondRound = secondRoundQid and true or false
local totalVotes = (
getStatementValue(electionQid, P_TOTAL_VALID_VOTES, getAmount)
or getStatementValue(firstRoundQid, P_TOTAL_VALID_VOTES, getAmount)
) -- @todo Calculate percentage based on a property of the number of votes per voter or of the overall majority
local totalVotes2 = hasSecondRound and getStatementValue(secondRoundQid, P_TOTAL_VALID_VOTES, getAmount) or nil
local statistics = getElectionStatistics(electionQid, firstRoundQid)
local statistics2 = getElectionStatistics(secondRoundQid)
mw.logObject({statistics, statistics2}, 'statistics')
local rootSpan, root = beginTable('wikitable sortable', electionQid)
-- Table header
local headerRow = root:tag('tr')
if not hasSecondRound then
addHeaderCell(headerRow, 'Candidate', 2)
addHeaderCell(headerRow, (args.partytitle or 'Party'))
addHeaderCell(headerRow, 'Votes')
addHeaderCell(headerRow, '%')
cols = cols+5
else
local secondHeaderRow = root:tag('tr')
addHeaderCell(headerRow, 'Candidate', 2, 2)
addHeaderCell(headerRow, (args.partytitle or 'Party'), 1, 2)
addHeaderCell(headerRow, 'First round', 2)
addHeaderCell(headerRow, 'Second round', 2)
addHeaderCell(secondHeaderRow, 'Votes')
addHeaderCell(secondHeaderRow, '%')
addHeaderCell(secondHeaderRow, 'Votes')
addHeaderCell(secondHeaderRow, '%')
cols = cols+7
end
-- Fetch parties data
local partyNameOverrides = filterArgs(args, 'name_override_Q%d+')
local candidatesData = getAllCandidaciesData({firstRoundQid, secondRoundQid}, 'candidate', nil, partyNameOverrides, nil)
mw.logObject(candidatesData)
-- Get parties list and make the rows
for _, candidate in ipairs(candidatesData) do
local row = root:tag('tr')
if candidate.qid == 'Q86630688' then --Others
addCell(row, 'Others', 'left', 3)
else
addColorCell(row, candidate.color)
addCell(row, candidate.candidateWikilink)
addCell(row, candidate.partyWikilink, 'left')
end
addCell(row, fmt(candidate.votes1), 'right', 1, (candidate.winning==1))
addCell(row, pct(candidate.votes1, (statistics.validVotes/statistics.magnitude)), 'right', 1, (candidate.winning==1))
if candidate.votes2 then
addCell(row, fmt(candidate.votes2), 'right', 1, (candidate.winning==2))
addCell(row, pct(candidate.votes2, (statistics2.validVotes/statistics2.magnitude)), 'right', 1, (candidate.winning==2))
end
end
-- Footer separator
addStatRow(root, 'Total', {statistics, statistics2}, 'validVotes', 'validVotes', 'totalVotes', true)
local row = root:tag('tr')
addHeaderCell(row, '', cols)
-- Footer rows (statistics & references)
addStatRow(root, 'Blank votes', {statistics, statistics2}, 'blankVotes', 'blankVotes', 'totalVotes')
addStatRow(root, 'Invalid votes', {statistics, statistics2}, 'invalidVotes', 'invalidVotes', 'totalVotes')
addStatRow(root, 'Total votes', {statistics, statistics2}, 'totalVotes', 'magnitude', nil, true, true)
addStatRow(root, 'Blank ballots', {statistics, statistics2}, 'blankBallots', 'blankBallots', 'totalBallots')
addStatRow(root, 'Invalid ballots', {statistics, statistics2}, 'invalidBallots', 'invalidBallots', 'totalBallots')
addStatRow(root, 'Total ballots', {statistics, statistics2}, 'totalBallots', nil, nil, true)
addStatRow(root, 'Registered voters/Turnout', {statistics, statistics2}, 'eligibleVoters', 'totalBallots', 'eligibleVoters')
formatReferencesRow(root, references, electionQid, cols)
return rootSpan
end
--[[ Wrappers ]]
function p.ch_proportional(frame)
-- Initialise and populate variables
local getArgs = require("Module:Arguments").getArgs
local args = getArgs(frame)
return p._ch_proportional(args)
end
function p.ch_majoritarian(frame)
-- Initialize and populate variables
local getArgs = require("Module:Arguments").getArgs
local args = getArgs(frame)
return p._ch_majoritarian(args)
end
return p