Info Istruzioni per l'uso
Questo è un modulo scritto in Lua. Le istruzioni che seguono sono contenute nella sottopagina Modulo:Grafico XY/man (modifica · cronologia)
Sandbox: Modulo:Grafico XY/sandbox (modifica · cronologia) · Sottopagine: lista · Test: Modulo:Grafico XY/test (modifica · cronologia · esegui)

Questo modulo serve a creare un grafico per {{Grafico XY}}.


require("Module:No globals")
local getArgs = require('Module:Arguments').getArgs
local p = {}

local flex = {}
flex['primo'] = {'<div style="display:flex;flex-direction:row;flex-wrap:wrap"><div style="flex-grow:0;flex-shrink:0;flex-basis:auto;padding: 0 2em 0 0">','</div>'}
flex['medio'] = {'<div style="flex-grow:0;flex-shrink:0;flex-basis:auto;padding: 0 2em 0 0">','</div>'}
flex['ultimo'] = {'<div style="flex-grow:0;flex-shrink:0;flex-basis:auto;padding: 0 2em 0 0">','</div></div>'}
flex['destra'] = {'<div class="floatright">','</div>'}

local clr = { "#1f77b4","#ff7f0e","#2ca02c2","#d62728","#9467bd","#8c564b","#e377c2","#7f7f7f","#bcbd22","#17becf" }

-- =====================================================================
-- Legge gli argomenti per caricare un array di valori numerici.
-- =====================================================================
local function leggi(args, a)
	local array = {}
	if args[a] then
		array = mw.text.split(string.gsub(args[a], "%s", ""), ",")
	end
	for _,v in ipairs(array) do
		v = tonumber(v)
	end
	return array
end
-- =====================================================================
-- Fonde due liste in un'unica lista
-- =====================================================================
local function unisci(a,b,c,d)
	local values = { }
	for i =1,#b do
		values[i] = { nx = a[i]/c, ny = b[i]/d, num = i }
	end
	return values
end

