Difference between revisions of "Module:Election box US auto"

From blackwiki
Jump to navigation Jump to search
blackwiki>Legoktm
(fix)
blackwiki>Legoktm
(implement join primary box if primary=yes. also smarter "gain" logic)
Line 1: Line 1:
 
local p = {}
 
local p = {}
 
local mError = require('Module:Error')
 
local mError = require('Module:Error')
 +
local mYesno = require('Module:Yesno')
 +
-- a global per #invoke
 +
local linked_write_in = false
  
 
function percent( part, total )
 
function percent( part, total )
Line 19: Line 22:
 
function p.make( frame )
 
function p.make( frame )
 
return frame:preprocess( make( frame:getParent() ) )
 
return frame:preprocess( make( frame:getParent() ) )
 +
end
 +
 +
function fmt_candidate(v, winner, total_votes,frame)
 +
local temp = "{{"
 +
if v[2] == winner[2] then
 +
temp = temp .. "Election box winning candidate"
 +
else
 +
temp = temp .. "Election box candidate"
 +
end
 +
local n_party = normalize_parties( v[3] )
 +
if n_party then
 +
temp = temp .. " with party link no change|party=" .. n_party
 +
else
 +
temp = temp .. " no party link no change"
 +
end
 +
link = frame.args[v[2] .. " link"]
 +
if link then
 +
link = mw.title.new(link)
 +
else
 +
-- bypass redirects, which is mostly important for display names
 +
link = mw.title.new(v[2])
 +
-- except if the redirect goes to an "elections" article (e.g. Kim Vann), then
 +
-- we don't want a bypass
 +
if link.isRedirect and not string.find(link.redirectTarget.prefixedText, "elections", 1, true ) then
 +
link = link.redirectTarget
 +
end
 +
end
 +
-- Strip disambiguators since we can't use the pipe trick
 +
display_name, ignore = mw.ustring.gsub(link.prefixedText, "%b()", "")
 +
if frame.args.redlinks or (link.exists and not link.isRedirect) then
 +
full_link = "[[" .. link.prefixedText .. "|" .. display_name .. "]]"
 +
else
 +
full_link = display_name
 +
end
 +
temp = temp .. "|candidate=" .. full_link
 +
if v[4] then
 +
-- incumbent
 +
temp  = temp .. " ([[incumbent]])"
 +
end
 +
if v[6] then
 +
-- write in
 +
if linked_write_in then
 +
temp = temp .. " (write-in)"
 +
else
 +
temp = temp .. " ([[Write-in candidate|write-in]])"
 +
linked_write_in = true -- only link it once
 +
end
 +
end
 +
temp = temp .. "|votes={{formatnum:" .. v[5] .. "}}"
 +
temp = temp .. "|percentage=" .. percent(v[5], total_votes) .. "%"
 +
temp = temp .. "}}"
 +
return temp
 
end
 
end
  
Line 42: Line 97:
 
end
 
end
 
end
 
end
local tab_name = state .. " Elections/" .. year .. "/" .. type .. "/Candidates.tab"
+
function load_tabular( state, year, type )
local tabular = mw.ext.data.get(tab_name)
+
local tab_name = state .. " Elections/" .. year .. "/" .. type .. "/Candidates.tab"
if not tabular then
+
local tabular = mw.ext.data.get(tab_name)
return mError.error({message="Unable to find tabular data: " .. tab_name})
+
if tabular then
 +
return tabular
 +
else
 +
return {error="Unable to find tabular data: " .. tab_name}
 +
end
 
end
 
end
local data = tabular.data
+
local tabular = load_tabular(state, year, type)
local candidates = {}
+
if tabular.error then
for k,v in pairs(data) do
+
return mError.error({message=tabular.error})
if v[1] == contest then
+
end
table.insert(candidates, v)
+
function find_candidates(data, contest)
 +
local candidates = {}
 +
for k,v in pairs(data) do
 +
if v[1] == contest then
 +
table.insert(candidates, v)
 +
end
 
end
 
end
 +
return candidates
 
end
 
end
local total_votes = 0
+
local candidates = find_candidates(tabular.data, contest)
local winner = {}
+
local incumb_party = false
winner[5] = 0
+
function sum_totals(candidates)
for k,v in pairs(candidates) do
+
local total_votes = 0
total_votes = total_votes + v[5]
+
local winner = {}
if v[5] > winner[5] then
+
winner[5] = 0
winner = v
+
for k,v in pairs(candidates) do
 +
total_votes = total_votes + v[5]
 +
if v[5] > winner[5] then
 +
winner = v
 +
end
 +
if v[4] then
 +
incumb_party = v[3]
 +
