Module:Bar
Appearance
(Redirected from Module:Bar box)
| This module is rated as beta. It is considered ready for widespread use, but as it is still relatively new, it should be applied with some caution to ensure results are as expected. |
| This module is currently protected from editing. See the protection policy and protection log for more details. Please discuss any changes on the talk page; you may submit an edit request to ask an administrator to make an edit if it is uncontroversial or supported by consensus. You may also request that this page be unprotected. |
| This module uses TemplateStyles: |
| This module depends on the following other modules: |
| This Lua module is used on many pages and changes may be widely noticed. Test changes in the module's /sandbox or /testcases subpages, or in your own module sandbox. Consider discussing changes on the talk page before implementing them. |
{{Bar box}}, is used for construction of horizontal bar charts.
Usage
{{Bar box
|width = ''width of the graph'' (optional)
|barwidth= ''width of the bar area'' (optional, defaults to 100px)
|float = (left|right|none) (optional, defaults to none)
|title = ''title of the chart'' (optional)
|titlebar= ''title bar colour'' (optional, defaults to none)
|left1 = ''first left column header'' (optional)
|left2 = ''second left column header'' (optional)
|right1 = ''first right column header'' (optional)
|right2 = ''second right column header'' (optional)
|bars = ''chart contents'' (see below)
|caption = ''caption under the chart'' (optional)
}}
Alternatives to avoid Wikipedia's Post-expand include size limit
Pages with many boxes and charts may come close to or exceed Wikipedia's Post-expand include size limit. In these cases consider using Module:Bar as follows:
- {{Bar box}} → {{#invoke:Bar|box}}
- {{Bar percent}} → {{#invoke:Bar|percent}}
- {{Bar pixel}} → {{#invoke:Bar|pixel}}
- {{Bar log}} → {{#invoke:Bar|log}}
- {{Bar stacked}} → {{#invoke:Bar|stacked}}
- {{Bar gap}} → {{#invoke:Bar|gap}}
- {{Bar table}} → {{#invoke:Bar|table}}
Tracking category
See also
- {{Vertical bar chart}}
- {{Bar chart}}
- {{Data bars}}
- WP:Graphs
require('Module:Lua class')
require('strict')
local frame = mw.getCurrentFrame()
local metatable = { -- Append to array by calling it
__call = function (t, v) t[#t+1] = v end,
__tostring = function(t) return table.concat(t) end
}
local function notblank(v) return (v or '') ~= '' end
local function ifblank(v, a) return notblank(v) and v or a end
local BarBox = class('BarBox', {
_css = 'Module:Bar/styles.css',
__init = function (self, args)
self.css = args[1] or args.css
self.float = args[2] or args.float or 'none'
self.backgroundcolor = args[3] or args.backgroundcolor or 'white'
self.borderwidth = args[4] or args.borderwidth or '1'
self.style = args[5] or args.style
self.width = args[6] or args.width-- or 'auto'
self.barwidth = args[7] or args.barwidth or '100px'
self.lineheight = args[8] or args.lineheight-- or '1.6'
self.title = args[9] or args.title
self.titlebar = args[10] or args.titlebar-- or 'none'
self.left1 = args[11] or args.left1
self.left2 = args[12] or args.left2
self.right1 = args[13] or args.right1
self.right2 = args[14] or args.right2
self.bars = args[15] or args.bars
self.caption = args[16] or args.caption -- deprecated
self.footer = args[17] or args.footer or args[16] or args.caption
end,
create = function (cls, args)
args = mw.clone(args)
args.float = args.float and args.float:lower()
args.width = tonumber(args.width) and args.width .. 'px' or args.width and args.width:lower()
args.barwidth = tonumber(args.barwidth) and args.barwidth .. 'px' or args.barwidth and args.barwidth:lower()
return cls(args)
end,
_sDefaultAlign = 'lrlr',
_tDefaultAlign = {false, 'r', false, 'r'},
_setAlign = function (obj, align)
obj._alignClasses = {}
for i, d in ipairs(obj._tDefaultAlign) do
local a = align:sub(i,i)
if a == 'l' then
a = false
elseif a == 'd' then
a = d
elseif a ~= 'c' and a ~= 'r' then
error('unrecognized align[' .. i .. ']')
end
obj._alignClasses[i] = a and 'class=bb-' .. a
end
end,
html = function (self)
local output = setmetatable({}, metatable)
output(frame:extensionTag('templatestyles', '', {src=self._css}) .. '\n')
output(self.css and frame:extensionTag('templatestyles', '', {src=self.css}) .. '\n' or '')
local class = 'barbox'
if self.float == 'left' or self.float == 'right' then
class = class .. ' t' .. self.float
end
output('<div class="' .. class .. '" style="background:' ..
self.backgroundcolor .. '; border:' .. self.borderwidth .. 'px solid silver'
)
if self.float == 'center' then output('; margin:0 auto') end
if self.width then output('; width:' .. self.width) end
if self.style then output('; ' .. self.style) end
output('">\n')
output('{|')
if self.lineheight then output(' style="line-height:' .. self.lineheight .. '"') end
output('\n')
if self.title then output(
'|+ class=bb-default' .. (self.titlebar and ' style="background:' .. self.titlebar .. '"' or '') .. ' |\n' ..
self.title .. '\n'
) end
output('|- class=bb-default style="font-size:88%; min-height:4px"\n')
if self._alignClasses then -- same as self.__class._alignClasses
self._alignClasses = self._alignClasses
self.__class._alignClasses = nil
else
self._setAlign(self, self._sDefaultAlign)
end
local attributes =
not self.left2 and 'colspan=2' .. (self._alignClasses[1] and ' ' .. self._alignClasses[1] or '') or self._alignClasses[1]
output('!' .. (attributes and attributes .. '|' or '') .. (self.left1 or ' '))
output(self.left2 and '!!' .. (self._alignClasses[2] and self._alignClasses[2] .. '|' or '') .. self.left2 or '')
output('!!style="width:' .. self.barwidth .. '"| ')
attributes =
not self.right2 and 'colspan=2' .. (self._alignClasses[4] and ' ' .. self._alignClasses[4] or '') or self._alignClasses[3]
output('!!' .. (attributes and attributes .. '|' or '') .. (self.right1 or self.right2 and ' ' or ''))
output(self.right2 and '!!' .. (self._alignClasses[4] and self._alignClasses[4] .. '|' or '') .. self.right2 or '')
output('\n')
if self.bars then output(self.bars .. '\n') end
if self.caption then output('\n[[Category:Pages using bar box with deprecated caption parameter]]') end
if self.footer then output(
'|- class=bb-default\n| colspan=5 style="padding:5px 0" | ' .. -- <p> is created if \n precedes the footer
self.footer .. '\n'
) end
output('|}\n</div>')
return tostring(output)
end,
__tostring = function (self)
return self.html()
end,
percent = function (args)
local output = setmetatable({'|-'}, metatable)
local percentage = (args[3] or '0') .. '%'
if args.bg then output(args.bg and 'style="background:' .. args.bg .. '"') end
output('\n')
output('|colspan=2 class=bb-min8|' .. (args[1] or ' '))
output('||class=bb-b|')
output('<div style="background:' .. (args[2] or 'gray') .. '; width:' .. percentage .. '">​</div>')
output('||' .. (args.note and '' or 'colspan=2 class=bb-r|') .. (args[4] or percentage))
if args.note then output('||class=bb-r|' .. args.note) end
return tostring(output)
end,
pixel = function (args)
local output = setmetatable({'|-'}, metatable)
local pixels = (args[3] or '0')
if args.bg then output('style="background:' .. args.bg .. '"') end
output('\n')
output('|colspan=2|' .. (args[1] or ' '))
output('||class=bb-b|')
output('<div style="background:' .. (args[2] or 'gray') .. '; width:' .. pixels .. 'px">​</div>')
output('||class="bb-min3' .. (args.note and '"' or ' bb-r" colspan=2') .. '|' .. (args[5] or pixels .. (args[4] or '')))
if args.note then output('||class=bb-r|' .. args.note) end
return tostring(output)
end,
stacked = function (cls, args)
local output = setmetatable({'|-'}, metatable)
if args.id then
output('class="mw-collapsible' ..
(args.collapsed and ' mw-collapsed' or '') ..
'" id=mw-customcollapsible-' .. args.id
)
end
output('\n')
if not cls._alignClasses then
cls._setAlign(cls, args.align and args.align:lower() or cls._sDefaultAlign)
end
local attributes =
not args.note1 and 'colspan=2' .. (cls._alignClasses[1] and ' ' .. cls._alignClasses[1] or '') or cls._alignClasses[1]
output('|' .. (attributes and attributes .. '|' or '') .. (args[1] or ' '))
if args.note1 then
output('||' .. (cls._alignClasses[2] and cls._alignClasses[2] .. '|' or '') .. args.note1)
end
output('||class=bb-b|')
local len = 0 -- can't use #args because of [[Module:Arguments#Known limitations]]
for k in pairs(args) do
local idx = tonumber(k) or 0
if idx > len then len = idx end
end
if args.bkgclasses then -- used when wikitext minimization is essential
for i = 1, len-2 do
local width, delim, title --is delim reset every cycle?
width = args[i+2] or 0
width = tonumber(('%.2f'):format(width))
if width > 0 then
if not delim then -- assuming title types are consistent
delim = tonumber(args['title' .. i]) and '' or '"'
end
title = args['title' .. i] and ' title=' .. delim .. args['title' .. i] .. delim or ''
output(
'<div' .. title .. ' class=' .. args.bkgclasses[i] .. ' style=width:' .. width .. 'px></div>'
)
end
end
else
for i = 1, (len-2) / 2 do
local width, title, background
width = args[2*i + 2] or 0
width = tonumber(('%.2f'):format(width))
if width > 0 then
title = args['title' .. i] and ' title="' .. args['title' .. i] .. '"' or ''
background = args[2*i + 1] or 'gray'
output(
'<div' .. title .. ' style="background:' .. background .. ';width:' .. width .. 'px"></div>'
)
end
end
end
if #output == 4 then output(' ') end
attributes =
not args.note2 and 'colspan=2' .. (cls._alignClasses[4] and ' ' .. cls._alignClasses[4] or '') or cls._alignClasses[3]
output('||')
if attributes then output(attributes .. '|') end
if (args[2] or args.note2) then output(' ') end
if args.note2 then
output('||')
if cls._alignClasses[4] then output (cls._alignClasses[4] .. '|') end
output(args.note2)
end
return tostring(output)
end,
gap = function (args)
local output = setmetatable({'|-\n'}, metatable)
local height = tonumber(args.height) and args.height .. 'px' or args.height and args.height:lower() or '10px'
output('|colspan=5 style="height:' .. height .. '"|' .. (args[1] or ''))
return tostring(output)
end,
['table'] = function (args)
local function expr(v, a)
v = frame:callParserFunction('formatnum', {ifblank(v, a), 'R'})
v = frame:callParserFunction('#expr', v)
return tonumber(ifblank(v, a)) or a
end
local barValue = expr(args[1], 0)
local scale = expr(args[3], 1)
local width = math.abs(scale * barValue)
local height = ifblank(args[4], '2ex')
local output = setmetatable({}, metatable)
-- Handle the display of the value and unit (parameters 1 and 2) --
if notblank(args[2]) then -- If a unit (parameter 2) is provided
local titleparts = mw.text.split(args[2], '/', true)
if notblank(titleparts[2]) then -- If unit has multiple parts (e.g., 'km|mi'), attempt conversion
if notblank(titleparts[1]) then -- If unit has a single part, display value and unit directly
output((args[1] or '') .. args[2])
else -- Otherwise, use the convert template to handle unit conversion
local cvtArgs = {
[1] = tostring(barValue),
[2] = titleparts[2] or '',
[3] = titleparts[3] or '',
[4] = titleparts[4] or '',
abbr= 'on'
}
local convert = require('Module:Convert')._convert
output(convert({}, cvtArgs))
end
else -- If unit is simple, display value and unit without conversion
output((args[1] or '') .. args[2])
end
else -- If no unit is provided, display value or default to em dash
output(ifblank(args[1], '—'))
end
-- Handle the bar visualization --
local sortString = 'data-sort-value="' .. barValue .. '"|'
local barString = sortString ..
'<div style="width:' .. width .. 'px;height:' .. height ..
';background:#aaa;color:inherit;' .. (args[5] or '') ..
'" title="' .. barValue .. '"> </div>'
if scale < 0 then -- If scale (parameter 3) is negative, add extra column
output('||')
if barValue < 0 then -- If value (parameter 1) is negative, align bar to the right & scale
output('align="right" ' .. barString)
else -- output hidden sort key for sortable wikitables
output(sortString)
end
end
output('\n|')
if barValue > 0 then -- if display value is positive, align bar to the left
output('align="left" ' .. barString)
else -- output hidden sort key for sortable wikitables
output(sortString)
end
return tostring(output)
end,
__classmethods = {'create', 'stacked'},
__staticmethods = {'_setAlign', 'percent', 'pixel', 'gap'},
__slots = {'_alignClasses'}
})
local getArgs = require('Module:Arguments').getArgs
local p = {BarBox}
function p.box(frame)
local args = getArgs(frame)
local box = BarBox.create(args)
return tostring(box)
end
function p.percent(frame)
local args = getArgs(frame)
return BarBox.percent(args)
end
function p.pixel(frame)
local args = getArgs(frame)
return BarBox.pixel(args)
end
function p.log(frame)
local args = getArgs(frame)
local outArgs = {[1] = args[2], [2] = args[3]}
outArgs[3] = math.log((tonumber(args[4]) ~= nil) and (args[4] + 1) or 100)/
math.log((tonumber(args[1]) ~= nil) and args[1] or 2)*30
outArgs[5] = ifblank(args[6], ((args[4] or '') .. (args[5] or '')))
return BarBox.pixel(outArgs)
end
function p.stacked(frame)
local yesno = require('Module:Yesno')
local args = getArgs(frame, {
valueFunc = function (key, value)
if value then
if key == 'collapsed' then
return yesno(value)
elseif key == 'bkgclasses' then
return mw.text.jsonDecode(value) -- string to table
end
value = mw.text.trim(value)
if value ~= '' then
return value
end
end
return nil
end
})
return BarBox.stacked(args)
end
function p.gap(frame)
local args = getArgs(frame)
return BarBox.gap(args)
end
function p.bartable(frame)
local args = frame.args
return BarBox['table'](args)
end
p['table'] = p.bartable
function p.tableTemplate(frame)
local args = frame:getParent().args
return BarBox['table'](args)
end
return p