Modulo:Grafico epidemia: differenze tra le versioni

Da Wikipedia, l'enciclopedia libera.
Vai alla navigazione Vai alla ricerca
Contenuto cancellato Contenuto aggiunto
m Commenti
dalla sandbox: 1) Usa classe per padding, 2) Non costruire elementi vuoti
Riga 340: Riga 340:
output[2] =
output[2] =
'<td ' .. (args.note1 and '' or 'colspan="2" ') ..
'<td ' .. (args.note1 and '' or 'colspan="2" ') ..
'style="padding-left:0.4em; padding-right:0.4em; text-align:' .. _align(1,'left') .. '">' ..
'class="grafico-epidemia-padded" style="text-align:' .. _align(1,'left') .. '">' ..
'⋮'..
'⋮'..
'</td>\n'
'</td>\n'
Riga 346: Riga 346:
output[2] =
output[2] =
'<td ' .. (args.note1 and '' or 'colspan="2" ') ..
'<td ' .. (args.note1 and '' or 'colspan="2" ') ..
'style="padding-left:0.4em; padding-right:0.4em; text-align:' .. _align(1,'left') .. '">' ..
'class="grafico-epidemia-padded" style="text-align:' .. _align(1,'left') .. '">' ..
mw.text.trim(lang:formatDate("d-m-Y", args[1]) or '') ..
mw.text.trim(lang:formatDate("d-m-Y", args[1]) or '') ..
'</td>\n'
'</td>\n'
Riga 353: Riga 353:
if args.note1 and args.note1 ~= '' then
if args.note1 and args.note1 ~= '' then
output[3] =
output[3] =
'<td style="padding-left:0.4em; padding-right:0.4em; text-align:' .. _align(2,'right') .. '">' ..
'<td class="grafico-epidemia-padded" style="text-align:' .. _align(2,'right') .. '">' ..
args.note1 ..
args.note1 ..
'</td>\n'
'</td>\n'
Riga 362: Riga 362:
output[4] = '<td style="border-left:1px solid silver; border-right:1px solid silver">\n'
output[4] = '<td style="border-left:1px solid silver; border-right:1px solid silver">\n'
for i=1,5,1 do
for i=1,5,1 do
width = mw.text.trim(args[(2*i) + 2] or '0');
output[i+4] =
'<div' .. (args['title' .. i] and (' title=' .. args['title' .. i]) or '') ..
if width ~= '0' then
output[i+4] =
'<div' .. (args['title' .. i] and (' title=' .. args['title' .. i]) or '') ..
' style="background:' .. (args[(2*i) + 1] or 'gray') ..
' style="background:' .. (args[(2*i) + 1] or 'gray') ..
'; float:left; overflow:hidden; width:' .. mw.text.trim(args[(2*i) + 2] or '0') .. 'px">' ..
'; float:left; overflow:hidden; width:' .. width .. 'px">' ..
'&#8203;' ..
'&#8203;' ..
'</div>\n'
'</div>\n'
else
output[i+4] = '';
end
end
end
Riga 375: Riga 380:
output[11] =
output[11] =
'<td ' .. (args.note2 and '' or 'colspan="2" ') ..
'<td ' .. (args.note2 and '' or 'colspan="2" ') ..
'style="padding-left:0.4em; padding-right:0.4em; text-align:' .. _align(3,'left') .. '">' ..
'class="grafico-epidemia-padded" style="text-align:' .. _align(3,'left') .. '">' ..
mw.text.trim(args[2] or '') ..
mw.text.trim(args[2] or '') ..
'</td>\n'
'</td>\n'
Riga 381: Riga 386:
if args.note2 and args.note2 ~= '' then
if args.note2 and args.note2 ~= '' then
output[12] =
output[12] =
'<td style="padding-left:0.4em; padding-right:0.4em; text-align:' .. _align(4,'right') .. '">' ..
'<td class="grafico-epidemia-padded" style="text-align:' .. _align(4,'right') .. '">' ..
args.note2 ..
args.note2 ..
'</td>\n'
'</td>\n'

Versione delle 15:13, 26 ago 2020

Questo modulo serve la creazione di grafici a barre inerenti a epidemie. Il modulo è stato costruito per importare dati scritti a modello statunitense, quindi con il "." come indicatore decimale e la "," come indicatore delle migliaia, oltre che con le date in formato "yyyy-mm-dd". Se inseriti in questa forma, il modulo li convertirà come nella notazione italiana.


local getArgs = require('Modulo:Arguments').getArgs
local yesno = require('Modulo:Yesno')

local p = {}

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

