请输入您要查询的百科知识:

 

词条 Module:Weather/sandbox
释义

local p = {}

require('Module:No globals')

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 '' .. str .. ''

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 "
" or " "

else

convertedUnitsSeparator = outputFormat.lineBreak == true and "
" 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 = "\| " .. 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, "\|-")

table.insert(output, "\! " .. 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, "\|}")

if format.show then

table.insert(output, "\\" .. message .. "")

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('\')

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"\|-\')

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) .. '\')

columns = columns + 1

if columns >= 10 then

columns = 0

wikitext:add('|-\')

end

end

wikitext:add('|}\')

make_chart(wikitext, 'Red', xvals, reds)

make_chart(wikitext, 'Green', xvals, greens)

make_chart(wikitext, 'Blue', xvals, blues)

return wikitext:join()

end

return p

随便看

 

开放百科全书收录14589846条英语、德语、日语等多语种百科知识,基本涵盖了大多数领域的百科知识,是一部内容自由、开放的电子版国际百科全书。

 

Copyright © 2023 OENC.NET All Rights Reserved
京ICP备2021023879号 更新时间:2024/9/22 1:00:51