end
 
end
 
end
 +
return total_votes, winner
 
end
 
end
 +
local total_votes, winner = sum_totals(candidates)
 
if mw.ustring.find(contest, "United States Representative", 1, true) then
 
if mw.ustring.find(contest, "United States Representative", 1, true) then
 
title = "[[United States House of Representatives elections, " .. year .. "]]"
 
title = "[[United States House of Representatives elections, " .. year .. "]]"
 +
elseif mw.ustring.find(contest, "State Assembly Member", 1, true) then
 +
title = "[[" .. state .. " State Assembly election, " .. year .. "]]"
 
elseif contest == "President" then
 
elseif contest == "President" then
 
title = "U.S. presidential election in " .. state .. ", " .. year
 
title = "U.S. presidential election in " .. state .. ", " .. year
Line 70: Line 146:
 
title = "...????"
 
title = "...????"
 
end
 
end
local ret = "{{Election box begin no change| title=" .. title .. '<ref name="' .. tab_name .. '">' .. tabular.sources .. "</ref>}}"
+
local primary = mYesno(frame.args.primary)
 +
ptabular = load_tabular(state, year, "Primary")
 +
if ptabular.error then
 +
-- todo log an error here?
 +
primary = false
 +
end
 +
if primary then
 +
open = "Election box open primary begin no change"
 +
else
 +
open = "Election box begin no change"
 +
end
 +
function make_ref(tabular)
 +
return '<ref name="' .. tabular.description .. '">' .. tabular.sources .. "</ref>"
 +
end
 +
local ref = make_ref(tabular)
 +
if primary then
 +
-- primary ref goes first
 +
ref = make_ref(ptabular) .. ref
 +
end
 +
local ret = "{{" .. open .. "| title=" .. title .. ref .. "}}"
 +
function total_box(total_votes)
 +
return "{{Election box total no change|votes= {{formatnum:" .. total_votes .. "}}|percentage = " .. percent(total_votes, total_votes) .. "%}}"
 +
end
 
function sort_candidates(a,b)
 
function sort_candidates(a,b)
 
return a[5] > b[5]
 
return a[5] > b[5]
 
end
 
end
 
table.sort(candidates, sort_candidates)
 
table.sort(candidates, sort_candidates)
local linked_write_in = false
+
if primary then
 +
local pcandidates = find_candidates(ptabular.data, contest)
 +
table.sort(pcandidates, sort_candidates)
 +
local ptotal_votes, pwinner = sum_totals(pcandidates)
 +
local fake_winner = {}
 +
-- we don't want a winner in primaries, so use a fake one that no
 +
-- candidate will match
 +
fake_winner[2] = ""
 +
for k,v in pairs(pcandidates) do
 +
ret = ret .. fmt_candidate(v, fake_winner,ptotal_votes,frame)
 +
end
 +
ret = ret .. total_box(ptotal_votes) .. "{{Election box open primary general election no change}}"
 +
end
 +
 
 
for k,v in pairs(candidates) do
 
for k,v in pairs(candidates) do
local temp = "{{"
+
ret = ret .. fmt_candidate(v, winner,total_votes,frame)
if v[2] == winner[2] then
 
temp = temp .. "Election box winning candidate"
 
else
 
temp = temp .. "Election box candidate"
 
end
 
local n_party = normalize_parties( v[3] )
 
if n_party then
 
temp = temp .. " with party link no change|party=" .. n_party
 
else
 
temp = temp .. " no party link no change"
 
end
 
link = frame.args[v[2] .. " link"]
 
if link then
 
link = mw.title.new(link)
 
else
 
-- bypass redirects, which is mostly important for display names
 
link = mw.title.new(v[2])
 
-- except if the redirect goes to an "elections" article (e.g. Kim Vann), then
 
-- we don't want a bypass
 
if link.isRedirect and not string.find(link.redirectTarget.prefixedText, "elections", 1, true ) then
 
link = link.redirectTarget
 
end
 
end
 
-- Strip disambiguators since we can't use the pipe trick
 
display_name, ignore = mw.ustring.gsub(link.prefixedText, "%b()", "")
 
if frame.args.redlinks or (link.exists and not link.isRedirect) then
 
full_link = "[[" .. link.prefixedText .. "|" .. display_name .. "]]"
 
else
 
full_link = display_name
 
end
 
temp = temp .. "|candidate=" .. full_link
 
if v[4] then
 
-- incumbent
 
temp  = temp .. " ([[incumbent]])"
 
end
 
if v[6] then
 
-- write in
 
if linked_write_in then
 
temp = temp .. " (write-in)"
 
else
 
