Jump to content
 







Main menu
   


Navigation  



Main page
Contents
Current events
Random article
About Wikipedia
Contact us
Donate
 




Contribute  



Help
Learn to edit
Community portal
Recent changes
Upload file
 








Search  

































Create account

Log in
 









Create account
 Log in
 




Pages for logged out editors learn more  



Contributions
Talk
 



















Contents

   



(Top)
 


1 Drawing Bar charts: "bar chart"  



1.1  Parameters  







2 Display in the mobile view  



2.1  Examples  



2.1.1  Basic  





2.1.2  Stacked  





2.1.3  Scale per group  









3 Drawing Pie charts: "pie chart"  



3.1  Parameters  





3.2  Examples  
















Module:Chart






Алтай тил
العربية

Asturianu
Авар
Azərbaycanca

Башҡортса
Беларуская

Български
Bosanski
Català
Čeština
Dansk
Deutsch
Ελληνικά
Español
فارسی
Føroyskt
Français
Galego
ГӀалгӀай


Հայերեն
ि
Bahasa Indonesia
Ирон
עברית

Kurdî
Latviešu
Лезги
Македонски



Мокшень
Nederlands


Нохчийн
Norsk bokmål
Oʻzbekcha / ўзбекча

Português
Română
Русский

Shqip

Simple English
Slovenčina
Suomi
Svenska
Tagalog
ி

Türkçe
Українська
اردو
Tiếng Vit

 

Edit links
 









Module
Talk
 

















Read
View source
View history
 








Tools
   


Actions  



Read
View source
View history
 




General  



What links here
Related changes
Upload file
Special pages
Permanent link
Page information
Get shortened URL
Download QR code
Wikidata item
 




Print/export  



Download as PDF
Printable version
 




In other projects  



Wikimedia Commons
Meta-Wiki
Wikidata
 
















Appearance
   

 





Permanently protected module

From Wikipedia, the free encyclopedia
 


Module Chart exports two functions: bar chart and pie chart

Note - Template:Graph:Chart is an alternative template, that may be more suitable for your use case.

Drawing Bar charts: "bar chart"

Parameters

parameter name what it does
delimiter string to delimit multiple values when given. default to colon ( : ). normally you do not want to touch this, it's provided for the off-chance you'll want to use colon as part of one of the parameters.
width number. if provided, must be at least 200. default: 500
height number. if provided, must be at least 200. default: 350
group n (where "n" is a number. use "group 1", "group 2" etc. for as many groups as there are in the graph) the values to be charted. see below.
tooltip n tooltip to be associated with specific bar. If no tooltip for a specific bar is defined, and this bar has a link, then this link will be used as tooltip. Otherwise, the tooltip will be combined from the group name and the value, optionally with "units prefix" and "units suffix".
links n links to articles to be associated with specific bar
stack whether to stack the different groups on top of each other. do not specify to show bars side by side. Any non-empty value means "yes". To say "no", simply do not supply this parameter at all, or leave the value blank.
tooltip value accumulation useful only with stack: when set to true, tooltip will show accumulated value of all blocks up to current one
colors the colors used to denote the various groups. should have exactly as many values as # of groups. can be given as standard html-recognized color names, or using #xxx or #xxxxxx notation.
x legends The legends for the X values. Wikicode, such as internal links or templates can be used.
hide group legends if set to true, group legends will not be shown below chart. Any non-empty value means "yes". To say "no", simply do not supply this parameter at all, or leave the value blank.
scale per group set to use separate Y- scale for each group. leave empty to use one scale for all groups. incompatible with "stack". Note that even if some of the scales are exactly the same, they will be drawn separately when this setting is on. Any non-empty value means "yes". To say "no", simply do not supply this parameter at all, or leave the value blank.
units prefix used in tooltip. e.g., $, so values will show as "$500" instead of "500" in the tooltip
units suffix ditto for units suffix. use, e.g. "Kg" so values will show as 88Kg instead of 88 in tooltip. underscore ("_") are replaced by spaces, to allow a space between the value and the suffix.
group names names of different groups
y tick marks number of tick marks on the y axis. if the value is negative or omitted, the module will attempt to automatically calculate a sensible number of tick marks.

Display in the mobile view

Bar charts behave unpredictably, causing problems with the axes and legend. Use Template:Graph:Chart instead. Pie charts aren't too bad.[dubiousdiscuss]

Examples

Basic

{{ #invoke:Chart | bar chart
| group 1 = 40 : 50 : 60 : 20
| group 2 = 20 : 60 : 12 : 44
| group 3 = 55 : 14 : 33 : 5
| links 1 = Apple : McCintosh : Golden delicious
| links 2 = Banana : Apricot : Peach
| links 3 = Orange : Pear : Bear
| tooltip 2 = tooltip 1 : tooltip 2 : tooltip 3 : tooltip 4
| colors = green : yellow : orange
| group names = Apple : Banana : Orange
| x legends = Before : During : After : Post mortem
}}