-- =====================================================================
-- Generazione del grafico
-- =====================================================================
function p._grafico(args)
	-- Definizione base del grafico
	local graph = {
		version = 2,
		width = 350,
		height = 250,
		padding = "auto",
		data = { },
		scales = {
			{
				name = "x",
				type = "linear",
				range = "width",
				zero = false,
				___domain = {fields = {{data = "tab",field = "nx"}, {data = "tab2",field = "nx"}, {data = "tab3",field = "nx"}}}
			},
			{
				name = "y",
				type = "linear",
				range = "height",
				zero = true,
				nice = true,
				___domain = {fields = {{data = "tab",field = "ny"}, {data = "tab2",field = "ny"}, {data = "tab3",field = "ny"}}}
			},
			{
				name = "colori",
				type = "ordinal",
				___domain = { data = "nomi", field = "testo"},
				range = { }
			}
		},
		axes = {
			{
				type = "x",
				scale = "x",
				title = "X",
				format = "d",
				grid = true,
			},
			{
				type = "y",
				scale = "y",
				title = "Y",
				grid = true,
				format = "d",
				layer = "back"
			}
		},
		legends = {
			{
				fill = "colori",
				title = "",
				orient = "top-left",
				offset = 8,
				shape = {value = "square"},
				strokeWidth =  0
			}
		},
		marks = { }
	}
	-- titoli assi
	local titoloX = args.titoloX or 'X'
	local fattoreX = args.fattoreX and tonumber(args.fattoreX) and tonumber(args.fattoreX) or 1
	if fattoreX == 0 then
		fattoreX = 1
	elseif fattoreX == 1000 then
		titoloX = titoloX..' (migliaia)'
	elseif fattoreX == 1000000 then
		titoloX = titoloX..' (milioni)'
	end
	graph['axes'][1]['title'] = titoloX
	local titoloY = args.titoloY or 'Y'
	local fattoreY = args.fattoreY and tonumber(args.fattoreY) and tonumber(args.fattoreY) or 1
	if fattoreY == 0 then
		fattoreY = 1
	elseif fattoreY == 1000 then
		titoloY = titoloY..' (migliaia)'
	elseif fattoreY == 1000000 then
		titoloY = titoloY..' (milioni)'
	end
	graph['axes'][2]['title'] = titoloY

	-- zero su assi
	if (args.zeroX and args.zeroX == 's') then graph['scales'][1]['zero'] = true end
	if (args.zeroY and args.zeroY == 'n') then graph['scales'][2]['zero'] = false end

	-- dimensioni
	graph['width'] = args.dimx and tonumber(args.dimx) and tonumber(args.dimx) or 350
	graph['height'] = args.dimy and tonumber(args.dimy) and tonumber(args.dimy) or 250

	-- legge valori
	local numero = 1
	while (args['x'..numero]) do numero = numero+1 end
	numero = numero-1
	
	local dx
	local dy
	for i = 1,numero do
		graph['data'][i] = {
			name = "tab"..i,
			transform = { { type = "sort", by = "nx" } },
		}
		dx = leggi(args, "x"..i)
		dy = leggi(args, "y"..i)
		graph['data'][i]['values'] =  unisci(dx, dy, fattoreX, fattoreY)

		graph['marks'][i] = {
			type = "line",
			from = {data = "tab"..i },
			properties = {
				enter = {
					interpolate = {value = "linear"},
					x = {scale = "x",field = "nx"},
					y = {scale = "y",field = "ny"},
					stroke = {value = clr[i%10+1] },
					strokeWidth = {value = 4},
					opacity = {value = 0.5}
				}
			}
		}
		graph['marks'][i+numero] = {
			type = "symbol",
			from = {data = "tab"..i },
			properties = {
				enter = {
					x = {scale = "x",field = "nx"},
					y = {scale = "y",field = "ny"},
					stroke = {value = clr[i%10+1] },
					fill = {value = "#fff"},
					size = {value = 30}
				}
			}
		}
		graph['marks'][i+2*numero] = {
			type = "text",
			from = { data = "tab"..i },
			properties = {
				enter = {
					x = {scale = "x",field = "nx"},
					y = {scale = "y",field = "ny", offset = -8},
					align = {value = "center"},
					fill = {value = "#000"},
					text = {field = "ny" }
				}
			}
		}
		graph['scales'][3]['range'][i] = clr[i%10+1]
		-- colori
		if args['colore'..i] then
			graph['marks'][i]['properties']['enter']['stroke']['value'] = args['colore'..i]
			graph['marks'][i+numero]['properties']['enter']['stroke']['value'] = args['colore'..i]
			graph['scales'][3]['range'][i] = args['colore'..i]
		end
		-- opzioni etichette
		if args['etichette'..i] then
			if args['etichette'..i] == 'dispari' then
				graph['marks'][i+2*numero]['from']['transform'] = {{ type = "filter", test = "datum.num % 2 == 1"}}
			elseif args['etichette'..i] == 'pari' then
				graph['marks'][i+2*numero]['from']['transform'] = {{ type = "filter", test = "datum.num % 2 == 0"}}
			elseif args['etichette'..i] == 'no' then
				graph['marks'][i+2*numero]['from']['transform'] = {{ type = "filter", test = "datum.num < 1"}}
			end
		end
		-- mostra dati
		if args['mostra'..i] then
			if args['mostra'..i] == '1' then
				graph['marks'][numero+i]['from']['transform'] = {{ type = "filter", test = "datum.num < 1"}}
			elseif args['mostra'..i] == '2' then
				graph['marks'][i]['from']['transform'] = {{ type = "filter", test = "datum.num < 1"}}
			end
		end
	end
	-- legenda
	graph['data'][numero+1] = {
		name = "nomi",
		values = { }
	}
	local lg = 1
	while (args['nome'..lg]) do
		graph['data'][numero+1]['values'][lg] = { testo = args['nome'..i] }
		lg = lg +1
	end
	if args.legenda then graph['legends'][1]['orient'] = args.legenda end

	local ris = {}
	local allinea = args['allinea'] or ''
	if (flex[allinea]) then table.insert(ris,flex[allinea][1]) end
	table.insert(ris,mw.getCurrentFrame():extensionTag('graph', mw.text.jsonEncode(graph)))
	if (args.didascalia) then
		table.insert(ris,'<p>'..args.didascalia..'</p>')
	end
	if (flex[allinea]) then table.insert(ris,flex[allinea][2]) end
	return table.concat(ris)
end

-- ======================================================================================================
-- Funzione di intefaccia con template:Demografia
-- ======================================================================================================
function p.grafico(frame)
	local args = getArgs(frame)
	return p._grafico(args)
end

return p