Module:Sandbox/Erutuon/Temperature arrays

From blackwiki
Jump to navigation Jump to search

Testcases

Random examples

−4 / −14 (25 / 6) −2 / −12 (28 / 10) 2 / −7 (36 / 19) 8 / −1 (47 / 30) 13 / 3 (56 / 38) 18 / 7 (64 / 44) 22 / 11 (71 / 52) 22 / 12 (72 / 54) 18 / 8 (64 / 47) 11 / 2 (52 / 36) 4 / −4 (39 / 25) 0 / −11 (32 / 12) 9 / −1 (49 / 31)
16
(−9)
19
(−7)
28
(−2)
39
(4)
47
(8)
54
(12)
62
(17)
63
(17)
56
(13)
44
(7)
32
(0)
20
(−7)
40
(4)
15.6 19.1 27.7 38.8 47.0 53.8 61.5 63.2 55.8 44.2 32.3 20.0 40.0
25 / 6 28 / 10 36 / 19 47 / 30 56 / 38 64 / 44 71 / 52 72 / 54 64 / 47 52 / 36 39 / 25 32 / 12 49 / 31
−4.1 / −14.2 −2.0 / −12.3 2.4 / −7.2 8.6 / −1.1 13.3 / 3.3 17.6 / 6.7 21.8 / 10.9 22.3 / 12.4 17.9 / 8.6 11.2 / 2.4 4.1 / −3.8 −2.2 / −11.1 9.3 / −0.4
25 / 6
(−4 / −14)
28 / 10
(−2 / −12)
36 / 19
(2 / −7)
47 / 30
(8 / −1)
56 / 38
(13 / 3)
64 / 44
(18 / 7)
71 / 52
(22 / 11)
72 / 54
(22 / 12)
64 / 47
(18 / 8)
52 / 36
(11 / 2)
39 / 25
(4 / −4)
28 / 12
(−2 / −11)
40 (4)
24.7 / 6.5
(−4.1 / −14.2)
28.4 / 9.9
(−2.0 / −12.3)
36.3 / 19.0
(2.4 / −7.2)
47.4 / 30.1
(8.6 / −1.1)
56.0 / 37.9
(13.3 / 3.3)
63.6 / 44.0
(17.6 / 6.7)
71.2 / 51.7
(21.8 / 10.9)
72.1 / 54.3
(22.3 / 12.4)
64.3 / 47.4
(17.9 / 8.6)
52.1 / 36.4
(11.2 / 2.4)
39.3 / 25.2
(4.1 / −3.8)
28.0 / 12.0
(−2.2 / −11.1)
48.7 / 31.3
(9.3 / −0.4)

California

