Difference between revisions of "Module:Sandbox/Erutuon/Temperature arrays"

From blackwiki
Jump to navigation Jump to search
blackwiki>Erutuon
(support for rudimentary output format parameter)
blackwiki>Erutuon
(allow small text to be set by output parameter; fix add_unit_names)
Line 20: Line 20:
 
error("Please provide the number of values and a unit in the input parameter")
 
error("Please provide the number of values and a unit in the input parameter")
 
else
 
else
length = tonumber(string.match(input_parameter, '(%d+)')) -- Find digits in the input parameter.
+
length = tonumber(string.match(input_parameter, "(%d+)")) -- Find digits in the input parameter.
input_unit = string.match(input_parameter, '([CF])') -- C or F
+
input_unit = string.match(input_parameter, "([CF])") -- C or F
 
end
 
end
 
 
Line 41: Line 41:
 
cell_format = {}
 
cell_format = {}
 
local n = 1
 
local n = 1
for unit in output_parameter:gmatch('[CF]') do
+
for unit in output_parameter:gmatch("[CF]") do
 
cell_format[n] = unit
 
cell_format[n] = unit
 
n = n + 1
 
n = n + 1
Line 52: Line 52:
 
cell_format["convert_units"] = "yes"
 
cell_format["convert_units"] = "yes"
 
end
 
end
if string.find(output_parameter, 'unit') then
+
if string.find(output_parameter, "unit") then
 
cell_format["unit_names"] = "yes"
 
cell_format["unit_names"] = "yes"
 
else
 
else
Line 58: Line 58:
 
add_message("<span style=\"background-color: #EEE; font-family: monospace;\">unit</span> not found in <span style=\"background-color: #EEE; font-family: monospace;\">output</span> parameter.")
 
add_message("<span style=\"background-color: #EEE; font-family: monospace;\">unit</span> not found in <span style=\"background-color: #EEE; font-family: monospace;\">output</span> parameter.")
 
end
 
end
if string.find(output_parameter, 'c') then
+
if string.find(output_parameter, "color") then
 
cell_format["color"] = "yes"
 
cell_format["color"] = "yes"
 
else
 
else
 
cell_format["color"] = "no"
 
cell_format["color"] = "no"
 
end
 
end
if string.find(output_parameter, 's') then
+
if string.find(output_parameter, "sortable") then
 
cell_format["sortable"] = "yes"
 
cell_format["sortable"] = "yes"
 
else
 
else
 
cell_format["sortable"] = "no"
 
cell_format["sortable"] = "no"
 +
end
 +
if string.find(output_parameter, "small") then
 +
cell_format["small_font"] = "yes"
 +
else
 +
cell_format["small_font"] = "no"
 
end
 
end
 
end
 
end
Line 84: Line 89:
 
if check_for_number(value) then
 
if check_for_number(value) then
 
value = tonumber(value)
 
value = tonumber(value)
local string = string.format('%.' .. decimals .. 'f', value)
+
local string = string.format("%." .. decimals .. "f", value)
 
return string
 
return string
 
else
 
else
Line 116: Line 121:
 
local array = {}
 
local array = {}
 
local n = 1
 
local n = 1
for number in parameter:gmatch('%-?%d+%.?%d?') do
+
for number in parameter:gmatch("%-?%d+%.?%d?") do
 
local number = number
 
local number = number
 
if n == 1 then
 
if n == 1 then
local decimals = number:match('%.(%d+)')
+
local decimals = number:match("%.(%d+)")
 
if decimals == nil then
 
if decimals == nil then
 
precision = "0"
 
precision = "0"
Line 216: Line 221:
 
if output_format.unit_names == "yes" then
 
if output_format.unit_names == "yes" then
 
if check_for_string(value) 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
 
return value -- Don't add a unit name to an empty string
else
 
return value .. "&nbsp;" .. degree .. unit
 
 
end
 
end
 
else
 
else

Revision as of 07:00, 28 September 2016

Testcases

Random examples

Lua error at line 3: Tried to write global weather. Lua error at line 3: Tried to write global weather. Lua error at line 3: Tried to write global weather. Lua error at line 3: Tried to write global weather. Lua error at line 3: Tried to write global weather.

