Module:Medical cases chart/sandbox3

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

local 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 = {

'#A50026', --deaths

'SkyBlue', --recoveries

'Tomato', --cases or altlbl1

'Gold', --altlbl2

'OrangeRed' --altlbl3

}

return colors[n]

end

function p._legend0(args)

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

end

function p._customBarStacked(args)

barargs = {}

barargs[1] = args[1]

local function _numwidth(nw)

if nw == 'n' then

return 0

elseif nw == 't' then

return 2.45

elseif nw == 'm' then

return 3.5

elseif nw == 'w' then

return 4.55

elseif nw == 'x' then

return 5.6

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) == 4 then

local padding = '0.3em'

if mw.ustring.sub(args.numwidth,3,3) == 'n' then

padding = '0'

end

barargs.note2 =

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

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

end

for 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]) == true then

change = '(' .. i18n.na .. ')'

elseif 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) == true then

local duration = tonumber(args.duration) or 15

if args.collapsed then

barargs.collapsed = args.collapsed

elseif args.rowsToEnd >= duration then

barargs.collapsed = 'y'

else

barargs.collapsed = ''

end

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] == 'alttot1' or 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 == 7 or 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 == 'alttot1' then

num = tonumber(barargs.alttot1 or barargs[4])

prevnum = tonumber(prevRow.alttot1 or prevRow[4])

elseif 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 == 'o' and '' or lang:formatNum(num) -- set value to num if changetype isn't 'o'

if not change and yesno(barargs['firstright' .. col] ~= true) then

if prevnum and prevnum ~= 0 then -- data on previous row

if num - prevnum ~= 0 then --data has changed since previous row

change = num-prevnum

if 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] = {f,g}

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), months

end

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 or ' mw-collapsed'

local uncollapsed = (args.active == ) and ' mw-collapsed' or

if args.nooverlap then

outString = '%s\n' ..

'%s' .. newline

if mw.ustring.sub(month,1,1) == 'l' and tonumber(mw.ustring.sub(month,2)) == 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,'$.', {

['$m'] = i18n.m[month],

['$s'] = args.month[2],

['$e'] = args.month[3]})

else -- "Mmm ##""

month = mw.ustring.gsub(i18n.toggleSingleDate,'$.', {

['$m'] = i18n.m[month],

['$s'] = args.month[2]})

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) == 'l' and tonumber(mw.ustring.sub(month,2)) == args.duration then

local customtoggles = {(' mw-customtoggle-l' .. args.duration)}

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 = '\n' ..

'' .. lastDays .. '' .. newline

else

local customtoggles = ' mw-customtoggle-' .. month .. ' mw-customtoggle-' .. month .. '-l' .. args.duration

outString = '' .. (i18n.m[month] or month) .. '\n' ..

'' .. newline

end

end

return outString

end

function 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.noOfDeaths or 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 == true then

if #monthList <= duration then

nooverlap = false

else

lastRow = #monthList - duration

end

end

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) == true then

if is(args.togglesbar) then

togglesbar = args.togglesbar

else

local toggles = {}

for i=1,#months do

toggles[#toggles+1] = p._monthToggleButton({month=months[i], duration=duration, nooverlap=nooverlap})

end

toggles[#toggles+1] = p._monthToggleButton({month={('l' .. duration)}, duration=duration, nooverlap=nooverlap})

togglesbar = '

\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({[1] = navbartitle, titleArg = ':' .. mw.getCurrentFrame():getParent():getTitle(), mini = 1, nodiv = 1}) ..

')
'

title[2] = p._legend0({[1] = p._barColors(1), [2] = 'Deaths'})

if args.recoveries then

title[3] = '   ' .. p._legend0({[1] = p._barColors(2), [2] = args.reclbl or i18n.recoveries})

else

title[3] = ''

end

title[4] = '   ' .. p._legend0({[1] = p._barColors(3), [2] = args.altlbl1 or i18n.activeCases})

if args.altlbl2 then

title[5] = '   ' .. p._legend0({[1] = p._barColors(4), [2] = args.altlbl2})

else

title[5] = ''

end

if args.altlbl3 then

title[6] = '   ' .. p._legend0({[1] = p._barColors(5), [2] = args.altlbl3}) ..'\n'

else

title[6] = '\n'

end

title[7] = togglesbar

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

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 = {['n'] = 0, ['t'] = 40, ['m'] = 55, ['w'] = 70, ['x'] = 85, ['d'] = 55}

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) == 4 then

numwidth = numwidth + _numwidth(3) + _numwidth(4)

if mw.ustring.sub(sNumwidthLower,3,3) == '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) == 4 then

right1 = right1 + _numwidth(3) + _numwidth(4)

if mw.ustring.sub(sNumwidthLower,3,3) == '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) == 'n' then

right2 = right2 - 2

else

right2 = right2 + 2

end

tRawPams.right2width = right2

end

-- barwidth and width

local tBarWidthMap = {['thin'] = 120, ['medium'] = 280, ['wide'] = 400, ['auto'] = 'auto'}

local sBarWidthLower = tRawPams['barwidth'] and mw.ustring.lower(tRawPams['barwidth']) or nil

tRawPams.barwidth = tBarWidthMap[sBarWidthLower] or 280

if tonumber(tRawPams.barwidth) then

tRawPams.sTotalWidth = (85 + tRawPams.barwidth + numwidth) .. 'px'

tRawPams.sBarWidth = tRawPams.barwidth .. 'px'

else

tRawPams.sTotalWidth = 'auto'

tRawPams.sBarWidth = 'auto'

end

-- recoveries, defaults to true for undefined or unrecognised values

tRawPams.recoveries = not (yesno(tRawPams.recoveries) == false)

-- 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 tRawPams

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 bars

end

function p.monthToggleButton(frame)

local args = {}

args.month = {frame:getParent().args.month or frame:getParent().args[1] or 'l15'}

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