Average daily high and low temperatures in °F (°C)
for locations in California,
colored and sortable by average monthly temperature
Place Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec Year
Alturas[1] 44 / 18
(7 / −8)
48 / 21
(9 / −6)
54 / 25
(12 / −4)
60 / 28
(16 / −2)
70 / 34
(21 / 1)
79 / 40
(26 / 4)
90 / 44
(32 / 7)
89 / 42
(32 / 6)
80 / 36
(27 / 2)
68 / 28
(20 / −2)
52 / 22
(11 / −6)
42 / 18
(6 / −8)
47
(8)
Bakersfield[2] 56 / 39
(13 / 4)
63 / 42
(17 / 6)
69 / 46
(21 / 8)
75 / 50
(24 / 10)
84 / 58
(29 / 14)
91 / 64
(33 / 18)
97 / 70
(36 / 21)
96 / 69
(36 / 21)
90 / 64
(32 / 18)
79 / 55
(26 / 13)
66 / 45
(19 / 7)
57 / 39
(14 / 4)
65
(18)
Bishop[3] 54 / 23
(12 / −5)
58 / 26
(14 / −3)
66 / 31
(19 / −1)
73 / 36
(23 / 2)
82 / 44
(28 / 7)
92 / 51
(33 / 11)
98 / 56
(37 / 13)
96 / 54
(36 / 12)
88 / 47
(31 / 8)
76 / 37
(24 / 3)
63 / 28
(17 / −2)
53 / 22
(12 / −6)
57
(14)
Bodie[4] 40 / 5
(4 / −15)
41 / 7
(5 / −14)
45 / 11
(7 / −12)
51 / 17
(11 / −8)
61 / 24
(16 / −4)
70 / 30
(21 / −1)
78 / 34
(26 / 1)
77 / 32
(25 / 0)
71 / 26
(22 / −3)
60 / 18
(16 / −8)
49 / 11
(9 / −12)
41 / 6
(5 / −14)
38
(3)
Death Valley[5] 67 / 40
(19 / 4)
73 / 46
(23 / 8)
82 / 55
(28 / 13)
90 / 62
(32 / 17)
100 / 73
(38 / 23)
110 / 81
(43 / 27)
116 / 88
(47 / 31)
115 / 86
(46 / 30)
106 / 76
(41 / 24)
93 / 62
(34 / 17)
77 / 48
(25 / 9)
65 / 38
(18 / 3)
77
(25)
Eureka[6] 56 / 41
(13 / 5)
56 / 42
(13 / 6)
57 / 43
(14 / 6)
58 / 44
(14 / 7)
60 / 48
(16 / 9)
62 / 50
(17 / 10)
63 / 52
(17 / 11)
64 / 53
(18 / 12)
64 / 50
(18 / 10)
62 / 47
(17 / 8)
58 / 44
(14 / 7)
55 / 41
(13 / 5)
53
(12)
Fresno[7] 55 / 38
(13 / 3)
62 / 42
(17 / 6)
68 / 46
(20 / 8)
75 / 49
(24 / 9)
84 / 56
(29 / 13)
92 / 62
(33 / 17)
98 / 68
(37 / 20)
97 / 66
(36 / 19)
91 / 62
(33 / 17)
80 / 53
(27 / 12)
65 / 43
(18 / 6)
55 / 38
(13 / 3)
64
(18)
Los Angeles[8] 68 / 48
(20 / 9)
69 / 49
(21 / 9)
70 / 51
(21 / 11)
73 / 54
(23 / 12)
74 / 57
(23 / 14)
78 / 60
(26 / 16)
83 / 64
(28 / 18)
84 / 64
(29 / 18)
83 / 63
(28 / 17)
78 / 59
(26 / 15)
73 / 52
(23 / 11)
68 / 48
(20 / 9)
65
(18)
Needles[9] 65 / 44
(18 / 7)
70 / 47
(21 / 8)
77 / 52
(25 / 11)
85 / 59
(29 / 15)
95 / 68
(35 / 20)
104 / 77
(40 / 25)
109 / 84
(43 / 29)
107 / 83
(42 / 28)
100 / 74
(38 / 23)
88 / 62
(31 / 17)
73 / 50
(23 / 10)
63 / 42
(17 / 6)
74
(23)
Redding[10] 55 / 36
(13 / 2)
60 / 39
(16 / 4)
64 / 43
(18 / 6)
70 / 46
(21 / 8)
81 / 54
(27 / 12)
90 / 62
(32 / 17)
98 / 66
(37 / 19)
97 / 63
(36 / 17)
90 / 58
(32 / 14)
78 / 49
(26 / 9)
62 / 41
(17 / 5)
54 / 36
(12 / 2)
62
(17)
Riverside[11] 69 / 43
(21 / 6)
70 / 45
(21 / 7)
73 / 46
(23 / 8)
78 / 50
(26 / 10)
82 / 55
(28 / 13)
89 / 59
(32 / 15)
95 / 64
(35 / 18)
96 / 64
(36 / 18)
92 / 61
(33 / 16)
83 / 55
(28 / 13)
75 / 46
(24 / 8)
68 / 42
(20 / 6)
67
(19)
Sacramento[12] 54 / 39
(12 / 4)
60 / 41
(16 / 5)
65 / 44
(18 / 7)
71 / 46
(22 / 8)
80 / 51
(27 / 11)
87 / 56
(31 / 13)
92 / 58
(33 / 14)
91 / 58
(33 / 14)
87 / 56
(31 / 13)
78 / 50
(26 / 10)
64 / 43
(18 / 6)
54 / 38
(12 / 3)
61
(16)
San Diego[13] 65 / 49
(18 / 9)
65 / 51
(18 / 11)
66 / 53
(19 / 12)
68 / 56
(20 / 13)
68 / 59
(20 / 15)
71 / 62
(22 / 17)
75 / 65
(24 / 18)
76 / 67
(24 / 19)
76 / 65
(24 / 18)
73 / 61
(23 / 16)
69 / 54
(21 / 12)
65 / 48
(18 / 9)
64
(18)
San
Francisco
[14]
57 / 46
(14 / 8)
60 / 48
(16 / 9)
62 / 48
(17 / 9)
63 / 49
(17 / 9)
64 / 51
(18 / 11)
66 / 53
(19 / 12)
66 / 54
(19 / 12)
68 / 55
(20 / 13)
70 / 55
(21 / 13)
69 / 54
(21 / 12)
63 / 50
(17 / 10)
57 / 46
(14 / 8)
57
(14)
San Jose[15] 58 / 42
(14 / 6)
62 / 45
(17 / 7)
66 / 47
(19 / 8)
69 / 49
(21 / 9)
74 / 52
(23 / 11)
79 / 56
(26 / 13)
82 / 58
(28 / 14)
82 / 58
(28 / 14)
80 / 57
(27 / 14)
74 / 52
(23 / 11)
64 / 46
(18 / 8)
58 / 42
(14 / 6)
61
(16)
Santa Rosa[16] 59 / 39
(15 / 4)
63 / 41
(17 / 5)
67 / 43
(19 / 6)
70 / 45
(21 / 7)
74 / 48
(23 / 9)
80 / 52
(27 / 11)
82 / 52
(28 / 11)
83 / 53
(28 / 12)
83 / 52
(28 / 11)
78 / 48
(26 / 9)
67 / 43
(19 / 6)
59 / 39
(15 / 4)
59
(15)
South Lake
Tahoe
[17]
43 / 16
(6 / −9)
44 / 18
(7 / −8)
48 / 22
(9 / −6)
54 / 27
(12 / −3)
64 / 32
(18 / 0)
72 / 37
(22 / 3)
81 / 41
(27 / 5)
80 / 40
(27 / 4)
74 / 34
(23 / 1)
63 / 28
(17 / −2)
50 / 22
(10 / −6)
43 / 16
(6 / −9)
44
(7)