temp = temp .. " ([[Write-in candidate|write-in]])"
 
linked_write_in = true -- only link it once
 
end
 
end
 
temp = temp .. "|votes={{formatnum:" .. v[5] .. "}}"
 
temp = temp .. "|percentage=" .. percent(v[5], total_votes) .. "%"
 
temp = temp .. "}}"
 
ret = ret .. temp
 
 
end
 
end
ret = ret .. "{{Election box total no change|votes= {{formatnum:" .. total_votes .. "}}|percentage = " .. percent(total_votes, total_votes) .. "%}}"
+
ret = ret .. total_box(total_votes)
 
local hold = frame.args.hold
 
local hold = frame.args.hold
 
local gain = false
 
local gain = false
Line 145: Line 208:
 
win_party = normalize_parties(frame.args.gain)
 
win_party = normalize_parties(frame.args.gain)
 
lose_party = normalize_parties(frame.args.loser)
 
lose_party = normalize_parties(frame.args.loser)
 +
gain = true
 +
elseif incumb_party and incumb_party ~= winner[3] then
 +
win_party = normalize_parties(winner[3])
 +
lose_party = normalize_parties(incumb_party)
 
gain = true
 
gain = true
 
end
 
end

Revision as of 08:00, 12 November 2018

This is used by {{Election box US auto}}.

Usage

