Մոդուլ:Medical cases chart

Վիքիպեդիայից՝ ազատ հանրագիտարանից

Կաղապար:Uses TemplateStyles

Description[խմբագրել կոդը]

This template should be used for all outbreak, epidemic and pandemic medical cases charts based on {{Bar box}} to maintain consistency. It displays horizontal bars for up to 5 different classifications of cases for each valid date. It also offers two columns to make numbers explicit and to show relative or absolute changes. It is designed to be flexible, but still standardizes some parts of the chart. This template should be transcluded in other templates, NOT in article pages. Please do not use templates other than {{Medical cases chart}} and, maybe, {{Medical cases chart/Row}} to get away with a custom formatting. Suggest features in the talk page or code it yourself if it's not controversial.

Usage[խմբագրել կոդը]

{{Medical cases chart
|barwidth   = width of the stacked bars area (thin|medium|wide)                        [optional, defaults to: medium]
|numwidth   = max width of the numbers in the right columns (AA or AAAA)<-(n|t|m|w|x|d)[optional, defaults to: mm,
                                                                                           see below and examples]
|rowheight  = height of each bar, in multiples of the text height                      [optional, defaults to: 1.6]
|float      = on what side of the page should the chart be located (left|right|none)   [optional, defaults to: right] 

|pretitle   = text at the beginning of the title                                       [optional]
|disease    = name of the disease
|location   = location of the outbreak the chart is showing
|location2  = broader location such as state/province or country                       [optional]
|location3  = broadest location such as country                                        [optional]
|posttitle  = text at the end of the title                                             [optional]
|outbreak   = name of the main outbreak (for link of the {{navbar}})

|recoveries = display recoveries in the legend (no|n|0)                                [optional, defaults to: yes]

|reclbl     = alternate label for the 2nd case classification                          [optional, defaults to: Recoveries]
|altlbl1    = alternate label for the 3rd case classification                          [optional, defaults to: Cases]
|altlbl2    = alternate label for the 4th case classification                          [optional]
|altlbl3    = alternate label for the 5th case classification                          [optional]

|togglesbar = HTML of the toggles bar to show/hide rows (use                           [optional]  {WIP}
              {{Medical cases chart/Month toggle button}})
                
|right1     = heading of the 1st data column                                           [optional, defaults to: # of cases]
|right1data = case classification for the 1st column                                   [optional, defaults to: 3 (if right1 is "# of cases")]
|changetype1= calculate percent change (%) or absolute change (#) (p|a)                [optional, defaults to: percent]
|right2     = heading of the 2nd data column                                           [optional]
|right2data = case classification for the 2nd column                                   [optional, defaults to: 1 (if right2 is "# of deaths")]
|changetype2= calculate percent change (%), absolute change (#), or onlypercent (p|a|o)[optional, defaults to: percent]
 
|divisor    = manual override of the scaling divisor of the bars                       [optional, defaults to: auto]
|collapsible= whether the rows are collapsible (yes|y|1)                               [optional, defaults to: no]  {WIP}
|data       = data lines for each valid date (see Data's and Rows' syntax)

|caption    = caption under the chart                                                  [optional]
}}

numwidth is a sequence of the initials of none, thin, medium, wide, extra wide and default, and it determines the maximum width of each number in the data columns. Therefore, one should be chosen that minimizes the total width, but which doesn't make the numbers break/wrap on mobile view. Using 2 or 4 characters allocates one or two data columns, respectively. For example, mw sets the right1 value column to medium and the right1 change column to wide. mwnt sets the right1 value column to medium, the right1 change column to wide, the right2 value column to none, and the right2 change column to thin.

To display absolute change in the first column and percent change in the second column, set the following (AA represents any two characters, # represents the classification number you are showing, which should be the same for right1data and right2data):

|numwidth = AAnw
|right1data = #
|changetype1 = a
|right2data = #
|changetype2 = o

Data[խմբագրել կոդը]

The |data= parameter should be populated by a sequence of lines with a format similar to the rows'. The difference is that the parameter separator is the semicolon, ;, and that repetitive parameters, like |divisor=, |numwidth=, and |collapsible=, may be written only once in the body of {{Medical cases chart}}. Using |data= also allows the divisor to be calculated automatically if the parameter is omitted.

|data=date;deaths;2nd classification (recoveries);3rd classification (total or altlbl1);4th classification #;5th classification #;1st column #;1st column change;2nd column #;2nd column change;other parameters=values
date;deaths;2nd classification (recoveries);3rd classification (total or altlbl1);4th classification #;5th classification #;1st column #;1st column change;2nd column #;2nd column change;other parameters=values
...

All values are optional, and empty values can be represented by sequential semicolons (e.g. ;;). Omitting the valid date will treat the row as a date jump, in which no new cases are reported.

The expression for total in the 3rd classification cases has deaths and recoveries automatically subtracted from it. If you want to manually calculate the number in that classification (generally active cases), use alttot1. The same applies to the expression for total in 5th classification and alttot2.

The 1st column #, 1st column change, 2nd column #, and 2nd column change values can be automatically calculated if omitted. The 1st column values will be automatically calculated if |right1= is omitted or set to # of cases, and the 2nd column values will be automatically calculated if |right2= is set to # of deaths. If |right1= or |right2= are set to other values, the columns can still be automatically calculated by setting |right1data= and |right2data= to the classification number you want to display in columns 1 and 2, respectively (e.g. 1 for deaths, 2 for recoveries, 3 for total, etc.). The changes in the first and second columns are automatically wrapped in parentheses.

The other parameters=values can be any number of the parameters below and their values, separated by semicolons. See examples.

;alttot1    = ''alternate expression for active cases (3rd classification)''
;alttot2    = ''alternate expression for number in 5th classification''
;firstright1= ''whether a change in the first column is not applicable (n.a.)'' (yes|y|1)
;firstright2= ''whether a change in the second column is not applicable (n.a.)'' (yes|y|1)
;collapsed  = ''manual override of the initial row state'' (yes|y|1)                       {WIP}
;id         = ''manual override of the row id''                                            {WIP}

To convert from the old format, remove {{Medical cases chart/Row| from the beginning and }} from the end of the line, replace all pipes (|) with semicolons (;), and remove any |divisor=, |numwidth=, and |collapsible= parameters from the end (and make sure they are listed in the main template at least once). For example:

{{Medical cases chart/Row|2020-04-15|1921||28059|||28,059|+1058||+4%|divisor=100|numwidth-mmnm}}

becomes

2020-04-15;1921;;28059;;;28,059;+1058;;+4%

Rows[խմբագրել կոդը]

Examples[խմբագրել կոդը]

{{Medical cases chart
|numwidth=mw

|disease=Green Flu
|location=Savannah|location2=Georgia|location3=United States
|outbreak=2009 Green Flu outbreak

|recoveries=n

|data=
2009-04-13;;;42;;;42;firstright1=y
2009-04-14;;;356;;;356;+748%
2009-04-15;;;1503;;;1,503;+322%
2009-04-16;57;;5915;;;5,915;+294%
2009-04-17;2000;;9500;;;~9,500;+60.6%
}}
Green Flu դեպքերը Savannah, Georgia, United States  ()
     Մահեր        Վարակված
Ամսաթիվ
դեպքերի #
2009-04-13
42(n.a.)
2009-04-14
356(+748%)
2009-04-15
1,503(+322%)
2009-04-16
5,915(+294%)
2009-04-17
~9,500(+60.6%)
{{Medical cases chart
|barwidth=wide
|numwidth=mwwd

|pretitle=Approximate
|disease=Spanish Flu
|location=the World
|posttitle=(excluding Oceania)
|outbreak=1918-20 Spanish Flu pandemic

|altlbl1=Active confirmed
|altlbl2=Suspected
|altlbl3=Estimated

|right1=Confirmed cases
|right2=Including suspected and estimated cases

|divisor=2550
|data=
1918-03-10;(2060-300);(3000-800);6000;;;6000;firstright1=y
1918-07;12600;20000;40000;12000;;alttot2=(34000-15000-8700+40);40000;+500%;10500;firstright2=y
;12600;20000;40000;12000;;alttot2=(34000-15000-8700+40);40000;;10500
1919;100000;250000;;;1000000;;;1mi;+500k

|caption=Foo Bar
}}
Approximate Spanish Flu դեպքերը the World (excluding Oceania)  ()
     Մահեր        Բուժված        Active confirmed        Suspected        Estimated
Ամսաթիվ
Confirmed cases
Including suspected and estimated cases
1918-03-10
6000(n.a.)
1918-07
40000(+500%) 10500(n.a.)
40000(=) 10500(=)
1919
1mi(+500k)
Foo Bar

Applied example[խմբագրել կոդը]

{{2019–20 coronavirus pandemic data/South Korea medical cases chart}} Կաղապար:2019–20 coronavirus pandemic data/South Korea medical cases chart

TemplateData[խմբագրել կոդը]

Produces charts based on {{Bar box}} for outbreak, epidemic and pandemic medical cases.

Template parameters

ParameterDescriptionTypeStatus
Diseasedisease

name of the disease

Տողrequired
Outbreakoutbreak

name of the main outbreak (for link of the {{navbar}})

Տողrequired
Locationlocation

location of the outbreak the chart is showing

Տողrequired
Datadata

data lines for each valid date (see Data's and Rows' syntax)

Auto value
Unknownrequired
Pretitlepretitle

text at the beginning of the title

Auto value
Unknownoptional
Bar widthbarwidth

width of the stacked bars area (thin|medium|wide)

Auto value
medium
Unknownoptional
Number widthnumwidth

max width of the numbers in the right columns (xx or xxxx)<-(n|t|m|w|d)

Auto value
mm
Unknownoptional
Floatfloat

on what side of the page should the chart be located (left|right|none)

Auto value
right
Տողoptional
Location 2location2

broader location such as state/province or country

Տողoptional
Location 3location3

broadest location such as country

Տողoptional
Post-titleposttitle

text at the end of the title

Unknownoptional
Recoveriesrecoveries

display recoveries in the legend (no|n|0)

Unknownoptional
Recoveries labelreclbl

alternate label for the recoveries classification

Unknownoptional
Alt label 1altlbl1

alternate label for the 3rd case classification

Unknownoptional
Alt label 2altlbl2

alternate label for the 4th case classification

Auto value
Cases
Unknownoptional
Alt label 3altlbl3

alternate label for the 5th case classification

Unknownoptional
Toggles bartogglesbar

HTML of the toggles bar to show/hide rows

Unknownoptional
Right 1right1

heading of the first data column

Auto value
# of cases
Unknownoptional
Right 2right2

heading of the second data column

Տողoptional
rowsrows

no description

Unknownoptional
Divisordivisor

manual override of the scaling divisor of the bars

Auto value
auto
Unknownoptional
Collapsiblecollapsible

whether the rows are collapsible (yes|y|1)

Unknownoptional
Captioncaption

caption under the chart

Unknownoptional

local getArgs = require('Module:Arguments').getArgs
local yesno = require('Module:Yesno')
local barBox = require('Module:Bar box')

local language = 'hy-AM' -- local default language

local i18n = require("Module:Medical cases chart/i18n")[language]

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 '<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') .. '">' .. '&nbsp;&nbsp;&nbsp;&nbsp;' .. '</span>' .. '&nbsp;' .. (args[2] or '') .. '</span>'
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] =
		'<span class="cbs-ibr" style="padding:0 0.3em 0 0; width:' .. width1 .. 'em">' .. (args[7] or '') .. '</span>' ..
		'<span class="cbs-ibl" style="width:' .. width2 .. 'em">' .. (args[8] or '') .. '</span>'

	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 =
			'<span class="cbs-ibr" style="padding:0 ' .. padding .. ' 0 0; width:' .. width3 .. 'em">' .. (args[9] or '') .. '</span>' ..
			'<span class="cbs-ibl" style="width:' .. width4 .. 'em">' .. (args[10] or '') .. '</span>'
	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] = '<strong class="error">' .. i18n.invalidTime .. '</strong>'
		end
	else
		barargs[1] = '⋮'
	end

	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

		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 = '<span class="mw-collapsible mw-customtoggle-' .. month .. ' %s" id="mw-customcollapsible-' .. month .. '" style="padding:0 8px">%s</span>\n' ..
				'<span class="mw-collapsible mw-customtoggle-' .. month .. ' %s" id="mw-customcollapsible-' .. month .. '" style="border:2px solid lightblue; padding:0 8px">%s</span>' .. 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
						-- "Mmm ##–##"
						month = mw.ustring.gsub(i18n.toggleRange,'$.', {
							['$m'] = i18n.m[month],
							['$s'] = args.month[2],
							['$e'] = args.month[3]})
					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 = '<span class="mw-collapsible' .. table.concat(customtoggles) .. collapsed .. '" id="mw-customcollapsible-' .. month .. '" style="padding:0 8px">' .. lastDays .. '</span>\n' ..
				'<span class="mw-collapsible' .. table.concat(customtoggles) .. uncollapsed .. '" id="mw-customcollapsible-' .. month .. '" style="border:2px solid lightblue; padding:0 8px">' .. lastDays .. '</span>' .. newline
			
		else
			local customtoggles = ' mw-customtoggle-' .. month .. ' mw-customtoggle-' .. month .. '-l' .. args.duration
			
			outString = '<span class="mw-collapsible' .. customtoggles .. uncollapsed .. '" id="mw-customcollapsible-' .. month .. '" style="padding:0 8px">' .. (i18n.m[month] or month)  .. '</span>\n' ..
				'<span class="mw-collapsible mw-customtoggle-' .. customtoggles .. collapsed .. '" id="mw-customcollapsible-' .. month .. '" style="border:2px solid lightblue; padding:0 8px">' .. (i18n.m[month] or month)  .. '</span>'  .. newline
		end
	end
	
	return outString
end

function 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 == 'n' then
			return 0
		elseif nw == 't' then
			return 40
		elseif nw == 'm' then
			return 55
		elseif nw == 'w' then
			return 70
		elseif nw == 'x' then
			return 85
		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) == 4 then
			numwidth = numwidth + _numwidth(3) + _numwidth(4)
			if mw.ustring.sub(args.numwidth,3,3) == '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) == 4 then
			right1 = right1 + _numwidth(3) + _numwidth(4)
			if mw.ustring.sub(args.numwidth,3,3) == 'n' then
				numwidth = numwidth + 6
			else
				numwidth = numwidth + 10
			end
		end
	end

	local barwidth = 280

	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'
	end

	if tonumber(barwidth) then
		barargs.width = 85 + barwidth + numwidth .. 'px'
		barargs.barwidth = barwidth .. 'px'
	else
		barargs.width = 'auto'
		barargs.barwidth = 'auto'
	end

	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 and ( not is(args.togglesbar) ) then
		duration = tonumber(args.duration) or 15 -- default if auto togglesbar is last 15 days
	end
	
	local months, togglesbar, lastdate = {{}}, '', nil
	if args.rows then
		barargs.bars = args.rows
		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.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.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 = '<div class="nomobile" style="text-align:center">\n' .. table.concat(toggles) .. '</div>'
			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 '') .. '<span class="nowrap">&nbsp;&nbsp;</span>(' ..
		navbar({[1] = navbartitle, titleArg = ':' .. mw.getCurrentFrame():getParent():getTitle(), mini = 1, nodiv = 1}) ..
		')<br />'
	title[2] = p._legend0({[1] = p._barColors(1), [2] = 'Մահեր'})
	if yesno(args.recoveries) == false then
		title[3] = ''
	else
		title[3] = '<span class="nowrap">&nbsp;&nbsp;&nbsp;</span>' .. p._legend0({[1] = p._barColors(2), [2] = args.reclbl or i18n.recoveries})
	end
	title[4] = '<span class="nowrap">&nbsp;&nbsp;&nbsp;</span>' .. p._legend0({[1] = p._barColors(3), [2] = args.altlbl1 or i18n.activeCases})
	if args.altlbl2 then
		title[5] = '<span class="nowrap">&nbsp;&nbsp;&nbsp;</span>' .. p._legend0({[1] = p._barColors(4), [2] = args.altlbl2})
	else
		title[5] = ''
	end
	if args.altlbl3 then
		title[6] = '<span class="nowrap">&nbsp;&nbsp;&nbsp;</span>' .. 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 =
		'<div class="center" style="width:77px">' .. -- 85-8 because of padding
			"'''" .. i18n.date .. "'''" ..
		'</div>'

	barargs.right1 =
		'<div class="center" style="width:' .. right1 .. 'px">' ..
			"'''" .. (args.right1 or i18n.noOfCases) .. "'''" ..
		'</div>'

	if args.right2 then
		local right2 = _numwidth(3) + _numwidth(4)
		if mw.ustring.sub(args.numwidth,3,3) == 'n' then
			right2 = right2 - 2
		else
			right2 = right2 + 2
		end

		barargs.right2 =
		'<div class="center" style="width:' ..right2 ..'px">' ..
			"'''" .. args.right2 .. "'''" ..
		'</div>'
	end

	barargs.caption = args.caption
	barargs.css = 'Template:Medical_cases_chart/styles.css'
	return barBox._box(barargs)
end

function p.chart(frame)
	local args = getArgs(frame, {
		valueFunc = function (key, value)
			if value then
				value = mw.text.trim(value)
				if ({['numwidth']=1,['barwidth']=1,['recoveries']=1,['changetype']=1})[mw.ustring.gsub(key,"%A","")] then
					value = mw.ustring.lower(value) --make numwidth, barwidth, recoveries, and changetype lower case
				end
				if is(value) then
					return value
				end
			end
			return nil
		end
	})
	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 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