Jump to content

Module:Population pyramid

From Wikipedia, the free encyclopedia

--
-- This module implements {{Population pyramid}}
--
local p = {}

local function get_values(val, total, rescale_flag)
	if ( rescale_flag ) then
		total =  (total > 0) and total or 1
		val = 100*(tonumber(val))/total
		local val_text = mw.ustring.format('%.2f', val)
		return val, val_text
	end

	return (tonumber(val or '0') or 0), (val or 'n/d')
end

-- this is the main function
function p.box(frame)
	local mArguments = require('Module:Arguments')
	local args = mArguments.getArgs(frame)

	-- create a sorted table of ages
	local ages = {}
	local max_pop, total_m, total_f = 0, 0, 0
	for k, v in pairs( args ) do
		local i = tonumber(tostring(k):match( '^%s*[mf]([%d]+)%s*$' ) or '-1')
		local mf = tostring(k):match( '^%s*([mf])[%d]+%s*$' ) or ''
		if ( i >= 0 and v ) then
			table.insert(ages, i)
			if ((tonumber(v) or 0) > max_pop) then
				max_pop = tonumber(v)
			end
			if ( mf == 'm' ) then
				total_m = total_m + (tonumber(v) or 0)
			elseif (mf == 'f') then
				total_f = total_f + (tonumber(v) or 0)
			end
		end
	end
	table.sort(ages)

	-- remove duplicates
	for k = 2,#ages do
		if ages[k] == ages[k-1] then
			table.remove(ages, k)
		end
	end

	-- compute the bar width
	local mmax = tonumber(args['mmax'] or '9') or 9
	if ( (args['mmax'] or '') == 'auto' and (max_pop > 0) ) then
		mmax = max_pop
	end
	local scale = tonumber(args['scale'] or '10') or 10
	local barmaxpx = mmax*scale

	local percent = ((args['percentage'] or '') == 'off') and '#' or '%'
	local rescale_values = ((args['percentage'] or '') == 'auto')
	
	-- create the inner table
	local root = mw.html.create('table')
		:css('width', '100%')
		:css('margin', '0')
	-- table header row
	local row = root:tag('tr')
	row:tag('th')
		:css('font-weight', 'normal')
		:css('text-align', 'right')
		:wikitext(percent)
	row:tag('th')
		:css('text-align', 'left')
		:css('font-weight', 'normal')
		:css('width', barmaxpx .. 'px')
		:wikitext('Males')
	row:tag('th')
		:css('font-weight', 'normal')
		:css('text-align', 'center')
		:wikitext('Age')
	row:tag('th')
		:css('font-weight', 'normal')
		:css('text-align', 'right')
		:css('width', barmaxpx .. 'px')
		:wikitext('Females')
	row:tag('th')
		:css('font-weight', 'normal')
		:css('text-align', 'left')
		:wikitext(percent)

	-- build the table starting from highest age group
	local prev_age = -1
	for k = #ages,1,-1 do
		local age = ages[k]
		local age_group = age .. '+'
		if (prev_age > 0) then
			age_group = age .. '–' .. (prev_age - 1)
		end
		local m, m_text = get_values(args['m' .. age], total_m, rescale_values)
		local f, f_text = get_values(args['f' .. age], total_f, rescale_values)
		row = root:tag('tr')
		row:tag('td')
			:css('font-size', 'x-small')
			:wikitext(m_text)
		row:tag('td')
			:css('text-align','right')
			:css('border-left', 'solid 1px silver')
			:css('border-right', 'solid 1px silver')
			:tag('div')
				:css('background', 'lightblue')
				:css('overflow', 'hidden')
				:css('margin-left', 'auto')
				:css('width', (m * scale) .. 'px')
				:wikitext(' ')
		row:tag('td')
			:css('font-size', 'x-small')
			:css('text-align', 'center')
			:css('white-space', 'nowrap')
			:wikitext(age_group)
		row:tag('td')
			:css('text-align','left')
			:css('border-left', 'solid 1px silver')
			:css('border-right', 'solid 1px silver')
			:tag('div')
				:css('background', 'pink')
				:css('overflow', 'hidden')
				:css('width', (f * scale) .. 'px')
				:wikitext(' ')
		row:tag('td')
			:css('font-size', 'x-small')
			:wikitext(f_text)
		prev_age = age
	end

	-- wrap the table in an infobox
	local year = args['year'] and ' <span style="font-weight:normal">' .. args['year'] .. '</span>' or '' 
	local below
	if (args['source'] or args['sourceref']) then
		below = '\'\'\'Source:\'\'\' '
		if args['source'] then
			below = below .. args['source']
		end
		if args['sourceref'] then
			below = below .. frame:extensionTag( {name='ref', content = args['sourceref']} )
		end
	end

	local infobox = require ('Module:Infobox').infobox
	return infobox({
		['abovestyle'] = 'text-align:center; font-size:100%; border-bottom:solid 1px silver;',
		['above'] = '[[Population pyramid]]' .. year,
		['datastyle'] = 'padding:0;',
		['belowstyle'] = below and 'text-align:left; font-weight:normal; font-size:100%; border-top:solid 1px silver;',
		['below'] = below,
		['data1'] = tostring(root)
	})
	
end

return p