Minnesota

Average Temperatures in Minnesota in °Fahrenheit (°Celsius), 1971–2000
Jan Feb Mar Apr May Jun Jul Aug Sept Oct Nov Dec Annual
Alexandria[18] 8 (−13) 15 (−9) 27 (−3) 43 (6) 56 (13) 65 (18) 70 (21) 68 (20) 58 (14) 45 (7) 28 (−2) 14 (−10) 41 (5)
Brainerd[19] 6 (−14) 13 (−11) 26 (−3) 42 (6) 56 (13) 64 (18) 69 (21) 66 (19) 56 (13) 44 (7) 28 (−2) 13 (−11) 40 (4)
Duluth[20] 10 (−12) 17 (−8) 26 (−3) 39 (4) 48 (9) 58 (14) 66 (19) 65 (18) 56 (13) 45 (7) 31 (−1) 17 (−8) 40 (4)
Grand Marais[21] 14 (−10) 19 (−7) 28 (−2) 38 (3) 47 (8) 53 (12) 61 (16) 63 (17) 55 (13) 45 (7) 32 (0) 19 (−7) 39 (4)
International Falls[22] 3 (−16) 11 (−12) 24 (−4) 39 (4) 53 (12) 62 (17) 66 (19) 64 (18) 53 (12) 42 (6) 24 (−4) 9 (−13) 32 (0)
Redwood Falls[23] 13 (−11) 20 (−7) 32 (0) 47 (8) 60 (16) 70 (21) 74 (23) 71 (22) 62 (17) 49 (9) 32 (0) 18 (−8) 46 (8)
Thief River Falls[24] 3 (−16) 11 (−12) 24 (−4) 42 (6) 56 (13) 64 (18) 69 (21) 67 (19) 56 (13) 44 (7) 24 (−4) 9 (−13) 39 (4)
Twin Cities[25] 13 (−11) 20 (−7) 32 (0) 47 (8) 59 (15) 68 (20) 73 (23) 71 (22) 61 (16) 49 (9) 32 (0) 19 (−7) 45 (7)
Winona[26] 18 (−8) 24 (−4) 36 (2) 50 (10) 62 (17) 71 (22) 76 (24) 73 (23) 64 (18) 52 (11) 32 (0) 23 (−5) 49 (9)
Worthington[27] 11 (−12) 18 (−8) 29 (−2) 44 (7) 57 (14) 67 (19) 71 (22) 68 (20) 59 (15) 47 (8) 30 (−1) 17 (−8) 43 (6)

  1. Template:WRCC
  2. Template:WRCC
  3. Template:WRCC
  4. Template:WRCC
  5. Template:WRCC
  6. Template:WRCC
  7. Template:WRCC
  8. Template:WRCC
  9. Template:WRCC
  10. Template:WRCC
  11. Template:WRCC
  12. Template:WRCC
  13. Template:WRCC
  14. Template:WRCC
  15. Template:WRCC
  16. Template:WRCC
  17. Template:WRCC
  18. Ross, Douglas (1971–2000). "Daily Normals for Alexandria, Minnesota". NCDC. Retrieved 2007-06-07.
  19. Ross, Douglas (1971–2000). "Daily Normals for Brainerd, Minnesota". NCDC. Retrieved 2007-12-27.
  20. Ross, Douglas (1971–2000). "Daily Normals for Duluth, Minnesota". NCDC. Retrieved 2007-06-07.
  21. Ross, Douglas (1971–2000). "Daily Normals for Grand Marais, Minnesota". NCDC. Retrieved 2007-12-27.
  22. Ross, Douglas (1971–2000). "Daily Normals for International Falls, Minnesota". NCDC. Retrieved 2007-06-07.
  23. Ross, Douglas (1971–2000). "Daily Normals for Redwood Falls, Minnesota". NCDC. Retrieved 2007-06-07.
  24. Ross, Douglas (1971–2000). "Daily Normals for Thief River Falls, Minnesota". NCDC. Retrieved 2007-06-07.
  25. Ross, Douglas (1971–2000). "Daily Normals for the Twin Cities". NCDC. Retrieved 2007-06-07.
  26. Ross, Douglas (1971–2000). "Daily Normals for Winona, Minnesota". NCDC. Retrieved 2007-06-07.
  27. Ross, Douglas (1971–2000). "Daily Normals for Worthington, Minnesota". NCDC. Retrieved 2007-06-07.
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 .. "&nbsp;" .. 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 = "&nbsp;"
			end
		elseif output_format.line_break == "yes" then
			converted_units_separator = "<br>"
		elseif output_format.line_break == "no" then
			converted_units_separator = "&nbsp;"
		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