local p =
function p.test(frame) local lang = mw.getContentLanguage local frame = mw.getCurrentFrame
local frozenset, set = unpack(require('Module:Lua set')) local fs = frozenset local s = set s.add(true) s.add(false) s.add(fs)
--local conc = for k in pairs(t) do conc = conc .. k end
return tostring(fs) .. ' ' .. tostring(s)end
local getArgs = require('Module:Arguments').getArgslocal yesno = require('Module:Yesno')local BarBox
local language = 'en' -- local default language
local i18n = require("Module:Medical cases chart/i18n")[language]
local function is(v) return (v or ) ~= end
function p._barColors(n) local colors =
return colors[n]end
function p._legend0(args) return '
' .. '' .. ' ' .. '' .. ' ' .. (args[2] or ) .. ''endfunction p._customBarStacked(args) local 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
local width1 = 3.5 local width2 = 3.5 local width3, width4 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
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 = '(=)' 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
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 = false 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].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, '\n'), 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 navbar = require('Module:Navbar')._navbar
local barargs =
local function _numwidth(p) local nw = mw.ustring.sub(args.numwidth or ,p,p) if nw
't' then return 40 elseif nw
'w' then return 70 elseif nw
'd' then return 55 end
return 0 end
local numwidth = 120 local right1 = numwidth - 8 -- -8 because of padding if args.numwidth then numwidth = _numwidth(1) + 10 + _numwidth(2) if mw.ustring.len(args.numwidth)
'n' then numwidth = numwidth + 6 else numwidth = numwidth + 10 end end
right1 = _numwidth(1) + 2 + _numwidth(2) if not args.right2 and mw.ustring.len(args.numwidth)
'n' then numwidth = numwidth + 6 else numwidth = numwidth + 10 end end end
local barwidth = 280
if args.barwidth
'medium' then barwidth = 280 elseif args.barwidth
'auto' then barwidth = 'auto' end
if tonumber(barwidth) then barargs.width = 85 + barwidth + numwidth .. 'px' barargs.barwidth = barwidth .. 'px' else barargs.width = 'auto' barargs.barwidth = 'auto' end barargs.lineheight = args.rowheight
barargs.float = args.float and args.float or 'right' 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' -- get duration for toggles local duration = 15 -- default if manual togglesbar is last 15 days if yesno(args.collapsible)
true then togglesbar = is(args.togglesbar) and args.togglesbar or end 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.duration = duration if is(args.togglesbar) then buildargs.nooverlap = false else buildargs.nooverlap = nooverlap end local monthList 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 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.title = table.concat(title) barargs.left1 = '
' .. -- 85-8 because of padding "" .. i18n.date .. "" .. '
'
barargs.right1 = '
' .. "" .. (args.right1 or i18n.noOfCases) .. "" .. '
'
if args.right2 then local right2 = _numwidth(3) + _numwidth(4) if mw.ustring.sub(args.numwidth,3,3)
barargs.right2 = '
' .. "" .. args.right2 .. "" .. '
' end
barargs.footer = args.caption barargs.css = 'Module:Medical_cases_chart/styles.css' local box = BarBox.create(barargs) return tostring(box)end
function p.chart(frame) BarBox = unpack(require('Module:Bar box')) local args = getArgs(frame,) return p._chart(args)end
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