{{#invoke:Election box US auto|function_name}}


local p = {}
local mError = require('Module:Error')
local mYesno = require('Module:Yesno')
-- a global per #invoke 
local linked_write_in = false

function percent( part, total )
	if total >= 1000000 then
		-- if > 1 million votes, then round to 2 decimals
		round_to = 2
	else
		round_to = 1
	end
	local ret = mw.ext.ParserFunctions.expr( "" .. 100 * part / total .. " round " .. round_to )
	if not string.find( ret, ".", 1, true ) then
		-- add the decimals that expr doesn't
		ret = ret .. "." .. string.rep("0", round_to)
	end
	return ret
end

function p.make( frame )
	return frame:preprocess( make( frame:getParent() ) )
end

function fmt_candidate(v, winner, total_votes,frame)
	local temp = "{{"
	if v[2] == winner[2] then
		temp = temp .. "Election box winning candidate"
	else
		temp = temp .. "Election box candidate"
	end
	local n_party = normalize_parties( v[3] )
	if n_party then
		temp = temp .. " with party link no change|party=" .. n_party
	else
		temp = temp .. " no party link no change"
	end
	link = frame.args[v[2] .. " link"]
	if link then
		link = mw.title.new(link)
	else
		-- bypass redirects, which is mostly important for display names
		link = mw.title.new(v[2])
		-- except if the redirect goes to an "elections" article (e.g. Kim Vann), then
		-- we don't want a bypass
		if link.isRedirect and not string.find(link.redirectTarget.prefixedText, "elections", 1, true ) then
			link = link.redirectTarget
		end
	end
	-- Strip disambiguators since we can't use the pipe trick
	display_name, ignore = mw.ustring.gsub(link.prefixedText, "%b()", "")
	if frame.args.redlinks or (link.exists and not link.isRedirect) then
		full_link = "[[" .. link.prefixedText .. "|" .. display_name .. "]]"
	else
		full_link = display_name
	end
	temp = temp .. "|candidate=" .. full_link
	if v[4] then
		-- incumbent
		temp  = temp .. " ([[incumbent]])"
	end
	if v[6] then
		-- write in
		if linked_write_in then
			temp = temp .. " (write-in)"
		else
			temp = temp .. " ([[Write-in candidate|write-in]])"
			linked_write_in = true -- only link it once
		end
	end
	temp = temp .. "|votes={{formatnum:" .. v[5] .. "}}"
	temp = temp .. "|percentage=" .. percent(v[5], total_votes) .. "%"
	temp = temp .. "}}"
	return temp
end

function make( frame )
	local state = frame.args[1]
	if not state then
		return mError.error({message="State is missing"})
	end
	local year = frame.args[2]
	if not year then
		return mError.error({message="Year is missing"})
	end
	local contest = frame.args[3]
	if not contest then
		return mError.error({message="Contest is missing"})
	end
	local type = "General"
	if frame.args.type then
		if frame.args.type == "Primary" then
			type = "Primary"
		else
			return mError.error({message="Invalid value for |type="})
		end
	end
	function load_tabular( state, year, type )
		local tab_name = state .. " Elections/" .. year .. "/" .. type .. "/Candidates.tab"
		local tabular = mw.ext.data.get(tab_name)
		if tabular then
			return tabular
		else
			return {error="Unable to find tabular data: " .. tab_name}
		end
	end
	local tabular = load_tabular(state, year, type)
	if tabular.error then
		return mError.error({message=tabular.error})
	end
	function find_candidates(data, contest)
		local candidates = {}
		for k,v in pairs(data) do
			if v[1] == contest then
				table.insert(candidates, v)
			end
		end
		return candidates
	end
	local candidates = find_candidates(tabular.data, contest)
	local incumb_party = false
	function sum_totals(candidates)
		local total_votes = 0
		local winner = {}
		winner[5] = 0
		for k,v in pairs(candidates) do
			total_votes = total_votes + v[5]
			if v[5] > winner[5] then
				winner = v
			end
			if v[4] then
				incumb_party = v[3]
			end
		end
		return total_votes, winner
	end
	local total_votes, winner = sum_totals(candidates)
	if mw.ustring.find(contest, "United States Representative", 1, true) then
		title = "[[United States House of Representatives elections, " .. year .. "]]"
	elseif mw.ustring.find(contest, "State Assembly Member", 1, true) then
		title = "[[" .. state .. " State Assembly election, " .. year .. "]]"
	elseif contest == "President" then
		title = "U.S. presidential election in " .. state .. ", " .. year
	else
		title = "...????"
	end
	local primary = mYesno(frame.args.primary)
	ptabular = load_tabular(state, year, "Primary")
	if ptabular.error then
		-- todo log an error here?
		primary = false
	end
	if primary then
		open = "Election box open primary begin no change"
	else
		open = "Election box begin no change"
	end
	function make_ref(tabular)
		return '<ref name="' .. tabular.description .. '">' .. tabular.sources .. "</ref>"
	end
	local ref = make_ref(tabular)
	if primary then
		-- primary ref goes first
		ref = make_ref(ptabular) .. ref
	end
	local ret = "{{" .. open .. "| title=" .. title .. ref .. "}}"
	function total_box(total_votes)
		return "{{Election box total no change|votes= {{formatnum:" .. total_votes .. "}}|percentage = " .. percent(total_votes, total_votes) .. "%}}"
	end
	function sort_candidates(a,b)
		return a[5] > b[5]
	end
	table.sort(candidates, sort_candidates)
	if primary then
		local pcandidates = find_candidates(ptabular.data, contest)
		table.sort(pcandidates, sort_candidates)
		local ptotal_votes, pwinner = sum_totals(pcandidates)
		local fake_winner = {}
		-- we don't want a winner in primaries, so use a fake one that no
		-- candidate will match
		fake_winner[2] = ""
		for k,v in pairs(pcandidates) do
			ret = ret .. fmt_candidate(v, fake_winner,ptotal_votes,frame)
		end
		ret = ret .. total_box(ptotal_votes) .. "{{Election box open primary general election no change}}"
	end

	for k,v in pairs(candidates) do
		ret = ret .. fmt_candidate(v, winner,total_votes,frame)
	end
	ret = ret .. total_box(total_votes)
	local hold = frame.args.hold
	local gain = false
	if hold == "held" or winner[4] then
		ret = ret .. "{{Election box hold with party link without swing|winner=" .. normalize_parties(winner[3]) .. "}}"
	elseif hold == "flip" then
		-- shorthand for D->R/R->D
		win_party = winner[3]
		if win_party == "Democratic" then
			lose_party = normalize_parties("Republican")
		else
			lose_party = normalize_parties("Democratic")
		end
		win_party = normalize_parties(win_party)
		gain = true
	elseif frame.args.gain then
		win_party = normalize_parties(frame.args.gain)
		lose_party = normalize_parties(frame.args.loser)
		gain = true
	elseif incumb_party and incumb_party ~= winner[3] then
		win_party = normalize_parties(winner[3])
		lose_party = normalize_parties(incumb_party)
		gain = true
	end
	if gain then
		ret = ret .. "{{Election box gain with party link without swing|winner=" .. win_party .. "|loser=" .. lose_party .. "}}"
	end

	ret = ret .. "{{Election box end}}"
	return ret
end

function normalize_parties( party )
	-- Drop all parties after the first one?
	party = mw.text.split( party, ",", true )[1]
	local parties = {
		Democratic = "Democratic Party (United States)",
		Republican = "Republican Party (United States)",
		Blank = "Independent (politician)",
		Independent = "Independent (politician)",
		Libertarian = "Libertarian Party (United States)",
		Green = "Green Party (United States)",
	}
	parties["Peace and Freedom"] = "Peace and Freedom Party"
	parties["No Party Preference"] = "No party preference"
	
	for k, v in pairs(parties) do
		if k == party then
			return v
		end
	end
	-- not found, return false
	return false
end

return p