Jump to content
Main menu
Main menu
move to sidebar
hide
Navigation
Main page
Recent changes
Random page
Help about MediaWiki
Humanipedia
Search
Search
Appearance
Create account
Log in
Personal tools
Create account
Log in
Pages for logged out editors
learn more
Contributions
Talk
Editing
Module:Medical cases chart
Module
Discussion
English
Read
Edit source
View history
Tools
Tools
move to sidebar
hide
Actions
Read
Edit source
View history
General
What links here
Related changes
Special pages
Page information
Appearance
move to sidebar
hide
Warning:
You are not logged in. Your IP address will be publicly visible if you make any edits. If you
log in
or
create an account
, your edits will be attributed to your username, along with other benefits.
Anti-spam check. Do
not
fill this in!
local yesno = require('Module:Yesno') local BarBox = unpack(require('Module:Bar')) local lang = mw.getContentLanguage() local language = lang:getCode() local 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 nil end function p._toggleButton(active, customtoggles, id, label) local on = active and '' or ' mw-collapsed' local off = active and ' mw-collapsed' or '' local outString = '<span class="mw-collapsible' .. on .. customtoggles .. '" id="mw-customcollapsible-' .. id .. '" ' .. 'style="border:2px solid lightblue">' .. label .. '</span>' .. '<span class="mw-collapsible' .. off .. customtoggles .. '" id="mw-customcollapsible-' .. id .. '">' .. label .. '</span>' return outString end 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, {' mw-customtoggle-' .. id} 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 = {{year=dateList[1].year, months={{mon=dateList[1].mon, combinations={}}}}} 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] = {year=month.year, months={}} months = years[#years].months -- switch months list end months[#months+1] = {mon=month.mon, combinations={}} 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] = '<div class="mw-collapsible' .. (year.l and '' or ' mw-collapsed') .. '" id="mw-customcollapsible-' .. year.year .. '">' .. table.concat(monthToggles) .. '</div>' end divs = '<div>' .. table.concat(yearToggles) .. '</div>' .. table.concat(monthsDivs) else for i, month in ipairs(months) do monthToggles[#monthToggles+1] = p._monthToggleButton(nil, month) end divs = '<div>' .. table.concat(monthToggles) .. '</div>' end divs = divs .. '<div>' .. p._lastXToggleButton(years, duration, combinationsL) .. '</div>' return '<div class="nomobile" style="text-align:center">' .. divs .. '</div>' end local numwidth = {n=0, t=2.45, m=3.5, d=3.5, w=4.55, x=5.6} local bkgClasses = { 'mcc-d', --deaths 'mcc-r', --recoveries 'mcc-c', --cases or altlbl1 'mcc-a2', --altlbl2 'mcc-a3' --altlbl3 } 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] = '<span class=mcc-r' .. _numwidth(1) .. '>' .. (args[7] or '') .. '</span>' .. '<span class=mcc-l' .. _numwidth(2) .. '>' .. (args[8] or '') .. '</span>' end if #args.numwidth == 4 then barargs.note2 = (args[9] or args[10]) and (args.numwidth:sub(3,3) ~= 'n' and '<span class=mcc-r' .. _numwidth(3) .. '>' .. (args[9] or '') .. '</span>' or '') .. '<span class=mcc-l' .. _numwidth(4) .. '>' .. (args[10] or '') .. '</span>' 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 = {year=tonumber(os.date('%Y', args.nDate)), mon=lang:formatDate('M', os.date('%Y-%m', args.nDate)), l=args.daysToEnd < duration and '-l' .. duration, nDate=args.nDate} 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 = {nStartDate=args.nStartDate, nAltStartDate=args.nAltStartDate, nEndDate=args.nEndDate, nAltEndDate=args.nAltEndDate} repeat id[#id+1] = (args.multiyear and y or '') .. lang:lc(monthAbbrs[m]) dates[#dates+1] = {year=y, mon=monthAbbrs[m]} 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), dates end 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 = {nDate=barargs.nDate-updatePeriod} prevRow[1] = os.date('%Y-%m-%d', prevRow.nDate) else prevRow = {nStartDate=(prevRow.nDate or prevRow.nEndDate)+updatePeriod, nEndDate=barargs.nDate-updatePeriod} 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 = '<span title="'.. sChngCmt .. '">' .. tostring(mw.ustring.format('%.1f', nDiff7/args.population*100000)) .. '</span>' 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 = '<span title="' .. sCmnt ..'">' .. lang:formatNum(nValue) .. '</span>' 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 ('<span title="7 days rolling average of daily change">r7: ' .. tostring(mw.ustring.format('%.0f', nDiff/7)) .. '</span>') or i18n.na else change = nDiff and ('<span title="7 days incidence per 100,000 population.">' .. tostring(mw.ustring.format('%.1f', nDiff/args.population*100000)) .. '</span>') or i18n.na if tPrevDayRow and tPrevDayRow[nDatCol] then value = '<span title="daily change: +' .. lang:formatNum(num - tPrevDayRow[nDatCol]) .. '>' .. value .. '</span>' 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 = {lastRow[2] or 0, lastRow[3] or 0, [4]=lastRow[5] or 0} 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'), dateList end p._barColors = { -- also in styles.css '#A50026', --deaths 'SkyBlue', --recoveries 'Tomato', --cases or altlbl1 'Gold', --altlbl2 'OrangeRed' --altlbl3 } function p._legend0(args) return '<span style="font-size:90%; margin:0px">' .. '<span style="background-color:' .. (args[1] or 'none') .. '; border:' .. (args.border or 'none') .. '; color:' .. (args[1] or 'none') .. '">' .. ' ' .. '</span>' .. ' ' .. (args[2] or '') .. '</span>' end function p._chart(args) for key, value in pairs(args) do if ({float=1, barwidth=1, numwidth=1, changetype=1})[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 '<span class="nowrap">' .. nbsp:rep(n) .. '</span>' 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({navbartitle, titleArg=':' .. mw.getCurrentFrame():getParent():getTitle(), mini=1, nodiv=1}) .. ')<br />' title[2] = p._legend0({p._barColors[1], i18n.deaths}) args.recoveries = args.recoveries == nil and true or args.recoveries title[3] = args.recoveries and spaces(3) .. p._legend0({p._barColors[2], args.reclbl or i18n.recoveries}) or '' title[4] = args.altlbl1 ~= 'hide' and spaces(3) .. p._legend0({p._barColors[3], args.altlbl1 or i18n.activeCases}) or '' title[5] = args.altlbl2 and spaces(3) .. p._legend0({p._barColors[4], args.altlbl2}) or '' title[6] = args.altlbl3 and spaces(3) .. p._legend0({p._barColors[5], args.altlbl3}) 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 '<br />' .. togglesbar or '' barargs.title = table.concat(title) barargs.left1 = '<div style="width:7.08em">' .. i18n.date .. '</div>' barargs.right1 = '<div class=center style="width:' .. right1width .. 'em">' .. args.right1 .. '</div>' --center isn't necessary with proper if args.right2 then --numwidth, but better safe than sorry barargs.right2 = '<div class=center style="width:' .. right2width ..'em">' .. args.right2 .. '</div>' 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, { valueFunc = function (key, value) if value and value ~= '' then key = key:gsub('%d', '') if ({rowheight=1, duration=1, rightdata=1})[key] then -- if key in {...} return tonumber(value) or value end if ({recoveries=1, collapsible=1, nooverlap=1})[key] then return yesno(value) end return value end return nil end }) return p._chart(args) end return p
Summary:
Please note that all contributions to Humanipedia may be edited, altered, or removed by other contributors. If you do not want your writing to be edited mercilessly, then do not submit it here.
You are also promising us that you wrote this yourself, or copied it from a public domain or similar free resource (see
Humanipedia:Copyrights
for details).
Do not submit copyrighted work without permission!
Cancel
Editing help
(opens in new window)
Templates used on this page:
Template:Lua
(
edit
)
Template:Uses TemplateStyles
(
edit
)
Module:Lua banner
(
edit
)
Module:Medical cases chart/doc
(
edit
)