Module:Shindo
Appearance
This module is rated as beta, and is ready for widespread use. It is still new and should be used with some caution to ensure the results are as expected. |
This module depends on the following other modules: |
Description | This is the Shindo module. |
---|---|
Code source | Shindo |
Status | Beta |
Dependencies |
This is the Shindo module. Named after the Japanese term used for classifying earthquakes 震度, this module provides utility for seismic intensity scales.
Seismic intensity data generated on Module:Shindo/data. Messages on Module:Shindo/messages.
Usage
{{#invoke:Shindo|color}}
returns styling for a given seismic intensity on a scale.{{#invoke:Shindo|formatInWikitable}}
returns styled text for a given seismic intensity on a scale, best suited for a wikitable.{{#invoke:Shindo|formatTag}}
returns styled text for a given seismic intensity on a scale, as an HTML tag.{{#invoke:Shindo|format}}
returns styled text for a given seismic intensity on a scale, as an HTML tag or table, depending on whether the parameter "format" is "wikitable".{{#invoke:Shindo|convert}}
will convert a given peak ground acceleration into a seismic intensity.{{#invoke:Shindo|scale}}
returns styled text for a specific scale, while shifting all the numbered arguments left, useful for invoking within templates that give specific scales.
Parameters
scale
: Which seismic intensity scale to be used. This is the first parameter.intensity
: The seismic intensity corresponding to the first scale. This is the second parameter (or first parameter when the scale is invoked as a function). If multiple intensities are desired they should be separated with a slash (/) with no spaces between them.scale2
: If specified, a second seismic intensity scale will be shown in parentheses (but colored the same as the original). Only used when formatting as a "tag". This is the third parameter (or second parameter when the scale is invoked as a function).intensity2
: The seismic intensity corresponding to the second scale. This is the fourth parameter (or third parameter when the scale is invoked as a function).format
: Either "wikitable" or "tag".link
: Whether to link to the relevant article. Default istrue
.color
: Whether to color the box for "formatTag" and "formatInWikitable". Default istrue
. If not then there will be no additional tag and the text will be unstyled.style
: Additional styling for the wikitable/tag, formatted as inline CSS.tag
: What tag to use in "formatTag". Default is "span".tagProps
: Properties for the tag (or wikitable) entry.labelScale
: Whether to label the ranking with the name of the scale (useful when the scale is relatively unknown to most).pga
: The peak ground acceleration in theconvert
function, in %g's. Same as the second parameter.
Documentation
Package items
shindo._color(args)
(function)- Gets the inline CSS for a particular scale's intensity color
- Parameters:
- Returns: Preprocessed text output (string)
shindo._formatInWikitable(args)
(function)- Gets the format of the scale as a wikitable
- Parameters:
args
frame arguments (table)args.scale
The name of the scale (string)args.intensity
The intensity of the scale (string)args.tagProps
additional properties for the wikitable row (string)args.header
if the formatting is done as a header (boolean)args.link
whether to link to the scale page (boolean)args.labelScale
whether to include the name of the scale (boolean)
- Returns: Preprocessed text output (string)
shindo._formatTag(args)
(function)- Gets the format of the scale as a tag
- Parameters:
args
frame arguments (table)args.scale
The name of the scale (string)args.scale2
The name of a second scale (string)args.intensity
The intensity of the scale (string)args.intensity2
The intensity for the second scale (string)args.tag
Tag name (string)args.style
styling for the tag (string)args.tagProps
additional properties for the tag (string)args.color
Whether to color the entry (boolean)args.link
whether to link to the scale page (boolean)
- Returns: Preprocessed text output (string)
--- This is the Shindo module. Named after the Japanese term used for classifying earthquakes {{lang|ja|{{ruby|[[wikt:震度|震度]]|しんど}}}}, this module provides utility for seismic intensity scales.
--
-- Seismic intensity data generated on [[Module:Shindo/data]]. Messages on [[Module:Shindo/messages]].
-- @module shindo
-- @alias p
-- @require Module:Arguments
-- @require Module:MakeInvokeFunc
-- @require Module:Message
-- @require Module:Yesno
-- @release beta
--
local p = {}
local getArgs = require("Module:Arguments").getArgs
local data = mw.loadData("Module:Shindo/data")
local messages = mw.loadData("Module:Shindo/messages")
local makeInvokeFunc = require("Module:MakeInvokeFunc")(p)
local message = require("Module:Message")(messages)
local yn = require("Module:Yesno")
--- Gets the grayscale value of a specific color
-- @function getValueOfColor
-- @param {table} tbl table for colors
-- @param {number} tbl[1] red value
-- @param {number} tbl[2] green value
-- @param {number} tbl[3] blue value
-- @return {number} Decimal value of the color.
local function getValueOfColor(tbl)
return (tbl[1] + tbl[2] + tbl[3]) / 3 / 255
end
--- Gets the color as a comma-separated value for CSS
-- @function rgbColor
-- @param {table} tbl table for colors
-- @param {number} tbl[1] red value
-- @param {number} tbl[2] green value
-- @param {number} tbl[3] blue value
-- @return {string} The color in the format red, green, blue
local function rgbColor(tbl)
return tbl[1] .. (tbl[2] and ", " .. tbl[2] .. (tbl[3] and ", " .. tbl[3] or "") or "")
end
--- Gets the average of multiple colors
-- @function averageColor
-- @param {table} tbl table of multiple colors
-- @return {number} Decimal value of the color.
local function averageColor(tbl)
local colors = {}
for k,v in pairs(tbl) do
colors[k] = v
end
local avg = {0, 0, 0}
for _,color in pairs(colors) do
avg[1] = avg[1] + color[1]
avg[2] = avg[2] + color[2]
avg[3] = avg[3] + color[3]
end
avg[1] = math.ceil(avg[1] / #colors) - avg[1] / #colors > 0.5 and math.floor(avg[1] / #colors) or math.ceil(avg[1] / #colors)
avg[2] = math.ceil(avg[2] / #colors) - avg[2] / #colors > 0.5 and math.floor(avg[2] / #colors) or math.ceil(avg[2] / #colors)
avg[3] = math.ceil(avg[3] / #colors) - avg[3] / #colors > 0.5 and math.floor(avg[3] / #colors) or math.ceil(avg[3] / #colors)
return avg
end
--- Gets all the intensity values from a scale
-- @function listIntensitiesFromScale
-- @param {string} scale First scale name
-- @param {string} intensities Table of intensity values
-- @param {boolean} labelScale Whether to label a scale
-- @param {string} scale Second scale name
-- @return {string} List of intensities
local function listIntensitiesFromScale(scale, intensities, labelScale, scale2)
local out = ''
if yn(labelScale) then
out = out .. data[scale].short .. ' '
end
local categoriesAreSame = true
local category = ""
for k,v in pairs(intensities) do
if data[scale].ranks[v] == nil then error(message("invalidIntensity", {v, scale})) end
out = out .. data[scale].ranks[v].label
if k ~= #intensities then
if #intensities == 2 then
out = out .. '–'
else
out = out .. '/'
end
end
if category == "" and categoriesAreSame then
category = data[scale].ranks[v].category or ""
end
categoriesAreSame = categoriesAreSame and category ~= "" and (data[scale].ranks[v].category and data[scale].ranks[v].category == category or false)
end
if categoriesAreSame and category ~= "" and not scale2 then
out = out .. " (''" .. category .. "'')"
end
return out
end
--- Gets the inline CSS for a particular scale's intensity color
-- @function p._color
-- @param {table} args frame arguments
-- @param {string} args.scale The name of the scale
-- @param {string} args.intensity The intensity of the scale
-- @return {string} Preprocessed text output
p._color = function(args)
local scale = string.lower(args.scale or args[1] or error(message("noScaleShortCode")))
local intensity = string.upper(args.intensity or args[2] or error(message("noIntensity")))
if data[scale] == nil then error(message("invalidScale", {scale})) end
if data[scale].ranks[intensity] == nil then error(message("invalidIntensity", {intensity, scale})) end
local order = data[scale].ranks[intensity].order
local color = data[scale].colors[order]
local colorIntensity = getValueOfColor(color)
return 'background-color:rgb(' .. rgbColor(color) .. '); color:' .. (colorIntensity < 0.5 and "white" or "black") .. ";"
end
--- Gets the format of the scale as a wikitable
-- @function p._formatInWikitable
-- @param {table} args frame arguments
-- @param {string} args.scale The name of the scale
-- @param {string} args.intensity The intensity of the scale
-- @param {string} args.tagProps additional properties for the wikitable row
-- @param {boolean} args.header if the formatting is done as a header
-- @param {boolean} args.link whether to link to the scale page
-- @param {boolean} args.labelScale whether to include the name of the scale
-- @return {string} Preprocessed text output
p._formatInWikitable = function(args)
local scale = string.lower(args.scale or args[1] or error(message("noScaleShortCode")))
local link = args.link ~= nil and args.link or true
local labelScale = args.labelScale ~= nil and args.labelScale or true
local doColor = args.color ~= nil and args.color or true
local intensity = string.upper(args.intensity or args[2] or error(message("noIntensity")))
local intensities = mw.text.split(intensity, "/") or { intensity }
if data[scale] == nil then error(message("invalidScale", {scale})) end
local colors = {}
for k,v in pairs(intensities) do
local order = data[scale].ranks[v].order
colors[k] = data[scale].colors[order]
end
local color = averageColor(colors)
local colorIntensity = getValueOfColor(color)
local out = ""
if yn(args.header or false) then
out = out .. "! "
else
out = out .. "| "
end
out = out .. (args.tagProps ~= nil and args.tagProps or "")
if (yn(doColor)) then
out = out .. 'style="background-color:rgba(' .. rgbColor(color) .. '); color:' .. (colorIntensity < 0.5 and "white" or "black") .. ';' .. (args.style or "") .. '" | '
elseif (args.style) then
out = out .. 'style="' .. (args.style or "") .. '" | '
end
if yn(link) then
out = out .. '[[' .. data[scale].name .. "#" .. data[scale].id_prefix .. data[scale].ranks[intensity].id .. "|"
end
if yn(doColor) then
out = out .. '<span style=\"color:' .. (colorIntensity < 0.5 and "white" or "black") .. ';">'
end
out = out .. listIntensitiesFromScale(scale, intensities, labelScale, false)
if yn(doColor) then
out = out .. '</span>'
end
if yn(link) then
out = out .. "]]"
end
return out
end
--- Gets the format of the scale as a tag
-- @function p._formatTag
-- @param {table} args frame arguments
-- @param {string} args.scale The name of the scale
-- @param {string} args.scale2 The name of a second scale
-- @param {string} args.intensity The intensity of the scale
-- @param {string} args.intensity2 The intensity for the second scale
-- @param {string} args.tag Tag name
-- @param {string} args.style styling for the tag
-- @param {string} args.tagProps additional properties for the tag
-- @param {boolean} args.color Whether to color the entry
-- @param {boolean} args.link whether to link to the scale page
-- @return {string} Preprocessed text output
p._formatTag = function(args)
local scale = string.lower(args.scale or args[1] or error(message("noScaleShortCode")))
local scale2 = args.scale2 or args[3] or nil
if scale2 ~= nil then scale2 = string.lower(scale2) end
local link = args.link ~= nil and args.link or true
local labelScale = args.labelScale ~= nil and args.labelScale or true
local doColor = args.color ~= nil and args.color or true
local intensity = string.upper(args.intensity or args[2] or error(message("noIntensity")))
local intensities = mw.text.split(intensity, "/") or { intensity }
local intensity2 = args.intensity2 or args[4] or (scale2 and error(message("noIntensity"))) or nil
local intensities2 = {}
if intensity2 ~= nil then
intensity2 = string.upper(intensity2)
intensities2 = mw.text.split(intensity2, "/") or { intensity2 }
end
if data[scale] == nil then error(message("invalidScale", {scale})) end
if scale2 and data[scale2] == nil then error(message("invalidScale", {scale2})) end
local colors = {}
for k,v in pairs(intensities) do
local order = data[scale].ranks[v].order
colors[k] = data[scale].colors[order]
end
local color = averageColor(colors)
local colorIntensity = getValueOfColor(color)
local out = ''
if yn(doColor) then
out = out .. '<' .. (args.tag or "span") .. ' style="background-color:rgba(' .. rgbColor(color) .. '); padding:4px; color:' .. (colorIntensity < 0.5 and "white" or "black") .. '; '
elseif args.style then
out = out .. '<' .. (args.tag or "span") .. ' style="'
else
out = out .. '<' .. (args.tag or "span")
end
if args.style then
out = out .. args.style
out = out .. '" '
elseif yn(doColor) then
out = out .. '" '
end
out = out .. (args.tagProps ~= nil and args.tagProps or "")
out = out .. ">"
if yn(link) then
out = out .. '[[' .. data[scale].name .. "#" .. data[scale].id_prefix .. data[scale].ranks[intensities[1]].id .. "|"
end
if yn(doColor) then
out = out .. '<span style=\"color:' .. (colorIntensity < 0.5 and "white" or "black") .. ';">'
end
out = out .. listIntensitiesFromScale(scale, intensities, labelScale, scale2)
if yn(doColor) then
out = out .. '</span>'
end
if yn(link) then
out = out .. "]]"
end
if (scale2) then
out = out .. " ("
if yn(link) then
out = out .. '[[' .. data[scale2].name .. "#" .. data[scale2].id_prefix .. data[scale2].ranks[intensities2[1]].id .. "|"
end
if yn(doColor) then
out = out .. '<span style=\"color:' .. (colorIntensity < 0.5 and "white" or "black") .. ';">'
end
out = out .. listIntensitiesFromScale(scale2, intensities2, true, true)
if yn(doColor) then
out = out .. '</span>'
end
if yn(link) then
out = out .. "]]"
end
out = out .. ")"
end
out = out .. '</' .. (args.tag or "span") .. '>'
return mw.getCurrentFrame():preprocess(out)
end
p._format = function(args)
if args["format"] == "wikitable" then
return p.formatInWikitable(args)
else
return p.formatTag(args)
end
end
p._getScaleName = function(args)
local scale = string.lower(args.scale or args[1] or error(message("noScaleShortCode")))
if data[scale] == nil then error(message("invalidScale", {scale})) end
local out = ''
if yn(args.link or true) then
out = out .. '[[' .. data[scale].name .. '|'
end
out = out .. data[scale].name
if yn(args.link or true) then
out = out .. ']]'
end
return out
end
-- uses binary search to convert a peak ground acceleration to a seismic intensity
function convert(pga, ranks, ranksSorted, left, right)
left = left ~= nil and left or 0
right = right ~= nil and right or #ranksSorted
index = math.floor((left + right) / 2)
local lower = ranks[ranksSorted[index + 1]].pga
local upper = ranksSorted[index + 2] and ranks[ranksSorted[index + 2]].pga or math.huge
if (pga >= upper) then
return convert(pga, ranks, ranksSorted, index, right)
elseif (pga < lower) then
return convert(pga, ranks, ranksSorted, left, index)
else
return ranksSorted[index + 1]
end
end
p._convert = function(args)
local scale = string.lower(args.scale or args[1] or error(message("noScaleShortCode")))
if data[scale] == nil then error(message("invalidScale", {scale})) end
local ranksSorted = {}
for k,v in ipairs(data["mmi"].ranksSorted) do ranksSorted[k] = v end
return convert(tonumber(args.pga or args[2]), data[scale].ranks, ranksSorted)
end
p.convert1 = convert --debugging
p._list = function(args)
local out = mw.html.create('ul')
for k,v in pairs(data) do
local list = out:tag('li')
list:wikitext('<code>' .. k .. '</code>: [[' .. v.name .. '|' .. v.name .. ']]')
local tb = list:tag('table'):addClass("wikitable")
tb
:tag("tr")
:tag("th"):wikitext("Seismic intensity"):done()
:tag("th"):wikitext("Display"):done()
:done()
for l,w in pairs(v.order) do
tb:tag('tr'):wikitext('<td><code>' .. w .. '</code></td> ' .. p.format({k, w, tag = "td"})):done()
end
list:done()
end
out:allDone()
return tostring(out)
end
-- make each scale invokable
for k,v in pairs(data) do
if p["_" .. k] ~= nil then error(message("scaleNameInvalid", k)) end
p["_" .. k] = function(args)
args["scale"] = k
args["intensity"] = args["intensity"] or args[1] or nil
args["scale2"] = args["scale2"] or args[2] or nil
args["intensity2"] = args["intensity2"] or args[3] or nil
if args["format"] == "wikitable" then
return p.formatInWikitable(args)
else
return p.formatTag(args)
end
end
end
-- make all functions that begin with _ invokable
local q = mw.clone(p)
for k,v in pairs(q) do
if mw.ustring.sub(k, 1, 1) == "_" then
p[mw.ustring.sub(k, 2, #k)] = makeInvokeFunc(k)
end
end
return p