Module:Medical cases chart explained

local yesno = require('Module:Yesno')local BarBox = unpack(require('Module:Bar'))

local lang = mw.getContentLanguagelocal language = lang:getCodelocal i18n = require('Module:Medical cases chart/i18n')[language]assert(i18n, 'no chart translations to: ' .. mw.language.fetchLanguageName(language, 'en'))local monthAbbrs = for i = 1, 12 do monthAbbrs[i] = lang:formatDate('M', '2020-' .. ('%02d'):format(i))end

local p =

function p._findIntervalRow(tRows, nTime, nTol, bAll) -- Loop backwards in tRows, assuming it to have monotonically increasing nDate entries in forward order. -- The first row with nDate within nTime +-nTol is returned. -- If nDate table entry is nil, the row will be skipped. -- If moving backwards a time stamp is found dating back to before tolerance window, nil is returned. -- If the end of tRows is reached without a match for the tolerance window, also nil is returned. -- With bAll present and true all rows back to the specified time window will be returned, or all rows back to -- the first row, that does not lie beyond nTime +-nTol if no match was found. local tRet = nil if bAll then tRet = end for nRowNum = #tRows, 1,-1 do if tRows[nRowNum] and tRows[nRowNum].nDate then local nDiff = nTime - tRows[nRowNum].nDate if nDiff > -nTol then if nDiff < nTol then if bAll then tRet[#tRet + 1] = tRows[nRowNum] return tRet else return tRows[nRowNum] end else return bAll and tRet or nil end end end if bAll then tRet[#tRet + 1] = tRows[nRowNum] end end --return tRows[nRowNum] return nilend

function p._toggleButton(active, customtoggles, id, label) local on = active and or ' mw-collapsed' local off = active and ' mw-collapsed' or local outString = '

' .. label .. '' .. '' .. label .. '' return outStringend

function p._yearToggleButton(year) return p._toggleButton(year.l, ' mw-customtoggle-' .. year.year, year.year, year.year)end

function p._monthToggleButton(year, month) local lmon, label = lang:lc(month.mon), month.mon local id = (year or ) .. lmon local customtoggles = ' mw-customtoggle-' .. id

if month.s then label = label .. ' ' .. month.s -- "Mmm ##" if month.s ~= month.e then -- "Mmm ##–##" label = label .. '–' .. month.e end else customtoggles = customtoggles .. (month.l and customtoggles .. month.l or ) end

for i, combination in ipairs(month.combinations) do customtoggles = customtoggles .. ' mw-customtoggle-' .. combination -- up to 2 combinations per month so no need to table.concat end

return p._toggleButton(false, customtoggles, id, label)end

