Module:Weather/sandbox
This is the module sandbox page for Module:Weather (diff). |
This module can be used to display temperatures in a table. It is under development and is intended to be efficient so a page can hold many tables.
- Input numbers must use a hyphen if negative (Unicode minus "−" would give an error).
- All displayed numbers (including inputs) use Unicode minus if negative.
- The input consists of 13 values, separated by any number of spaces.
- Each of the 13 values must be a number. Any invalid value results in the corresponding cell being blank with no error message or tracking category.
The following functions are available:
Function | Input | Output |
---|---|---|
CtoF |
°C | °C (°F) |
FfromC |
°C | °F (°C) |
CfromF |
°F | °C (°F) |
FtoC |
°F | °F (°C) |
The following templates use the module:
An example using the above templates and the module is at:
The output can be examined by entering the following example at Special:ExpandTemplates. The output from each of the following lines is identical.
{{#invoke:weather|CtoF|-10 -5 0 5 10 15 20 25 30 35 40 45 50}} ---- {{#invoke:weather|CfromF|14 23 32 41 50 59 68 77 86 95 104 113 122}}
Optional parameter
|palette=
name- Where name is the built-in name of a palette:
- cool (default)
- cool2 (modified)
- cool2avg (modified and intended for average temperatures)
- Where name is the built-in name of a palette:
Testing
[edit]The function show
provides a way to test the color schemes. It generates a graph of how the red, green, and blue portions of the color vary with temperature, and a table of the full range of temperatures in °C.
Optional parameters
- Two unnamed parameters may be entered to specify the first and last Celsius temperatures (
|-90|59
by default). - The palette can be specified with
|palette=
name as above.
The following codes produce the same result:
{{#invoke:weather|show}}
{{#invoke:weather|show|palette=cool}}
−90 | −89 | −88 | −87 | −86 | −85 | −84 | −83 | −82 | −81 |
−80 | −79 | −78 | −77 | −76 | −75 | −74 | −73 | −72 | −71 |
−70 | −69 | −68 | −67 | −66 | −65 | −64 | −63 | −62 | −61 |
−60 | −59 | −58 | −57 | −56 | −55 | −54 | −53 | −52 | −51 |
−50 | −49 | −48 | −47 | −46 | −45 | −44 | −43 | −42 | −41 |
−40 | −39 | −38 | −37 | −36 | −35 | −34 | −33 | −32 | −31 |
−30 | −29 | −28 | −27 | −26 | −25 | −24 | −23 | −22 | −21 |
−20 | −19 | −18 | −17 | −16 | −15 | −14 | −13 | −12 | −11 |
−10 | −9 | −8 | −7 | −6 | −5 | −4 | −3 | −2 | −1 |
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 |
30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 |
40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 |
50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 |
Graphs are unavailable due to technical issues. Updates on reimplementing the Graph extension, which will be known as the Chart extension, can be found on Phabricator and on MediaWiki.org. |
Graphs are unavailable due to technical issues. Updates on reimplementing the Graph extension, which will be known as the Chart extension, can be found on Phabricator and on MediaWiki.org. |
Graphs are unavailable due to technical issues. Updates on reimplementing the Graph extension, which will be known as the Chart extension, can be found on Phabricator and on MediaWiki.org. |
Modified palette:
{{#invoke:weather|show|palette=cool2}}
−90 | −89 | −88 | −87 | −86 | −85 | −84 | −83 | −82 | −81 |
−80 | −79 | −78 | −77 | −76 | −75 | −74 | −73 | −72 | −71 |
−70 | −69 | −68 | −67 | −66 | −65 | −64 | −63 | −62 | −61 |
−60 | −59 | −58 | −57 | −56 | −55 | −54 | −53 | −52 | −51 |
−50 | −49 | −48 | −47 | −46 | −45 | −44 | −43 | −42 | −41 |
−40 | −39 | −38 | −37 | −36 | −35 | −34 | −33 | −32 | −31 |
−30 | −29 | −28 | −27 | −26 | −25 | −24 | −23 | −22 | −21 |
−20 | −19 | −18 | −17 | −16 | −15 | −14 | −13 | −12 | −11 |
−10 | −9 | −8 | −7 | −6 | −5 | −4 | −3 | −2 | −1 |
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 |
30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 |
40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 |
50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 |
Graphs are unavailable due to technical issues. Updates on reimplementing the Graph extension, which will be known as the Chart extension, can be found on Phabricator and on MediaWiki.org. |
Graphs are unavailable due to technical issues. Updates on reimplementing the Graph extension, which will be known as the Chart extension, can be found on Phabricator and on MediaWiki.org. |
Graphs are unavailable due to technical issues. Updates on reimplementing the Graph extension, which will be known as the Chart extension, can be found on Phabricator and on MediaWiki.org. |
This modified palette is intended for average temperatures. It results in good colors between the extreme highest average monthly temperature of +39 °C (102 °F) in Death Valley, California, and −68 °C (−90 °F), the extreme lowest average monthly temperature at Vostok Station, at a high elevation on the Antarctic ice sheet. These are the highest and lowest known average temperatures recorded on Earth, not to be confused with the highest and lowest records, which are quite a bit hotter and colder.
{{#invoke:weather|show|palette=cool2avg}}
−90 | −89 | −88 | −87 | −86 | −85 | −84 | −83 | −82 | −81 |
−80 | −79 | −78 | −77 | −76 | −75 | −74 | −73 | −72 | −71 |
−70 | −69 | −68 | −67 | −66 | −65 | −64 | −63 | −62 | −61 |
−60 | −59 | −58 | −57 | −56 | −55 | −54 | −53 | −52 | −51 |
−50 | −49 | −48 | −47 | −46 | −45 | −44 | −43 | −42 | −41 |
−40 | −39 | −38 | −37 | −36 | −35 | −34 | −33 | −32 | −31 |
−30 | −29 | −28 | −27 | −26 | −25 | −24 | −23 | −22 | −21 |
−20 | −19 | −18 | −17 | −16 | −15 | −14 | −13 | −12 | −11 |
−10 | −9 | −8 | −7 | −6 | −5 | −4 | −3 | −2 | −1 |
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 |
30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 |
40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 |
50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 |
Graphs are unavailable due to technical issues. Updates on reimplementing the Graph extension, which will be known as the Chart extension, can be found on Phabricator and on MediaWiki.org. |
Graphs are unavailable due to technical issues. Updates on reimplementing the Graph extension, which will be known as the Chart extension, can be found on Phabricator and on MediaWiki.org. |
Graphs are unavailable due to technical issues. Updates on reimplementing the Graph extension, which will be known as the Chart extension, can be found on Phabricator and on MediaWiki.org. |
local p = {}
require('strict')
local degree = "°" -- used by addUnitNames()
local minus = "−" -- used by makeRow() and makeTable()
local thinSpace = mw.ustring.char(0x2009) -- used by makeCell()
local precision, decimals
-- if not empty
local function ine(var)
var = tostring(var)
if var == "" then
return nil
else
return var
end
end
-- Error message handling
local message = ""
local function addMessage(newMessage)
if ine(message) then
message = message .. " " .. newMessage
else
message = "Notices: " .. newMessage
end
end
local function monospace(str)
return '<span style="background-color: #EEE; font-family: monospace;">' .. str .. '</span>'
end
-- Input and output parameters
local function getFormat(inputParameter, outputParameter, palette, messages)
local length, inputUnit, outputUnit, palette, show, cellFormat
if inputParameter == nil then
error('Please provide the number of values and a unit in the input parameter')
else
-- Find as many as two digits in the input parameter.
length = tonumber(string.match(inputParameter, "(%d%d?)"))
if not length then
length = 13
addMessage('getFormat has not found a length value in the input parameter; length defaults to "13"')
end
-- Find C or F, but not both
if string.find(inputParameter, "C") and string.find(inputParameter, "F") then
error("Input unit must be either C (Celsius) or F (Fahrenheit)")
else
inputUnit = string.match(inputParameter, "([CF])") or error("Please provide an input unit in the input parameter: F for Fahrenheit or C for Celsius", 0)
end
if inputUnit == "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
-- Since there are default values, the module will still generate output with an empty output parameter.
addMessage("No output format has been provided in the " .. monospace("output") .. " parameter, so default values will be used.")
else
cellFormat = {}
for i, unit in require("Module:StringTools").imatch(outputParameter, "[CF]") do
cellFormat[i] = unit
if i > 2 then
break
end
end
local function setFormat(key, variable, value)
if string.find(outputParameter, key) then
cellFormat[variable] = value
else
cellFormat[variable] = not value
end
end
if cellFormat[1] then
cellFormat.first = cellFormat[1]
else
error('C or F not found in output parameter')
end
if cellFormat[2] == nil then
cellFormat["convertUnits"] = false
else
if cellFormat[2] == cellFormat[1] then
error('There should not be two of the same unit name in the output parameter.')
else
cellFormat["convertUnits"] = true
end
end
setFormat("unit", "unitNames", true)
setFormat("no ?color", "color", false)
setFormat("sort", "sortable", true)
setFormat("full ?size", "smallFont", false)
setFormat("no ?brackets", "brackets", false)
setFormat("round", "decimals", "0", "")
if string.find(outputParameter, "line break") then
cellFormat["lineBreak"] = true
elseif string.find(outputParameter, "one line") then
cellFormat["lineBreak"] = false
else
cellFormat["lineBreak"] = "auto"
end
if string.find(outputParameter, "one line") and
string.find(outputParameter, "line break") then
error('Place either "one line" or "line break" in the output parameter, not both')
end
end
palette = palette or "cool2avg"
show = messages == "show"
return {
length = length, inputUnit = inputUnit, outputUnit = outputUnit,
cellFormat = cellFormat, show = show, palette = palette
}
end
-- Math functions
local function round(value, decimals)
value = tonumber(value)
if type(value) == "number" then
return string.format("%." .. decimals .. "f", value)
else
error("Format was asked to operate on " .. tostring(value) .. ", which cannot be converted to a number.", 2)
return ""
end
end
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 == "C" then
return round(value * 9/5 + 32, decimals)
elseif unit == "F" then
return round((value - 32) * 5/9, decimals)
else
error("Input unit not recognized", 2)
end
else
-- to avoid concatenation errors
return ""
end
end
-- 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
end
end
-- Color generation
p.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 that, on the scale from 0 (black) to 255 (saturated), the color
is 0 below 11°C and above 44°C, and is 255 from 22°C to 33°C.
The color rises from 0 to 255 between 11°C and 22°C, and falls from 255 to 0
between 33°C and 44°C.
]]
cool = {
{ -42.75, 4.47, 41.5, 60 }, -- red
{ -42.75, 4.47, 4.5, 41.5 }, -- green
{ -90 , -42.78, 4.5, 23 }, -- blue
white = { -23.3, 37.8 }, -- background
},
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 },
},
}
--[[ 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 { -23, 35 })
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, textColor
end
local function colorCSS(backgroundColor, textColor)
if backgroundColor and textColor then
return 'background: #' .. backgroundColor .. '; color: #' .. textColor .. ';'
elseif backgroundColor then
return 'background: #' .. backgroundColor .. ';'
else
return ''
end
end
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 == nil then
error("The function " .. monospace("temperatureCSS") .. " is receiving a nil value")
else
if unit == 'F' then
value = convert(value, 'F', decimals)
elseif unit ~= 'C' then
unitError(unit or "nil")
end
return colorCSS(temperatureColor(palette, value))
end
end
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 == 'F' then
value = convert(value, 'F', 1)
elseif unit ~= 'C' then
error('Unrecognized unit: ' .. unit)
end
return styleAttribute(palette, value)
end
p.temperature_style = p.temperatureStyle
--[[ ==== Cell, row, table generation ==== ]]
local outputFormats = {
high_low_average_F =
{ first = "F",
convertUnits = true,
unitNames = false,
color = true,
smallFont = true,
sortable = true,
decimals = "0",
brackets = true,
lineBreak = "auto", },
high_low_average_C =
{ first = "C",
convertUnits = true,
unitNames = false,
color = true,
smallFont = true,
sortable = true,
decimals = "0",
brackets = true,
lineBreak = "auto", },
high_low_F =
{ first = "F",
convertUnits = true,
unitNames = false,
color = false,
smallFont = true,
sortable = false,
decimals = "",
brackets = true,
lineBreak = "auto", },
high_low_C =
{ first = "C",
convertUnits = true,
unitNames = false,
color = false,
smallFont = true,
sortable = false,
decimals = "0",
brackets = true,
lineBreak = "auto", },
average_F =
{ first = "F",
convertUnits = true,
unitNames = false,
color = true,
smallFont = true,
sortable = false,
decimals = "0",
brackets = true,
lineBreak = "auto", },
average_C =
{ first = "C",
convertUnits = true,
unitNames = false,
color = true,
smallFont = true,
sortable = false,
decimals = "0",
brackets = true,
lineBreak = "auto", },
}
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 == true and ine(value) and value .. " " .. degree .. unit or value
return value
end
local function ifYes(parameter, realization1, realization2)
local result
if realization1 then
if realization2 then
result = parameter == true and { realization1, realization2 } or { "", "" }
else
result = parameter == true and realization1 or ""
end
else
result = ""
addMessage(monospace("ifYes") .. " needs at least one realization.")
end
return result
end
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 = { round(a, decimals), round(b, decimals) },
{ thinSpace .. "/" .. thinSpace, ifYes(outputFormat.convertUnits, thinSpace .. "/" .. thinSpace) }
elseif tonumber(a) then
values = { round(a, decimals), "" }
elseif tonumber(c) then
values = { round(c, decimals), "" }
end
if outputFormat.first == format.inputUnit then
if outputFormat.convertUnits == true then
convertedUnits = { addUnitNames(convert(values[1], format.inputUnit, decimals), outputFormat.unitNames, format.outputUnit), addUnitNames(convert(values[2], format.inputUnit, decimals), outputFormat.unitNames, format.outputUnit) }
end
values = { addUnitNames(values[1], outputFormat.unitNames, format.inputUnit), addUnitNames(values[2], outputFormat.unitNames, format.inputUnit) }
elseif outputFormat.first == "C" or outputFormat.first == "F" then
if outputFormat.convertUnits == true then
convertedUnits = { addUnitNames(values[1], outputFormat.unitNames, format.inputUnit), addUnitNames(values[2], outputFormat.unitNames, format.inputUnit) }
end
values = { addUnitNames(convert(values[1], format.inputUnit, decimals), outputFormat.unitNames, format.outputUnit), addUnitNames(convert(values[2], format.inputUnit, decimals), outputFormat.unitNames, format.outputUnit) }
else
addMessage(monospace(tostring(outputFormat.first)) .. ", the value for " .. monospace("first") .. " in " .. monospace("outputFormat") .. " 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 outputFormat.convertUnits == true then
brackets = outputFormat.brackets == true and { "(", ")" } or { "", "" }
if outputFormat.lineBreak == "auto" then
convertedUnitsSeparator = ( ine(values[2]) or decimals ~= "0" or outputFormat.showUnits == true ) and "<br>" or " "
else
convertedUnitsSeparator = outputFormat.lineBreak == true and "<br>" or outputFormat.lineBreak == false and " " or error('Value for lineBreak not recognized')
end
end
cellContent = values[1] .. highLowSeparator[1] .. values[2] .. convertedUnitsSeparator .. brackets[1] .. convertedUnits[1] .. highLowSeparator[2] .. convertedUnits[2] .. brackets[2]
if tonumber(c) then
colorCSS = outputFormat.color == true and temperatureCSS(c, format.inputUnit, format.palette, format.inputUnit) or ""
if tonumber(b) and tonumber(a) then
local attributeValue = outputFormat.first == format.inputUnit and c or convert(c, format.inputUnit, decimals)
sortkey = outputFormat.sortable == 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 temperatureCSS(a, format.inputUnit, format.palette) or ""
else
addMessage('Neither a nor b nor c are strings.')
end
otherCSS = outputFormat.smallFont == true and "font-size: 85%;" or ""
if ine(colorCSS) or ine(otherCSS) then
styleAttribute = { "style=\"", "\"" }
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 cell
end
--[[
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 output
end
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 = { "{| class=\"wikitable center nowrap\"" }
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
for i = 1, format.length do
if not outputFormat then
outputFormat = outputFormats.high_low_average_F
end
table.insert(output, makeCell(outputFormat, a[i], b[i], c[i], format))
end
elseif b then
for i = 1, format.length do
if not outputFormat then
outputFormat = outputFormats.high_low_F
end
table.insert(output, makeCell(outputFormat, a[i], b[i], nil, format))
end
elseif a then
for i = 1, format.length do
if not outputFormat then
outputFormat = outputFormats.average_F
end
table.insert(output, makeCell(outputFormat, a[i], nil, nil, format))
end
end
table.insert(output, "\n|}")
if format.show then
table.insert(output, "\n\n<span style=\"color: red; font-size: 80%; line-height: 100%;\">" .. message .. "</span>")
end
output = table.concat(output)
output = hyphenToMinus(output)
return output
end
local chart = [[
{{Graph: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 {
n = 0,
add = function (self, item)
if item then
self.n = self.n + 1
self[self.n] = item
end
end,
join = function (self, sep)
return table.concat(self, sep)
end,
}
end
local function make_chart(result, color, xvalues, yvalues)
result:add('\n')
result:add(frame:preprocess((chart:gsub('__[A-Z]+', {
__COLOR = color,
__XVALUES = xvalues:join(','),
__YVALUES = yvalues:join(','),
}))))
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('{| class="wikitable"\n|-\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('|}\n')
make_chart(wikitext, 'Red', xvals, reds)
make_chart(wikitext, 'Green', xvals, greens)
make_chart(wikitext, 'Blue', xvals, blues)
return wikitext:join()
end
return p