Module:Historical populations
| This Lua module is used on approximately 61,000 pages and changes may be widely noticed. Test changes in the module's /sandbox or /testcases subpages, or in your own module sandbox. Consider discussing changes on the talk page before implementing them. |
| This module uses TemplateStyles: |
This module implements {{historical populations}}. Please see the template page for documentation.
--
-- This template implements {{Historical populations}}
--
local p = {}
local lang = mw.getContentLanguage()
local 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 false
end
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, ''
end
end
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 num
end
-- this function creates an array with the {year, population, percent change}
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 = '[[' .. tostring(yearnum) .. ' United States census|' .. year .. ']]'
elseif( ifexist(tostring(yearnum) .. ' United States census') ) then
year = '[[' .. tostring(yearnum) .. ' United States census|' .. 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 {year, formatnum(pop) .. popref, percent }
end
-- this function creates an array with table header labels
local function getheadrow(percentages, popname, yearname, percentname)
-- year cell
if(yearname == '') then
yearname = 'Year'
end
-- population cell
if(popname == '') then
popname = '<abbr title="Population" class="abbr-header">Pop.</abbr>'
end
-- percentages cell
if( percentages ~= 'off' and percentname == '') then
if( percentages == 'pagr' ) then
percentname = '<abbr title="Per annum growth rate" class="abbr-header">±% p.a.</abbr>'
elseif( percentages == 'monthly' ) then
percentname = '<abbr title="Per month growth rate" class="abbr-header">±% p.m.</abbr>'
else
percentname = '<abbr title="Percent change" class="abbr-header">±%</abbr>'
end
end
return {yearname, popname, percentname}
end
local function rendergraph(frame, data, gwidth, gheight, gthumb, gtype)
-- find some data limits
local minyear, maxyear, maxpop = 999999, 0, 0
local years = {}
local pops = {}
for i = 1, #data do
local year,pop = data[i][1], data[i][2]
-- delink if necessary
if year:match('^%s*%[%[[^%[%]]*%|([^%[%]]*)%]%]') then
year = year:match('^%s*%[%[[^%[%]]*%|([^%[%]]*)%]%]')
end
year = year:match('^%s*([%d][%d]*).-$')
year = formatnumR(year)
pop = formatnumR(pop)
if ( year and pop ) then
table.insert(years, year)
table.insert(pops, pop)
minyear = (year < minyear) and year or minyear
maxyear = (year > maxyear) and year or maxyear
maxpop = (pop > maxpop) and pop or maxpop
end
end
local logbound = 10^(math.floor(math.log(maxpop)/math.log(10)+1))
local scalemajor = logbound/10
local scaleminor = scalemajor/2
maxpop = scaleminor*(math.floor(maxpop/scaleminor + 1))
local timeline = {
'Colors=',
' id:lightgrey value:gray(0.9)',
' id:darkgrey value:gray(0.3)',
' id:sfondo value:rgb(1,1,1)',
' id:barra value:rgb(0.664, 0.664, 0.930)', -- dark lavender
'',
'ImageSize = width:' .. tostring(gwidth) .. ' height:' .. tostring(gheight),
'PlotArea = left:44 bottom:27 top:20 right:10',
'DateFormat = x.y',
'Period = from:0 till:' .. tostring(maxpop),
'TimeAxis = orientation:vertical',
'AlignBars = justify',
'ScaleMajor = gridcolor:darkgrey increment:' .. tostring(scalemajor) .. ' start:0',
'ScaleMinor = gridcolor:lightgrey increment:' .. tostring(scaleminor) .. ' start:0',
'BackgroundColors = canvas:sfondo',
'TextData =',
' pos:(' .. tostring(math.floor(gwidth/2)) .. ',20) textcolor:black fontsize:M',
' text:"year"',
' pos:(' .. tostring(math.floor(gwidth/2)-15) .. ',' .. tostring(gheight+2) .. ') textcolor:black fontsize:M',
' text:"population"',
'BarData='
}
local yearlabels = math.max(math.floor(gwidth/60), 1)
local yearscale = math.max(math.floor((maxyear - minyear)/yearlabels),1)
yearscale = 5*math.max(math.floor(yearscale / 5), 1)
local barwidth = math.min(math.max(math.floor(gwidth/((maxyear - minyear)*0.5)), 2),5)
minyear = yearscale*math.floor(minyear/yearscale)
maxyear = yearscale*math.ceil(maxyear/yearscale)
for year = minyear,maxyear do
local text = ( (year % yearscale) == 0) and ' text:' .. year or ''
table.insert(timeline, ' bar:' .. year .. text)
end
table.insert(timeline,'\nPlotData=\n color:barra width:' .. barwidth .. ' align:left\n')
for i = 1, #years do
local year = years[i]
local pop = pops[i]
table.insert(timeline, ' bar:' .. year .. ' from: 0 till:' .. pop)
end
local timeline = frame:extensionTag{ name = 'timeline', content = '\n' .. table.concat(timeline,'\n') .. '\n' }
local graph = mw.html.create('div')
if ( gthumb == '' ) then
graph
:addClass('center')
:wikitext(timeline)
else
graph:addClass('thumb')
if ( gthumb == 'left' ) then
graph:addClass('floatleft')
elseif( gthumb == 'right' ) then
graph:addClass('floatright')
else
graph:addClass('tnone')
:css('margin-left', 'auto')
:css('margin-right', 'auto')
:css('clear', 'both')
end
graph:tag('div')
:addClass('thumbinner')
:css('width', tostring(gwidth + 2) .. 'px')
:css('max-width', tostring(gwidth + 2) .. 'px')
:css('height', tostring(gheight + 2) .. 'px')
:css('max-height', tostring(gheight + 2) .. 'px')
:wikitext(timeline)
end
return tostring(graph)
end
-- this function renders the population table in a vertical format
local 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 var(--color-base, #000000)')
: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
if( cols <= 1) then
local caption = root:tag('caption')
caption
:css('padding', '0.25em')
:css('font-weight', 'bold')
:attr('class', 'caption-purple')
:wikitext(title)
end
if( cols > 1) then
local caption = root:tag('td')
caption
:css('padding', '0.25em')
:css('font-weight', 'bold')
:attr('colspan', cols)
divcaption = caption:tag('div')
divcaption
:css('margin', '-0.65em -0.565em 0 -0.565em')
:css('border-left', '0')
:css('border-right', '0')
:css('text-align', 'center')
:css('padding', '0.3em 0')
:attr('class', 'caption-purple')
:wikitext(title)
root:attr('role', 'presentation')
end
-- 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 var(--color-base, #000000)')
: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:css('vertical-align', '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 var(--color-base, #000000)')
: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 var(--color-base, #000000)')
:css('font-size', '85%')
:css('text-align', alignfn)
:wikitext(footnote)
end
if((graphpos == 'right' or graphpos == 'r') and graph ~= '') then
root = mw.html.create('table')
:tag('tr')
:css('vertical-align', 'top')
:tag('td')
:wikitext(tostring(root))
:done()
:tag('td')
:wikitext(graph)
:done()
:done()
:done()
graph = ''
end
if((graphpos == 'left' or graphpos == 'l') and graph ~= '') then
root = mw.html.create('table')
:tag('tr')
:css('vertical-align', 'top')
:tag('td')
:wikitext(graph)
:done()
:tag('td')
:wikitext(tostring(root))
:done()
:done()
:done()
graph = ''
end
return graph .. tostring(root)
end
-- this function renders the population table in a horizontal format
local 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 var(--color-base, #000000)')
: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 var(--color-base, #000000)')
: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 var(--color-base, #000000)')
:css('font-size', '85%')
:css('text-align', alignfn)
:attr('colspan', colsperrow + 1)
:wikitext(footnote)
end
return graph .. tostring(root)
end
-- this is the main function
function p.poptable(frame)
local raw_data = {}
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 datapage = args['data'] or ''
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 'table-pale'
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 .. '<br/>'
end
end
footnote = footnote .. source
-- setup the data header cols/rows
local head = getheadrow(percentages, popname, yearname, percentname)
-- counts for the total number of population rows
local argcount = 0
local rowcount = 0
if ( not isempty(datapage) ) then
-- load external data page from commons if it is specified
local external_data = mw.ext.data.get(datapage).data
for _, v in ipairs(external_data) do
table.insert(raw_data, tostring(v[1])) -- year
table.insert(raw_data, tostring(v[2])) -- population
rowcount = rowcount + 1
argcount = argcount + 2
end
if ( footnote ~= '' ) then
footnote = footnote .. '<br />'
end
footnote = footnote .. '[[:commons:Data:' .. datapage .. '|Source data]]'
else
-- load data from the args instead
for k, v in pairs( args ) do
if ( type( k ) == 'number' and k >= 1 and math.floor(k) == k ) then
raw_data[k] = v
if ( not isempty(args[k]) ) then
argcount = (k > argcount) and k or argcount
if( math.fmod(k - 1, 2) == 0 ) then
rowcount = rowcount + 1
end
end
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"))
for r = 1,rowcount do
-- skip blank rows
while(isempty(raw_data[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(raw_data[offset], raw_data[offset + 1] or '', pyear, ppop,
linktype, percentages, current_year) )
pyear = raw_data[offset]
ppop = raw_data[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 math.floor(math.max(math.min(220, rowcount*5), 800))
local gheight= tonumber(graphheight) or 180
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 (200 * cols)
local gheight= tonumber(graphheight) or 180
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
Content Disclaimer
Informasi ini disarikan dari Wikipedia dan disajikan kembali untuk tujuan edukasi. Konten tersedia di bawah lisensi CC BY-SA 3.0. Kami tidak bertanggung jawab atas ketidakakuratan data yang bersumber dari kontribusi publik tersebut.
- The information displayed on this website is sourced in part or in whole from Wikipedia and has been adapted for the purpose of restating it. We strive to provide accurate and relevant information, however:
- There is no guarantee of absolute accuracy. Wikipedia is an open, collaborative project that can be edited by anyone, so information is subject to change.
- It is not intended to constitute professional advice. The content displayed is for informational and educational purposes only. For important decisions (e.g., medical, legal, or financial), please consult a professional.
- Content copyright. Wikipedia is licensed under the Creative Commons Attribution-ShareAlike License (CC BY-SA). This means that content may be reused with appropriate attribution and shared under a similar license.
- Responsible use. Any risk arising from the use of information from this website is entirely the responsibility of the user.