உள்ளடக்கத்துக்குச் செல்

Module:Medical cases chart

கட்டற்ற கலைக்களஞ்சியமான விக்கிப்பீடியாவில் இருந்து.
en>Ahecht பயனரால் செய்யப்பட்ட 21:44, 21 ஏப்ரல் 2020 அன்றிருந்தவாரான திருத்தம் (Sync from sandbox. Fix column heading bolding, change last 15 days to be the last 15 days where data exists, automatically calculate values in right1 and right2, optimize redundant code)

Documentation for this module may be created at Module:Medical cases chart/doc

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

local function is(v)
	return (v or '') ~= ''
end

local p = {}

function p._barColors(n)
	local colors = {
		'DimGrey', --deaths
		'SkyBlue', --recoveries
		'Tomato', --cases or altlbl1
		'Gold', --altlbl2
		'OrangeRed' --altlbl3
	}

	return colors[n]
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') .. ';">' .. '&nbsp;&nbsp;&nbsp;&nbsp;' .. '</span>' .. '&nbsp;' .. (args[2] or '') .. '</span>'
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 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="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(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
	
	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">Error: Invalid time.</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 = '(n.a.)'
		elseif (yesno(args['firstright' .. firstright]) == false) or (not is(args['firstright' .. firstright])) then
			if (not is(args[1])) and is(args[valuecol]) then
				change = '(=)'
			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
	
	if yesno(args.collapsible) == true then
		if args.collapsed then
			barargs.collapsed = args.collapsed
		elseif args.rowsToEnd >= 15 then
			barargs.collapsed = 'y'
		else
			barargs.collapsed = ''
		end
		
		if args.id then
			barargs.id = args.id
		else
			barargs.id = mw.ustring.lower(mw.getLanguage('en'):formatDate('\M',rowDate))
			if args.rowsToEnd < 15 then
				barargs.id = barargs.id .. '-l15'
			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 bars, rows, 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 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 = mw.getContentLanguage():formatNum(num) -- set value to num
				if (not change) and yesno(barargs['firstright' .. col] ~= true) then
					if(prevnum) then -- data on previous row
						if (num-prevnum ~= 0) then --data has changed since previous row
							change = 100 * (num - prevnum) / (prevnum) -- calculate percent
							local rounding = ( (math.abs(change)>=10) and "%.0f" or ((math.abs(change)>=1) and "%.1f" or "%.2f") )
							change = tonumber( mw.ustring.format(rounding, change) ) -- round to two sigfigs
							if change > 0 then
								change = '+' .. change .. '%'
							elseif change < 0 then
								change = change .. '%'
							else
								change = '='
							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 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
		
		barargs.prevDate = prevRow[1]
		rows[#rows+1] = barargs
		prevRow = barargs
	end
	
	for i=1,#rows,1 do
		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
		bars[i] = p._row(rows[i])
	end
	
	return table.concat(bars)
end

function p._chart(args)
	local navbar = require('Module:Navbar')._navbar
	
	local barargs = {}
	
	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
	
	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'
		
	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">&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] = 'Deaths'})	
	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 'Recoveries')})
	end
	title[4] = '<span class="nowrap">&nbsp;&nbsp;&nbsp;</span>' .. p._legend0({[1] = p._barColors(3),[2] = (args.altlbl1 or 'Active cases')})
	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] = (args.togglesbar or '') -- this feature is WIP
	
	barargs.title = table.concat(title)
	barargs.left1 = 
		'<div class="center" style="width:77px;">' .. -- 85-8 because of padding
			"'''Date'''" ..
		'</div>'
	
	barargs.right1 = 
		'<div class="center" style="width:' .. right1 .. 'px;">' ..
			"'''" .. (args.right1 or "&#35; 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="width:' ..right2 ..'px;">' .. 
			"'''" .. args.right2 .. "'''" ..
		'</div>'
	end

	if args.rows then
		barargs.bars = args.rows
	elseif args.data then
		barargs.bars = p._buildBars({
			barwidth = tonumber(barwidth) or 280,
			data = args.data,
			divisor = args.divisor,
			numwidth = args.numwidth,
			collapsible = args.collapsible,
			right1data = args.right1data or -- if no right1data and right1 title is default, use 3rd classification
				( (not args.right1) and 3 ), 
			right2data = args.right2data or -- if no right2data and right2 title is deaths, use 1st classification
				( (args.right2 == '# of deaths' or args.right2 == '&#35; of deaths') and 1 ) 
			})
	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 (key == 'numwidth') or (key == 'barwidth') or (key == 'recoveries') then
					value = mw.ustring.lower(value)
				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)
	return p._buildBars(frame.args)
end

return p
"https://ta.wikipedia.org/w/index.php?title=Module:Medical_cases_chart&oldid=2999061" இலிருந்து மீள்விக்கப்பட்டது