tooltip 1
tooltip 2
tooltip 3

10

20

30

40

50

60

Before

During

After

Post mortem


Stacked

Here is the same graph, with more modest height and width, using "stack", and adding "units suffix" for good measure:

{{ #invoke:Chart | bar chart
| height = 250
| width = 300
| stack = 1
| group 1 = 40 : 50 : 60 : 20
| group 2 = 20 : 60 : 12 : 44
| group 3 = 55 : 14 : 33 : 5
| colors = green : yellow : orange
| group names = Apple : Banana : Orange
| units suffix = Kg
| x legends = Before : During : After : Post mortem
}}

25

50

75

100

125

150

Before

During

After

Post mortem


Scale per group

This option has been disabled. It was rarely used and broke in the last code update. Here is an example with large number of groups - mainly to test how it looks with large number of legends:

{{ #invoke:Chart | bar chart
| width = 800
| height = 550
| group 1 = 1:2:3:4:5:4:3:2:1
| group 2 = 1:2:3:4:5:4:3:2:1
| group 3 = 1:2:3:4:5:4:3:2:1
| group 4 = 1:2:3:4:5:4:3:2:1
| group 5 = 1:2:3:4:5:4:3:2:1
| group 6 = 1:2:3:4:5:4:3:2:1
| group 7 = 1:2:3:4:5:4:3:2:1
| group 8 = 1:2:3:4:5:4:3:2:1
| group 9 = 1:2:3:4:5:4:3:2:1
| group 10 = 1:2:3:4:5:4:3:2:1
| group 11 = 1:2:3:4:5:4:3:2:1
| group 12 = 1:2:3:4:5:4:3:2:1
| group 13 = 1:2:3:4:5:4:3:2:1
| group 14 = 1:2:3:4:5:4:3:2:1
| group 15 = 1:2:3:4:5:4:3:2:1
| group 16 = 1:2:3:4:5:4:3:2:1
| group 17 = 1:2:3:4:5:4:3:2:1
| group 18 = 1:2:3:4:5:4:3:2:1
| group 19 = 1:2:3:4:5:4:3:2:1
| group 20 = 1:2:3:4:5:4:3:2:1
| group 21 = 1:2:3:4:5:4:3:2:1
| colors = Silver:Gray:Black:Red:Maroon:Yellow:Olive:Lime:Green:Aqua:Teal:Blue:Navy:Fuchsia:Purple:ForestGreen:Tomato:LightSeaGreen:RosyBrown:DarkOliveGreen:MediumVioletRed
| group names = Alabama:Alaska:Arizona:Arkansas:California:Colorado:Connecticut:Delaware:Florida:Georgia:Hawaii:Idaho:Illinois:Indiana:Iowa:Kansas:Kentucky:Louisiana:Maine:Maryland:Massachusetts
| x legends = 1920 : 1930 : 1940: 1950 : 1960 : 1970 : 1990 : 2000 : 2010
| units prefix = $
| units suffix = _billion
| stack = 1
}}

25

50

75

100

125

150

1920

1930

1940

1950

1960

1970

1990

2000

2010


If there are many values, x legends can be diluted by using delimiters with nothing in between:

{{ #invoke:Chart | bar chart
| group 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
| units suffix = _Things
| group names = Some
| x legends = ::::1940::::::::::1950::::::::::1960::::::::::1970::::::::::1980::::::::::1990::::
}}

10

20

30

40

50

60

1940

1950

1960

1970

1980

1990

Drawing Pie charts: "pie chart"

Parameters

parameter name what it does
delimiter string to delimit multiple values when given. default to colon ( : ). normally you do not want to touch this, it's provided for the off-chance you'll want to use colon as part of one of the parameters.
radius number. The radius of the pie in pixels
slices Tuples, in parenthesis. Use delimiter inside the tuple:
( Value1 : Name1 : Color1 : Link1  ) ( Value2 : Name2 : Color2 : Link2 ) ...

The values are numbers. The numbers can be integers or decimal fractions, or using the scientific notation: 7.24e6, 7,240,000, or 7240000.00 are all acceptable for 7 Million and 240 thousands.

Names are strings. Colors are optional. you can use any Web colors, such as "red" or "#FF0000". Up to 26 default colors are defined, but if your pie has more than 26 slices, you must define the colors of slice #27 and up. Links can be external or internal links, including linking to internal anchors and paragraphs in the same article, like so: [[Article|Tooltip]] for internal link, [[#Paragraph name|Tooltip]] for linking to an anchor in same article, or [http://example.org Tooltip] for external link.

