Module:Historical populations/sandbox explained

---- This template implements --local p = local lang = mw.getContentLanguagelocal Date -- lazy initialization

local function ifexist(page) if not page then return false end if mw.title.new(page).exists then return true end return falseend

local function isempty(s) return not s or s:match('^%s*(.-)%s*$')

end

local function splitnumandref(s) s = s:match('^%s*(.-)%s*$') local t1 = mw.text.unstrip(s) local t2 = s:match('^([%d][%d,]*)') if(t1

t2) then local t3 = s:match('^[%d][%d,]*(.-)$') return t1, t3 else return s, endend

local function formatnumR(num) return tonumber(lang:parseFormattedNumber(num))end

local function formatnum(num) return lang:parseFormattedNumber(num) and lang:formatNum(lang:parseFormattedNumber(num)) or numend

-- this function creates an array with the local function getpoprow(year, popstr, pyear, ppopstr, linktype, percentages, current_year) local pop, popref = splitnumandref(popstr or ) local ppop, ppopref = splitnumandref(ppopstr or ) local percent = local yearnum = formatnumR(mw.ustring.gsub(year or , '^%s*([%d][%d][%.%d]+).*$', '%1') or ) local pyearnum = formatnumR(mw.ustring.gsub(pyear or , '^%s*([%d][%d][%.%d]+).*$', '%1') or ) local popnum = formatnumR(pop) local ppopnum = formatnumR(ppop) if(linktype

'US' or linktype

'USA') then if((yearnum or 0) >= 1790 and yearnum <= current_year and math.fmod(math.floor(yearnum), 10)

0) then if(yearnum < current_year) then year = '' .. year .. '' elseif(ifexist(tostring(yearnum) .. ' United States census')) then year = '' .. year .. '' end end end if(percentages ~= 'off') then local pstr = '—    ' if(popnum ~= nil and ppopnum ~= nil and (ppopnum > 0)) then if(percentages

'pagr') then pstr = mw.ustring.format('%.2f', 100*math.abs(math.pow(popnum/ppopnum,1/(yearnum-pyearnum)) - 1)) elseif(percentages

'monthly') then if Date

nil then Date = require('Module:Date')._Date end local date1 = Date(year) local date2 = Date(pyear) local diff = date1 - date2 local months = (diff.age_days/(365.25/12)) pstr = mw.ustring.format('%.2f', 100*math.abs(math.pow(popnum/ppopnum,1/months) - 1)) else pstr = mw.ustring.format('%.1f', 100*math.abs(popnum/ppopnum - 1)) end if(popnum < ppopnum) then pstr = '−' .. pstr .. '%' else pstr = '+' .. pstr .. '%' end elseif(popnum ~= nil and ppopnum ~= nil and (ppopnum

popnum)) then pstr = mw.ustring.format('%.2f', 0) .. '%' end percent = pstr end -- strip the fractional part of the year, if there is one year = mw.ustring.gsub(year or , '^%s*([%d][%d][%d]+)%.[%d]*', '%1') return end

-- this function creates an array with table header labelslocal function getheadrow(percentages, popname, yearname, percentname) -- year cell if(yearname

) then yearname = 'Year' end -- population cell if(popname

) then popname = 'Pop.' end

-- percentages cell if(percentages ~= 'off' and percentname

) then if(percentages

'pagr') then percentname = '±% p.a.' elseif(percentages

'monthly') then percentname = '±% p.m.' else percentname = '±%' end end return end

-- this function builds the json for the population graphlocal function graphjson(data, gwidth, gheight, gtype) local yearcount = #data local graphargs = local firstpoint = true for offset = 1,yearcount do local x,y = data[offset][1], data[offset][2] -- delink if necessary if x:match('^%s*%[%[[^%[%]]*%|([^%[%]]*)%]%]') then x = x:match('^%s*%[%[[^%[%]]*%|([^%[%]]*)%]%]') end y = formatnumR(y) if x and y then graphargs['x'] = graphargs['x'] .. (firstpoint and or ', ') .. x graphargs['y'] = graphargs['y'] .. (firstpoint and or ', ') .. y firstpoint = false end end local Graph = require('Module:Graph') return Graph.chartend