function p._lastXToggleButton(years, duration, combinationsL) local months, id = years[#years].months, 'l' .. duration local i, customtoggles = #months,

if #years > 1 then local year = years[#years].year while months[i].l do customtoggles[#customtoggles+1] = ' mw-customtoggle-' .. year .. lang:lc(months[i].mon) .. '-' .. id if i

1 then if year

years[#years].year then year = years[#years-1].year months = years[#years-1].months i = #months else -- either first month is also lastX month or lastX spans more than 2 years, which is not intended yet break end else i = i - 1 end end else while i > 0 and months[i].l do customtoggles[#customtoggles+1] = ' mw-customtoggle-' .. lang:lc(months[i].mon) .. '-' .. id i = i - 1 end end

for i, combinationL in ipairs(combinationsL) do customtoggles[#customtoggles+1] = ' mw-customtoggle-' .. combinationL -- up to 3 combinationsL in 90 days end

return p._toggleButton(true, table.concat(customtoggles), id, mw.ustring.format(i18n.lastXDays, duration))end

function p._buildTogglesBar(dateList, duration, nooverlap) local years = local months, combinationsL = years[1].months,

local function addMonth(month) if month.mon ~= months[#months].mon then -- new month if month.year ~= years[#years].year then -- new year years[#years+1] = months = years[#years].months -- switch months list end months[#months+1] = end end for i = 2, #dateList do -- deduplicate years and months if #dateList[i]

0 then -- specific date addMonth(dateList[i]) months[#months].l = months[#months].l or dateList[i].l -- so that both ...-mon and ...-mon-lX classes are created elseif #dateList[i]

1 then -- interval within month addMonth(dateList[i][1]) months[#months].l = months[#months].l or dateList[i].l else -- multimonth interval for j, month in ipairs(dateList[i]) do addMonth(month) months[#months].combinations[#months[#months].combinations+1] = dateList[i].id end combinationsL[#combinationsL+1] = dateList[i].id:find('-l%d+$') and dateList[i].id end end

if nooverlap then local lastDate = dateList[#dateList] months[#months].e = tonumber(os.date('%d', lastDate.nDate or lastDate.nEndDate or lastDate.nAltEndDate)) -- end of final month

local i = #dateList repeat i = i - 1 until i

0 or (dateList[i].mon or dateList[i][1].mon) ~= months[#months].mon if i

0 then -- start of first and final month months[#months].s = tonumber(os.date('%d', dateList[1].nDate)) else months[#months].s = 1 end end

years[#years].l = true -- to activate toggle and respective months bar

local monthToggles, divs =, nil if #years > 1 then local yearToggles, monthsDivs =, for i, year in ipairs(years) do yearToggles[#yearToggles+1] = p._yearToggleButton(year) monthToggles = months = year.months for j, month in ipairs(months) do monthToggles[#monthToggles+1] = p._monthToggleButton(year.year, month) end monthsDivs[#monthsDivs+1] = '

' .. table.concat(monthToggles) .. '

' end divs = '

' .. table.concat(yearToggles) .. '

' .. table.concat(monthsDivs) else for i, month in ipairs(months) do monthToggles[#monthToggles+1] = p._monthToggleButton(nil, month) end divs = '

' .. table.concat(monthToggles) .. '

' end divs = divs .. '

' .. p._lastXToggleButton(years, duration, combinationsL) .. '

' return '

' .. divs .. '

'end

local numwidth =

local bkgClasses =

function p._customBarStacked(args) local barargs =

barargs[1] = args[1]

local function _numwidth(i) return args.numwidth:sub(i,i) end

if args[7] or args[8] then -- is it acceptable to have one and not the other? barargs[2] = '

' .. (args[7] or ) .. '' .. '' .. (args[8] or ) .. '' end if #args.numwidth

4 then barargs.note2 = (args[9] or args[10]) and (args.numwidth:sub(3,3) ~= 'n' and '

' .. (args[9] or ) .. '' or ) .. '' .. (args[10] or ) .. '' or end

for i = 1, 5 do barargs[i+2] = args[i+1] / args.divisor barargs['title' .. i] = args[i+1] end

barargs.align = 'cdcc' barargs.bkgclasses = bkgClasses barargs.collapsed = args.collapsed barargs.id = args.id

return BarBox.stacked(barargs)end

function p._row(args) local barargs =

barargs[1] = (args[1] or '⋮') .. (args.note0 or ) barargs[2] = args[2] or 0 barargs[3] = args[3] or 0

if args['alttot1'] then barargs[4] = args['alttot1'] elseif args[4] then barargs[4] = (args[4] or 0) - (barargs[2] or 0) - (barargs[3] or 0) else barargs[4] = 0 end

barargs[5] = args[5] or 0

if args['alttot2'] then barargs[6] = args['alttot2'] elseif args[6] then barargs[6] = (args[6] or 0) - (barargs[2] or 0) - (barargs[3] or 0) else barargs[6] = 0 end

barargs[7] = args[7]

local function changeArg(firstright, valuecol, changecol) local change = if args['firstright' .. firstright] then change = '(' .. i18n.na .. ')' elseif not args[1] and args[valuecol] then change = '(=)' else change = args[changecol] and '(' .. args[changecol] .. ')' or end change = change .. (args['note' .. firstright] or )

return change ~= and change end

barargs[8] = changeArg(1, 7, 8) barargs[9] = args[9] barargs[10] = changeArg(2, 9, 10)

barargs.divisor = args.divisor barargs.numwidth = args.numwidth

local dates if args.collapsible then local duration = args.duration if args.daysToEnd >= duration then barargs.collapsed = true else barargs.collapsed = false end

if args.nooverlap and args.daysToEnd < duration then barargs.id = 'l' .. duration elseif args.nDate then dates = barargs.id = (args.multiyear and dates.year or ) .. lang:lc(dates.mon) .. (dates.l or ) else local id, y, m, ey, em =, tonumber(os.date('%Y', args.nStartDate or args.nAltStartDate)), tonumber(os.date('%m', args.nStartDate or args.nAltStartDate)), tonumber(os.date('%Y', args.nEndDate or args.nAltEndDate)), tonumber(os.date('%m', args.nEndDate or args.nAltEndDate)) dates =

repeat id[#id+1] = (args.multiyear and y or ) .. lang:lc(monthAbbrs[m]) dates[#dates+1] = y = y + math.floor(m / 12) m = m % 12 + 1 until y

ey and m > em or y > ey

dates.l = args.daysToEnd < duration and '-l' .. duration id = table.concat(id, '-') .. (dates.l or ) barargs.id = id dates.id = id end else barargs.collapsed = false end

return p._customBarStacked(barargs), datesend

function p._buildBars(args) local frame = mw.getCurrentFrame local updatePeriod = 86400 -- temporary implementation only supports daily updates

local function getUnix(timestamp) return lang:formatDate('U', timestamp) end -- some info for changetype 'w' local sChngTp1 = args.changetype1 local sChngTp2 = args.changetype2 local xData1Key = args.right1data or 3 local xData2Key = args.right2data or 1 xData1Key = (type(xData1Key)

"number") and (xData1Key+1) or xData1Key xData2Key = (type(xData2Key)

"number") and (xData2Key+1) or xData2Key local nPop = not (args.population

nil) and tonumber(args.population) or nil local bIsW1 = sChngTp1

'w' and nPop local bIsW2 = sChngTp2

'w' and nPop

local rows, prevRow, tStats =,, local nData1Diff1Max, nData1Diff1MaxDate, nData2Diff1Max, nData2Diff1MaxDate local nData1i7Max, nData1i7MaxDate, nData2i7Max, nData2i7MaxDate for line in mw.text.gsplit(args.data, '\n') do local i, barargs = 1, -- line parameter parsing, basic type/missing value handling for parameter in mw.text.gsplit(line, ';') do if parameter:find('^%s*%a') then parameter = mw.text.split(parameter, '=') parameter[1] = mw.text.trim(parameter[1]) if parameter[1]:find('^alttot') then parameter[2] = tonumber(frame:callParserFunction('#expr', parameter[2])) else parameter[2] = mw.text.trim(parameter[2]) if parameter[1]:find('^firstright') then parameter[2] = yesno(parameter[2]) elseif parameter[2]

then parameter[2] = nil end end barargs[parameter[1]] = parameter[2] else parameter = mw.text.trim(parameter) if parameter ~= then if i >= 2 and i <= 6 then parameter = tonumber(frame:callParserFunction('#expr', parameter)) if not parameter then error(('Data parameters 2 to 6 must not be formatted. i=%d, line=%s'):format(i, line)) end end barargs[i] = parameter end i = i + 1 end end

local bValid, nDateDiff -- get relevant date info based on previous row if barargs[1] then bValid, barargs.nDate = pcall(getUnix, barargs[1]) assert(bValid, 'invalid date "' .. barargs[1] .. '"') if prevRow.nDate or prevRow.nEndDate then nDateDiff = barargs.nDate - (prevRow.nDate or prevRow.nEndDate) if nDateDiff > updatePeriod then if nDateDiff

2 * updatePeriod then prevRow = prevRow[1] = os.date('%Y-%m-%d', prevRow.nDate) else prevRow = end rows[#rows+1] = prevRow end else prevRow.nEndDate = barargs.nDate - updatePeriod if prevRow.nStartDate

prevRow.nEndDate then prevRow.nDate = prevRow.nEndDate prevRow[1] = os.date('%Y-%m-%d', prevRow.nDate) -- as nAltStartDate assumes a minimal multiday interval, it's possible for it to be greater if a true previous span is 1 day elseif prevRow.nAltStartDate and prevRow.nAltStartDate >= prevRow.nEndDate then error('a row in a consecutive intervals group is 1 day long and misses the date parameter') end end else if barargs.enddate then bValid, barargs.nEndDate = pcall(getUnix, barargs.enddate) assert(bValid, 'invalid enddate "' .. barargs.enddate .. '"') end if prevRow.nDate or prevRow.nEndDate then barargs.nStartDate = (prevRow.nDate or prevRow.nEndDate) + updatePeriod if barargs.nStartDate

barargs.nEndDate then barargs.nDate = barargs.nEndDate barargs[1] = os.date('%Y-%m-%d', barargs.nDate) end else prevRow.nAltEndDate = (prevRow.nStartDate or prevRow.nAltStartDate) + updatePeriod barargs.nAltStartDate = prevRow.nAltEndDate + updatePeriod if barargs.nEndDate and barargs.nAltStartDate >= barargs.nEndDate then error('a row in a consecutive intervals group is 1 day long and misses the date parameter') end end end

-- update tStats if at least one column changetype is 'w' local tBarStats = nil if barargs[1] and (bIsW1 or bIsW2) then bValid, barargs.nDate = pcall(getUnix, barargs[1]) assert(bValid, 'invalid date "' .. barargs[1] .. '"') barargs.nDate = tonumber(barargs.nDate) tBarStats = local tBarStats1 = tStats[barargs.nDate-86400] -- previous days info local tBarStats7 = tStats[barargs.nDate-604800] -- 7 days before info local tBarStats14 = tStats[barargs.nDate-1209600] -- 14 days before info local nData1 = barargs[xData1Key] or barargs[4] local nData2 = barargs[xData2Key] or barargs[2] -- local nData1Diff1Max, nData1Diff1MaxDate, nData12Diff1Max, nData2Diff1MaxDate-- local nData1i7Max, nData1i7MaxDate, nData12i7Max, nData2i7MaxDate

if bIsW1 and nData1 then tBarStats.nData1 = nData1 -- if stats exist from day before if not (tBarStats1

nil) and not (tBarStats1.nData1

nil) then tBarStats.nData1Diff1 = nData1 - tBarStats1.nData1 if nData1Diff1Max

nil or nData1Diff1Max < tBarStats.nData1Diff1 then nData1Diff1Max = tBarStats.nData1Diff1 nData1Diff1MaxDate = barargs[1] end end -- if stats exist from 7 days before if not (tBarStats7

nil) then if not (tBarStats7.nData1

nil) then tBarStats.nData1Diff7 = nData1 - tBarStats7.nData1 if nData1i7Max

nil or nData1i7Max < tBarStats.nData1Diff7/nPop*100000 then nData1i7Max = tBarStats.nData1Diff7/nPop*100000 nData1i7MaxDate = barargs[1] end end if not (tBarStats7.nData1Diff1

nil) then tBarStats.nData1P7Diff1 = tBarStats7.nData1Diff1 end end -- if stats exist from 14 days before if not (tBarStats14

nil) then if not (tBarStats14.nData1

nil) then tBarStats.nData1Diff14 = nData1 - tBarStats14.nData1 end if not (tBarStats14.nData1Diff1

nil) then tBarStats.nData1P14Diff1 = tBarStats14.nData1Diff1 end end end if bIsW2 and nData2 then tBarStats.nData2 = nData2 -- if stats exist from day before if not (tBarStats1

nil) and not (tBarStats1.nData2

nil) then tBarStats.nData2Diff1 = nData2 - tBarStats1.nData2 if nData2Diff1Max

nil or nData2Diff1Max < tBarStats.nData2Diff1 then nData2Diff1Max = tBarStats.nData2Diff1 nData2Diff1MaxDate = barargs[1] end end -- if stats exist from 7 days before if not (tBarStats7

nil) then if not (tBarStats7.nData2

nil) then tBarStats.nData2Diff7 = nData2 - tBarStats7.nData2 if nData2i7Max

nil or nData2i7Max < tBarStats.nData2Diff7/nPop*100000 then nData2i7Max = tBarStats.nData2Diff7/nPop*100000 nData2i7MaxDate = barargs[1] end end if not (tBarStats7.nData2Diff1

nil) then tBarStats.nData2P7Diff1 = tBarStats7.nData2Diff1 end end -- if stats exist from 14 days before if not (tBarStats14

nil) then if not (tBarStats14.nData2

nil) then tBarStats.nData2Diff14 = nData2 - tBarStats14.nData2 end if not (tBarStats14.nData2Diff1

nil) then tBarStats.nData2P14Diff1 = tBarStats14.nData2Diff1 end end end tStats[barargs.nDate] = tBarStats end

local function fillCols(col, change) local data = args['right' .. col .. 'data'] local changetype = args['changetype' .. col] local value, num, prevnum

if data

'alttot1' then num = barargs.alttot1 or barargs[4] prevnum = prevRow.alttot1 or prevRow[4] elseif data

'alttot2' then num = barargs.alttot2 or barargs[6] prevnum = prevRow.alttot2 or prevRow[6] elseif data then num = barargs[data+1] prevnum = prevRow[data+1] end

-- changetype w if not (tBarStats

nil) and not (tBarStats["nData"..col]

nil) then local nDiff7 = tBarStats["nData"..col.."Diff7"] local sChngCmt = "" if col

1 and not (nData1i7Max

nil) then sChngCmt = "all time high: " .. mw.ustring.format('%.1f', nData1i7Max) .. " on " .. nData1i7MaxDate elseif col

2 and not (nData2i7Max

nil) then sChngCmt = "all time high: " .. mw.ustring.format('%.1f', nData2i7Max) .. " on " .. nData2i7MaxDate end if nDiff7

nil then change = i18n.na else change = '

' .. tostring(mw.ustring.format('%.1f', nDiff7/args.population*100000)) .. '' end local nValue = tBarStats["nData"..col] local nDiff1 = tBarStats["nData"..col.."Diff1"] local nP7Diff1 = tBarStats["nData"..col.."P7Diff1"] local nP14Diff1 = tBarStats["nData"..col.."P14Diff1"] local sCmnt if nDiff1

nil then sCmnt = "" else sCmnt = "daily change: +" .. lang:formatNum(nDiff1) end if not (nP7Diff1

nil) and not (sCmnt

"") then sCmnt = sCmnt .. ", 7 days before: +" .. lang:formatNum(nP7Diff1) end if not (nP14Diff1

nil) and not (sCmnt

"") then sCmnt = sCmnt .. ", 14 days before: +" .. lang:formatNum(nP14Diff1) end if col

1 and not (nData1Diff1Max

nil) and not (sCmnt

"") then sCmnt = sCmnt .. ", all-time high: +" .. lang:formatNum(nData1Diff1Max) .. " on " .. nData1Diff1MaxDate end if col

2 and not (nData2Diff1Max

nil) and not (sCmnt

"") then sCmnt = sCmnt .. ", all-time high: +" .. lang:formatNum(nData2Diff1Max) .. " on " .. nData2Diff1MaxDate end value = '

' .. lang:formatNum(nValue) .. '' elseif data and num then -- nothing in column, source found, and data exists value = changetype

'o' and or lang:formatNum(num) -- set value to num if changetype isn't 'o' if not change and not barargs['firstright' .. col] then if prevnum and prevnum ~= 0 then -- data on previous row if num - prevnum ~= 0 then --data has changed since previous row local nChange = num - prevnum if changetype

'a' then -- change type is "absolute" if nChange > 0 then change = '+' .. lang:formatNum(nChange) end elseif changetype

'w' and args.population then -- changetype

'r' or -- change type is "r"(olling average over 7 days period) or "w"(eekly incidence per 100.000 pop) if barargs.nDate and rows then -- find data row from 7 days before +- 1 hour local tIntervRow = p._findIntervalRow(rows, barargs.nDate-7*24*3600, 3600, false) local tPrevDayRow = p._findIntervalRow(rows, barargs.nDate-24*3600, 3600, false) if tIntervRow then local nDatCol = (col

1) and 4 or 2 local nDiff = tIntervRow[nDatCol] and (num - tIntervRow[nDatCol]) or nil if changetype

'r' then change = nDiff and ('

r7: ' .. tostring(mw.ustring.format('%.0f', nDiff/7)) .. '') or i18n.na else change = nDiff and ('' .. tostring(mw.ustring.format('%.1f', nDiff/args.population*100000)) .. '') or i18n.na if tPrevDayRow and tPrevDayRow[nDatCol] then value = '' .. value .. '' end end else change = i18n.na end else change = i18n.na end

else -- change type is "percent", "only percent" or undefined local percent = 100 * nChange / prevnum -- calculate percent local rounding = math.abs(percent) >= 10 and '%.0f' or math.abs(percent) >= 1 and '%.1f' or '%.2f' percent = tonumber(rounding:format(percent)) -- round to two sigfigs

if percent > 0 then change = '+' .. lang:formatNum(percent) .. '%' elseif percent < 0 then change = lang:formatNum(percent) .. '%' else change = '=' end end else -- data has not changed since previous row change = '=' end else -- no data on previous row barargs['firstright' .. col] = true -- set to (n.a.) end end end

return value, change end

if not barargs[7] then barargs[7], barargs[8] = fillCols(1, barargs[8]) end if not barargs[9] then barargs[9], barargs[10] = fillCols(2, barargs[10]) end

rows[#rows+1] = barargs prevRow = barargs end

--error(mw.dumpObject(tStats))

-- calculate and pass repetitive (except daysToEnd) parameters to each row local lastRow = rows[#rows] local total = total[3] = lastRow.alttot1 or lastRow[4] and lastRow[4] - total[1] - total[2] or 0 total[5] = lastRow.alttot2 or lastRow[6] and lastRow[6] - total[1] - total[2] or 0 local divisor = (total[1] + total[2] + total[3] + total[4] + total[5]) / (args.barwidth - 5) --should be -3 if borders didn't go inward local firstDate, lastDate = rows[1].nDate, lastRow.nDate or lastRow.nEndDate local multiyear = os.date('%Y', firstDate) ~= os.date('%Y', lastDate - (args.nooverlap and args.duration * 86400 or 0)) if args.collapsible ~= false then args.collapsible = (lastDate - firstDate) / 86400 >= args.duration end

local bars, dateList =, for i, row in ipairs(rows) do -- build rows row.divisor = divisor row.numwidth = args.numwidth row.collapsible = args.collapsible row.duration = args.duration row.nooverlap = args.nooverlap row.daysToEnd = (lastDate - (row.nDate or row.nEndDate or row.nAltEndDate)) / 86400 row.multiyear = multiyear

bars[#bars+1], dateList[#dateList+1] = p._row(row) end

return table.concat(bars, '\n'), dateListend

p._barColors =

function p._legend0(args) return '

' .. '' .. '    ' .. '' .. ' ' .. (args[2] or ) .. ''end

function p._chart(args) for key, value in pairs(args) do if [key:gsub('%d', '')] then args[key] = value:lower end end

local barargs =

barargs.css = 'Module:Medical cases chart/styles.css' barargs.float = args.float or 'right'

args.barwidth = args.barwidth or 'medium' local barwidth if args.barwidth

'thin' then barwidth = 120 elseif args.barwidth

'medium' then barwidth = 280 elseif args.barwidth

'wide' then barwidth = 400 elseif args.barwidth

'auto' then barwidth = 'auto' else error('unrecognized barwidth') end

local function _numwidth(i) local nw = args.numwidth:sub(i,i) return assert(numwidth[nw], 'unrecognized numwidth[' .. i .. ']') end

args.numwidth = args.numwidth or 'mm' if args.numwidth:sub(1,1)

'n' or args.numwidth:sub(2,2)

'n' or args.numwidth:sub(4,4)

'n' then error('"n" is only allowed in numwidth[3]') end

local buffer = 0.3 --until automatic numwidth determination local right1width, right2width = _numwidth(1) + 0.3 + _numwidth(2) + buffer, 0 if #args.numwidth

4 then right2width = _numwidth(3) + _numwidth(4) + buffer if args.numwidth:sub(3,3) ~= 'n' then right2width = right2width + 0.3 end if args.right2 then right2width = math.ceil(right2width / 0.88 * 100) / 100 -- from td scale to th else right1width = right1width + 0.8 + right2width right2width = 0 end end right1width = math.ceil(right1width / 0.88 * 100) / 100

if tonumber(barwidth) then -- transform colswidth from th to td scale, add it with border-spacing, and finally transform to table scale local relwidth = math.ceil(((7.08 + right1width + right2width) * 0.88 + 0.8 * (args.right2 and 5 or 4)) * 88) / 100 barargs.width = 'calc(' .. relwidth .. 'em + ' .. barwidth .. 'px)' --why do the bar borders go inward (no +2)? barargs.barwidth = barwidth .. 'px' else barargs.width = 'auto' barargs.barwidth = 'auto' end barargs.lineheight = args.rowheight

local title =

local function spaces(n) local nbsp = ' ' return '

' .. nbsp:rep(n) .. '' end

local location = lang:ucfirst(mw.ustring.gsub(args.location, i18n.the_, )) local navbartitle = args.outbreak .. i18n._data .. '/' .. (args.location3 and args.location3 .. '/' or ) .. (args.location2 and args.location2 .. '/' or ) .. location .. i18n._medicalCasesChart

local navbar = require('Module:Navbar')._navbar 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 ) .. spaces(2) ..'(' .. navbar .. ')
'

title[2] = p._legend0 args.recoveries = args.recoveries

nil and true or args.recoveries title[3] = args.recoveries and spaces(3) .. p._legend0 or title[4] = args.altlbl1 ~= 'hide' and spaces(3) .. p._legend0 or title[5] = args.altlbl2 and spaces(3) .. p._legend0 or title[6] = args.altlbl3 and spaces(3) .. p._legend0 or

local togglesbar, buildargs = nil,

args.right1 = args.right1 or i18n.noOfCases args.duration = args.duration or 15 args.nooverlap = args.nooverlap or false

buildargs.barwidth = tonumber(barwidth) or 280 buildargs.numwidth = args.numwidth:gsub('d', 'm') if args.datapage then local externalData = require('Module:Medical cases chart/data')._externalData buildargs.data = externalData(args) else buildargs.data = args.data end -- if no right1data and right1 title is cases, use 3rd classification buildargs.right1data = args.right1data or args.right1

i18n.noOfCases and 3 -- if no right2data and right2 title is deaths, use 1st classification buildargs.right2data = args.right2data or (args.right2

i18n.noOfDeaths or args.right2

i18n.noOfDeaths2) and 1 buildargs.changetype1 = (args.changetype1 or args.changetype or ):sub(1,1) -- 1st letter buildargs.changetype2 = (args.changetype2 or args.changetype or ):sub(1,1) -- 1st letter buildargs.collapsible = args.collapsible buildargs.duration = args.duration buildargs.nooverlap = args.nooverlap buildargs.population = args.population

local dateList barargs.bars, dateList = p._buildBars(buildargs)

if buildargs.collapsible then togglesbar = p._buildTogglesBar(dateList, args.duration, args.nooverlap) end

title[7] = togglesbar and '
' .. togglesbar or barargs.title = table.concat(title)

barargs.left1 = '

' .. i18n.date .. '

' barargs.right1 = '

' .. args.right1 .. '

' --center isn't necessary with proper if args.right2 then --numwidth, but better safe than sorry barargs.right2 = '

' .. args.right2 .. '

' end

barargs.footer = args.footer local box = BarBox.create(barargs) return tostring(box)end

local getArgs = require('Module:Arguments').getArgs

function p.barColors(frame) local args = getArgs(frame) return p._barColors[tonumber(args[1])]end

function p.chart(frame) local args = getArgs(frame,) return p._chart(args)end

return p