slice n alternative syntax to "slices". n is the slice number, beginning with 1. make sure not to skip: if you define "slice 1", "slice 2", "slice 4", "slice 5"..., skipping slice 3, only the first two slices will be shown. this syntax is incompatible with "slices", i.e., they should not be used in conjunction in the same invocation. Using both "slices" and "slice n" in the same invocation will cause unpredictable results. The value is like a single "tuple" as explained above, but without the parenthesis:
 | slice 1 = Value1 : Name1 : Color1 : Link1
 | slice 2 = Value2 : Name2 : Color2 : Link2
 | ...

This syntax allows you to use parenthesis in names, links, and colors.

percent if used, the percentage of each slice will be calculated and added to the legend: so if you have two slices, like so: ( 1 : Younglings ) ( 3 : elders ), and use define "percent", the legends will become "Younglings: 1 (25%)" and "Elders: 3 (75%)", instead of simply "Younglings: 1" and "Elders: 3". Any non-empty value means "yes". To say "no", simply do not supply this parameter at all, or leave the value blank.
units prefix used in the legend. e.g., defining "units prefix=$", values will show as "$500" instead of "500" in the legends
units suffix ditto for units suffix. use, e.g. "Kg" so values will show as 88Kg instead of 88 in legend. underscore ("_") are replaced by spaces, to allow a space between the value and the suffix.
hide group legends Setting to true prevents displaying of the group legends under the chart. Any non-empty value means "yes". To say "no", simply do not supply this parameter at all, or leave the value blank.

Examples

Apples: 1,000,000 Tonne (17.2%)Bananas: 2,000,000 Tonne (34.3%)Apricots: 1,440,000 Tonne (24.7%)PearsPineapples: 750,000 Tonne (12.9%)

1: 1 Units (0.2%)7: 7 Units (1.5%)8: 8 Units (1.7%)9: 9 Units (1.9%)10: 10 Units (2.1%)11: 11 Units (2.3%)12: 12 Units (2.5%)13: 13 Units (2.7%)14: 14 Units (2.9%)15: 15 Units (3.2%)16: 16 Units (3.4%)17: 17 Units (3.6%)18: 18 Units (3.8%)19: 19 Units (4.0%)20: 20 Units (4.2%)21: 21 Units (4.4%)22: 22 Units (4.6%)23: 23 Units (4.8%)24: 24 Units (5.0%)25: 25 Units (5.3%)26: 26 Units (5.5%)27: 27 Units (5.7%)28: 28 Units (5.9%)29: 29 Units (6.1%)30: 30 Units (6.3%)31: 31 Units (6.5%)

--[[
 keywords are used for languages: they are the names of the actual
 parameters of the template
]]

local keywords = {
 barChart = 'bar chart',
 pieChart = 'pie chart',
 width = 'width',
 height = 'height',
 stack = 'stack',
 colors = 'colors',
 group = 'group',
 xlegend = 'x legends',
 yticks = 'y tick marks',
 tooltip = 'tooltip',
 accumulateTooltip = 'tooltip value accumulation',
 links = 'links',
 defcolor = 'default color',
 scalePerGroup = 'scale per group',
 unitsPrefix = 'units prefix',
 unitsSuffix = 'units suffix',
 groupNames = 'group names',
 hideGroupLegends = 'hide group legends',
 slices = 'slices',
 slice = 'slice',
 radius = 'radius',
 percent = 'percent',

} -- here is what you want to translate

local defColors = mw.loadData("Module:Chart/Default colors")
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="list-style:none;column-width:12em;"},
    table.concat( list, '\n' )
   )
  )
  table.insert( tab, '</div>' )
 end
end

local 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()

 local function getArg( s, def, subst, with )
  local result = args[keywords[s]] or def or ''
  if subst and with then result = string.gsub( result, subst, with ) end
  return result
 end

 local function analyzeParams()
  local 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( 'Slice %d: "%s", first item("%s") could not be parsed as a number', i, value or '', slice ) )
   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 = 0
  for slice in string.gmatch( slicesStr or '', "%b()" ) do
   i = i + 1
   addSlice( i, string.match( slice, '^%(%s*(.-)%s*%)$' ) )
  end

  for k, v in pairs(args) do
   local ind = string.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] = string.format( '%s: %s%s%s%s', names[i], prefix, lang:formatNum( value ), suffix, addprec )
   links[i] = mw.text.trim( links[i] or string.format( '[[#noSuchAnchor|%s]]', legends[i] ) )
  end
 end

 local function addRes( ... )
  for _, v in pairs( { ... } ) do
   table.insert( res, v )
  end
 end

 local function createImageMap()
  addRes( '{{#tag:imagemap|', 'File:Circle frame.svg{{!}}' .. ( radius * 2 ) .. 'px' )
  addRes( unpack( imslices ) )
  addRes( 'desc none', '}}' )
 end

 local 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, border
  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

 local function createSlices()
  local 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