local function rendergraph(frame, data, gwidth, gheight, gthumb, gtype) local graph = frame:extensionTag

if(gthumb ~= ) then local graphdiv = mw.html.create('div') :addClass('thumb') :addClass(gthumb

'right' and 'tright' or 'tleft') :css('clear', 'none') graphdiv :tag('div') :addClass('thumbinner') :wikitext(graph) return tostring(graphdiv) end return '

' .. graph .. '

'end

-- this function renders the population table in a vertical formatlocal function rendervertical(data, head, title, footnote, alignfn, class, style, width, shading, percol, cols, graphpos, graph) -- define a couple helper functions local function addrowcell(trow, tag, text, align, shading, style) cell = trow:tag(tag) cell :css('text-align', align) :css('padding', '1px') :wikitext(text) :css('border-bottom', shading ~= 'off' and '1px solid #bbbbbb' or nil) :cssText(style) end local function addheadcell(trow, text, align, width, pad) cell = trow:tag('th') cell :css('border-bottom', '1px solid black') :css('padding', pad and ('1px ' .. pad) or '1px') :css('text-align', align) :css('width', width) :wikitext(text) end

local colspan = 3 local yearcount = #data local argcount = 2*yearcount if(isempty(width)) then width = '15em' end -- override the value of cols if percol has been specified if(percol > 0) then cols = math.floor((yearcount - 1) / percol) + 1 end -- compute the number of rows per col local rowspercol = math.floor((yearcount - 1) / cols) + 1

-- specify the colspan for the title and footer lines if(cols > 1) then colspan = cols else if (head[3]

) then colspan = 2 else colspan = 3 end end

-- compute outer table width local twidth = width if((cols > 1) and width:match('^%s*[%d]+[%w]+%s*$')) then local widthnum = mw.ustring.gsub(width, '^%s*([%d]+)([%w]+)%s*$', '%1') local widthunit = mw.ustring.gsub(width, '^%s*([%d]+)([%w]+)%s*$', '%2') twidth = tostring(widthnum*cols) .. widthunit end -- create the outer table local root = mw.html.create('table') root :addClass(class) :css('width', twidth) :css('border-top-width', '0') :cssText(style['table']) -- add title local caption = root:tag('caption') caption :css('border-top', '1px #aaa solid') :css('border-left', '1px #aaa solid') :css('border-right', '1px #aaa solid') :css('background-color', 'lavender') :css('padding', '0.25em') :css('font-weight', 'bold') :wikitext(title) -- add the graph line (if top graph) if((graphpos

'top' or graphpos

't') and graph ~= ) then row = root:tag('tr') cell = row:tag('td') cell :attr('colspan', colspan) :css('border-bottom', '1px solid black') :wikitext(graph) graph = end -- loop over columns and rows within columns local offset = 1 local t = root for c = 1,cols do -- add inner tables if we are rendering more than one column if(cols > 1) then if (c

1) then row = root:tag('tr') row:attr('valign', 'top') cell = row:tag('td') cell:css('padding', '0 0.5em') else cell = row:tag('td') cell :css('padding', '0 0.5em') :css('border-left', 'solid 1px #aaa') end t = cell:tag('table') t :css('border-spacing', '0') :css('width', width) end -- start column headers local hrow = t:tag('tr') hrow:css('font-size', '95%') -- year header addheadcell(hrow, head[1], nil, head[3] ~= and '3em' or 'auto', nil, nil) -- population header addheadcell(hrow, head[2], 'right', nil, '2px') -- percentages header if(head[3] ~= ) then addheadcell(hrow, head[3], 'right', nil, nil) end -- end column headers -- start population rows for r = 1,rowspercol do -- generate the row if we have not exceeded the rowcount -- shade every fifth row, unless shading = off local s = 'off' if(math.fmod((c - 1)*rowspercol + r, 5)

0 and r ~= rowspercol) then s = shading end if(offset <= yearcount) then -- start population row local prow = t:tag('tr') -- year cell addrowcell(prow, 'th', data[offset][1], 'center', s, style['year']) -- population cell addrowcell(prow, 'td', data[offset][2], 'right', s, style['pop']) -- percentage cell if(not isempty(head[3])) then addrowcell(prow, 'td', data[offset][3], 'right', s, style['pct']) end -- end population row offset = offset + 1 end end end

