local p =
require('strict')
local degree = "°" -- used by addUnitNameslocal minus = "−" -- used by makeRow and makeTablelocal thinSpace = mw.ustring.char(0x2009) -- used by makeCell
local precision, decimals
-- if not emptylocal function ine(var) var = tostring(var) if var
-- Error message handlinglocal message = ""
local function addMessage(newMessage) if ine(message) then message = message .. " " .. newMessage else message = "Notices: " .. newMessage endend
local function monospace(str) return '
' .. str .. ''end-- Input and output parameterslocal function getFormat(inputParameter, outputParameter, palette, messages) local length, inputUnit, outputUnit, palette, show, cellFormat if inputParameter
"C" then outputUnit = "F" else outputUnit = "C" end -- Make sure nothing except C, F, numbers, or spaces is in the input parameter. if string.find(inputParameter, "[^CF%d%s]") then addMessage("There are extraneous characters in the " .. monospace("output") .. " parameter.") end end if outputParameter
nil then cellFormat["convertUnits"] = false else if cellFormat[2]
"show" return end
-- Math functions
local function round(value, decimals) value = tonumber(value) if type(value)
local function convert(value, unit, decimals) -- Unit is the unit being converted from. if not unit then error("No unit supplied to convert.", 2) end if tonumber(value) then local value = tonumber(value) if unit
"F" then return round((value - 32) * 5/9, decimals) else error("Input unit not recognized", 2) end else -- to avoid concatenation errors return "" endend
-- Stick numbers into array. Find out if any have decimals.-- Throw an error if any are invalid.local function _makeArray(format) return function(parameter) if not parameter then return nil end local array = -- If there are multiple parameters for numbers, and the first doesn't have -- decimals, the rest will have their decimals rounded off. format.precision = format.precision or parameter:find("%d%.%d") and "1" or "0" local numbers = mw.text.split(parameter, "%s+") if #numbers ~= format.length then addMessage('There are not ' .. format.length .. ' values in the ' .. parameter .. ' parameter.') end for i, number in ipairs(numbers) do if not number:find("^%-?%d%d?%d?.?(%d?)$") then error('The number "' .. number .. '" does not fit the expected pattern.') end table.insert(array, number) end return array endend
-- Color generation
p.palettes =
--Return style for a table cell based on the given value which should be a temperature in °C. local function temperatureColor(palette, value, outRGB) local backgroundColor, textColor value = tonumber(value) if not value then backgroundColor, textColor = 'FFF', '000' addMessage("Value supplied to " .. monospace("temperatureColor") .. " is not recognized.") else local min, max = unpack(palette.white or) if value < min or value >= max then textColor = 'FFF' -- Else nil. -- This assumes that black text color is the default for most readers. end
local backgroundRGB = outRGB or for i, v in ipairs(palette) do local a, b, c, d = unpack(v) if value <= a then backgroundRGB[i] = 0 elseif value < b then backgroundRGB[i] = (value - a) * 255 / (b - a) elseif value <= c then backgroundRGB[i] = 255 elseif value < d then backgroundRGB[i] = 255 - ((value - c) * 255 / (d - c)) else backgroundRGB[i] = 0 end end backgroundColor = string.format('%02X%02X%02X', unpack(backgroundRGB)) end return backgroundColor, textColorend
local function colorCSS(backgroundColor, textColor) if backgroundColor and textColor then return 'background: #' .. backgroundColor .. '; color: #' .. textColor .. ';' elseif backgroundColor then return 'background: #' .. backgroundColor .. ';' else return endend
local function temperatureColorCSS(palette, value, outRGB) return colorCSS(temperatureColor(palette, value, outRGB))end
local function temperatureCSS(value, unit, palette) local palette = p.palettes[palette] or p.palettes.cool local value = tonumber(value) if value
'F' then value = convert(value, 'F', decimals) elseif unit ~= 'C' then unitError(unit or "nil") end return colorCSS(temperatureColor(palette, value)) endend
local function styleAttribute(palette, value, outRGB) local fontSize = "font-size: 85%;" local color = temperatureColorCSS(palette, value, outRGB) return 'style=\"' .. color .. ' ' .. fontSize .. '\"'end
local style_attribute = styleAttribute
--[=[ Used by {{Average temperature table/row/C/sandbox}}, {{Average temperature table/row/F/sandbox}}, {{Average temperature table/row/C/sandbox}}, {{Template:Avg temp row F/sandbox2}}, {{Template:Avg temp row C/sandbox2}}. ]=]function p.temperatureStyle(frame) local palette = p.palettes[frame.args.palette] or p.palettes.cool local unit = frame.args.unit or 'C' local value = tonumber(frame.args[1]) if unit
p.temperature_style = p.temperatureStyle
--
local outputFormat
local function addUnitNames(value, yesOrNo, unit) if not unit then error("No unit supplied as argument 3 to addUnitNames", 2) end -- Don't add a unit name to an empty string value = yesOrNo
local function ifYes(parameter, realization1, realization2) local result if realization1 then if realization2 then result = parameter
true and realization1 or "" end else result = "" addMessage(monospace("ifYes") .. " needs at least one realization.") end return resultend
local function makeCell(outputFormat, a, b, c, format) local cell, cellContent = "", "" local colorCSS, otherCSS, titleAttribute, sortkey, attributeSeparator, convertedUnitsSeparator = "", "", "", "", "", "", "" -- Distinguish styleAttribute variable from styleAttribute function above. local styleAttribute, highLowSeparator, brackets, values, convertedUnits = ,,,, -- Precision is 1 if any number has one or more decimals. decimals = tonumber(outputFormat.decimals) and outputFormat.decimals or format.precision if tonumber(b) and tonumber(a) then values, highLowSeparator =, elseif tonumber(a) then values = elseif tonumber(c) then values = end if outputFormat.first
true then convertedUnits = end values = elseif outputFormat.first
"F" then if outputFormat.convertUnits
true then brackets = outputFormat.brackets
"auto" then convertedUnitsSeparator = (ine(values[2]) or decimals ~= "0" or outputFormat.showUnits
true and "
" or outputFormat.lineBreak
true and temperatureCSS(c, format.inputUnit, format.palette, format.inputUnit) or "" if tonumber(b) and tonumber(a) then local attributeValue = outputFormat.first
true and " data-sort-value=\"" .. attributeValue .. "\"" or "" titleAttribute = " title=\"Average temperature: " .. attributeValue .. " " .. degree .. outputFormat.first .. "\"" end elseif tonumber(b) then colorCSS = "" elseif tonumber(a) then colorCSS = outputFormat.color
true and "font-size: 85%;" or "" if ine(colorCSS) or ine(otherCSS) then styleAttribute = end if ine(otherCSS) or ine(colorCSS) or ine(titleAttribute) or ine(sortkey) then attributeSeparator = " | " end cell = "\n| " .. styleAttribute[1] .. colorCSS .. otherCSS .. styleAttribute[2] .. titleAttribute .. sortkey .. attributeSeparator .. cellContent return cellend
--Replaces hyphens that have a punctuation or space character before them and a number after them, making sure that hyphens in "data-sort-type" are not replaced with minuses. If Lua had (?<=), a capture would not be necessary. local function hyphenToMinus(str) return str:gsub("([%p%s])-(%d)", "%1" .. minus .. "%2")end
function p.makeRow(frame) local args = frame.args local format = getFormat(args.input, args.output, args.palette, args.messages) local makeArray = _makeArray(format) local a, b, c = makeArray(args.a), makeArray(args.b), makeArray(args.c) local output = if args[1] then table.insert(output, "\n|-") table.insert(output, "\n! " .. args[1]) if args[2] then table.insert(output, " !! " .. args[2]) end end if format.cellFormat then outputFormat = format.cellFormat end -- Assumes that if c is defined, b and a are, and if b is defined, a is. if c then if not outputFormat then outputFormat = outputFormats.high_low_average_F end for i = 1, format.length do table.insert(output, makeCell(outputFormat, a[i], b[i], c[i], format)) end elseif b then if not outputFormat then outputFormat = outputFormats.high_low_F end for i = 1, format.length do table.insert(output, makeCell(outputFormat, a[i], b[i], nil, format)) end elseif a then if not outputFormat then outputFormat = outputFormats.average_F end for i = 1, format.length do table.insert(output, makeCell(outputFormat, a[i], nil, nil, format)) end end output = table.concat(output) output = hyphenToMinus(output) return outputend
function p.makeTable(frame) local args = frame.args local format = getFormat(args.input, args.output, args.palette, args.messages) local makeArray = _makeArray(format) local a, b, c = makeArray(args.a), makeArray(args.b), makeArray(args.c) local output = ") if format.show then table.insert(output, "\n\n
" .. message .. "") end output = table.concat(output) output = hyphenToMinus(output) return outputendlocal chart = width=600|height=180|xAxisTitle=Celsius|yAxisTitle=__COLOR|type=line|x=__XVALUES|y=__YVALUES|colors=__COLOR}}
function p.show(frame) -- For testing, return wikitext to show graphs of how the red/green/blue colors -- vary with temperature, and a table of the resulting colors. local function collection -- Return a table to hold items. return end local function make_chart(result, color, xvalues, yvalues) result:add('\n') result:add(frame:preprocess((chart:gsub('__[A-Z]+',)))) end local function with_minus(value) if value < 0 then return minus .. tostring(-value) end return tostring(value) end local args = frame.args local first = args[1] or -90 local last = args[2] or 59 local palette = p.palettes[args.palette] or p.palettes.cool local xvals, reds, greens, blues = collection, collection, collection, collection local wikitext = collection wikitext:add('
-\n') local columns = 0 for celsius = first, last do local backgroundRGB = local style = styleAttribute(palette, celsius, backgroundRGB) local R = math.floor(backgroundRGB[1]) local G = math.floor(backgroundRGB[2]) local B = math.floor(backgroundRGB[3]) xvals:add(celsius) reds:add(R) greens:add(G) blues:add(B) wikitext:add(' | ' .. style .. ' | ' .. with_minus(celsius) .. '\n') columns = columns + 1 if columns >= 10 then columns = 0 wikitext:add(' | -\n') end end wikitext:add(' |
return p