Module:Sandbox/Erutuon/Temperature arrays
Testcases
Random examples
Lua error at line 4: Tried to write global weather. Lua error at line 4: Tried to write global weather. Lua error at line 4: Tried to write global weather. Lua error at line 4: Tried to write global weather. Lua error at line 4: Tried to write global weather.
Lua error at line 4: Tried to write global weather. Lua error at line 4: Tried to write global weather.
California
Lua error at line 4: Tried to write global weather.Lua error at line 4: Tried to write global weather.Lua error at line 4: Tried to write global weather.Lua error at line 4: Tried to write global weather.Lua error at line 4: Tried to write global weather.Lua error at line 4: Tried to write global weather.Lua error at line 4: Tried to write global weather.Lua error at line 4: Tried to write global weather.Lua error at line 4: Tried to write global weather.Lua error at line 4: Tried to write global weather.Lua error at line 4: Tried to write global weather.Lua error at line 4: Tried to write global weather.| Place | Jan | Feb | Mar | Apr | May | Jun | Jul | Aug | Sep | Oct | Nov | Dec | Year
Lua error at line 4: Tried to write global weather. Lua error at line 4: Tried to write global weather. Lua error at line 4: Tried to write global weather. Lua error at line 4: Tried to write global weather. Lua error at line 4: Tried to write global weather. |
|---|
Minnesota
| Jan | Feb | Mar | Apr | May | Jun | Jul | Aug | Sept | Oct | Nov | Dec | Annual
Lua error at line 4: Tried to write global weather. Lua error at line 4: Tried to write global weather. Lua error at line 4: Tried to write global weather. Lua error at line 4: Tried to write global weather. Lua error at line 4: Tried to write global weather. Lua error at line 4: Tried to write global weather. Lua error at line 4: Tried to write global weather. Lua error at line 4: Tried to write global weather. Lua error at line 4: Tried to write global weather. Lua error at line 4: Tried to write global weather. |
|---|
f = {}
degree = "°"
minus = "−" -- not currently used
weather = require("Module:Weather/sandbox")
message = ""
local function add_message(new_message)
if show then
if check_for_string(message) then
message = message .. " " .. new_message
else
message = "Notices: " .. new_message
end
end
end
local function get_format (frame)
local input_parameter = frame.args.input
local output_parameter = frame.args.output
if input_parameter == nil then
error("Please provide the number of values and a unit in the input parameter")
else
length = tonumber(string.match(input_parameter, "(%d+)")) -- Find digits in the input parameter.
input_unit = string.match(input_parameter, "([CF])") -- C or F
if string.find(input_parameter, "[^CF%d%s]") then
add_message("There are extraneous characters in the <span style=\"background-color: #EEE; font-family: monospace;\">output</span> parameter.")
end
end
if input_unit == "C" then
output_unit = "F"
elseif input_unit == "F" then
output_unit = "C"
else
error ("Please provide an input unit in the input parameter: F for Fahrenheit or C for Celsius", 0)
end
if length == nil then
error ("get_format has not found a length value in the input parameter")
end
if output_parameter == nil then
add_message("No output format has been provided in the <span style=\"background-color: #EEE; font-family: monospace;\">output</span> parameter.")
else
cell_format = {}
local n = 1
for unit in output_parameter:gmatch("[CF]") do
cell_format[n] = unit
n = n + 1
if n > 2 then
break
end
end
local function set_format(key, formatVariable, formatValue1, formatValue2)
if string.find(output_parameter, key) then
cell_format[formatVariable] = formatValue1
else
cell_format[formatVariable] = formatValue2
end
end
if cell_format[1] then
cell_format.first = cell_format[1]
else
error("C or F not found in output parameter")
end
if cell_format[2] == nil then
cell_format["convert_units"] = "no"
else
if cell_format[2] == cell_format[1] then
error("There should not be two of the same unit name in the output parameter.")
else
cell_format["convert_units"] = "yes"
end
end
set_format("unit", "unit_names", "yes", "no")
set_format("no ?color", "color", "no", "yes")
set_format("sort", "sortable", "yes", "no")
set_format("full ?size", "small_font", "no", "yes")
set_format("no ?brackets", "brackets", "no", "yes")
set_format("round", "decimals", "0", "")
cell_format["line break"] = "auto"
if string.find(output_parameter, "line break") then
cell_format["line_break"] = "yes"
end
if string.find(output_parameter, "one line") then
cell_format["line_break"] = "no"
end
if string.find(output_parameter, "one line") and string.find(output_parameter, "line break") then
error("Place either \"one line\" or \"line break\" in the output parameter, not both")
end
end
if frame.args.palette == nil then
palette = "cool2avg"
else
palette = frame.args.palette
end
if frame.args.messages == "show" then
show = true
else
show = false
end
return length, input_unit, output_unit
end
local function check_for_number(value)
return type(tonumber(value)) == "number"
end
function check_for_string(string)
string = tostring(string)
return string ~= "" and string ~= nil
end
local function round(value, decimals)
value = tonumber(value)
if type(value) == "number" then
local string = string.format("%." .. decimals .. "f", value)
return string
elseif value == nil then
value = "nil"
add_message("Format was asked to operate on " .. value .. ", which cannot be converted to a number.", 2)
return ""
end
end
local function convert(value, decimals, unit) -- Unit is the unit being converted from. It defaults to input_unit.
if not unit then
unit = input_unit
end
if check_for_number(value) then
local value = tonumber(value)
if unit == "C" then
add_message(value .. " " .. degree .. unit .. " was converted.")
return round(value * 9/5 + 32, decimals)
elseif unit == "F" then
add_message(value .. " " .. degree .. unit .. " was converted.")
return round((value - 32) * 5/9, decimals)
else
error("Input unit not recognized", 2)
end
else
return "" -- Setting result to empty string if value is not a number avoids concatenation errors.
end
end
function make_array(parameter, array, frame)
local array = {}
local n = 1
for number in parameter:gmatch("%-?%d+%.?%d?") do
local number = number
if n == 1 then
local decimals = number:match("%.(%d+)")
if decimals == nil then
precision = "0"
else
precision = #decimals
end
end
table.insert(array, n, number)
n = n + 1
if n > length then
break
end
end
if not array[length] then
add_message("There are not " .. length .. " values in the " .. parameter .. " parameter.")
end
return array, precision
end
function make_arrays(frame)
get_format(frame)
local parameter_a = frame.args.a
local parameter_b = frame.args.b
local parameter_c = frame.args.c
if parameter_a then
a = make_array(parameter_a, a, frame)
else
error("Please provide a set of numbers in parameter a")
end
if parameter_b then
b = make_array(parameter_b, b, frame)
else
add_message("There is no content in parameter <span style=\"background-color: #EEE; font-family: monospace;\">b</span>.")
end
if parameter_c then
c = make_array(parameter_c, c, frame)
else
add_message("There is no content in parameter <span style=\"background-color: #EEE; font-family: monospace;\">c</span>.")
end
return a, b, c
end
local output_formats = {
high_low_average_F =
{ first = "F",
convert_units = "yes",
unit_names = "no",
color = "yes",
small_font = "yes",
sortable = "yes",
decimals = "0",
brackets = "yes",
line_break = "auto", },
high_low_average_C =
{ first = "C",
convert_units = "yes",
unit_names = "no",
color = "yes",
small_font = "yes",
sortable = "yes",
decimals = "0",
brackets = "yes",
line_break = "auto", },
high_low_F =
{ first = "F",
convert_units = "yes",
unit_names = "no",
color = "no",
small_font = "yes",
sortable = "no",
decimals = "",
brackets = "yes",
line_break = "auto", },
high_low_C =
{ first = "C",
convert_units = "yes",
unit_names = "no",
color = "no",
small_font = "yes",
sortable = "no",
decimals = "0",
brackets = "yes",
line_break = "auto", },
average_F =
{ first = "F",
convert_units = "yes",
unit_names = "no",
color = "yes",
small_font = "yes",
sortable = "no",
decimals = "0",
brackets = "yes",
line_break = "auto", },
average_C =
{ first = "C",
convert_units = "yes",
unit_names = "no",
color = "yes",
small_font = "yes",
sortable = "no",
decimals = "0",
brackets = "yes",
line_break = "auto", },
}
local function add_unit_names(value, unit)
if not unit then unit = input_unit end
if output_format.unit_names == "yes" then
if check_for_string(value) then
return value .. " " .. degree .. unit
else
return value -- Don't add a unit name to an empty string
end
else
return value
end
end
local function if_yes(parameter, realization1, realization2)
if realization1 then
if realization2 then
if parameter == "yes" then
parameter = { realization1, realization2 }
else
parameter = { "", "" }
end
else
if parameter == "yes" then
parameter = realization1
else
parameter = ""
end
end
else
parameter = ""
add_message("<span style=\"background-color: #EEE; font-family: monospace;\">if_yes</span> needs at least one realization")
end
return parameter
end
function format_cell(output_format, a, b, c)
local cell, cell_content = "", ""
local color_CSS, other_CSS, title_attribute, sortkey, attribute_separator, decimals, converted_units_separator = "", "", "", "", "", "", ""
local style_attribute, high_low_separator, brackets, values, converted_units = {"", ""}, {"", ""}, {"", ""}, {"", ""}, {"", ""}
if check_for_number(output_format.decimals) then
decimals = output_format.decimals
--[[ Precision is the number of decimals in the first number of the last array.
This may be a problem for data from Weatherbase,
which seems to inappropriately remove .0 from numbers that have it. ]]
else
decimals = precision
end
if check_for_number(b) and check_for_number(a) then
values, high_low_separator = { round(a, decimals), round(b, decimals) }, { " / ", if_yes(output_format.convert_units, " / ") }
elseif check_for_number(a) then
values = { round(a, decimals), "" }
elseif check_for_number(c) then
values = { round(c, decimals), "" }
end
if output_format.first == input_unit then
if output_format.convert_units == "yes" then
converted_units = { add_unit_names(convert(values[1], decimals), output_unit), add_unit_names(convert(values[2], decimals), output_unit) }
end
values = { add_unit_names(values[1]), add_unit_names(values[2]) }
elseif output_format.first == "C" or output_format.first == "F" then
if output_format.convert_units == "yes" then
converted_units = { add_unit_names(values[1]), add_unit_names(values[2]) }
end
values = { add_unit_names(convert(values[1], decimals), output_unit), add_unit_names(convert(values[2], decimals), output_unit) }
else
if output_format.first == nil then
output_format.first = "nil"
end
add_message("<span style=\"background-color: #EEE; font-family: monospace;\">" .. output_format.first .. "</span>, the value for <span style=\"background-color: #EEE; font-family: monospace;\">first</span> in <span style=\"background-color: #EEE; font-family: monospace;\">output_format</span> is not recognized.")
end
--[[
Regarding line breaks:
If there are two values, there will be at least three characters: 9/1.
If there is one decimal, numbers will be three to five characters long
and there will be 3 to 10 characters total even without unit conversion:
1.1, 111.1/90.9.
If there are units, that adds three characters per number: 25 °C/20 °C.
In each of these cases, a line break is needed so that table cells are not too wide;
even more so when more than one of these things are true.
]]
if output_format.convert_units == "yes" then
brackets = if_yes(output_format.brackets, "(", ")" )
if output_format.line_break == "auto" then
if check_for_string(values[2]) or decimals ~= "0" or output_format.show_units == "yes" then
converted_units_separator = "<br>"
else
converted_units_separator = " "
end
elseif output_format.line_break == "yes" then
converted_units_separator = "<br>"
elseif output_format.line_break == "no" then
converted_units_separator = " "
else
error("Value for line_break not recognized")
end
end
cell_content = values[1] .. high_low_separator[1] .. values[2] .. converted_units_separator .. brackets[1] .. converted_units[1] .. high_low_separator[2] .. converted_units[2] .. brackets[2]
if check_for_number(c) then
color_CSS = if_yes(output_format.color, temperature_CSS(c, input_unit, palette))
if check_for_number(b) and check_for_number(a) then
local attribute_value
if output_format.first == input_unit then
attribute_value = c
else
attribute_value = convert(c, decimals)
end
sortkey = if_yes(output_format.sortable, " data-sort-value=\"" .. attribute_value .. "\"")
title_attribute = " title=\"Average temperature: " .. attribute_value .. " " .. degree .. output_unit .. "\""
end
elseif check_for_number(b) then
color_css = ""
elseif check_for_number(a) then
color_CSS = if_yes(output_format.color, temperature_CSS(a, input_unit, palette))
else
add_message("Neither a nor b nor c are strings.")
end
other_CSS = if_yes(output_format.small_font, "font-size: 85%;")
if check_for_string(color_CSS) or check_for_string(other_CSS) then
style_attribute = { "style=\"", "\"" }
end
if check_for_string(other_CSS) or check_for_string(color_CSS) or check_for_string(title_attribute) or check_for_string(sortkey) then
attribute_separator = " | "
end
cell = "\n| " .. style_attribute[1] .. color_CSS .. other_CSS .. style_attribute[2] .. title_attribute .. sortkey .. attribute_separator .. cell_content
return cell
end
function f.makeTable(frame)
make_arrays(frame)
local output = "{| class=\"wikitable center nowrap\""
if cell_format then
output_format = cell_format
end
if a and b and c then
for i = 1, length do
if not output_format then
output_format = output_formats.high_low_average_F
end
output = output .. format_cell(output_format, a[i], b[i], c[i])
end
elseif a and b then
for i = 1, length do
if not output_format then
output_format = output_formats.high_low_F
end
output = output .. format_cell(output_format, a[i], b[i])
end
elseif a then
for i = 1, length do
if not output_format then
output_format = output_formats.average_F
end
output = output .. format_cell(output_format, a[i])
end
end
output = string.gsub(output, "([%(%s;])-", "%1" .. minus)
--[[ Makes sure that hyphens in "data-sort-type" are not replaced with minuses.
";" is the last character in " ", the the HTML character reference for the thin space, used above.
If Lua had (?<=), a capture would not be necessary. ]]
output = output .. "\n|}"
if show then
output = output .. "\n\n<span style=\"color: red; font-size: 80%; line-height: 100%;\">" .. message .. "</span>"
end
return output
end
function f.makeRow(frame)
make_arrays(frame)
local output = ""
if frame.args[1] then
output = "\n|-"
output = output .. "\n! " .. frame.args[1]
if frame.args[2] then
output = output .. " !! " .. frame.args[2]
end
end
if cell_format then
output_format = cell_format
end
if a and b and c then
for i = 1, length do
if not output_format then
output_format = output_formats.high_low_average_F
end
output = output .. format_cell(output_format, a[i], b[i], c[i])
end
elseif a and b then
for i = 1, length do
if not output_format then
output_format = output_formats.high_low_F
end
output = output .. format_cell(output_format, a[i], b[i])
end
elseif a then
for i = 1, length do
if not output_format then
output_format = output_formats.average_F
end
output = output .. format_cell(output_format, a[i])
end
end
output = string.gsub(output, "([%(%s;])-", "%1" .. minus)
return output
end
return f