-- add the graph line (if bottom graph) if((graphpos

'bottom' or graphpos

'b') and graph ~= ) then row = root:tag('tr') cell = row:tag('td') cell :attr('colspan', colspan) :css('border-top', '1px solid black') :wikitext(graph) graph = end -- add the footnote line if(footnote ~= ) then row = root:tag('tr') cell = row:tag('td') cell :attr('colspan', colspan) :css('border-top', '1px solid black') :css('font-size', '85%') :css('text-align', alignfn) :wikitext(footnote) end return graph .. tostring(root)end

-- this function renders the population table in a horizontal formatlocal function renderhorizontal(data, head, title, footnote, alignfn, class, style, width, shading, perrow, rows, graphpos, graph) local row local cell local yearcount = #data local argcount = 2*yearcount -- override the value of rows if perrow has been specified if(perrow > 0) then rows = math.floor((yearcount - 1) / perrow) + 1 end -- compute the number of cols per row local colsperrow = math.floor((yearcount - 1) / rows) + 1

-- create the outer table local root = mw.html.create('table') root :addClass(class) :css('font-size', '90%') :cssText(style['table']) -- create title row row = root:tag('tr') cell = row:tag('th') cell :css('padding', '0.25em') :attr('colspan', colsperrow + 1) :wikitext(title)

-- add the graph line (if top graph) if((graphpos

'top' or graphpos

't') and graph ~= ) then row = root:tag('tr') cell = row:tag('td') cell :attr('colspan', colsperrow + 1) :css('border-bottom', '1px solid black') :wikitext(graph) graph = end

-- loop over rows and columns within rows local offset = 1 for r = 1,rows do local rowoffset = offset -- render the years row = root:tag('tr') cell = row:tag('th') cell:wikitext(head[1]) :css('border-top', r > 1 and '2px solid #000' or nil) for c = 1,colsperrow do cell = row:tag('td') if(offset <= yearcount) then cell:wikitext(data[offset][1]) :css('text-align', 'center') :css('border-top', r > 1 and '2px solid #000' or nil) :cssText(style['year']) else cell:css('border-width', r > 1 and '2px 0 0 0' or 0) :css('border-top', r > 1 and '2px solid #000' or nil) end offset = offset + 1 end -- render the pop offset = rowoffset row = root:tag('tr') cell = row:tag('th') cell:wikitext(head[2]) for c = 1,colsperrow do cell = row:tag('td') if(offset <= yearcount) then cell:wikitext(data[offset][2]) :css('text-align', 'right') :css('padding-right', '2px') :cssText(style['pop']) else cell:css('border-width', 0) end offset = offset + 1 end -- render the percentages if(head[3] ~= ) then offset = rowoffset row = root:tag('tr') cell = row:tag('th') cell:wikitext(head[3]) for c = 1,colsperrow do cell = row:tag('td') if(offset <= yearcount) then cell:wikitext(data[offset][3]) :css('text-align', 'right') :css('padding-right', '2px') :cssText(style['pct']) else cell:css('border-width', 0) end offset = offset + 1 end end end -- add the graph line (if bottom graph) if((graphpos

'bottom' or graphpos

'b') and graph ~= ) then row = root:tag('tr') cell = row:tag('td') cell :attr('colspan', colsperrow + 1) :css('border-top', '1px solid black') :wikitext(graph) graph = end -- add the footnote line if(footnote ~= ) then row = root:tag('tr') cell = row:tag('td') cell :css('border-top', '2px solid black') :css('font-size', '85%') :css('text-align', alignfn) :attr('colspan', colsperrow + 1) :wikitext(footnote) end return graph .. tostring(root)end

-- this is the main functionfunction p.poptable(frame) local data = local style = local args = frame.args[1] and frame.args or frame:getParent.args