Lua error at line 3: Tried to write global weather. Lua error at line 3: Tried to write global weather.

California

Lua error at line 3: Tried to write global weather.Lua error at line 3: Tried to write global weather.Lua error at line 3: Tried to write global weather.Lua error at line 3: Tried to write global weather.Lua error at line 3: Tried to write global weather.Lua error at line 3: Tried to write global weather.Lua error at line 3: Tried to write global weather.Lua error at line 3: Tried to write global weather.Lua error at line 3: Tried to write global weather.Lua error at line 3: Tried to write global weather.Lua error at line 3: Tried to write global weather.Lua error at line 3: Tried to write global weather.
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

Lua error at line 3: Tried to write global weather. Lua error at line 3: Tried to write global weather. Lua error at line 3: Tried to write global weather. Lua error at line 3: Tried to write global weather. Lua error at line 3: Tried to write global weather.

Minnesota

Average Temperatures in Minnesota in °Fahrenheit (°Celsius), 1971–2000
Jan Feb Mar Apr May Jun Jul Aug Sept Oct Nov Dec Annual

Lua error at line 3: Tried to write global weather. Lua error at line 3: Tried to write global weather. Lua error at line 3: Tried to write global weather. Lua error at line 3: Tried to write global weather. Lua error at line 3: Tried to write global weather. Lua error at line 3: Tried to write global weather. Lua error at line 3: Tried to write global weather. Lua error at line 3: Tried to write global weather. Lua error at line 3: Tried to write global weather. Lua error at line 3: Tried to write global weather.


f = {}
degree = "°"
weather = require("Module:Weather/sandbox")

message = ""

local function add_message(new_message)
	if check_for_string(message) then
		message = message .. " " .. new_message
	else
		message = "Notices: " .. new_message
	end
end

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
	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
		cell_format.first = cell_format[1]
		if check_for_string(cell_format[2]) and cell_format[2] ~= cell_format[1] then
			cell_format["convert_units"] = "yes"
		end
		if string.find(output_parameter, "unit") then
			cell_format["unit_names"] = "yes"
		else
			cell_format["unit_names"] = "no"
			add_message("<span style=\"background-color: #EEE; font-family: monospace;\">unit</span> not found in <span style=\"background-color: #EEE; font-family: monospace;\">output</span> parameter.")
		end
		if string.find(output_parameter, "color") then
			cell_format["color"] = "yes"
		else
			cell_format["color"] = "no"
		end
		if string.find(output_parameter, "sortable") then
			cell_format["sortable"] = "yes"
		else
			cell_format["sortable"] = "no"
		end
		if string.find(output_parameter, "small") then
			cell_format["small_font"] = "yes"
		else
			cell_format["small_font"] = "no"
		end
	end
	
	return length, input_unit, output_unit
end

local function check_for_number(value)
	return type(tonumber(value)) == "number"
end

function check_for_string(string)
	return tostring(string) ~= "" and tostring(string) ~= nil
end

local function round(value, decimals)
	if check_for_number(value) then
		value = tonumber(value)
		local string = string.format("%." .. decimals .. "f", value)
		return string
	else
		if value == nil then
			value = "nil"
		end
		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
			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
		return "" -- Setting result to empty string if value is not a number avoids concatenation errors.
	end
end

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

