Modulo:Grafico XY
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 è 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("strict")
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","#2ca02c","#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 = { }
local t
for i =1,#b do
t = string.format("%g",math.floor(10*b[i]/d+0.5)/10)
t = t:gsub('%.',',')
values[i] = { nx = a[i]/c, ny = b[i]/d, num = i, txt = t }
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 = {}}
},
{
name = "y",
type = "linear",
range = "height",
zero = true,
nice = true,
domain = {fields = {}}
},
{
name = "colori",
type = "ordinal",
domain = { data = "nomi", field = "testo"},
range = { }
},
{
name = "colori2",
type = "ordinal",
domain = { data = "area", field = "testo"},
range = { }
}
},
axes = {
{
type = "x",
scale = "x",
title = "",
format = args['formatoX'] or "d",
labelOverlap = "greedy",
grid = true,
properties = {
labels = { font = { value = "Helvetica" } },
title = { font = { value = "Helvetica" } },
}
},
{
type = "y",
scale = "y",
title = "",
grid = true,
format = args['formatoY'] or "d",
labelOverlap = "greedy",
layer = "back",
properties = {
labels = { font = { value = "Helvetica" } },
title = { font = { value = "Helvetica" } },
}
}
},
legends = {
{
fill = "colori",
title = "",
orient = "top-left",
offset = 8,
properties = {
labels = { font = { value = "Helvetica" }, fontSize = { value = 12 } },
symbols = {
strokeWidth = { value = 0 },
shape = { value = "square" },
opacity = { value = 0.7 }
},
legend = { fill = { value = "#fff" } }
}
},
{
fill = "colori2",
title = "",
orient = "top-left",
offset = 8,
properties = {
labels = { font = { value = "Helvetica" }, fontSize = { value = 12 } },
symbols = {
strokeWidth = { value = 0 },
shape = { value = "square" },
opacity = { value = 0.3 }
},
legend = { fill = { value = "#fff" } }
}
}
},
marks = {
{
type = "rect",
from = { data = "area" },
properties = {
enter = {
x = {scale = "x",field = "x1"},
x2 = {scale = "x",field = "x2"},
y = {value = 0},
y2 = {signal = "height"},
fill = {scale = "colori2", field = "testo" },
opacity = {value =0.2 }
}
}
}
}
}
-- titoli assi
local titoloX = args.titoloX or ''
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 ''
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
local dx, dy, dt, cc
local err = '-'
dt = {}
while (args['x'..numero]) do
dx = leggi(args, "x"..numero)
dy = leggi(args, "y"..numero)
if (dx and dy) then
if (#dx == #dy) then
dt[numero] = unisci(dx, dy, fattoreX, fattoreY)
else
err = 'Errore nel numero di elementi per serie '..numero
break
end
else
err = 'Errore nella serie '..numero
break
end
numero = numero+1
end
numero = numero-1
if err == '-' then
for i = 1,numero do
cc = i%10
if cc == 0 then cc = 10 end
graph['data'][i] = {
name = "tab"..i,
transform = { { type = "sort", by = "nx" } },
}
graph['data'][i]['values'] = dt[i]
graph['marks'][1+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[cc] },
strokeWidth = {value = 4},
opacity = {value = 0.5}
}
}
}
graph['marks'][1+i+numero] = {
type = "symbol",
from = {data = "tab"..i },
properties = {
enter = {
x = {scale = "x",field = "nx"},
y = {scale = "y",field = "ny"},
stroke = {value = clr[cc] },
fill = {value = "#fff"},
size = {value = 30}
}
}
}
graph['marks'][1+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"},
font = {value = "Helvetica"},
fontSize = { value = 12 },
text = {field = "txt" }
}
}
}
graph['scales'][1]['domain']['fields'][i] = {data = "tab"..i,field = "nx"}
graph['scales'][2]['domain']['fields'][i] = {data = "tab"..i,field = "ny"}
graph['scales'][3]['range'][i] = clr[cc]
-- colori
if args['colore'..i] then
graph['marks'][1+i]['properties']['enter']['stroke']['value'] = args['colore'..i]
graph['marks'][1+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'][1+i+2*numero]['from']['transform'] = {{ type = "filter", test = "datum.num % 2 == 1"}}
elseif args['etichette'..i] == 'pari' then
graph['marks'][1+i+2*numero]['from']['transform'] = {{ type = "filter", test = "datum.num % 2 == 0"}}
elseif args['etichette'..i] == 'no' then
graph['marks'][1+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'][1+numero+i]['from']['transform'] = {{ type = "filter", test = "datum.num < 1"}}
elseif args['mostra'..i] == '2' then
graph['marks'][1+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'..lg] }
lg = lg +1
end
if args.legenda then graph['legends'][1]['orient'] = args.legenda end
-- annotazioni
graph['data'][numero+2] = {
name = "area",
values = { }
}
lg = 1
while (args['area'..lg]) do
graph['data'][numero+2]['values'][lg] = { testo = args['area'..lg], x1 = args['area'..lg..'_x1'], x2 = args['area'..lg..'_x2'] }
graph['scales'][4]['range'][lg] = args['area'..lg..'_colore'] or clr[lg]
graph['scales'][1]['domain']['fields'][numero+2*lg-1] = {data = "area",field = "x1"}
graph['scales'][1]['domain']['fields'][numero+2*lg] = {data = "area",field = "x2"}
lg = lg +1
end
if args.area_legenda then graph['legends'][2]['orient'] = args.area_legenda end
if (args.minimoX and tonumber(args.minimoX)) then
graph['scales'][1]['domainMin'] = tonumber(args.minimoX)
end
if (args.massimoX and tonumber(args.massimoX)) then
graph['scales'][1]['domainMax'] = tonumber(args.massimoX)
end
if (args.minimoY and tonumber(args.minimoY)) then
graph['scales'][2]['domainMin'] = tonumber(args.minimoY)
end
if (args.massimoY and tonumber(args.massimoY)) then
graph['scales'][2]['domainMax'] = tonumber(args.massimoY)
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 style="font-size:90%;margin-left:30px">'..args.didascalia..'</p>')
end
if (flex[allinea]) then table.insert(ris,flex[allinea][2]) end
if args['debug'] then
return mw.text.jsonEncode(graph)
else
return table.concat(ris)
end
else
return '<span style="color:red"><b>Template GraficoXY:</b> '..err..'</span>'
end
end
-- ======================================================================================================
-- Funzione di intefaccia con template:Grafico XY
-- ======================================================================================================
function p.grafico(frame)
local args = getArgs(frame)
return p._grafico(args)
end
return p