local title = args['title'] or local align = args['align'] or local clear = args['clear'] or local direction = args['direction'] or local percentages = args['percentages'] or local state = args['state'] or local linktype = args['type'] or local shading = args['shading'] or 'on' local width = args['width'] or local subbox = args['subbox'] or local popname = args['pop_name'] or local yearname = args['year_name'] or local percentname = args['percent_name'] or local footnote = args['footnote'] or local alignfn = args['align-fn'] or local source = args['source'] or local graphpos = args['graph-pos'] or local graphwidth = args['graph-width'] or local graphheight = args['graph-height'] or local graphtype = args['graph-type'] or 'line' local percol = tonumber(args['percol']) or 0 local cols = tonumber(args['cols']) or 1 local perrow = tonumber(args['perrow']) or 0 local rows = tonumber(args['rows']) or 1 style['year'] = args['year_style'] style['pop'] = args['pop_style'] style['pct'] = args['pct_style']

-- setup classes and styling for outer table local class = direction

'horizontal' and 'wikitable' or 'toccolours' if(state

'collapsed') then class = class .. ' collapsible collapsed' end

if(isempty(title)) then title = 'Historical population' end

if(isempty(align)) then align = direction ~= 'horizontal' and 'right' or 'center' end if(isempty(alignfn)) then alignfn = 'left' end if(isempty(clear)) then clear = align

'center' and or align end local margin = '0.5em 0 1em 0.5em' if(align

'left') then margin = '0.5em 1em 0.5em 0' elseif(align

'none') then margin = '0.5em 1em 0.5em 0' elseif(align

'center') then margin = '0.5em auto' align = end

if(isempty(subbox)) then style['table'] = 'border-spacing: 0;' .. (align ~= and 'float:' .. align .. ';' or ) .. (clear ~= and 'clear:' .. clear .. ';' or ) .. 'margin:' .. margin .. ';' else style['table'] = 'margin:0;' .. 'border-collapse:collapse;' .. 'border:none;' end style['table'] = style['table'] .. (args['table_style'] or ) -- setup the footer text if(source ~= ) then source = 'Source: ' .. source if(footnote ~= ) then footnote = footnote .. '
' end end footnote = footnote .. source -- setup the data header cols/rows local head = getheadrow(percentages, popname, yearname, percentname) -- count the total number of population rows local argcount = 0 local rowcount = 0 for k, v in pairs(args) do if ((type(k)

'number') and (not isempty(args[k]))) then if(k >= 1 and math.floor(k)

k and k > argcount) then argcount = k end if(math.fmod(k - 1, 2)

0) then rowcount = rowcount + 1 end end end

-- here is where we build all the data for the table -- loop over columns and rows within columns local pyear = local ppop = local offset = 1 local current_year = tonumber(os.date("%Y", os.time)) for r = 1,rowcount do -- skip blank rows while(isempty(args[offset]) and offset <= argcount) do offset = offset + 2 end -- generate the row if we have not exceeded the rowcount if(offset <= argcount) then table.insert(data, getpoprow(args[offset], args[offset + 1] or , pyear, ppop, linktype, percentages, current_year)) pyear = args[offset] ppop = args[offset+1] or offset = offset + 2 end end

local graph = graphpos = graphpos:lower -- now that we have the data for the table, render it in the requested format

if (direction

'horizontal') then if graphpos ~= then local gwidth = tonumber(graphwidth) or 200 local gheight= tonumber(graphheight) or 170 local gthumb = (graphpos

'r' or graphpos

'right' and 'right') or (graphpos

'l' or graphpos

'left' and 'left') or graph = rendergraph(frame, data, gwidth, gheight, gthumb, graphtype) end return renderhorizontal(data, head, title, footnote, alignfn, class, style, width, shading, perrow, rows, graphpos, graph) else if graphpos ~= then local gwidth = tonumber(graphwidth) or (170 * cols) local gheight= tonumber(graphheight) or 170 local gthumb = (graphpos

'r' or graphpos

'right' and 'right') or (graphpos

'l' or graphpos

'left' and 'left') or graph = rendergraph(frame, data, gwidth, gheight, gthumb, graphtype) end return rendervertical(data, head, title, footnote, alignfn, class, style, width, shading, percol, cols, graphpos, graph) end

end

return p