local output_formats = {
	high_low_average_F =
		{ first = "F",
		convert_units = "yes",
		unit_names = "no",
		color = "yes",
		small_font = "yes",
		sortable = "yes",
		decimals = "0", },
	high_low_average_C =
		{ first = "C",
		convert_units = "yes",
		unit_names = "no",
		color = "yes",
		small_font = "yes",
		sortable = "yes",
		decimals = "0", },
	high_low_F =
		{ first = "F",
		convert_units = "yes",
		unit_names = "no",
		color = "no",
		small_font = "yes",
		sortable = "no",
		decimals = "0", },
	high_low_C =
		{ first = "C",
		convert_units = "yes",
		unit_names = "no",
		color = "no",
		small_font = "yes",
		sortable = "no",
		decimals = "0", },
	average_F =
		{ first = "F",
		convert_units = "yes",
		unit_names = "no",
		color = "yes",
		small_font = "yes",
		sortable = "no",
		decimals = "0", },
	average_C =
		{ first = "C",
		convert_units = "yes",
		unit_names = "no",
		color = "yes",
		small_font = "yes",
		sortable = "no",
		decimals = "0", },
	}

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 format_cell(output_format, a, b, c)
	local cell, cell_content = "", ""
	local color_CSS, other_CSS, title_content, sortkey, attribute_separator, decimals, converted_units_separator = "", "", "", "", "", "", ""
	local style_attribute, title_attribute, high_low_separator, brackets, values, converted_units = {"", ""}, {"", ""}, {"", ""}, {"", ""}, {"", ""}, {"", ""}
	
	if output_format.decimals then
		decimals = output_format.decimals
	else
		decimals = precision -- Precision is the number of decimals in the first number of the last array.
	end
	
	if b then
		values, high_low_separator = { round(a, decimals), round(b, decimals)  }, { "/", if_yes(output_format.convert_units, "/") }
	else
		values = { round(a, decimals), "" }
	end
	if output_format.first == input_unit then
		converted_units = if_yes(output_format.convert_units, add_unit_names(convert(values[1], decimals), output_unit), add_unit_names(convert(values[2], decimals), output_unit))
		values = { add_unit_names(values[1]), add_unit_names(values[2]) }
	elseif output_format.first == "C" or output_format.first == "F" then
		converted_units = if_yes(output_format.convert_units, add_unit_names(values[1]), add_unit_names(values[2]) )
		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
	
	if output_format.convert_units == "yes" then
		brackets = { "(", ")" }
		if check_for_string(values[2]) or decimals ~= "0" or output_format.show_units == "yes" then -- Add line break between first unit and conversion if text would be too long without it.
			converted_units_separator = "<br>"
		else
			converted_units_separator = "&nbsp;"
		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 c then
		color_CSS = if_yes(output_format.color, temperature_CSS(c, input_unit, "cool2avg"))
		if output_format.first == input_unit then
			title_content = "Average temperature: " .. c .. " " .. degree .. input_unit
			sortkey = if_yes(output_format.sortable, " data-sort-value=\"" .. c .. "\"")
		else
			title_content = "Average temperature: " .. convert(c, decimals) .. " " .. degree .. output_unit
			sortkey = if_yes(output_format.sortable, " data-sort-value=\"" .. convert(c, decimals) .. "\"")
		end
		title_attribute = { " title=\"", "\"" }
	elseif a and not b then
		color_CSS = if_yes(output_format.color, temperature_CSS(a, input_unit, "cool2avg"))
	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_content) or check_for_string(sortkey) then
		attribute_separator = " | "
	end
	cell = "\n| " .. style_attribute[1] .. color_CSS .. other_CSS .. style_attribute[2] .. title_attribute[1] .. title_content .. title_attribute[2] .. sortkey .. attribute_separator .. cell_content
	return cell
end

function f.makeTable(frame)
	make_arrays(frame)
	local output = "{| class=\"wikitable center\""
	if a and b and c then
		for i = 1, length do
			if cell_format then
				output_format = cell_format
			else
				output_format = output_formats.high_low_average_F
			end
			output = output .. format_cell(output_format, a[i], b[i], c[i])
		end
	elseif a and b then
		for i = 1, length do
			output_format = output_formats.high_low_F
			output = output .. format_cell(output_format, a[i], b[i])
		end
	elseif a then
		for i = 1, length do
			output_format = output_formats.average_F
			output = output .. format_cell(output_format, a[i])
		end
	end
	return output .. "\n|}" .. "\n\n<span style=\"color: red; font-size: 80%; line-height: 100%;\">" .. message .. "</span>"
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 a and b and c then
		for i = 1, length do
			output_format = output_formats.high_low_average_F
			output = output .. format_cell(output_format, a[i], b[i], c[i])
		end
	elseif a and b then
		for i = 1, length do
			output_format = output_formats.high_low_F
			output = output .. format_cell(output_format, a[i], b[i])
		end
	elseif a then
		for i = 1, length do
			output_format = output_formats.average_F
			output = output .. format_cell(output_format, a[i])
		end
	end
	return output
end

return f