Open main menu
Home
Random
Donate
Recent changes
Special pages
Community portal
Preferences
About Stockhub
Disclaimers
Search
User menu
Talk
Contributions
Create account
Log in
Editing
Module:Sandbox/Erutuon/Temperature arrays
Warning:
You are not logged in. Your IP address will be publicly visible if you make any edits. If you
log in
or
create an account
, your edits will be attributed to your username, along with other benefits.
Anti-spam check. Do
not
fill this in!
f = {} degree = "°" -- used by add_unit_names() minus = "−" -- used by makeRow() and makeTable() thinSpace = mw.ustring.char(0x2009) -- used by makeCell() -- Error message handling 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 -- Input and output parameters 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", "") if string.find(output_parameter, "line break") then cell_format["line_break"] = "yes" elseif string.find(output_parameter, "one line") then cell_format["line_break"] = "no" else cell_format["line_break"] = "auto" 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 -- Number and string-handling functions 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 -- Input parsing 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 -- Color generation palettes = { -- The first three arrays in each palette defines background color using a table of four numbers, -- say { 11, 22, 33, 44 } (values in °C). -- That means the color is 0 below 11 and above 44, and is 255 from 22 to 33. -- The color rises from 0 to 255 between 11 and 22, and falls between 33 and 44. cool = { { -42.75, 4.47, 41.5, 60 }, { -42.75, 4.47, 4.5, 41.5 }, { -90 , -42.78, 4.5, 23 }, white = { -23.3, 37.8 }, }, cool2 = { { -42.75, 4.5 , 41.5, 56 }, { -42.75, 4.5 , 4.5, 41.5 }, { -90 , -42.78, 4.5, 23 }, white = { -23.3, 35 }, }, cool2avg = { { -38, 4.5, 25 , 45 }, { -38, 4.5, 4.5, 30 }, { -70, -38 , 4.5, 23 }, white = { -23.3, 25 }, }, } local function temperature_color(palette, value, out_rgb) --[[ Return style for a table cell based on the given value which should be a temperature in °C. ]] local background_color, text_color value = tonumber(value) if value == nil then background_color, text_color = 'FFF', '000' add_message("Value supplied to <span style=\"background-color: #EEE; font-family: monospace;\">temperature_color</span> is not recognized.") else local min, max = unpack(palette.white or { -23, 35 }) if value < min or value >= max then text_color = 'FFF' else text_color = '' -- This assumes that black text color is the default for most readers. end local background_rgb = out_rgb or {} for i, v in ipairs(palette) do local a, b, c, d = unpack(v) if value <= a then background_rgb[i] = 0 elseif value < b then background_rgb[i] = (value - a) * 255 / (b - a) elseif value <= c then background_rgb[i] = 255 elseif value < d then background_rgb[i] = 255 - ( (value - c) * 255 / (d - c) ) else background_rgb[i] = 0 end end background_color = string.format('%02X%02X%02X', background_rgb[1], background_rgb[2], background_rgb[3]) end if text_color == "" then return background_color else return background_color, text_color end end local function color_CSS(background_color, text_color) if background_color and text_color then return 'background: #' .. background_color .. '; color: #' .. text_color .. ';' elseif background_color then return 'background: #' .. background_color .. ';' else return '' end end function temperature_CSS(value, unit, palette) local palette = palettes[palette] or palettes.cool local value = tonumber(value) if value == nil then error("The function <span style=\"background-color: #EEE; font-family: monospace;\">temperature_CSS</span> is receiving a nil value") else if unit == 'C' then return color_CSS(temperature_color(palette, value)) elseif unit == 'F' then return color_CSS(temperature_color(palette, convert(value, decimals, 'F'))) else unit_error(unit or "nil") end end end --[[ ==== Cell, row, table generation ==== ]] 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 makeCell(output_format, a, b, c) local cell, cell_content = "", "" local color_CSS, other_CSS, title_attribute, sortkey, attribute_separator, 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) }, { thinSpace .. "/" .. thinSpace, if_yes(output_format.convert_units, thinSpace .. "/" .. thinSpace) } 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, 116.5/88.0. 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_format.first .. "\"" 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.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 .. makeCell(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 .. makeCell(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 .. makeCell(output_format, a[i]) end end output = mw.ustring.gsub(output, "([%p%s])-(%d)", "%1" .. minus .. "%2") return output 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 .. makeCell(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 .. makeCell(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 .. makeCell(output_format, a[i]) end end output = mw.ustring.gsub(output, "([%p%s])-(%d)", "%1" .. minus .. "%2") --[[ Makes sure that hyphens in "data-sort-type" are not replaced with minuses. 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 return f
Summary:
Please note that all contributions to Stockhub may be edited, altered, or removed by other contributors. If you do not want your writing to be edited mercilessly, then do not submit it here.
You are also promising us that you wrote this yourself, or copied it from a public domain or similar free resource (see
Stockhub:Copyrights
for details).
Do not submit copyrighted work without permission!
Cancel
Editing help
(opens in new window)
Templates used on this page:
Template:Abbr
(
edit
)
Template:Cite web
(
edit
)
Template:WRCC
(
edit
)
Module:Sandbox/Erutuon/Temperature arrays
(
edit
)
Module:Sandbox/Erutuon/Temperature arrays/doc
(
edit
)