local 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, yticks, stack, delimiter = 500, 350, -1, false, args.delimiter or ':'
 local chartWidth, chartHeight, defcolor, scalePerGroup, accumulateTooltip


 local numGroups, numValues
 local scaleWidth

 local function validate()
  local function asGroups( name, tab, toDuplicate, emptyOK )
   if #tab == 0 and not emptyOK then
    error( "must supply values for " .. 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] .. ' must contain the same number of items as the number of groups, but it contains ' .. #tab .. ' items and there are ' .. numGroups .. ' groups')
   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( 'Illegal settings: %s and %s are incompatible.', keywords.stack, keywords.scalePerGroup ) )
  end
  for gi = 2, numGroups do
   if #values[gi] ~= numValues then error( keywords.group .. " " .. gi .. " does not have same number of values as " .. keywords.group .. " 1" ) end
  end
  if #xlegends ~= numValues then error( 'Illegal number of ' .. keywords.xlegend .. '. Should be exactly ' .. numValues ) end
 end

 local function extractParams()
  local function testone( keyword, key, val, tab )
   local i = keyword == key and 0 or key:match( keyword .. "%s+(%d+)" )
   if not i then return end
   i = tonumber( i ) or error("Expect numerical index for key " .. keyword .. " instead of '" .. 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( 'Illegal width value (must be a number, and at least 200): ' .. v )
    end
   elseif k == keywords.height then
    height = tonumber( v )
    if not height or height < 200 then
     error( 'Illegal height value (must be a number, and at least 200): ' .. v )
    end
   elseif k == keywords.stack then stack = true
   elseif k == keywords.yticks then yticks = tonumber(v) or -1
   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

 local 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

 local 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

 local 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 = mw.text.killMarkers(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 string.gsub(groupName .. prefix .. mw.getContentLanguage():formatNum( tonumber( val ) or 0 ) .. suffix, '_', ' '), false
 end

 local function calcHeights( gi, i, val )
  local barHeight = math.max( 2, math.floor( val / yscales[gi] * chartHeight + 0.5 ) ) -- add half to make it "round" instead of "trunc", min height to 2 to avoid negative bar sizes
  local top, base = chartHeight - barHeight, 0
  if stack then
   for j = 1, gi - 1 do
    if tonumber(values[j][i]) > 0 then
     base = base + math.max( 2, math.floor( values[j][i] / yscales[gi] * chartHeight + 0.5 ) ) -- sum the "i" value of all the groups below our group, gi, and keep the same calculation for each bar 
    end
   end
  end
  return barHeight, top - base
 end

 local function groupBounds( i )
  local setWidth = math.floor( chartWidth / numValues )
  local setOffset = ( i - 1 ) * setWidth
  return setOffset, setWidth
 end

 local 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

 local 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'. see talkpage

  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 string.format( '[[File: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


 local function drawYScale()
  local function drawSingle( gi, color, width, yticks, single )
   local yscale = yscales[gi]
   local _, top, ordermag = roundup( yscale * 0.999 )
   local numnotches = yticks >= 0 and yticks or
     (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, yticks )
    table.insert( res, '</div>' )
   end
  else
   drawSingle( 1, 'black', scaleWidth, yticks, true )
  end
 end

 local 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 + 1, setWidth - 2, setWidth - 2 ) }, xlegends[i] or '' ) )
    table.insert( res, mw.text.tag( 'div', { style = string.format( tickDivstyleFormat, setOffset + setWidth / 2 ) }, '' ) )
   end
  end
 end

 local function drawChart()
  table.insert( res, mw.text.tag( 'div', { class = 'chart noresize', style = string.format( 'padding-top:10px;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,
}

Retrieved from "https://en.wikipedia.org/w/index.php?title=Module:Chart&oldid=1227038826"

Hidden category: 
Wikipedia extended-confirmed-protected modules
 



This page was last edited on 3 June 2024, at 09:00 (UTC).

Text is available under the Creative Commons Attribution-ShareAlike License 4.0; additional terms may apply. By using this site, you agree to the Terms of Use and Privacy Policy. Wikipedia® is a registered trademark of the Wikimedia Foundation, Inc., a non-profit organization.



Privacy policy

About Wikipedia

Disclaimers

Contact Wikipedia

Code of Conduct

Developers

Statistics

Cookie statement

Mobile view



Wikimedia Foundation
Powered by MediaWiki