Module:Medical cases chart/sandbox2
![]() | This module depends on the following other modules: |
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 or interval. It offers two columns to make numbers explicit and to show relative or absolute changes. It also uses a sophisticated toggling system to control the visualization of data rows across many months or years. 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. Suggest features in the talk page or code them if they're neither controversial nor incompatibility prone.
Usage
{{Medical cases chart |float = side of the page where the chart will be located (left|center|right|none) [optional, defaults to: right] |barwidth = width of the stacked bars area (thin|medium|wide|auto) [optional, defaults to: medium] |numwidth = max width of the numbers in the right columns (AA or AAAA)←(n|t|m|w|x|d) [suggested, defaults to: mm; see info below] |rowheight = height of each bar in multiples of the text height [optional, defaults to: 1.6] |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 the links of the {{navbar}} [see info below] |recoveries = whether to display recoveries in the legend (yesno) [optional, defaults to: yes] |reclbl = alternate label for the 2nd cases classification [optional, defaults to: Recoveries] |altlbl1 = alternate label for the 3rd cases classification (hide) [optional, defaults to: Active cases] |altlbl2 = alternate label for the 4th cases classification [optional] |altlbl3 = alternate label for the 5th cases classification [optional] |collapsible = whether rows are collapsible (forced no if days span <= duration) (yesno) [optional, defaults to: 'auto'] |duration = span of last days to initially display to control default chart height [optional, defaults to: 15] |weekly = whether to create one row per week, rather than per day [optional, defaults to: no] |weeklyoffset= what day of the week to pull weekly data from (0-6) [optional, defaults to: 0] |nooverlap = whether to prevent the last month's toggle from overlapping, in days, [optional, defaults to: no; see info below] with the "Last XX days" toggle (yesno) |right1 = heading of the 1st data column [optional, defaults to: # of cases] |right1data = cases classification of the 1st column for auto filling (1-5|alttot1-2) [optional, defaults to: 3, if right1 is "# of cases"] |changetype1 = calculate percent change (%), absolute change (#), [optional, defaults to: percent] or weekly incidence (w) (p|a|w) |right2 = heading of the 2nd data column [optional] |right2data = cases classification of the 2nd column for auto filling (1-5|alttot1-2) [optional, defaults to: 1, if right2 is "# of deaths"] |changetype2 = calculate percent change (%), absolute change (#), onlypercent (o), [optional, defaults to: percent] or weekly incidence (w) (p|a|o|w) |changetype = applies to both 1st and 2nd change columns [optional] |population = population count, required for weekly incidence, otherwise no effect [optional, if changetype w is set without population, it will default to percent] |datapage = tabular data page from Commons to scrape cases data from [optional; see its talk section and module] |data = data lines for each valid date or interval [suggested; see Data's syntax] |footer = footer of the chart [suggested] }}
It may be desirable to make a specific outbreak chart have different widths depending on the page it is displayed. The barwidth
parameter can be used to achieve this. For example, |barwidth={{{barwidth|wide}}}
will display the chart wide in the template page itself, but will allow different widths when the outbreak template is transcluded with this parameter in article pages.
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, |numwidth=mw
sets the right1 value column to medium and the right1 change column to wide. |numwidth=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.
numwidth | Number | Percent change[a] | Absolute change[a] |
---|---|---|---|
t | 1−9,999 | none | ±1−±99 |
m | 10,000−99,999 | ±X.X% or ±1%−±99% | ±100−±999 |
w | 100,000−9,999,999 | ±0.XX% or +100%−±999% | ±1,000−±99,999 |
x | 10,000,000−999,999,999 | ±0.00XX% or ±1,000−±99,999% | ±100,000−±999,999 |
The {{navbar}} links are constructed like this: "outbreak
data/[
[
location3
/]
location2
/]
*location
medical cases chart". outbreak
may be more descriptive than disease
to avoid page name collisions. So, for example, COVID-19 charts have |outbreak=COVID-19 pandemic
. location
has "the " internally removed and is capitalized to become *location
.
By default, the "Last X days" button toggles days which intersect with those of the last months. This happens regardless of the state (activated or not) of the month buttons. In fact, due to limitations of custom collapsing, toggles are stateless (a workaround is used to simulate two 'states'). All in all, this can lead to situations where clicking one button causes unintuitive toggling like creating date gaps. nooverlap
works around this issue by forcing the buttons of the last months to not overlap with the "Last X days" button. The result is usually a partial last month button, "Mon XX-XX", where XX are the first and last days of the month that the button affects. Extra info in the main bug discussion.
To display absolute change in the first column and percent change in the second column, set the following (AA represents any two allowed characters, # represents the classification number being shown, 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 containing a different set of parameters separated by semicolons, ;
.
|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 date will treat the row as a date interval, unless the date can be automatically interpolated (for 1 day intervals). This is mostly done when no new cases are reported. Omitting a classification value makes a 0 width stacked bar and omitting all values or the line itself is recommended to depict dates where no data is reported.
The expression for total in the 3rd cases classification has deaths and recoveries automatically subtracted from it. If a manual calculation of the number in that classification (generally active cases) is wanted, use alttot1
. The same applies to the expression for total in the 5th cases 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 |right1=# of cases
, and the 2nd column values will be automatically calculated if |right2=# 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 wanted for 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 the examples.
alttot1 = alternate expression for active cases (3rd cases classification) alttot2 = alternate expression for number in the 5th cases classification firstright1 = whether a change in the first column is not applicable (n.a.) (yesno) firstright2 = whether a change in the second column is not applicable (n.a.) (yesno) enddate = end date of interval if automatic one causes incorrect toggling behavior [required if chart ends with interval] note0 = note text post-fixed to the date, that should create a minimum space consuming object, like a note link, to avoid wrapping note1 = like note0, only post-fixed to column 1 note2 = like note1, only post-fixed to column 2
Examples
{{#invoke:Medical cases chart|chart
|float=center
|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%
}}
{{#invoke:Medical cases chart|chart
|barwidth=wide
|numwidth=mwwd
|rowheight=1.8
|pretitle=Approximate
|disease=Spanish Flu
|location=the World
|posttitle=(excluding Oceania)
|outbreak=1918-20 Spanish Flu pandemic
|altlbl1=Active confirmed
|altlbl2=Suspected
|altlbl3=Estimated
|collapsible=n
|right1=Confirmed cases
|right2=Including suspected and estimated cases
|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
}}
{{#invoke:Medical cases chart|chart
|numwidth=tttt
|disease=Ebola
|location=Guinea-Bissau
|outbreak=2014 EVD epidemic
|altlbl1=hide
|altlbl2=Moderate cases
|altlbl3=Severe cases (hospitalized)
|duration=5
|nooverlap=y
|right1=# of severe cases
|right1data=alttot2
|right2=# of deaths
|changetype=a
|data=
2014-01-01;;;;;;alttot2=1;;+1
2014-01-15;1;;;;;alttot2=1;;=;;+1
<!-- no data reported -->
2014-01-20;2;;;1;;alttot2=1;;=;;+1
<!-- no data reported -->note0={{efn|On Jan 21st, there was a national blackout that forced the data to be reported on the next day.}}
2014-01-22;2;;;2;;alttot2=2;;+1;;=
;2;;;2;;alttot2=2
;2;1;;1;;alttot2=2
2014-02-05;3;1;;1;;alttot2=1
;3;2;;;;alttot2=1;enddate=2014-03-01
;3;2;;1;;alttot2=1
2014-03-30;3;4;;;;alttot2=0;note1={{efn|On Mar 30th, new cases were reported just before the press conference, thus they weren't included in the official count.}}
2014-03-31;3;4;;2;;alttot2=1;;+1
2014-04-01;3;5;;4;;alttot2=2
2014-04-02;5;6;;5;;alttot2=3;note2={{efn|The death of a foreigner at a border crossing medical tent is under dispute if it should be included in Guinea-Bissau's count.}}
;5;8;;3;;alttot2=3;enddate=2014-04-04
|footer={{notelist}}
}}
Applied example
{{COVID-19 pandemic data/Mainland China medical cases chart}}
{{#invoke:Medical cases chart|chart
|numwidth=mmmw
|disease=COVID-19
|location=Mainland China
|outbreak=COVID-19 pandemic
|altlbl1=Tested
|altlbl2=Clinically diagnosed (C.D.)
|altlbl3=Tested or C.D.
|right1=Number of cases<br />(excluding C.D.)
|right2=Number of cases<br />(including C.D.)
|data=
...
|footer=
<div class="center" style="width:90%; margin-left:auto; margin-right:auto;"><small>...</small></div>
...
}}
TemplateData
Produces charts based on {{Bar box}} for outbreak, epidemic and pandemic medical cases.
Parameter | Description | Type | Status | |
---|---|---|---|---|
Float | float | side of the page where the chart will be located (left|center|right|none)
| String | optional |
Bar width | barwidth | width of the stacked bars area (thin|medium|wide|auto)
| String | optional |
Number width | numwidth | maximum width of the numbers in the right columns (AA or AAAA)←(n|t|m|w|x|d)
| String | suggested |
Row height | rowheight | height of each bar in multiples of the text height
| Number | optional |
Pretitle | pretitle | text at the beginning of the title | String | optional |
Disease | disease | name of the disease
| String | required |
Location | location | location of the outbreak the chart is showing
| String | required |
Location 2 | location2 | broader location such as state/province or country
| String | optional |
Location 3 | location3 | broadest location such as country
| String | optional |
Post-title | posttitle | text at the end of the title
| String | optional |
Outbreak | outbreak | name of the main outbreak for the links of the {{navbar}}
| String | required |
Recoveries | recoveries | whether to display recoveries in the legend (yesno)
| Unknown | optional |
Recoveries label | reclbl | alternate label for the recoveries classification
| String | optional |
Alternate label 1 | altlbl1 | alternate label for the third cases classification (hide)
| String | optional |
Alternate label 2 | altlbl2 | alternate label for the fourth cases classification
| String | optional |
Alternate label 3 | altlbl3 | alternate label for the fifth cases classification
| String | optional |
Collapsible | collapsible | whether the rows are collapsible (forced "no" if the days span <= Duration) (yesno)
| Unknown | optional |
Duration | duration | span of last days to initially display to control the default chart height
| Number | optional |
Weekly rows | weekly | whether to create one row per week, rather than per day
| Boolean | optional |
Weekly offset | weeklyoffset | What day of the week to pull data from if weekly=yes
| Number | optional |
No overlap | nooverlap | whether to prevent the last month's toggle from overlapping, in days, with the "Last XX days" toggle (yesno)
| Unknown | optional |
Right 1 | right1 | heading of the first data column
| String | optional |
Right 1 data | right1data | cases classification of the first column for auto filling (1-5|alttot1-2)
| Unknown | optional |
Change type 1 | changetype1 | whether to calculate percent change (%) or absolute change (#) (p|a)
| String | optional |
Right 2 | right2 | heading of the second data column
| String | optional |
Right 2 data | right2data | cases classification of the second column for auto filling (1-5|alttot1-2)
| Unknown | optional |
Change type 2 | changetype2 | whether to calculate percent change (%), absolute change (#) or onlypercent (p|a|o)
| String | optional |
Change type | changetype | applies to both first and second change columns
| String | optional |
Data page | datapage | tabular data page from Commons to scrape cases data from
| Unknown | optional |
Data | data | data lines for each valid date or interval (see Data's syntax)
| Content | suggested |
Caption | caption | caption under the chart
| Content | suggested |
local getArgs = require('Module:Arguments').getArgs
local yesno = require('Module:Yesno')
local p = {}
function p._barColors(n)
if n == 1 then
return 'Black' --deaths
elseif n == 2 then
return 'SkyBlue' --recoveries
elseif n == 3 then
return 'Tomato' --cases or altlbl1
elseif n == 4 then
return 'Gold' --altlbl2
elseif n == 5 then
return 'OrangeRed' --altlbl3
end
return nil
end
function p._legend0(args)
return '<span style="margin:0px; font-size:90%;">' .. '<span style="' .. 'border:' .. (args.border or 'none') .. '; background-color:' .. (args[1] or 'none') .. '; color:' .. (args[1] or 'none') .. ';">' .. ' ' .. '</span>' .. ' ' .. (args[2] or '') .. '</span>'
end
function p._buildBars(args)
local lines = mw.text.split( args.data, '\n' )
local i = 1
if (not args.divisor) or (args.divisor == '') then
local total1, total2 = 0, 0
for parameter in mw.text.gsplit( lines[#lines], ';' ) do
if not string.find( parameter, '^ *%a' ) then
if i == 7 then
total1 = tonumber( (string.gsub( parameter, '%D', '' )) )
if not total1 then
total1 = 0
end
elseif i == 9 then
total2 = tonumber( (string.gsub( parameter, '%D', '' )) )
if not total2 then
total2 = 0
end
break
end
i = i + 1
end
end
args.divisor = math.max( total1, total2 ) / ( 0.95 * args.barwidth )
end
local bars = {}
local barargs
for k, line in pairs( lines ) do
barargs, i = {}, 1
for parameter in mw.text.gsplit( line, ';' ) do
if string.find( parameter, '^ *%a' ) then
parameter = mw.text.split( parameter, '=' )
barargs[parameter[1]] = parameter[2]
else
if parameter ~= '' then
barargs[i] = parameter
end
i = i + 1
end
end
barargs.divisor = args.divisor
barargs.numwidth = args.numwidth
barargs.collapsible = args.collapsible
bars[#bars+1] = p._row(barargs)
end
return table.concat(bars)
end
function p._row(args)
local barargs = {}
frame = mw.getCurrentFrame()
lang=mw.language.getContentLanguage()
if args[1] then
if pcall(function () lang:formatDate('', args[1]) end) then
barargs[1] = args[1]
else
barargs[1] = '<strong class="error">Error: Invalid time.</strong>'
end
else
barargs[1] = '⋮'
end
local two = args[2] or 0
barargs[2] = frame:callParserFunction('#expr', two)
local three = args[3] or 0
barargs[3] = frame:callParserFunction('#expr', three)
if args['alttot1'] then
barargs[4] = frame:callParserFunction('#expr', args['alttot1'])
elseif args[4] then
barargs[4] = frame:callParserFunction('#expr', (args[4] .. '-' .. two .. '-' .. three) )
else
barargs[4] = 0
end
local five = args[5] or 0
barargs[5] = frame:callParserFunction('#expr', five)
if args['alttot2'] then
barargs[6] = frame:callParserFunction('#expr', args['alttot2'])
elseif args[6] then
barargs[6] = frame:callParserFunction('#expr', (args[6] .. '-' .. two .. '-' .. three) )
else
barargs[6] = 0
end
barargs[7] = args[7] or ''
if yesno(args.firstright1) == true then
barargs[8] = '(n.a.)'
elseif (yesno(args.firstright1) == false) or (args.firstright1 == '') or (not args.firstright1) then
if args[1] then
if args[8] then
barargs[8] = '(' .. args[8] .. ')'
else
barargs[8] = ''
end
else
if args[7] then
barargs[8] = '(=)'
elseif args[8] then
barargs[8] = '(' .. args[8] .. ')'
else
barargs[8] = ''
end
end
else
barargs[8] = ''
end
barargs[9] = args[9] or ''
if yesno(args.firstright2) == true then
barargs[10] = '(n.a.)'
elseif (yesno(args.firstright2) == false) or (args.firstright2 == '') or (not args.firstright2) then
if args[1] then
if args[10] then
barargs[10] = '(' .. args[10] .. ')'
else
barargs[10] = ''
end
else
if args[9] then
barargs[10] = '(=)'
elseif args[10] then
barargs[10] = '(' .. args[10] .. ')'
else
barargs[10] = ''
end
end
else
barargs[10] = ''
end
barargs.divisor = args.divisor or 1
barargs.numwidth = args.numwidth
local elapsedDays = (lang:formatDate('\U') - lang:formatDate('\U',args[1])) / 86400
if yesno(args.collapsible) == true then
if args.collapsed then
barargs.collapsed = args.collapsed
elseif ( elapsedDays > 15 ) then
barargs.collapsed = 'y'
else
barargs.collapsed = ''
end
if args.id then
barargs.id = args.id
else
barargs.id = mw.ustring.lower(lang:formatDate('\M',args[1]))
if elapsedDays <= 15 then
barargs.id = barargs.id .. '-l15'
end
end
else
barargs.collapsed = ''
barargs.id = ''
end
return p._customBarStacked(barargs)
end
function p._customBarStacked(args)
barargs = {}
barargs[1] = args[1]
local function _numwidth(n)
if n == 'n' then
return 0
elseif n == 't' then
return 2.45
elseif n == 'm' then
return 3.5
elseif n == 'w' then
return 4.55
elseif n == d then
return 3.5
end
return 3.5
end
width1 = 3.5
width2 = 3.5
if args.numwidth and 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="nowrap">' ..
'<span style="width:' .. width1 .. 'em;padding:0 0.3em 0 0" class="cbs-ibr">' .. (args[7] or '') .. '</span>' ..
'<span style="width:' .. width2 .. 'em" class="cbs-ibl">' .. (args[8] or '') .. '</span>\n' ..
'</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 style="width:' .. width3 .. 'em;padding:0 ' .. padding .. ' 0 0" class="cbs-ibr">'
.. (args[9] or '') ..
'</span>' ..
'<span style="width:' .. width4 .. 'em" class="cbs-ibl">' ..
(args[10] or '') ..
'</span>'
end
for i=1,5,1 do
barargs[(2*i) + 1] = p._barColors(i)
barargs[(2*i) + 2] = tonumber(mw.ustring.format("%.2f", tonumber(args[i+1])/tonumber(args.divisor) ) )
barargs['title' .. i] = args[i+1]
end
barargs.align = 'cdcc'
barargs.collapsed = args.collapsed
barargs.id = args.id
return p._barStacked(barargs)
end
function p._barStacked(args)
local function _align(n, default)
if args.align and args.align ~= '' then
local a = mw.ustring.sub(args.align,n,n)
if a == 'l' then
return 'left'
elseif a == 'c' then
return 'center'
elseif a == 'r' then
return 'right'
elseif a == 'd' then
return default
end
end
return default
end
local output = {}
if args.id and args.id ~= '' then
output[1] = '<tr class="mw-collapsible' .. ( yesno(args.collapsed) and ' mw-collapsed' or '') ..
'" id="mw-customcollapsible-' .. args.id .. '"}}>\n'
else
output[1] = '<tr>\n'
end
output[2] =
'<td ' .. (args.note1 and '' or 'colspan="2" ') ..
'style="text-align:' .. _align(1,'left') .. '" class="bs-04em">' ..
mw.text.trim(args[1] or '') ..
'</td>\n'
if args.note1 and args.note1 ~= '' then
output[3] =
'<td style="text-align:' .. _align(2,'right') .. '" class="bs-04em">' ..
args.note1 ..
'</td>\n'
else
output[3] = ''
end
output[4] = '<td class="bs-silver">\n'
for i=1,5,1 do
if ( (tonumber(args['title' .. i]) or 0) == 0) or ( (tonumber(args[(2*i) + 2]) or 0) == 0) then
output[i+4] = ''
else
output[i+4] =
'<div' .. (args['title' .. i] and (' title=' .. args['title' .. i]) or '') ..
' style="background:' .. (args[(2*i) + 1] or 'gray') ..
';width:' .. mw.text.trim(args[(2*i) + 2] or '0') .. 'px" class="bs-fl">' ..
'​' ..
'</div>\n'
end
end
output[10] = '</td>\n'
output[11] =
'<td ' .. (args.note2 and '' or 'colspan="2" ') ..
'style="text-align:' .. _align(3,'left') .. '" class="bs-04em">' ..
mw.text.trim(args[2] or '') ..
'</td>\n'
if args.note2 and args.note2 ~= '' then
output[12] =
'<td style="text-align:' .. _align(4,'right') .. '" class="bs-04em">' ..
args.note2 ..
'</td>\n'
else
output[12] = ''
end
output[13] = '</tr>\n'
return table.concat(output)
end
function p._chart(args)
local navbar = require('Module:Navbar')._navbar
local barargs = {}
local barwidth = 280
if args.barwidth == 'thin' then
barwidth = 120
elseif args.barwidth == 'medium' then
barwidth = 280
elseif args.barwidth == 'wide' then
barwidth = 400
end
local function _numwidth(p)
local n = mw.ustring.sub((args.numwidth or ''),p,p)
if n == 'n' then
return 0
elseif n == 't' then
return 40
elseif n == 'm' then
return 55
elseif n == 'w' then
return 70
elseif n == '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
barargs.width = (85 + barwidth + numwidth) .. 'px'
barargs.barwidth = barwidth .. 'px'
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 and '/') or '') ..
((args.location2) and (args.location2 and '/') or '') ..
location .. ' medical cases chart'
local title = {}
title[1] = ((args.pretitle) and (args.pretitle .. ' ') or ('')) ..
args.disease .. ' cases in ' .. args.location ..
((args.location2) and (', ' .. args.location2) or '') ..
((args.location3) and (', ' .. args.location3) or '') ..
((args.posttitle) and (' ' .. args.posttitle) or '') .. '<span class="nowrap"> </span>(' ..
navbar({[1] = navbartitle, titleArg = (':' .. mw.getCurrentFrame():getParent():getTitle()), mini = 1, nodiv = 1}) ..
')<br />'
title[2] = p._legend0({[1] = p._barColors(1),[2] = 'Deaths'})
if yesno(args.recoveries) == false then
title[3] = ''
else
title[3] = '<span class="nowrap"> </span>' .. p._legend0({[1] = p._barColors(2),[2] = (args.reclbl or 'Recoveries')})
end
title[4] = '<span class="nowrap"> </span>' .. p._legend0({[1] = p._barColors(3),[2] = (args.altlbl1 or 'Active cases')})
if args.altlbl2 then
title[5] = '<span class="nowrap"> </span>' .. p._legend0({[1] = p._barColors(4),[2] = args.altlbl2})
else
title[5] = ''
end
if args.altlbl3 then
title[6] = '<span class="nowrap"> </span>' .. p._legend0({[1] = p._barColors(5),[2] = args.altlbl3}) ..'\n'
else
title[6] = '\n'
end
title[7] = (args.togglesbar or '') -- this feature is WIP
barargs.title = table.concat(title)
barargs.left1 =
'<div class="center" style="margin-left:auto; margin-right:auto;width:77px;">' .. -- 85-8 because of padding
"'''Date'''" ..
'</div>'
barargs.right1 =
'<div class="center" style="margin-left:auto; margin-right:auto;width:' .. right1 .. 'px;">' ..
(args.right1 or "'''# of cases'''") ..
'</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="margin-left:auto; margin-right:auto;width:' ..right2 ..'px;">' ..
"'''" .. args.right2 .. "'''" ..
'</div>'
end
if args.rows then
barargs.bars = args.rows
elseif args.data then
barargs.bars = p._buildBars({
barwidth = barwidth,
data = args.data,
divisor = args.divisor,
numwidth = args.numwidth,
collapsible = args.collapsible
})
end
barargs.caption = args.caption
return p._barBox(barargs)
end
function p._barBox(args)
local width = args.width or 'auto'
local class = 'barbox'
if args.float == 'left' or args.float == 'right' or args.float == 'none' then
class = 'barbox t' .. args.float
elseif args.float == 'center' then
class = 'barbox tnone'
end
local output = {}
output[1] = mw.getCurrentFrame():extensionTag{ name = 'templatestyles', args = {src='Template:Medical_cases_chart/styles.css'} }
if (args.float == 'left') or (args.float == 'right') then
output[2] = ''
output[12] = ''
else
output[2] = '<table style="margin:' .. ( (args.float == 'center') and '0 auto' or 'auto' ) .. '; border:none;"><tr><td style="border:none; padding:0;">'
output[12] = '</td></tr></table>[[Category:Pages using bar box without float left or float right|' .. ( (width == 'auto') and 'Ω' or '' ) .. mw.title.getCurrentTitle().text .. ']]'
end
output[3] =
'<div class="' .. class .. '" style="overflow-x: auto;' .. (args.style or '') .. '">\n' ..
'<div style="border:' .. (args.border_width or '1') .. 'px solid silver; font-size:88%; padding:0.4em; width:' .. width .. '; background: ' .. (args['background-color'] or 'white') .. ';">\n' ..
'<table style="text-align:left; border-collapse:collapse; width:100%;">\n'
if args.title then
output[4] =
'<tr style="background:' .. (args.titlebar or 'none') .. '">' ..
'<th style="text-align:center;" colspan="5">' .. args.title .. '</th>' ..
'</tr>\n'
else
output[4] = ''
end
output[5] =
'<tr style="font-size:88%; height:4px;">\n' ..
'<td ' .. (args.left2 and '' or 'colspan="2"') .. ' style="padding:0 4px; text-align:left;">' ..
(args.left1 or '') ..
'</td>\n'
if args.left2 then
output[6] = '<td style="padding:0 4px; text-align:right;">' .. args.left2 .. '</td>\n'
else
output[6] = ''
end
output[7] = '<td style="width:' .. (args.barwidth or '100px') .. '; text-align:left;"></td>\n' ..
'<td ' .. (args.right2 and '' or 'colspan="2"') .. ' style="padding:0 4px; width:1em; text-align:right;">' ..
(args.right1 or '') ..
'</td>\n'
if args.right2 then
output[8] = '<td style="padding:0 4px; text-align:right;">' .. args.right2 .. '</td>\n'
else
output[8] = ''
end
output[9] = '</tr>\n' .. (args.bars or '')
if args.caption then
output[10] = '<tr><td colspan="5" style="padding:5px; text-align:left;">' .. args.caption .. '</td></tr>\n'
else
output[10] = ''
end
output[11] = '</table>\n</div>\n</div>\n'
-- output[12] defined above
return table.concat(output)
end
function p.barBox(frame)
local args = getArgs(frame, {
valueFunc = function (key, value)
if value then
value = mw.text.trim(value)
if (key == 'width') or (key == 'float') then
value = mw.ustring.lower(value)
end
if value ~= '' then
return value
end
end
return nil
end
})
return p._barBox(args)
end
function p.chart(frame)
local args = getArgs(frame, {
valueFunc = function (key, value)
if value then
value = mw.text.trim(value)
if (key == 'numwidth') or (key == 'barwidth') or (key == 'recoveries') then
value = mw.ustring.lower(value)
end
if value ~= '' then
return value
end
end
return nil
end
})
return p._chart(args)
end
function p.buildBars(frame)
return p._buildBars(frame.args)
end
return p