function p._barColors(n)
	if n == 1 then
		return 'Black' --morti
	elseif n == 2 then
		return 'Lightgreen' --guarigioni o reclbl
	elseif n == 3 then
		return 'Red' --casi o altlbl1
	elseif n == 4 then
		return 'Gold' --etichettacategoria4
	elseif n == 5 then
		return 'OrangeRed' --etichettacategoria5 
	end

	return nil
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
		
		function format_thousand(v)
    		local s = string.format("%d", math.floor(v))
			local pos = string.len(s) % 3
    		if pos == 0 then pos = 3 end
    		return string.sub(s, 1, pos)
    		.. string.gsub(string.sub(s, pos+1), "(...)", ".%1")
		end

		local function fillCols(col, change)
			local data 
			local changetype 
			local value, num, prevnum
			if col == 1 then 
				data = args.right1data or 3
			   changetype = args.changetype1 or 'p'
			else 
				data = args.right2data or 1
				changetype = args.changetype2 or 'p'
			end
				num = tonumber(barargs[tonumber(data) + 1])
			    prevnum = tonumber(prevRow[tonumber(data) + 1])
			    
			if  num then -- nothing in column, source found, and data exists
				value = num
				
				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 = '='
								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
				value = format_thousand(value)
			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 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
		bars[i] = p._row(rows[i])
	end
	
	return table.concat(bars)
end

function p._row(args)
	local barargs = {}
	local rowDate = args.prevDate or ''
	frame = mw.getCurrentFrame()
	lang=mw.language.getContentLanguage()
	
	if args[1] then
		if pcall(function () lang: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
	
	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

	if args[7] then
		barargs[7] = string.gsub(args[7],",",".") or ''
	else
		barargs[7] = ''
	end
	
	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 ''
				change = string.gsub(change,"%.",",")
			end
		end

		return change
	end

	barargs[8] = changeArg(1,7,8)
	if args[9] then
		barargs[9] = string.gsub(args[9],",",".") or ''	
	else
		barargs[9] = ''
	end
	barargs[10] = changeArg(2,9,10)
	
	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(mw.getLanguage('it'):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; text-align:right; display:inline-block">' .. (args[7] or '') .. '</span>' ..
			'<span style="width:' .. width2 .. 'em; text-align:left; display:inline-block">' .. (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; text-align:right; display:inline-block">' 
				.. (args[9] or '') .. 
			'</span>' ..
			'<span style="width:' .. width4 .. 'em; text-align:left; display:inline-block">' ..
				(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
	
	if args[1]=='⋮' then
	output[2] =
		'<td ' .. (args.note1 and '' or 'colspan="2" ') .. 
		'class="grafico-epidemia-padded" style="text-align:' .. _align(1,'left') .. '">' .. 
			'⋮'..  
		'</td>\n'
	else 
	output[2] =
		'<td ' .. (args.note1 and '' or 'colspan="2" ') .. 
		'class="grafico-epidemia-padded" style="text-align:' .. _align(1,'left') .. '">' .. 
			 mw.text.trim(lang:formatDate("d-m-Y", args[1]) or '') ..	
		'</td>\n'
	end
	
	if args.note1 and args.note1 ~= '' then
		output[3] = 
			'<td class="grafico-epidemia-padded" style="text-align:' .. _align(2,'right') .. '">' .. 
				args.note1 .. 
			'</td>\n'
	else
		output[3] = ''
	end
	
	output[4] = '<td style="border-left:1px solid silver; border-right:1px solid silver">\n'
	
	for i=1,5,1 do
		width = mw.text.trim(args[(2*i) + 2] or '0');
		if width ~= '0' then
			output[i+4] = 
				'<div' .. (args['title' .. i] and (' title=' .. args['title' .. i]) or '') ..
				' style="background:' .. (args[(2*i) + 1] or 'gray') ..
				'; float:left; overflow:hidden; width:' .. width .. 'px">' ..
					'&#8203;' ..
				'</div>\n'
		else
			output[i+4] = '';
		end
	end
	
	output[10] = '</td>\n'
	
	output[11] = 
		'<td ' .. (args.note2 and '' or 'colspan="2" ') .. 
		'class="grafico-epidemia-padded" style="text-align:' .. _align(3,'left') .. '">' .. 
			mw.text.trim(args[2] or '') .. 
		'</td>\n'
	
	if args.note2 and args.note2 ~= '' then
		output[12] = 
		'<td class="grafico-epidemia-padded" style="text-align:' .. _align(4,'right') .. '">' .. 
			args.note2 ..
		'</td>\n'
	else
		output[12] = ''
	end
	
	output[13] = '</tr>\n'
	
	return table.concat(output)
end

function p.buildBars(frame)
	return p._buildBars(frame.args)
end

return p