local getArgs = require('Module:Arguments').getArgslocal yesno = require('Module:Yesno')local barBox = require('Module:Bar box')
local language = 'en-US' -- local default language
local i18n = require("Module:Medical cases chart/i18n")[language]local navbar = require('Module:Navbar')._navbar
local function is(v) return (v or ) ~= end
local p =
function p._barColors(n) local colors =
return colors[n]end
function p._legend0(args) return '
' .. '' .. ' ' .. '' .. ' ' .. (args[2] or ) .. ''endfunction p._customBarStacked(args) barargs = barargs[1] = args[1]
local function _numwidth(nw) if nw
't' then return 2.45 elseif nw
'w' then return 4.55 elseif nw
'd' then return 3.5 end
return 3.5 end
width1 = 3.5 width2 = 3.5 if is(args.numwidth) then width1 = _numwidth(mw.ustring.sub(args.numwidth,1,1)) width2 = _numwidth(mw.ustring.sub(args.numwidth,2,2)) width3 = _numwidth(mw.ustring.sub(args.numwidth,3,3)) width4 = _numwidth(mw.ustring.sub(args.numwidth,4,4)) end
barargs[2] = '
' .. (args[7] or ) .. '' .. '' .. (args[8] or ) .. ''if mw.ustring.len(args.numwidth)
'n' then padding = '0' end
barargs.note2 = '
' .. (args[9] or ) .. '' .. '' .. (args[10] or ) .. '' endfor i=1,5 do barargs[2*i + 1] = p._barColors(i) barargs[2*i + 2] = (tonumber(args[i+1]) or 0)/(tonumber(args.divisor) or 1) barargs['title' .. i] = args[i+1] end
barargs.align = 'cdcc' barargs.collapsed = args.collapsed barargs.id = args.id barargs.rowstyle = is(tonumber(args.rowheight)) and ('line-height:'..args.rowheight..';') or nil
return barBox._stacked(barargs)end
function p._row(args) local barargs = local rowDate = args.prevDate or
if is(args[1]) then if pcall(function mw.getContentLanguage:formatDate(, args[1]) end) then barargs[1] = args[1] rowDate = args[1] else barargs[1] = '' .. i18n.invalidTime .. '' end else barargs[1] = '⋮' end barargs[1] = barargs[1] .. (args['note0'] or )
barargs[2] = args[2] or 0 barargs[3] = args[3] or 0
if is(args['alttot1']) then barargs[4] = args['alttot1'] elseif args[4] then barargs[4] = (tonumber(args[4]) or 0) - (tonumber(barargs[2]) or 0) - (tonumber(barargs[3]) or 0) else barargs[4] = 0 end
barargs[5] = args[5] or 0
if is(args['alttot2']) then barargs[6] = args['alttot2'] elseif args[6] then barargs[6] = (tonumber(args[6]) or 0) - (tonumber(barargs[2]) or 0) - (tonumber(barargs[3]) or 0) else barargs[6] = 0 end
barargs[7] = args[7] or
local function changeArg(firstright, valuecol, changecol) local change = if yesno(args['firstright' .. firstright])
false or not is(args['firstright' .. firstright]) then if not is(args[1]) and is(args[valuecol]) then change = '(' .. i18n['='] .. ')' else change = is(args[changecol]) and '(' .. args[changecol] .. ')' or end end change = change .. (args['note' .. firstright] or )
return change end
barargs[8] = changeArg(1,7,8) barargs[9] = args[9] or barargs[10] = changeArg(2,9,10)
barargs.divisor = args.divisor or 1 barargs.numwidth = args.numwidth barargs.rowheight = args.rowheight
if yesno(args.collapsible)
if args.id then barargs.id = args.id elseif args.nooverlap and args.rowsToEnd < duration then barargs.id = 'l' .. duration else barargs.id = mw.ustring.lower(mw.getLanguage('en'):formatDate('M', rowDate)) if args.rowsToEnd < duration then barargs.id = barargs.id .. '-l' .. duration end end else barargs.collapsed = barargs.id = end
return p._customBarStacked(barargs)end
function p._buildBars(args) local lines = mw.text.split(args.data, '\n') local frame = mw.getCurrentFrame local lang = mw.getContentLanguage
local bars, rows, months, prevRow, maxparam =,,, , 1 for k, line in pairs(lines) do local barargs, i =, 1 for parameter in mw.text.gsplit(line, ';') do parameter = mw.text.trim(parameter) if string.find(parameter, '^%a') then parameter = mw.text.split(parameter, '=') if parameter[1]
'alttot2' then parameter[2] = tonumber(frame:callParserFunction('#expr', parameter[2])) if is(parameter[2]) then maxparam = math.max(maxparam, parameter[2]) end end barargs[parameter[1]] = parameter[2] else if is(parameter) then if i >= 2 and i <= 6 then parameter = tonumber(frame:callParserFunction('#expr', frame:callParserFunction('formatnum',parameter,'R'))) maxparam = math.max(maxparam, parameter or 1) end barargs[i] = parameter if i
9 then parameter = tonumber(mw.ustring.match(frame:callParserFunction('formatnum',parameter,'R'), '^%d*')) maxparam = math.max(maxparam, parameter or 1) end end i = i + 1 end end
local function fillCols(col, change) local data = args['right' .. col .. 'data'] local changetype = args['changetype' .. col] local value, num, prevnum
if data
'alttot2' then num = tonumber(barargs.alttot2 or barargs[6]) prevnum = tonumber(prevRow.alttot2 or prevRow[6]) elseif is(data) then num = tonumber(barargs[tonumber(data) + 1]) prevnum = tonumber(prevRow[tonumber(data) + 1]) end
if is(data) and num then -- nothing in column, source found, and data exists value = changetype
'a' then -- change type is "absolute" if change > 0 then change = '+' .. lang:formatNum(change) end else -- change type is "percent", "only percent" or undefined local percent = 100 * change / prevnum -- calculate percent local rounding = math.abs(percent) >= 10 and "%.0f" or math.abs(percent) >= 1 and "%.1f" or "%.2f" percent = tonumber(mw.ustring.format(rounding, percent)) -- round to two sigfigs if percent > 0 then change = '+' .. lang:formatNum(percent) .. '%' elseif percent < 0 then change = lang:formatNum(percent) .. '%' else change = i18n['='] end end else -- data has not changed since previous row change = i18n['='] end else -- no data on previous row barargs['firstright' .. col] = true -- set to (n.a.) end end end
return value, change end
if not is(barargs[7]) then barargs[7], barargs[8] = fillCols(1, barargs[8]) end if not is(barargs[9]) then barargs[9], barargs[10] = fillCols(2, barargs[10]) end if is(barargs[1]) then local e,f,g = pcall(function return mw.getLanguage('en'):formatDate('M',barargs[1]), mw.getLanguage('en'):formatDate('j',barargs[1]) end ) if e then months[#months+1] = end end barargs.prevDate = prevRow[1] rows[#rows + 1] = barargs prevRow = barargs end
for i=1,#rows do -- build rows rows[i].divisor = tonumber(args.divisor) and tonumber(args.divisor) or maxparam / (0.95 * args.barwidth) rows[i].numwidth = args.numwidth rows[i].collapsible = args.collapsible rows[i].rowsToEnd = #rows - i rows[i].rowheight = args.rowheight rows[i].duration = args.duration if #months>(args.duration or 0) then rows[i].nooverlap = args.nooverlap end bars[i] = p._row(rows[i]) end return table.concat(bars), monthsend
function p._monthToggleButton(args) local month = mw.ustring.lower(mw.ustring.sub(args.month[1] or ,1,3)) local outString = local newline = (args.nonewline or false) and or '\n' if is(month) then local collapsed = (args.active
) and ' mw-collapsed' or if args.nooverlap then outString = '
%s\n' .. '%s' .. newline if mw.ustring.sub(month,1,1)args.duration then --"Last ## days" local lastDays = mw.ustring.format(i18n.lastDays, args.duration) outString = mw.ustring.format(outString, collapsed, lastDays, uncollapsed, lastDays) else if i18n.m[month] then if is(args.month[2]) and is(args.month[3]) then if (args.month[2] ~= args.month[3]) then -- "Mmm ##–##" month = mw.ustring.gsub(i18n.toggleRange,'$.',) else -- "Mmm ##"" month = mw.ustring.gsub(i18n.toggleSingleDate,'$.',) end else --"Mmm" month = i18n.m[month] end end outString = mw.ustring.format(outString, uncollapsed, month, collapsed, month) end elseif mw.ustring.sub(month,1,1)
args.duration then local customtoggles = for k in pairs(i18n.m) do --list of months customtoggles[#customtoggles + 1] = ' mw-customtoggle-' .. k .. '-l' .. args.duration end local lastDays = mw.ustring.format(i18n.lastDays, args.duration) outString = '
' .. lastDays .. '\n' .. '' .. lastDays .. '' .. newline else local customtoggles = ' mw-customtoggle-' .. month .. ' mw-customtoggle-' .. month .. '-l' .. args.duration outString = '' .. (i18n.m[month] or month) .. '\n' .. '' .. (i18n.m[month] or month) .. '' .. newline end end return outStringendfunction p._chart(args)
local barargs =
-- mappings and defaults moved to _getChartPams local numwidth = args.numwidthwidth local right1 = args.right1width local right2 = args.right2width local barwidth = args.barwidth barargs.width = args.sTotalWidth barargs.barwidth = args.sBarWidth barargs.float = args.float local duration = args.nDuration
local months, togglesbar, lastdate =, , nil if args.rows then barargs.bars = args.rows togglesbar = yesno(args.collapsible) and (args.togglesbar or ) or nil elseif is(args.data) or is(args.datapage) then local buildargs = local nooverlap = yesno(args.nooverlap) buildargs.barwidth = tonumber(barwidth) or 280 buildargs.data = is(args.datapage) and require('Module:Medical cases chart/data')._externalData(args) or args.data buildargs.divisor = args.divisor buildargs.numwidth = args.numwidth buildargs.collapsible = args.collapsible buildargs.right1data = args.right1data or -- if no right1data and right1 title is default, use 3rd classification not args.right1 and 3 buildargs.right2data = args.right2data or -- if no right2data and right2 title is deaths, use 1st classification (args.right2
i18n.noOfDeaths2) and 1 --buildargs.changetype1 = mw.ustring.sub(args.changetype1 or (args.changetype or ),1,1) -- 1st letter --buildargs.changetype2 = mw.ustring.sub(args.changetype2 or (args.changetype or ),1,1) -- 1st letter buildargs.changetype1 = args.changetype1 buildargs.changetype2 = args.changetype2 buildargs.rowheight = args.rowheight buildargs.duration = duration if is(args.togglesbar) then buildargs.nooverlap = false else buildargs.nooverlap = nooverlap end barargs.bars, monthList = p._buildBars(buildargs) local lastRow = #monthList if nooverlap
for i=1,(lastRow) do -- deduplicate months if monthList[i][1] ~= months[#months][1] then --new month if #months > 1 and i > 1 then months[#months][3] = monthList[i-1][2] --store end of previous month end months[#months+1] = monthList[i] --store start of this month end end months[#months][3] = monthList[lastRow][2] --store end of final month -- automatically generate toggles if yesno(args.collapsible)
\n' .. table.concat(toggles) .. '
' end end end local location = mw.ustring.gsub(args.location, 'the ', ) location = mw.ustring.upper(mw.ustring.sub(location,1,1)) .. mw.ustring.sub(location,2)
local navbartitle = args.outbreak .. ' data/' .. (args.location3 and args.location3 .. '/' or ) .. (args.location2 and args.location2 .. '/' or ) .. location .. ' medical cases chart'
local title = title[1] = (args.pretitle and args.pretitle .. ' ' or ) .. args.disease .. ' ' .. i18n.casesIn .. ' ' .. args.location .. (args.location2 and ', ' .. args.location2 or ) .. (args.location3 and ', ' .. args.location3 or ) .. (args.posttitle and ' ' .. args.posttitle or ) .. '
(' .. navbar .. ')barargs.left1 = '
' .. -- 85-8 because of padding "" .. i18n.date .. "" .. '
'
barargs.right1 = '
' .. "" .. (args.right1 or i18n.noOfCases) .. "" .. '
'
if args.right2 then barargs.right2 = '
' .. "" .. args.right2 .. "" .. '
' end
barargs.caption = args.caption barargs.css = 'Template:Medical_cases_chart/styles.css' return barBox._box(barargs)end
function p.chart(frame) local tRawPams = getArgs(frame)
local tChartPams = p._getChartPams(tRawPams) --local tRawRows, tChartPams = p._getChartPams(tRawPams) --local tBoxPams = p._getBoxPams(tRawPams)
--tBoxPams.bars = p._getDataRows(tRawRows, tChartPams)
--return barBox._box(tBoxPams)
return p._chart(tChartPams)end
function p._getChartPams(tRawPams) --local tRawRows = tRawPams.data
--local tChartPams =
-- numwidth local sNumwidthLower = tRawPams.numwidth and mw.ustring.lower(tRawPams.numwidth) or nil local tNumWidthMap = local function _numwidth(p) local nw = mw.ustring.sub(sNumwidthLower or ,p,p) return tNumWidthMap[nw] or 0 end local numwidth = 120 local right1 = numwidth - 8 -- -8 because of padding if sNumwidthLower then numwidth = _numwidth(1) + 10 + _numwidth(2) if mw.ustring.len(sNumwidthLower)
'n' then numwidth = numwidth + 6 else numwidth = numwidth + 10 end end right1 = _numwidth(1) + 2 + _numwidth(2) if not tRawPams.right2 and mw.ustring.len(sNumwidthLower)
'n' then numwidth = numwidth + 6 else numwidth = numwidth + 10 end end end tRawPams.numwidthwidth = numwidth tRawPams.right1width = right1 if tRawPams.right2 then local right2 = _numwidth(3) + _numwidth(4) if mw.ustring.sub(tRawPams.numwidth,3,3)
-- recoveries, defaults to true for undefined or unrecognised values tRawPams.recoveries = not (yesno(tRawPams.recoveries)
-- changetype[|1|2] local sChangeType = tRawPams.changetype and mw.ustring.lower(mw.ustring.sub(tRawPams.changetype, 1, 1)) or tRawPams.changetype1 = tRawPams.changetype1 and mw.ustring.lower(mw.ustring.sub(tRawPams.changetype1, 1, 1)) or sChangeType tRawPams.changetype2 = tRawPams.changetype2 and mw.ustring.lower(mw.ustring.sub(tRawPams.changetype2, 1, 1)) or sChangeType
-- float tRawPams.float = tRawPams.float or 'right'
-- duration (togglesbar) local bCanSetDur = yesno(tRawPams.collapsible) and not tRawPams.togglesbar tRawPams.nDuration = bCanSetDur and tonumber(tRawPams.duration) or 15
--return tRawRows, tChartPams return tRawPamsend
function p.barColors(frame) return p._barColors(tonumber(frame:getParent.args[1]))end
function p.buildBars(frame) local bars = p._buildBars(frame.args) return barsend
function p.monthToggleButton(frame) local args = args.month = args.active = frame:getParent.args.active or 'true' args.duration = frame:getParent.args.duration or 15 args.nonewline = true return p._monthToggleButton(args)end
return p