Modulo in Lua per gestire le funzioni di ((ClimaAnnuale)) e ((ClimaAnnualeAustrale))
local p = {}
local language = mw.language.getContentLanguage()
local getArgs = require('Module:Arguments').getArgs
local index_month = {"01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12"}
--carico le tabelle dei colori
local tempo_config = mw.loadData( 'Modulo:ClimaAnnuale/Configurazione' );
local function dump(t, ...)
local args = {...}
for _, s in ipairs(args) do
table.insert(t, s)
end
end
-- Nota il lua non ha una funzione di arrotondamento
-- funzione copiata da http://lua-users.org/wiki/SimpleRound
function round(num, idp)
local mult = 10^(idp or 0)
if num >= 0 then return math.floor(num * mult + 0.5) / mult
else return math.ceil(num * mult - 0.5) / mult end
end
-- prima di provare ad applicare tonumber a una stringa converte
-- eventuali virgole in punti
local function tonumber_comma(s)
if s then
s = string.gsub(s, ',', '.')
s = string.gsub(s, '−', '-')
return tonumber(s)
else
return nil
end
end
-- Per leggere una stringa di dati, si aspetta di leggere una stringa
-- di valori separati da "," o ";" da args[<basename>].
-- In caso contrario controlla se sono presenti come sequenza di
-- parametri i valori "args[<base_name>01] .. "args[<basename>12]"
-- Se legge almeno un valore si assicura di restituire almeno 12 valori
-- sostituendo i mancanti con "0"
local function dataArray(args, base_name)
local list = {}
local csv = args[base_name]
if csv then
if string.find(csv, ";") then
list = mw.text.split(string.gsub(csv, "%s", ""), ";")
else
list = mw.text.split(string.gsub(csv, "%s", ""), ",")
end
for i =1, 12 do
if not list[i] or list[i] == '' then list[i] = "0" end
end
elseif args[base_name .. "01"] then
for i, index_string in ipairs(index_month) do
list[i] = args[base_name .. index_string] or "0"
end
end
return list
end
-- Per leggere una stringa di dati, si aspetta di leggere una stringa
-- di valori separati da "," o ";"
local function noteArray(args, base_name, extend)
local list = {}
local csv = args[base_name]
if csv then
if string.find(csv, ";") then
list = mw.text.split(string.gsub(csv, "%s", ""), ";")
else
list = mw.text.split(string.gsub(csv, "%s", ""), ",")
end
else
for i, index_string in ipairs(index_month) do
list[i] = args[base_name .. index_string] or ""
end
end
return list
end
---------------------------------------------------------------
-- Funzioni di generazione del colore celle
-- Ognuna di queste funzioni riceve un valore e ritorna un valore
-- esadecimale da usare come sfondo per la cella, il valore può essere
-- basato su una tabella memorizzata in Modulo:ClimaAnnuale/Configurazione
-- oppure può essere calcolato sulla base di una formula matematica
---------------------------------------------------------------------------
local function TempToColour(temp)
temp = round(temp)
if temp < -19 then return tempo_config.temperatura[-19] end
return tempo_config.temperatura[temp] or 'FF1F00'
end
local function PressureToColour(press)
press = round(press)
if press < -90 then return tempo_config.pressione[-90] end
return tempo_config.pressione[press] or 'FFFFFF'
end
local function PressureToColour1000(press)
return PressureToColour(press-1000)
end
local function WarmToColour(temp)
temp = round(temp)
if temp < 0 then return tempo_config.warm[0] end
return tempo_config.warm[temp] or 'FF0060'
end
local function CloudToColour(okta)
okta = round(okta, 1)
if okta < 0.0 then return tempo_config.cloud[0.0] end
return tempo_config.cloud[okta] or 'FFF0F0'
end
local function RainToColour(mm)
mm = round(mm, 0)
if mm < 0 then return tempo_config.rain[0] end
return tempo_config.rain[mm] or '0000FF'
end
local function RainToColour10(days)
return RainToColour(days*10)
end
local function SnowToColour(cm)
cm = round(cm, 0)
if cm < 0 then return tempo_config.snow[0] end
return tempo_config.snow[cm] or '0000FF'
end
local function SnowToColour10(days)
return SnowToColour(days*10)
end
local function convert_to_FF(val, base, mult)
local result = round(base - (val or 0) * mult)
return math.max(math.min(result, 255), 0)
end
local function IceToColour(days)
return string.format('%02X%02XE5', convert_to_FF(days, 229, 8), convert_to_FF(days, 230, 1))
end
local function FogToColour(days)
return string.format('%02X%02XE5', convert_to_FF(days, 229, 2), convert_to_FF(days, 230, 0.8))
end
local function HumToColour(hum_percent)
local base_percent = convert_to_FF(hum_percent-50, 255, 4.1)
return string.format('%02X%02XFF', base_percent, base_percent)
end
local function HelioToColour(elio)
return string.format('FF%02X%02X', convert_to_FF(-elio, 128, 6.375), convert_to_FF(-elio, 51, 5.1))
end
local function OreSoleToColour(hours)
return string.format('FF%02X%02X', convert_to_FF(hours, 128, .3), convert_to_FF(hours, 51, .1))
end
local function SunToColour(rad)
rad = round(rad/100, 0) * 100
if rad < 0 then return tempo_config.sun[0] end
return tempo_config.sun[rad] or '0000FF'
end
local function GiorniSerenoToColour(days)
return string.format('FF%02X%02X', convert_to_FF(days, 175, 3), convert_to_FF(days, 81, 2))
end
local function IntensitaToColour(rad)
return 'FFFFFF'
end
--------------------------------------------------------------------------
--Fine funzioni di generazione del colore cella
--------------------------------------------------------------------------
local function format_numero(value, force_decimal)
local value_string = language:formatNum(value)
if force_decimal and value % 1 == 0 then
value_string = value_string .. ',0'
end
value_string = mw.ustring.gsub(value_string, "^-", "−")
return value_string
end
--Calcolo del valore medio degli argomenti in ingresso arrotondato alla prima cifra decimale
local function Media( ... )
local args = { ... }
local sum = 0
for _, s in ipairs(args) do
sum = sum + s
end
return round(sum / #args, 1)
end
--Calcolo del totale degli ingressi
local function Totale( ... )
local args = { ... }
local sum = 0
for _, s in ipairs(args) do
sum = sum + s
end
return round(sum, 1)
end
-- Restituisce il valore esadecimale del colore della cella, riceve:
---- color: funzione da richiamare per resistuire il colore
---- value: il valore da usare per il calcolo del valore
---- aggregate_function: la funzione di aggregazione usata
---- div: il numero per cui dividere il valore (3 per la somma di tre mesi, 12 per la somma annuale) per cui dividere il
---- value se la funzione di aggregazione era Total)
local function Cell_color(color, value, aggregate_function, div)
if aggregate_function == Totale then
return color(round(value / div))
else
return color(value)
end
end
-- Configurazione dei dati da leggere e della corrispondente riga di tabella da generare:
---- name: nome base della variabile che contiene il valore
---- color: funzione che assegna il colore alla cella
---- yearname: presente solo per alcune righe. Il nome base della della variabile con l'anno del dato
----- direction: presente solo per intensità (vento). il nome base della variabile con la direzione del vento
---- aggregate: funzione per il calcolo dei valori aggregati (stagionali e annuali)
---- aggregatelabel: attributo css "title" delle celle dei dati aggregati
---- force_decimal: se forzare o meno i dati/risultato con uno zero decimale (",0") quando sono interi
local data_type = {
{ name = 'tempmax', color = TempToColour, aggregate = Media, label = '[[Temperatura|T. max. media]] ([[Grado Celsius|°C]])', aggregatelabel = 'media' },
{ name = 'tempmedia', color = TempToColour, aggregate = Media, label = '[[Temperatura|T. media]] ([[Grado Celsius|°C]])', aggregatelabel= 'media' },
{ name = 'tempmin', color = TempToColour, aggregate = Media, label = '[[Temperatura|T. min. media]] ([[Grado Celsius|°C]])', aggregatelabel= 'media' },
{ name = 'tempassmax', color = TempToColour, aggregate = math.max, yearname = 'annotempassmax', label = '[[Temperatura|T. max. assoluta]] ([[Grado Celsius|°C]])', aggregatelabel= 'massimo' },
{ name = 'tempassmin', color = TempToColour, aggregate = math.min, yearname = 'annotempassmin', label='[[Temperatura|T. min. assoluta]] ([[Grado Celsius|°C]])', aggregatelabel= 'minimo' },
{ name = 'warm', color = WarmToColour, aggregate = Totale, label = '[[Onda di calore|Giorni di calura]] ([[temperatura|T<sub>max</sub>]] ≥ 30 [[Grado Celsius|°C]])', aggregatelabel = 'totale'},
{ name = 'giornigelo', color =IceToColour, aggregate = Totale, label = '[[Giorno di gelo|Giorni di gelo]] ([[temperatura|T<sub>min</sub>]] ≤ 0 [[Grado Celsius|°C]])', aggregatelabel = 'totale'},
{ name = 'giornighiaccio', color=IceToColour, aggregate = Totale, label ='[[Giorno di ghiaccio|Giorni di ghiaccio]] ([[temperatura|T<sub>max</sub>]] ≤ 0 [[Grado Celsius|°C]])', aggregatelabel='totale'},
{ name = 'nubi', color=CloudToColour, aggregate=Media, label='[[Nuvola#Nuvolosità|Nuvolosità]] ([[okta]] al [[giorno]])', aggregatelabel='media' },
{ name = 'pioggia', color=RainToColour, aggregate=Totale, label='[[Precipitazione (meteorologia)|Precipitazioni]] ([[Metro#Multipli e sottomultipli|mm]])', aggregatelabel='totale'},
{ name = 'giornipioggia', color=RainToColour10, aggregate=Totale, label='[[Giorno di pioggia|Giorni di pioggia]]', aggregatelabel='totale'},
{ name = 'neve', color=SnowToColour, aggregate=Totale, label='[[Neve|Nevicate]] ([[Metro#Multipli e sottomultipli|cm]])', aggregatelabel='totale'},
{ name = 'giornineve', color=SnowToColour10, aggregate=Totale, label='[[Neve|Giorni di neve]]', aggregatelabel='totale'},
{ name = 'mantonevoso', color=SnowToColour10, aggregate=Totale, label='[[Neve|Giorni con manto nevoso]] ≥ 1 [[Metro#Multipli e sottomultipli|cm]]', aggregatelabel='totale'},
{ name = 'giornigrandine', color=SnowToColour10, aggregate=Totale, label='[[Grandine|Giorni di grandine]]', aggregatelabel='totale'},
{ name = 'giorninebbia', color=FogToColour, aggregate=Totale, label='[[Nebbia|Giorni di nebbia]]', aggregatelabel='totale'},
{ name = 'umidomax', color=HumToColour, aggregate=Media, label='[[Umidità relativa|Umidità relativa massima media]] (%)', aggregatelabel='media'},
{ name = 'umido', color=HumToColour, aggregate=Media, label='[[Umidità relativa|Umidità relativa media]] (%)', aggregatelabel="media"},
{ name = 'umidomin', color=HumToColour, aggregate=Media, label='[[Umidità relativa|Umidità relativa minima media]] (%)', aggregatelabel='media'},
{ name = 'giornisereno', color= GiorniSerenoToColour, aggregate = Totale, label ='[[Sole|Giorni di cielo sereno]]', aggregatelabel='totale'},
{ name = 'elio', color=HelioToColour, aggregate=Media, label='[[Eliofania|Eliofania assoluta]] ([[ora|ore]] al [[giorno]])', aggregatelabel='media'},
{ name = 'sole', color=SunToColour, aggregate=Totale, label='[[Radiazione solare|Radiazione solare globale media]] (centesimi di [[Joule|MJ]]/[[metro quadrato|m²]])', aggregatelabel='totale'},
{ name = 'oresoleggiamento', color=OreSoleToColour, aggregate=Totale, label='[[Sole|Ore di soleggiamento mensili]]', aggregatelabel='totale'},
{ name= 'pressionereale', color=PressureToColour1000, aggregate=Media, label='[[Pressione atmosferica|Pressione]] a [[Grado Celsius|0 °C]] ([[Pascal (unità di misura)|hPa]])', aggregatelabel='media'},
{ name= 'pressione', color=PressureToColour1000, aggregate=Media, label='[[Pressione atmosferica|Pressione]] a [[livello del mare|0 metri s.l.m.]] ([[Pascal (unità di misura)|hPa]])', aggregatelabel='media'},
{ name= 'tensionevapore', color=PressureToColour, aggregate=Media, label='[[Pressione di vapore|Tensione di vapore]] ([[Pascal (unità di misura)|hPa]])', aggregatelabel='media'},
{ name= 'intensità', color=IntensitaToColour, aggregate=Media, direction='vento', label='[[Vento]] ([[Rosa dei venti|direzione]]-[[metro|m]]/[[secondo|s]])', aggregatelabel='media'}
}
-- ordine in cui aggregare i valori
local aggregate_index = {12, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}
-- ordine dei nomi delle stagioni secondo emisfero boreale/australe
local seasons = {
boreale = { "[[Inverno|Inv]]", "[[Primavera|Pri]]", "[[Estate|Est]]", " [[Autunno|Aut]] " },
australe = { "[[Estate|Est]]", "[[Autunno|Aut]]", "[[Inverno|Inv]]", "[[Primavera|Pri]]" }
}
function p.ClimaAnnuale(frame)
-- Se chiamata mediante #invoke, usa gli argomenti passati al template invocante.
-- Altrimenti a scopo di test assume che gli argomenti siano passati direttamente
local args = getArgs(frame)
local emisphere = args.emisfero or 'boreale'
local season = seasons[emisphere] or seasons.borealea
local equatorial = false
if args.equatoriale and (args.equatoriale == 's' or args.equatoriale == 'S') then
equatorial = true
end
local output = {}
-- testata della tabella
dump(output, '<div style="overflow-x:auto" >',
'<table class="wikitable" style="margin-top:.5em; margin-bottom:.5em; text-align: center;">',
'<tr><th rowspan="2" style="border-right-width: 2px;">', args['nome'] or 'Mese', '</th>',
'<th colspan="12"> [[Mese|Mesi]] </th>')
if not equatorial then
dump(output,'<th colspan="4" style="border-left-width: 2px;" > [[Stagione|Stagioni]] </th>')
end
dump(output, '<th rowspan="2" style="border-left-width: 2px; "> [[Anno]] </th>',
'</tr>',
'<tr>',
'<th> [[Gennaio|Gen]] </th>',
'<th> [[Febbraio|Feb]] </th>',
'<th> [[Marzo|Mar]] </th>',
'<th> [[Aprile|Apr]] </th>',
'<th> [[Maggio|Mag]] </th>',
'<th> [[Giugno|Giu]] </th>',
'<th> [[Luglio|Lug]] </th>',
'<th> [[Agosto|Ago]] </th>',
'<th> [[Settembre|Set]] </th>',
'<th> [[Ottobre|Ott]] </th>',
'<th> [[Novembre|Nov]] </th>',
'<th> [[Dicembre|Dic]] </th>')
if not equatorial then
dump(output, '<th style="border-left-width: 2px;" >', season[1], '</th>')
for j = 2, 4 do
dump(output, '<th>', season[j], '</th>')
end
end
dump(output, '</tr>')
-- generazione delle righe
for _,row in ipairs(data_type) do
local values = dataArray(args, row.name)
local force_decimal = false
--check esistenza del tipo di dato della riga
if #values > 0 then
local yearnames = row.yearname and noteArray(args, row.yearname, false)
local directions = row.direction and noteArray(args, row.direction, false)
dump(output, '<tr><th style="border-right-width: 2px"> ', row.label, ' </th>')
-- ciclo per leggere tutti i valori dei mesi
for i,raw_value in ipairs(values) do
if string.find(raw_value, '.', 1, true) or string.find(raw_value, ',', 1, true) then
force_decimal = true
end
-- converto il valore del mese in numero, se non definito lo setto a 0
values[i] = tonumber_comma(raw_value) or 0
-- apro la cella e genero il valore
dump(output, '<td style="background:#', row.color(values[i]), ';">')
-- per la direzione del vento (da mettere prima della velocità)
if row.direction and directions[i] and directions[i]~= "" then
dump(output, '<small>', directions[i], '</small> <br />')
end
-- aggiungo il valore alla cella
dump(output, format_numero(values[i], force_decimal) )
-- check se devo controllare e aggiungere l'anno del dato
if row.yearname and yearnames[i] ~= '' then
dump(output, '<br /><small>(', yearnames[i], ')</small>')
end
dump(output,'</td>')
end
-- ciclo per generare i dati stagionali aggregati
if not equatorial then
for j = 1, 10, 3 do
local aggregate_season = row.aggregate(values[aggregate_index[j]], values[aggregate_index[j+1]], values[aggregate_index[j+2]])
dump(output, '<td title="', row.aggregatelabel, '" style="border-left-width: 2px; background:#',
Cell_color(row.color, aggregate_season, row.aggregate, 3), ';">\'\'\'', format_numero(aggregate_season, force_decimal), "'''</td>" )
end
end
-- genero il dato annuale aggregato
local aggregate_year = row.aggregate(unpack(values))
dump(output, '<td title="', row.aggregatelabel, '" style="border-left-width: 2px; background:#',
Cell_color(row.color, aggregate_year, row.aggregate, 12), ';">\'\'\'', format_numero(aggregate_year, force_decimal), "'''</td>")
dump(output, '</tr>')
end
end
dump(output, '</table></div>')
return table.concat(output)
end
return p