Módulo:Diagrama
[ máis información | ver o historial | | | ver as instrucións ]
Obxectivo
editarMódulo para a creación de diagramas de barras e circulares. Usa dúas funcións: "diagrama de barras" e "diagrama circular"
Subpáxinas
editarDiagrama de barras
editarNome da función: diagrama de barras
Parámetros
editarParámetro | Función |
---|---|
delimiter | cadea para delimitar múltiples valores, por defecto ( : ). Xeralmente non debe especificarse. |
ancho | Número. Mínimo 200, por defecto 500 |
alto | Número. Mínimo 200, por defecto 350 |
grupo n | Onde "n" é un número. Valores para cada grupo |
tooltip n | Texto emerxente asociado coa barra correspondente. Se non se define pero si se define unha ligazón, amósase a ligazón como texto emerxente. Se non se define ningún deles o texto combina o nome do grupo e o valor, engadindo prefixos e sufixos se existen |
ligazóns n | ligazóns ós artigos asociados con cada barra |
agrupar | Se agrupar os valores un por riba doutro. Calquera valor non baleiro significa "si", para omitir non especificar o parámetro ou deixar en branco. |
acumular tooltip | Cando se define agrupar máis este parámetro, o texto emerxente amosará o valor acumulado |
cores | Cores para as barras. Ver Módulo:Diagrama/Cores |
lenda x | Lendas para os valores do eixo X. Pode usarse código wiki |
agochar lenda grupo | Agochar a lenda de valores do eixo X |
escala por grupo | Definir para amosar unha escala Y distinta por grupo. |
prefixo unidades | Usado no tooltip como prefixo |
sufixo unidades | Usado no tooltip como sufixo |
nomes grupo | Nomes dos distintos grupos |
Exemplos
editarBásicos
editar{{ #invoke:Diagrama | diagrama de barras | grupo 1 = 40 : 50 : 60 : 20 | ligazóns 1 = Xaneiro : Febreiro : Marzo : Abril | cores = green | nomes grupo = Meses | lenda x = Xaneiro : Febreiro : Marzo : Abril }}
10
20
30
40
50
60
Xaneiro
Febreiro
Marzo
Abril
{{ #invoke:Diagrama | diagrama de barras | grupo 1 = 40 : 50 : 60 : 20 | grupo 2 = 20 : 60 : 12 : 44 | grupo 3 = 55 : 14 : 33 : 5 | ligazóns 1 = Mazá : Can : Gato | ligazóns 2 = Plátano : Amorodo : Carballo | ligazóns 3 = Laranxa : Pera : Lugo | tooltip 2 = tooltip 1 : tooltip 2 : tooltip 3 : tooltip 4 | cores = green : yellow : orange | nomes grupo = Castro : Mar : Terra | lenda x = Antes : Durante : Despois : Final }}
10
20
30
40
50
60
Antes
Durante
Despois
Final
- Castro
- Mar
- Terra
Agrupado
editarDiagrama semellante ó anterior cun axuste de alto e ancho, agrupando e engadindo sufixo de unidades
{{ #invoke:Diagrama | diagrama de barras | alto = 250 | ancho = 300 | agrupar = 1 | grupo 1 = 40 : 50 : 60 : 20 | grupo 2 = 20 : 60 : 12 : 44 | grupo 3 = 55 : 14 : 33 : 5 | cores = green : yellow : orange | nomes grupo = Mazá : Plátano : Laranxa | sufixo unidades = Kg | lenda x = Antes : Durante : Despois : Final }}
25
50
75
100
125
150
Antes
Durante
Despois
Final
- Mazá
- Plátano
- Laranxa
Escalas por grupo
editarPódese representar cada un dos grupos usando diferentes escalas e unidades:
{{ #invoke:Diagrama | diagrama de barras | ancho = 800 | grupo 1 = 1500000 : 2500000 : 3500000 | grupo 2 = 200 : 5000 : 45000 | grupo 3 = 2000 : 5000 : 20000 | cores = red : blue : green | nomes grupo = Xente : Coches : Custo medio | lenda x = 1920 : 1965 : 2002 | tooltip 2 = : Non hai datos válidos para 1965, estimado 5000 | prefixo unidade = : : $ | escala por grupo = 1 }}
1.000.000
2.000.000
3.000.000
4.000.000
10.000
20.000
30.000
40.000
50.000
5.000
10.000
15.000
20.000
1920
1965
2002
- Xente
- Coches
- Custo medio
Outro exemplo cun gran número de grupos
{{ #invoke:Diagrama | diagrama de barras | ancho = 800 | alto = 550 | grupo 1 = 1:2:3:4:5:4:3:2:1 | grupo 2 = 1:2:3:4:5:4:3:2:1 | grupo 3 = 1:2:3:4:5:4:3:2:1 | grupo 4 = 1:2:3:4:5:4:3:2:1 | grupo 5 = 1:2:3:4:5:4:3:2:1 | grupo 6 = 1:2:3:4:5:4:3:2:1 | grupo 7 = 1:2:3:4:5:4:3:2:1 | grupo 8 = 1:2:3:4:5:4:3:2:1 | grupo 9 = 1:2:3:4:5:4:3:2:1 | grupo 10 = 1:2:3:4:5:4:3:2:1 | grupo 11 = 1:2:3:4:5:4:3:2:1 | grupo 12 = 1:2:3:4:5:4:3:2:1 | grupo 13 = 1:2:3:4:5:4:3:2:1 | grupo 14 = 1:2:3:4:5:4:3:2:1 | grupo 15 = 1:2:3:4:5:4:3:2:1 | grupo 16 = 1:2:3:4:5:4:3:2:1 | grupo 17 = 1:2:3:4:5:4:3:2:1 | grupo 18 = 1:2:3:4:5:4:3:2:1 | grupo 19 = 1:2:3:4:5:4:3:2:1 | grupo 20 = 1:2:3:4:5:4:3:2:1 | grupo 21 = 1:2:3:4:5:4:3:2:1 | cores = Silver:Gray:Black:Red:Maroon:Yellow:Olive:Lime:Green:Aqua:Teal:Blue:Navy:Fuchsia:Purple:ForestGreen:Tomato:LightSeaGreen:RosyBrown:DarkOliveGreen:MediumVioletRed | nomes grupo = Alabama:Alaska:Arizona:Arkansas:California:Colorado:Connecticut:Delaware:Florida:Georgia:Hawaii:Idaho:Illinois:Indiana:Iowa:Kansas:Kentucky:Louisiana:Maine:Maryland:Massachusetts | lenda x = 1920 : 1930 : 1940: 1950 : 1960 : 1970 : 1990 : 2000 : 2010 | prefixo unidades = $ | sufixo unidades = _Billion | agrupar = 1 }}
25
50
75
100
125
150
1920
1930
1940
1950
1960
1970
1990
2000
2010
- Alabama
- Alaska
- Arizona
- Arkansas
- California
- Colorado
- Connecticut
- Delaware
- Florida
- Georgia
- Hawaii
- Idaho
- Illinois
- Indiana
- Iowa
- Kansas
- Kentucky
- Louisiana
- Maine
- Maryland
- Massachusetts
As lendas do eixo X poden espallarse con delimitadores sen valores entre eles
{{ #invoke:Diagrama | diagrama de barras | grupo 1 = 1:2:3:4:5:6:7:8:9:10:11:12:13:14:15:16:17:18:19:20:21:22:23:24:25:26:27:28:29:30 :31:32:33:34:35:36:37:38:39:40:41:42:43:44:45:46:47:48:49:50:51:52:53:54:55:56:57:58:59 | sufixo unidades = _Cousas | nomes grupo = Algo | lenda x = ::::1940::::::::::1950::::::::::1960::::::::::1970::::::::::1980::::::::::1990:::: }}
10
20
30
40
50
60
1940
1950
1960
1970
1980
1990
Diagrama circular
editarNome da función: diagrama circular
Parámetros
editarParámetro | Función |
---|---|
delimiter | cadea para delimitar múltiples valores, por defecto ( : ). Xeralmente non debe especificarse. |
radio | Número. Radio da torta en píxeles |
porcións | Conxuntos de valores, entre parénteses: ( Valor1 : Nome1 : Cor1 : Ligazón1 ) ( Valor2 : Nome2 : Cor2 : Ligazón2 ) ... Os valores deben ser números, poden ser enteiros, fraccións decimais ou con notación científica. Os nomes son cadeas de texto. As cores son opcionais. |
porción n | sintaxe alternativa, n é o número de porción. Exemplo:
| porción 1 = Valor1 : Nome1 : Cor1 : Ligazón1 | porción 2 = Valor2 : Nome2 : Cor2 : Ligazón2 | ... |
porcentaxe | Se se define como verdadeiro, calcula a porcentaxe de cada porción e engádea na lenda. |
prefixo unidades | Usado no tooltip como prefixo |
sufixo unidades | Usado no tooltip como sufixo |
agochar lenda grupo | Agochar a lenda de valores do eixo X |
Exemplos
editar{{#invoke:Diagrama|diagrama circular | radio = 150 | porcións = ( 1000000 : Apples ) ( 2000000 : Bananas : gold) ( 1440000 : Apricots ) ( 6.4e5 : Pears : : [[Pear|Pears]] ) ( 750,000 : Pineapples ) | sufixo unidades = _Tonne | porcentaxe = true }}
- Mazás: 1.000.000 Toneladas (9.2%)
- Plátanos: 2.000.000 Toneladas (18.4%)
- Laranxas: 1.440.000 Toneladas (13.3%)
- Peras: 6.400.000 Toneladas (59.0%)
- Piñas: 750 Toneladas (0.0%)
Sintaxe alternativa
{{#invoke:Diagrama|diagrama circular |radio= 200 |sufixo unidades = _Unidades | porción 1 = 1 : 1 | porción 2 = 7 : 7 | porción 3 = 8 : 8 | porción 4 = 9 : 9 | porción 5 = 10 : 10 | porción 6 = 11 : 11 | porción 7 = 12 : 12 | porción 8 = 13 : 13 | porción 9 = 14 : 14 | porción 10 = 15 : 15 | porción 11 = 16 : 16 | porción 12 = 17 : 17 | porción 13 = 18 : 18 | porción 14 = 19 : 19 | porción 15 = 20 : 20 | porción 16 = 21 : 21 | porción 17 = 22 : 22 | porción 18 = 23 : 23 | porción 19 = 24 : 24 | porción 20 = 25 : 25 | porción 21 = 26 : 26 | porción 22 = 27 : 27 | porción 23 = 28 : 28 | porción 24 = 29 : 29 | porción 25 = 30 : 30 | porción 26 = 31 : 31 | porcentaxe = true }}
- 1: 1 Unidades (0.2%)
- 7: 7 Unidades (1.5%)
- 8: 8 Unidades (1.7%)
- 9: 9 Unidades (1.9%)
- 10: 10 Unidades (2.1%)
- 11: 11 Unidades (2.3%)
- 12: 12 Unidades (2.5%)
- 13: 13 Unidades (2.7%)
- 14: 14 Unidades (2.9%)
- 15: 15 Unidades (3.2%)
- 16: 16 Unidades (3.4%)
- 17: 17 Unidades (3.6%)
- 18: 18 Unidades (3.8%)
- 19: 19 Unidades (4.0%)
- 20: 20 Unidades (4.2%)
- 21: 21 Unidades (4.4%)
- 22: 22 Unidades (4.6%)
- 23: 23 Unidades (4.8%)
- 24: 24 Unidades (5.0%)
- 25: 25 Unidades (5.3%)
- 26: 26 Unidades (5.5%)
- 27: 27 Unidades (5.7%)
- 28: 28 Unidades (5.9%)
- 29: 29 Unidades (6.1%)
- 30: 30 Unidades (6.3%)
- 31: 31 Unidades (6.5%)
[ máis información | ver o historial | | | ver as instrucións ]
Esta documentación está transcluída desde Módulo:Diagrama/uso. Os editores poden probar cambios no mesmo en Módulo:Diagrama/probas.
Por favor, engade as categorías na subpáxina de documentación e os interwikis no Wikidata. Ver as subpáxinas deste módulo.
Por favor, engade as categorías na subpáxina de documentación e os interwikis no Wikidata. Ver as subpáxinas deste módulo.
--<syntaxhighlight lang="lua">
--[[
keywords are used for languages: they are the names of the actual
parameters of the template
]]
local keywords = {
barChart = 'diagrama de barras',
pieChart = 'diagrama circular',
width = 'ancho',
height = 'alto',
stack = 'agrupar',
colors = 'cores',
group = 'grupo',
xlegend = 'lenda x',
tooltip = 'tooltip',
accumulateTooltip = 'acumular tooltip',
links = 'ligazóns',
defcolor = 'cor por defecto',
scalePerGroup = 'escala por grupo',
unitsPrefix = 'prefixo unidades',
unitsSuffix = 'sufixo unidades',
groupNames = 'nomes grupo',
hideGroupLegends = 'agochar lenda grupo',
slices = 'porcións',
slice = 'porción',
radius = 'radio',
percent = 'porcentaxe',
} -- here is what you want to translate
local defColors = require "Module:Diagrama/Cores"
local hideGroupLegends
local function nulOrWhitespace( s )
return not s or mw.text.trim( s ) == ''
end
local function createGroupList( tab, legends, cols )
if #legends > 1 and not hideGroupLegends then
table.insert( tab, mw.text.tag( 'div' ) )
local list = {}
local spanStyle = "padding:0 1em;background-color:%s;border:1px solid %s;margin-right:1em;-webkit-print-color-adjust:exact;"
for gi = 1, #legends do
local span = mw.text.tag( 'span', { style = string.format( spanStyle, cols[gi], cols[gi] ) }, ' ' ) .. ' '.. legends[gi]
table.insert( list, mw.text.tag( 'li', {}, span ) )
end
table.insert( tab,
mw.text.tag( 'ul',
{style="width:100%;list-style:none;-webkit-column-width:12em;-moz-column-width:12em;column-width:12em;"},
table.concat( list, '\n' )
)
)
table.insert( tab, '</div>' )
end
end
function pieChart( frame )
local res, imslices, args = {}, {}, frame.args
local radius
local values, colors, names, legends, links = {}, {}, {}, {}, {}
local delimiter = args.delimiter or ':'
local lang = mw.getContentLanguage()
function getArg( s, def, subst, with )
local result = args[keywords[s]] or def or ''
if subst and with then result = mw.ustring.gsub( result, subst, with ) end
return result
end
function analyzeParams()
function addSlice( i, slice )
local value, name, color, link = unpack( mw.text.split( slice, '%s*' .. delimiter .. '%s*' ) )
values[i] = tonumber( lang:parseFormattedNumber( value ) )
or error( string.format( 'A porción %d: "%s", primeiro elemento("%s") non se puido avaliar coma un número', i, value or '', sliceStr ) )
colors[i] = not nulOrWhitespace( color ) and color or defColors[i * 2]
names[i] = name or ''
links[i] = link
end
radius = getArg( 'radius', 150 )
hideGroupLegends = not nulOrWhitespace( args[keywords.hideGroupLegends] )
local slicesStr = getArg( 'slices' )
local prefix = getArg( 'unitsPrefix', '', '_', ' ' )
local suffix = getArg( 'unitsSuffix', '', '_', ' ' )
local percent = args[keywords.percent]
local sum = 0
local i, value = 0
for slice in mw.ustring.gmatch( slicesStr or '', "%b()" ) do
i = i + 1
addSlice( i, mw.ustring.match( slice, '^%(%s*(.-)%s*%)$' ) )
end
for k, v in pairs(args) do
local ind = mw.ustring.match( k, '^' .. keywords.slice .. '%s+(%d+)$' )
if ind then addSlice( tonumber( ind ), v ) end
end
for _, val in ipairs( values ) do sum = sum + val end
for i, value in ipairs( values ) do
local addprec = percent and string.format( ' (%0.1f%%)', value / sum * 100 ) or ''
legends[i] = mw.ustring.format( '%s: %s%s%s%s', names[i], prefix, lang:formatNum( value ), suffix, addprec )
links[i] = mw.text.trim( links[i] or mw.ustring.format( '[[#noSuchAnchor|%s]]', legends[i] ) )
end
end
function addRes( ... )
for _, v in pairs( { ... } ) do
table.insert( res, v )
end
end
function createImageMap()
addRes( '{{#tag:imagemap|', 'Image:Circle frame.svg{{!}}' .. ( radius * 2 ) .. 'px' )
addRes( unpack( imslices ) )
addRes( 'desc none', '}}' )
end
function drawSlice( i, q, start )
local color = colors[i]
local angle = start * 2 * math.pi
local sin, cos = math.abs( math.sin( angle ) ), math.abs( math.cos( angle ) )
local wsin, wcos = sin * radius, cos * radius
local s1, s2, w1, w2, w3, w4, width, border
local style
if q == 1 then
border = 'left'
w1, w2, w3, w4 = 0, 0, wsin, wcos
s1, s2 = 'bottom', 'left'
elseif q == 2 then
border = 'bottom'
w1, w2, w3, w4 = 0, wcos, wsin, 0
s1, s2 = 'bottom', 'right'
elseif q == 3 then
border = 'right'
w1, w2, w3, w4 = wsin, wcos, 0, 0
s1, s2 = 'top', 'right'
else
border = 'top'
w1, w2, w3, w4 = wsin, 0, 0, wcos
s1, s2 = 'top', 'left'
end
local style = string.format( 'border:solid transparent;position:absolute;%s:%spx;%s:%spx;width:%spx;height:%spx', s1, radius, s2, radius, radius, radius )
if start <= ( q - 1 ) * 0.25 then
style = string.format( '%s;border:0;background-color:%s', style, color )
else
style = string.format( '%s;border-width:%spx %spx %spx %spx;border-%s-color:%s', style, w1, w2, w3, w4, border, color )
end
addRes( mw.text.tag( 'div', { style = style }, '' ) )
end
function createSlices()
function coordsOfAngle( angle )
return ( 100 + math.floor( 100 * math.cos( angle ) ) ) .. ' ' .. ( 100 - math.floor( 100 * math.sin( angle ) ) )
end
local sum, start = 0, 0
for _, value in ipairs( values ) do sum = sum + value end
for i, value in ipairs(values) do
local poly = { 'poly 100 100' }
local startC, endC = start / sum, ( start + value ) / sum
local startQ, endQ = math.floor( startC * 4 + 1 ), math.floor( endC * 4 + 1 )
for q = startQ, math.min( endQ, 4 ) do drawSlice( i, q, startC ) end
for angle = startC * 2 * math.pi, endC * 2 * math.pi, 0.02 do
table.insert( poly, coordsOfAngle( angle ) )
end
table.insert( poly, coordsOfAngle( endC * 2 * math.pi ) .. ' 100 100 ' .. links[i] )
table.insert( imslices, table.concat( poly, ' ' ) )
start = start + values[i]
end
end
analyzeParams()
if #values == 0 then error( "no slices found - can't draw pie chart" ) end
addRes( mw.text.tag( 'div', { class = 'chart noresize', style = string.format( 'margin-top:0.5em;max-width:%spx;', radius * 2 ) } ) )
addRes( mw.text.tag( 'div', { style = string.format( 'position:relative;min-width:%spx;min-height:%spx;max-width:%spx;overflow:hidden;', radius * 2, radius * 2, radius * 2 ) } ) )
createSlices()
addRes( mw.text.tag( 'div', { style = string.format( 'position:absolute;min-width:%spx;min-height:%spx;overflow:hidden;', radius * 2, radius * 2 ) } ) )
createImageMap()
addRes( '</div>' ) -- close "position:relative" div that contains slices and imagemap.
addRes( '</div>' ) -- close "position:relative" div that contains slices and imagemap.
createGroupList( res, legends, colors ) -- legends
addRes( '</div>' ) -- close containing div
return frame:preprocess( table.concat( res, '\n' ) )
end
function barChart( frame )
local res = {}
local args = frame.args -- can be changed to frame:getParent().args
local values, xlegends, colors, tooltips, yscales = {}, {}, {}, {} ,{}, {}, {}
local groupNames, unitsSuffix, unitsPrefix, links = {}, {}, {}, {}
local width, height, stack, delimiter = 500, 350, false, args.delimiter or ':'
local chartWidth, chartHeight, defcolor, scalePerGroup, accumulateTooltip
local numGroups, numValues
local scaleWidth
function validate()
function asGroups( name, tab, toDuplicate, emptyOK )
if #tab == 0 and not emptyOK then
error( "deben fornecerse valores para " .. keywords[name] )
end
if #tab == 1 and toDuplicate then
for i = 2, numGroups do tab[i] = tab[1] end
end
if #tab > 0 and #tab ~= numGroups then
error ( keywords[name] .. ' debe conter o mesmo número de elementos que o número de grupos, pero contén ' .. #tab .. ' elementos e hai ' .. numGroups .. ' grupos')
end
end
-- do all sorts of validation here, so we can assume all params are good from now on.
-- among other things, replace numerical values with mw.language:parseFormattedNumber() result
chartHeight = height - 80
numGroups = #values
numValues = #values[1]
defcolor = defcolor or 'blue'
colors[1] = colors[1] or defcolor
scaleWidth = scalePerGroup and 80 * numGroups or 100
chartWidth = width -scaleWidth
asGroups( 'unitsPrefix', unitsPrefix, true, true )
asGroups( 'unitsSuffix', unitsSuffix, true, true )
asGroups( 'colors', colors, true, true )
asGroups( 'groupNames', groupNames, false, false )
if stack and scalePerGroup then
error( string.format( 'Uso de parámetros non válido: %s e %s son incompatibles.', keyword.stack, keyword.scalePerGroup ) )
end
for gi = 2, numGroups do
if #values[gi] ~= numValues then error( keywords.group .. " " .. gi .. " non ten o mesmo número de valores ca " .. keywords.group .. " 1" ) end
end
if #xlegends ~= numValues then error( 'Número incorrecto de ' .. keywords.xlegend .. '. Debería ser exactamente ' .. numValues ) end
end
function extractParams()
function testone( keyword, key, val, tab )
i = keyword == key and 0 or key:match( keyword .. "%s+(%d+)" )
if not i then return end
i = tonumber( i ) or error("Agárdase un índice numérico para a chave " .. keyword .. " no lugar de '" .. key .. "'")
if i > 0 then tab[i] = {} end
for s in mw.text.gsplit( val, '%s*' .. delimiter .. '%s*' ) do
table.insert( i == 0 and tab or tab[i], s )
end
return true
end
for k, v in pairs( args ) do
if k == keywords.width then
width = tonumber( v )
if not width or width < 200 then
error( 'Valor de ancho non válido (debe ser un número, mínimo 200): ' .. v )
end
elseif k == keywords.height then
height = tonumber( v )
if not height or height < 200 then
error( 'Valor de alto non válido (debe ser un número, mínimo 200): ' .. v )
end
elseif k == keywords.stack then stack = true
elseif k == keywords.scalePerGroup then scalePerGroup = true
elseif k == keywords.defcolor then defcolor = v
elseif k == keywords.accumulateTooltip then accumulateTooltip = not nulOrWhitespace( v )
elseif k == keywords.hideGroupLegends then hideGroupLegends = not nulOrWhitespace( v )
else
for keyword, tab in pairs( {
group = values,
xlegend = xlegends,
colors = colors,
tooltip = tooltips,
unitsPrefix = unitsPrefix,
unitsSuffix = unitsSuffix,
groupNames = groupNames,
links = links,
} ) do
if testone( keywords[keyword], k, v, tab )
then break
end
end
end
end
end
function roundup( x ) -- returns the next round number: eg., for 30 to 39.999 will return 40, for 3000 to 3999.99 wil return 4000. for 10 - 14.999 will return 15.
local ordermag = 10 ^ math.floor( math.log10( x ) )
local normalized = x / ordermag
local top = normalized >= 1.5 and ( math.floor( normalized + 1 ) ) or 1.5
return ordermag * top, top, ordermag
end
function calcHeightLimits() -- if limits were passed by user, use them, otherwise calculate. for "stack" there's only one limet.
if stack then
local sums = {}
for _, group in pairs( values ) do
for i, val in ipairs( group ) do sums[i] = ( sums[i] or 0 ) + val end
end
local sum = math.max( unpack( sums ) )
for i = 1, #values do yscales[i] = sum end
else
for i, group in ipairs( values ) do yscales[i] = math.max( unpack( group ) ) end
end
for i, scale in ipairs( yscales ) do yscales[i] = roundup( scale * 0.9999 ) end
if not scalePerGroup then for i = 1, #values do yscales[i] = math.max( unpack( yscales ) ) end end
end
function tooltip( gi, i, val )
if tooltips and tooltips[gi] and not nulOrWhitespace( tooltips[gi][i] ) then return tooltips[gi][i], true end
local groupName = not nulOrWhitespace( groupNames[gi] ) and groupNames[gi] .. ': ' or ''
local prefix = unitsPrefix[gi] or unitsPrefix[1] or ''
local suffix = unitsSuffix[gi] or unitsSuffix[1] or ''
return mw.ustring.gsub(groupName .. prefix .. mw.getContentLanguage():formatNum( tonumber( val ) or 0 ) .. suffix, '_', ' '), false
end
function calcHeights( gi, i, val )
local barHeight = math.floor( val / yscales[gi] * chartHeight + 0.5 ) -- add half to make it "round" instead of "trunc"
local top, base = chartHeight - barHeight, 0
if stack then
local rawbase = 0
for j = 1, gi - 1 do rawbase = rawbase + values[j][i] end -- sum the "i" value of all the groups below our group, gi.
base = math.floor( chartHeight * rawbase / yscales[gi] ) -- normally, and especially if it's "stack", all the yscales must be equal.
end
return barHeight, top - base
end
function groupBounds( i )
local setWidth = math.floor( chartWidth / numValues )
local setOffset = ( i - 1 ) * setWidth
return setOffset, setWidth
end
function calcx( gi, i )
local setOffset, setWidth = groupBounds( i )
if stack or numGroups == 1 then
local barWidth = math.min( 38, math.floor( 0.8 * setWidth ) )
return setOffset + (setWidth - barWidth) / 2, barWidth
end
setWidth = 0.85 * setWidth
local barWidth = math.floor( 0.75 * setWidth / numGroups )
local left = setOffset + math.floor( ( gi - 1 ) / numGroups * setWidth )
return left, barWidth
end
function drawbar( gi, i, val, ttval )
if val == '0' then return end -- do not show single line (borders....) if value is 0, or rather, '0'.
local color, tooltip, custom = colors[gi] or defcolor or 'blue', tooltip( gi, i, ttval or val )
local left, barWidth = calcx( gi, i )
local barHeight, top = calcHeights( gi, i, val )
-- borders so it shows up when printing
local style = string.format("position:absolute;left:%spx;top:%spx;height:%spx;min-width:%spx;max-width:%spx;background-color:%s;-webkit-print-color-adjust:exact;border:1px solid %s;border-bottom:none;overflow:hidden;",
left, top, barHeight-1, barWidth-2, barWidth-2, color, color)
local link = links[gi] and links[gi][i] or ''
local img = not nulOrWhitespace( link ) and mw.ustring.format( '[[Ficheiro:Transparent.png|1000px|link=%s|%s]]', link, custom and tooltip or '' ) or ''
table.insert( res, mw.text.tag( 'div', { style = style, title = tooltip, }, img ) )
end
function drawYScale()
function drawSingle( gi, color, width, single )
local yscale = yscales[gi]
local _, top, ordermag = roundup( yscale * 0.999 )
local numnotches = top <= 1.5 and top * 4
or top < 4 and top * 2
or top
local valStyleStr =
single and 'position:absolute;height=20px;text-align:right;vertical-align:middle;width:%spx;top:%spx;padding:0 2px'
or 'position:absolute;height=20px;text-align:right;vertical-align:middle;width:%spx;top:%spx;left:3px;background-color:%s;color:white;font-weight:bold;text-shadow:-1px -1px 0 #000,1px -1px 0 #000,-1px 1px 0 #000,1px 1px 0 #000;padding:0 2px'
local notchStyleStr = 'position:absolute;height=1px;min-width:5px;top:%spx;left:%spx;border:1px solid %s;'
for i = 1, numnotches do
local val = i / numnotches * yscale
local y = chartHeight - calcHeights( gi, 1, val )
local div = mw.text.tag( 'div', { style = string.format( valStyleStr, width - 10, y - 10, color ) }, mw.getContentLanguage():formatNum( tonumber( val ) or 0 ) )
table.insert( res, div )
div = mw.text.tag( 'div', { style = string.format( notchStyleStr, y, width - 4, color ) }, '' )
table.insert( res, div )
end
end
if scalePerGroup then
local colWidth = 80
local colStyle = "position:absolute;height:%spx;min-width:%spx;left:%spx;border-right:1px solid %s;color:%s"
for gi = 1, numGroups do
local left = ( gi - 1 ) * colWidth
local color = colors[gi] or defcolor
table.insert( res, mw.text.tag( 'div', { style = string.format( colStyle, chartHeight, colWidth, left, color, color ) } ) )
drawSingle( gi, color, colWidth )
table.insert( res, '</div>' )
end
else
drawSingle( 1, 'black', scaleWidth, true )
end
end
function drawXlegends()
local setOffset, setWidth
local legendDivStyleFormat = "position:absolute;left:%spx;top:10px;min-width:%spx;max-width:%spx;text-align:center;vertical-align:top;"
local tickDivstyleFormat = "position:absolute;left:%spx;height:10px;width:1px;border-left:1px solid black;"
for i = 1, numValues do
if not nulOrWhitespace( xlegends[i] ) then
setOffset, setWidth = groupBounds( i )
-- setWidth = 0.85 * setWidth
table.insert( res, mw.text.tag( 'div', { style = string.format( legendDivStyleFormat, setOffset + 5, setWidth - 10, setWidth - 10 ) }, xlegends[i] or '' ) )
table.insert( res, mw.text.tag( 'div', { style = string.format( tickDivstyleFormat, setOffset + setWidth / 2 ) }, '' ) )
end
end
end
function drawChart()
table.insert( res, mw.text.tag( 'div', { class = 'chart noresize', style = string.format( 'margin-top:1em;max-width:%spx;', width ) } ) )
table.insert( res, mw.text.tag( 'div', { style = string.format("position:relative;min-height:%spx;min-width:%spx;max-width:%spx;", height, width, width ) } ) )
table.insert( res, mw.text.tag( 'div', { style = string.format("float:right;position:relative;min-height:%spx;min-width:%spx;max-width:%spx;border-left:1px black solid;border-bottom:1px black solid;", chartHeight, chartWidth, chartWidth ) } ) )
local acum = stack and accumulateTooltip and {}
for gi, group in pairs( values ) do
for i, val in ipairs( group ) do
if acum then acum[i] = ( acum[i] or 0 ) + val end
drawbar( gi, i, val, acum and acum[i] )
end
end
table.insert( res, '</div>' )
table.insert( res, mw.text.tag( 'div', { style = string.format("position:absolute;height:%spx;min-width:%spx;max-width:%spx;", chartHeight, scaleWidth, scaleWidth, scaleWidth ) } ) )
drawYScale()
table.insert( res, '</div>' )
table.insert( res, mw.text.tag( 'div', { style = string.format( "position:absolute;top:%spx;left:%spx;width:%spx;", chartHeight, scaleWidth, chartWidth ) } ) )
drawXlegends()
table.insert( res, '</div>' )
table.insert( res, '</div>' )
createGroupList( res, groupNames, colors )
table.insert( res, '</div>' )
end
extractParams()
validate()
calcHeightLimits()
drawChart()
return table.concat( res, "\n" )
end
return {
['bar-chart'] = barChart,
[keywords.barChart] = barChart,
[keywords.pieChart] = pieChart,
}
--</syntaxhighlight>