<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="yi">
	<id>https://yi.hamichlol.org.il/w/index.php?action=history&amp;feed=atom&amp;title=%D7%99%D7%97%D7%99%D7%93%D7%94%3AChart</id>
	<title>יחידה:Chart - ווערסיע היסטאריע</title>
	<link rel="self" type="application/atom+xml" href="https://yi.hamichlol.org.il/w/index.php?action=history&amp;feed=atom&amp;title=%D7%99%D7%97%D7%99%D7%93%D7%94%3AChart"/>
	<link rel="alternate" type="text/html" href="https://yi.hamichlol.org.il/w/index.php?title=%D7%99%D7%97%D7%99%D7%93%D7%94:Chart&amp;action=history"/>
	<updated>2026-04-20T23:08:02Z</updated>
	<subtitle>ווערסיע היסטאריע פאר דעם בלאט אויפן וויקי</subtitle>
	<generator>MediaWiki 1.39.4</generator>
	<entry>
		<id>https://yi.hamichlol.org.il/w/index.php?title=%D7%99%D7%97%D7%99%D7%93%D7%94:Chart&amp;diff=196040&amp;oldid=prev</id>
		<title>צמא לדעת: 1 רעוויזיע אימפארטירט: אימפארטירט פון די ענגלישע וויקיפעדיע, זע ביישטייערער ליסטע</title>
		<link rel="alternate" type="text/html" href="https://yi.hamichlol.org.il/w/index.php?title=%D7%99%D7%97%D7%99%D7%93%D7%94:Chart&amp;diff=196040&amp;oldid=prev"/>
		<updated>2023-01-25T14:16:28Z</updated>

		<summary type="html">&lt;p&gt;1 רעוויזיע אימפארטירט: אימפארטירט פון די ענגלישע וויקיפעדיע, זע ביישטייערער ליסטע&lt;/p&gt;
&lt;table style=&quot;background-color: #fff; color: #202122;&quot; data-mw=&quot;interface&quot;&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;tr class=&quot;diff-title&quot; lang=&quot;yi&quot;&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;→ עלטערע  ווערסיע&lt;/td&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;רעוויזיע פון 14:16, 25 יאנואר 2023&lt;/td&gt;
				&lt;/tr&gt;
&lt;!-- diff cache key hamichlol_main_yi-mw_:diff::1.12:old-196039:rev-196040 --&gt;
&lt;/table&gt;</summary>
		<author><name>צמא לדעת</name></author>
	</entry>
	<entry>
		<id>https://yi.hamichlol.org.il/w/index.php?title=%D7%99%D7%97%D7%99%D7%93%D7%94:Chart&amp;diff=196039&amp;oldid=prev</id>
		<title>en&gt;Andrybak: replace deprecated &quot;Image:&quot; with &quot;File:&quot;</title>
		<link rel="alternate" type="text/html" href="https://yi.hamichlol.org.il/w/index.php?title=%D7%99%D7%97%D7%99%D7%93%D7%94:Chart&amp;diff=196039&amp;oldid=prev"/>
		<updated>2022-09-29T01:55:44Z</updated>

		<summary type="html">&lt;p&gt;replace deprecated &lt;a href=&quot;/w/index.php?title=%D7%94%D7%99%D7%9C%D7%A3:Files&amp;amp;action=edit&amp;amp;redlink=1&quot; class=&quot;new&quot; title=&quot;הילף:Files (בלאַט עקזיסטירט נאכנישט)&quot;&gt;&amp;quot;Image:&amp;quot; with &amp;quot;File:&amp;quot;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;נייער בלאַט&lt;/b&gt;&lt;/p&gt;&lt;div&gt;--[[&lt;br /&gt;
	keywords are used for languages: they are the names of the actual&lt;br /&gt;
	parameters of the template&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
local keywords = {&lt;br /&gt;
	barChart = 'bar chart',&lt;br /&gt;
	pieChart = 'pie chart',&lt;br /&gt;
	width = 'width',&lt;br /&gt;
	height = 'height',&lt;br /&gt;
	stack = 'stack',&lt;br /&gt;
	colors = 'colors',&lt;br /&gt;
	group = 'group',&lt;br /&gt;
	xlegend = 'x legends',&lt;br /&gt;
	yticks = 'y tick marks',&lt;br /&gt;
	tooltip = 'tooltip',&lt;br /&gt;
	accumulateTooltip = 'tooltip value accumulation',&lt;br /&gt;
	links = 'links',&lt;br /&gt;
	defcolor = 'default color',&lt;br /&gt;
	scalePerGroup = 'scale per group',&lt;br /&gt;
	unitsPrefix = 'units prefix',&lt;br /&gt;
	unitsSuffix = 'units suffix',&lt;br /&gt;
	groupNames = 'group names',&lt;br /&gt;
	hideGroupLegends = 'hide group legends',&lt;br /&gt;
	slices = 'slices',&lt;br /&gt;
	slice = 'slice',&lt;br /&gt;
	radius = 'radius',&lt;br /&gt;
	percent = 'percent',&lt;br /&gt;
&lt;br /&gt;
} -- here is what you want to translate&lt;br /&gt;
&lt;br /&gt;
local defColors = mw.loadData(&amp;quot;Module:Chart/Default colors&amp;quot;)&lt;br /&gt;
local hideGroupLegends&lt;br /&gt;
&lt;br /&gt;
local function nulOrWhitespace( s )&lt;br /&gt;
	return not s or mw.text.trim( s ) == ''&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function createGroupList( tab, legends, cols )&lt;br /&gt;
	if #legends &amp;gt; 1 and not hideGroupLegends then&lt;br /&gt;
		table.insert( tab, mw.text.tag( 'div' ) )&lt;br /&gt;
		local list = {}&lt;br /&gt;
		local spanStyle = &amp;quot;padding:0 1em;background-color:%s;border:1px solid %s;margin-right:1em;-webkit-print-color-adjust:exact;&amp;quot;&lt;br /&gt;
		for gi = 1, #legends do&lt;br /&gt;
			local span = mw.text.tag( 'span', { style = string.format( spanStyle, cols[gi], cols[gi] ) }, '&amp;amp;nbsp;' ) .. ' '..  legends[gi]&lt;br /&gt;
			table.insert( list, mw.text.tag( 'li', {}, span ) )&lt;br /&gt;
		end&lt;br /&gt;
		table.insert( tab,&lt;br /&gt;
			mw.text.tag( 'ul',&lt;br /&gt;
				{style=&amp;quot;width:100%;list-style:none;column-width:12em;&amp;quot;},&lt;br /&gt;
				table.concat( list, '\n' )&lt;br /&gt;
			)&lt;br /&gt;
		)&lt;br /&gt;
		table.insert( tab, '&amp;lt;/div&amp;gt;' )&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function pieChart( frame )&lt;br /&gt;
	local res, imslices, args = {}, {}, frame.args&lt;br /&gt;
	local radius&lt;br /&gt;
	local values, colors, names, legends, links = {}, {}, {}, {}, {}&lt;br /&gt;
	local delimiter = args.delimiter or ':'&lt;br /&gt;
	local lang = mw.getContentLanguage()&lt;br /&gt;
&lt;br /&gt;
	local function getArg( s, def, subst, with )&lt;br /&gt;
		local result = args[keywords[s]] or def or ''&lt;br /&gt;
		if subst and with then result = string.gsub( result, subst, with ) end&lt;br /&gt;
		return result&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local function analyzeParams()&lt;br /&gt;
		local function addSlice( i, slice )&lt;br /&gt;
			local value, name, color, link = unpack( mw.text.split( slice, '%s*' .. delimiter .. '%s*' ) )&lt;br /&gt;
			values[i] = tonumber( lang:parseFormattedNumber( value ) )&lt;br /&gt;
				or error( string.format( 'Slice %d: &amp;quot;%s&amp;quot;, first item(&amp;quot;%s&amp;quot;) could not be parsed as a number', i, value or '', slice ) )&lt;br /&gt;
			colors[i] = not nulOrWhitespace( color ) and color or defColors[i * 2]&lt;br /&gt;
			names[i] = name or ''&lt;br /&gt;
			links[i] = link&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		radius = getArg( 'radius', 150 )&lt;br /&gt;
		hideGroupLegends = not nulOrWhitespace( args[keywords.hideGroupLegends] )&lt;br /&gt;
		local slicesStr = getArg( 'slices' )&lt;br /&gt;
		local prefix = getArg( 'unitsPrefix', '', '_', ' ' )&lt;br /&gt;
		local suffix = getArg( 'unitsSuffix', '', '_', ' ' )&lt;br /&gt;
		local percent = args[keywords.percent]&lt;br /&gt;
		local sum = 0&lt;br /&gt;
		local i = 0&lt;br /&gt;
		for slice in string.gmatch( slicesStr or '', &amp;quot;%b()&amp;quot; ) do&lt;br /&gt;
			i = i + 1&lt;br /&gt;
			addSlice( i, string.match( slice, '^%(%s*(.-)%s*%)$' ) )&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		for k, v in pairs(args) do&lt;br /&gt;
			local ind = string.match( k, '^' .. keywords.slice .. '%s+(%d+)$' )&lt;br /&gt;
			if ind then addSlice( tonumber( ind ), v ) end&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		for _, val in ipairs( values ) do sum = sum + val end&lt;br /&gt;
		for i, value in ipairs( values ) do&lt;br /&gt;
			local addprec = percent and string.format( ' (%0.1f%%)', value / sum * 100 ) or ''&lt;br /&gt;
			legends[i] = string.format( '%s: %s%s%s%s', names[i], prefix, lang:formatNum( value ), suffix, addprec )&lt;br /&gt;
			links[i] = mw.text.trim( links[i] or string.format( '[[#noSuchAnchor|%s]]', legends[i] ) )&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local function addRes( ... )&lt;br /&gt;
		for _, v in pairs( { ... } ) do&lt;br /&gt;
			table.insert( res, v )&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local function createImageMap()&lt;br /&gt;
		addRes( '{{#tag:imagemap|', 'File:Circle frame.svg{{!}}' .. ( radius * 2 ) .. 'px' )&lt;br /&gt;
		addRes( unpack( imslices ) )&lt;br /&gt;
		addRes( 'desc none', '}}' )&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local function drawSlice( i, q, start )&lt;br /&gt;
		local color = colors[i]&lt;br /&gt;
		local angle = start * 2 * math.pi&lt;br /&gt;
		local sin, cos = math.abs( math.sin( angle ) ), math.abs( math.cos( angle ) )&lt;br /&gt;
		local wsin, wcos = sin * radius, cos * radius&lt;br /&gt;
		local s1, s2, w1, w2, w3, w4, border&lt;br /&gt;
		if q == 1 then&lt;br /&gt;
			border = 'left'&lt;br /&gt;
			w1, w2, w3, w4 = 0, 0, wsin, wcos&lt;br /&gt;
			s1, s2 = 'bottom', 'left'&lt;br /&gt;
		elseif q == 2 then&lt;br /&gt;
			border = 'bottom'&lt;br /&gt;
			w1, w2, w3, w4 = 0, wcos, wsin, 0&lt;br /&gt;
			s1, s2 = 'bottom', 'right'&lt;br /&gt;
		elseif q == 3 then&lt;br /&gt;
			border = 'right'&lt;br /&gt;
			w1, w2, w3, w4 = wsin, wcos, 0, 0&lt;br /&gt;
			s1, s2 = 'top', 'right'&lt;br /&gt;
		else&lt;br /&gt;
			border = 'top'&lt;br /&gt;
			w1, w2, w3, w4 = wsin, 0, 0, wcos&lt;br /&gt;
			s1, s2 = 'top', 'left'&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		local style = string.format( 'border:solid transparent;position:absolute;%s:%spx;%s:%spx;width:%spx;height:%spx', s1, radius, s2, radius, radius, radius )&lt;br /&gt;
		if start &amp;lt;= ( q - 1 ) * 0.25 then&lt;br /&gt;
			style = string.format( '%s;border:0;background-color:%s', style, color )&lt;br /&gt;
		else&lt;br /&gt;
			style = string.format( '%s;border-width:%spx %spx %spx %spx;border-%s-color:%s', style, w1, w2, w3, w4, border, color )&lt;br /&gt;
		end&lt;br /&gt;
		addRes( mw.text.tag( 'div', { style = style }, '' ) )&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local function createSlices()&lt;br /&gt;
		local function coordsOfAngle( angle )&lt;br /&gt;
			return ( 100 + math.floor( 100 * math.cos( angle ) ) ) .. ' ' .. ( 100 - math.floor( 100 * math.sin( angle ) ) )&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		local sum, start = 0, 0&lt;br /&gt;
		for _, value in ipairs( values ) do sum = sum + value end&lt;br /&gt;
		for i, value in ipairs(values) do&lt;br /&gt;
			local poly = { 'poly 100 100' }&lt;br /&gt;
			local startC, endC =  start / sum, ( start + value ) / sum&lt;br /&gt;
			local startQ, endQ = math.floor( startC * 4 + 1 ), math.floor( endC * 4 + 1 )&lt;br /&gt;
			for q = startQ, math.min( endQ, 4 ) do drawSlice( i, q, startC ) end&lt;br /&gt;
			for angle = startC * 2 * math.pi, endC * 2 * math.pi, 0.02 do&lt;br /&gt;
				table.insert( poly,  coordsOfAngle( angle ) )&lt;br /&gt;
			end&lt;br /&gt;
			table.insert( poly, coordsOfAngle( endC * 2 * math.pi ) .. ' 100 100 ' .. links[i] )&lt;br /&gt;
			table.insert( imslices, table.concat( poly, ' ' ) )&lt;br /&gt;
			start = start + values[i]&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	analyzeParams()&lt;br /&gt;
	if #values == 0 then error( &amp;quot;no slices found - can't draw pie chart&amp;quot; ) end&lt;br /&gt;
	addRes( mw.text.tag( 'div', { class = 'chart noresize', style = string.format( 'margin-top:0.5em;max-width:%spx;', radius * 2 ) } ) )&lt;br /&gt;
	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 ) } ) )&lt;br /&gt;
	createSlices()&lt;br /&gt;
	addRes( mw.text.tag( 'div', { style = string.format( 'position:absolute;min-width:%spx;min-height:%spx;overflow:hidden;', radius * 2, radius * 2 ) } ) )&lt;br /&gt;
	createImageMap()&lt;br /&gt;
	addRes( '&amp;lt;/div&amp;gt;' ) -- close &amp;quot;position:relative&amp;quot; div that contains slices and imagemap.&lt;br /&gt;
	addRes( '&amp;lt;/div&amp;gt;' ) -- close &amp;quot;position:relative&amp;quot; div that contains slices and imagemap.&lt;br /&gt;
	createGroupList( res, legends, colors ) -- legends&lt;br /&gt;
	addRes( '&amp;lt;/div&amp;gt;' ) -- close containing div&lt;br /&gt;
	return frame:preprocess( table.concat( res, '\n' ) )&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
local function barChart( frame )&lt;br /&gt;
	local res = {}&lt;br /&gt;
	local args = frame.args -- can be changed to frame:getParent().args&lt;br /&gt;
	local values, xlegends, colors, tooltips, yscales = {}, {}, {}, {}, {}&lt;br /&gt;
	local groupNames, unitsSuffix, unitsPrefix, links = {}, {}, {}, {}&lt;br /&gt;
	local width, height, yticks, stack, delimiter = 500, 350, -1, false, args.delimiter or ':'&lt;br /&gt;
	local chartWidth, chartHeight, defcolor, scalePerGroup, accumulateTooltip&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
	local numGroups, numValues&lt;br /&gt;
	local scaleWidth&lt;br /&gt;
&lt;br /&gt;
	local function validate()&lt;br /&gt;
		local function asGroups( name, tab, toDuplicate, emptyOK )&lt;br /&gt;
			if #tab == 0 and not emptyOK then&lt;br /&gt;
				error( &amp;quot;must supply values for &amp;quot; .. keywords[name] )&lt;br /&gt;
			end&lt;br /&gt;
			if #tab == 1 and toDuplicate then&lt;br /&gt;
				for i = 2, numGroups do tab[i] = tab[1] end&lt;br /&gt;
			end&lt;br /&gt;
			if #tab &amp;gt; 0 and #tab ~= numGroups then&lt;br /&gt;
				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')&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		-- do all sorts of validation here, so we can assume all params are good from now on.&lt;br /&gt;
		-- among other things, replace numerical values with mw.language:parseFormattedNumber() result&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
		chartHeight = height - 80&lt;br /&gt;
		numGroups = #values&lt;br /&gt;
		numValues = #values[1]&lt;br /&gt;
		defcolor = defcolor or 'blue'&lt;br /&gt;
		colors[1] = colors[1] or defcolor&lt;br /&gt;
		scaleWidth = scalePerGroup and 80 * numGroups or 100&lt;br /&gt;
		chartWidth = width - scaleWidth&lt;br /&gt;
		asGroups( 'unitsPrefix', unitsPrefix, true, true )&lt;br /&gt;
		asGroups( 'unitsSuffix', unitsSuffix, true, true )&lt;br /&gt;
		asGroups( 'colors', colors, true, true )&lt;br /&gt;
		asGroups( 'groupNames', groupNames, false, false )&lt;br /&gt;
		if stack and scalePerGroup then&lt;br /&gt;
			error( string.format( 'Illegal settings: %s and %s are incompatible.', keywords.stack, keywords.scalePerGroup ) )&lt;br /&gt;
		end&lt;br /&gt;
		for gi = 2, numGroups do&lt;br /&gt;
			if #values[gi] ~= numValues then error( keywords.group .. &amp;quot; &amp;quot; .. gi .. &amp;quot; does not have same number of values as &amp;quot; .. keywords.group .. &amp;quot; 1&amp;quot; ) end&lt;br /&gt;
		end&lt;br /&gt;
		if #xlegends ~= numValues then error( 'Illegal number of ' .. keywords.xlegend .. '. Should be exactly ' .. numValues ) end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local function extractParams()&lt;br /&gt;
		local function testone( keyword, key, val, tab )&lt;br /&gt;
			local i = keyword == key and 0 or key:match( keyword .. &amp;quot;%s+(%d+)&amp;quot; )&lt;br /&gt;
			if not i then return end&lt;br /&gt;
			i = tonumber( i ) or error(&amp;quot;Expect numerical index for key &amp;quot; .. keyword .. &amp;quot; instead of '&amp;quot; .. key .. &amp;quot;'&amp;quot;)&lt;br /&gt;
			if i &amp;gt; 0 then tab[i] = {} end&lt;br /&gt;
			for s in mw.text.gsplit( val, '%s*' .. delimiter .. '%s*' ) do&lt;br /&gt;
				table.insert( i == 0 and tab or tab[i], s )&lt;br /&gt;
			end&lt;br /&gt;
			return true&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		for k, v in pairs( args ) do&lt;br /&gt;
			if k == keywords.width then&lt;br /&gt;
				width = tonumber( v )&lt;br /&gt;
				if not width or width &amp;lt; 200 then&lt;br /&gt;
					error( 'Illegal width value (must be a number, and at least 200): ' .. v )&lt;br /&gt;
				end&lt;br /&gt;
			elseif k == keywords.height then&lt;br /&gt;
				height = tonumber( v )&lt;br /&gt;
				if not height or height &amp;lt; 200 then&lt;br /&gt;
					error( 'Illegal height value (must be a number, and at least 200): ' .. v )&lt;br /&gt;
				end&lt;br /&gt;
			elseif k == keywords.stack then stack = true&lt;br /&gt;
			elseif k == keywords.yticks then yticks = tonumber(v) or -1&lt;br /&gt;
			elseif k == keywords.scalePerGroup then scalePerGroup = true&lt;br /&gt;
			elseif k == keywords.defcolor then defcolor = v&lt;br /&gt;
			elseif k == keywords.accumulateTooltip then accumulateTooltip = not nulOrWhitespace( v )&lt;br /&gt;
			elseif k == keywords.hideGroupLegends then hideGroupLegends = not nulOrWhitespace( v )&lt;br /&gt;
			else&lt;br /&gt;
				for keyword, tab in pairs( {&lt;br /&gt;
					group = values,&lt;br /&gt;
					xlegend = xlegends,&lt;br /&gt;
					colors = colors,&lt;br /&gt;
					tooltip = tooltips,&lt;br /&gt;
					unitsPrefix = unitsPrefix,&lt;br /&gt;
					unitsSuffix = unitsSuffix,&lt;br /&gt;
					groupNames = groupNames,&lt;br /&gt;
					links = links,&lt;br /&gt;
					} ) do&lt;br /&gt;
						if testone( keywords[keyword], k, v, tab )&lt;br /&gt;
							then break&lt;br /&gt;
						end&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	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.&lt;br /&gt;
		local ordermag = 10 ^ math.floor( math.log10( x ) )&lt;br /&gt;
		local normalized = x /  ordermag&lt;br /&gt;
		local top = normalized &amp;gt;= 1.5 and ( math.floor( normalized + 1 ) ) or 1.5&lt;br /&gt;
		return ordermag * top, top, ordermag&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local function calcHeightLimits() -- if limits were passed by user, use them, otherwise calculate. for &amp;quot;stack&amp;quot; there's only one limet.&lt;br /&gt;
		if stack then&lt;br /&gt;
			local sums = {}&lt;br /&gt;
			for _, group in pairs( values ) do&lt;br /&gt;
				for i, val in ipairs( group ) do sums[i] = ( sums[i] or 0 ) + val end&lt;br /&gt;
			end&lt;br /&gt;
			local sum = math.max( unpack( sums ) )&lt;br /&gt;
			for i = 1, #values do yscales[i] = sum end&lt;br /&gt;
		else&lt;br /&gt;
			for i, group in ipairs( values ) do yscales[i] = math.max( unpack( group ) ) end&lt;br /&gt;
		end&lt;br /&gt;
		for i, scale in ipairs( yscales ) do yscales[i] = roundup( scale * 0.9999 ) end&lt;br /&gt;
		if not scalePerGroup then for i = 1, #values do yscales[i] = math.max( unpack( yscales ) ) end end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local function tooltip( gi, i, val )&lt;br /&gt;
		if tooltips and tooltips[gi] and not nulOrWhitespace( tooltips[gi][i] ) then return tooltips[gi][i], true end&lt;br /&gt;
		local groupName = mw.text.killMarkers(not nulOrWhitespace( groupNames[gi] ) and groupNames[gi] .. ': ' or '')&lt;br /&gt;
		local prefix = unitsPrefix[gi] or unitsPrefix[1] or ''&lt;br /&gt;
		local suffix = unitsSuffix[gi] or unitsSuffix[1] or ''&lt;br /&gt;
		return string.gsub(groupName .. prefix .. mw.getContentLanguage():formatNum( tonumber( val ) or 0 ) .. suffix, '_', ' '), false&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local function calcHeights( gi, i, val )&lt;br /&gt;
		local barHeight = math.floor( val / yscales[gi] * chartHeight + 0.5 ) -- add half to make it &amp;quot;round&amp;quot; instead of &amp;quot;trunc&amp;quot;&lt;br /&gt;
		local top, base = chartHeight - barHeight, 0&lt;br /&gt;
		if stack then&lt;br /&gt;
			local rawbase = 0&lt;br /&gt;
			for j = 1, gi - 1 do rawbase = rawbase + values[j][i] end -- sum the &amp;quot;i&amp;quot; value of all the groups below our group, gi.&lt;br /&gt;
			base = math.floor( chartHeight * rawbase / yscales[gi] ) -- normally, and especially if it's &amp;quot;stack&amp;quot;, all the yscales must be equal.&lt;br /&gt;
		end&lt;br /&gt;
		if barHeight &amp;lt; 2 then&lt;br /&gt;
			barHeight = 2 -- Otherwise the template would try to create a bar with a negative height&lt;br /&gt;
		end &lt;br /&gt;
		return barHeight, top - base&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local function groupBounds( i )&lt;br /&gt;
		local setWidth = math.floor( chartWidth / numValues )&lt;br /&gt;
		local setOffset = ( i - 1 ) * setWidth&lt;br /&gt;
		return setOffset, setWidth&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local function calcx( gi, i )&lt;br /&gt;
		local setOffset, setWidth = groupBounds( i )&lt;br /&gt;
		if stack or numGroups == 1 then&lt;br /&gt;
			local barWidth = math.min( 38, math.floor( 0.8 * setWidth ) )&lt;br /&gt;
			return setOffset + (setWidth - barWidth) / 2, barWidth&lt;br /&gt;
		end&lt;br /&gt;
		setWidth = 0.85 * setWidth&lt;br /&gt;
		local barWidth = math.floor( 0.75 * setWidth / numGroups )&lt;br /&gt;
		local left = setOffset + math.floor( ( gi - 1 ) / numGroups * setWidth )&lt;br /&gt;
		return left, barWidth&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local function drawbar( gi, i, val, ttval )&lt;br /&gt;
		if val == '0' then return end -- do not show single line (borders....) if value is 0, or rather, '0'. see talkpage&lt;br /&gt;
&lt;br /&gt;
		local color, tooltip, custom = colors[gi] or defcolor or 'blue', tooltip( gi, i, ttval or val )&lt;br /&gt;
		local left, barWidth = calcx( gi, i )&lt;br /&gt;
		local barHeight, top = calcHeights( gi, i, val )&lt;br /&gt;
&lt;br /&gt;
		-- borders so it shows up when printing&lt;br /&gt;
		local style = string.format(&amp;quot;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;&amp;quot;,&lt;br /&gt;
						left, top, barHeight-1, barWidth-2, barWidth-2, color, color)&lt;br /&gt;
		local link = links[gi] and links[gi][i] or ''&lt;br /&gt;
		local img = not nulOrWhitespace( link ) and string.format( '[[File:Transparent.png|1000px|link=%s|%s]]', link, custom and tooltip or '' ) or ''&lt;br /&gt;
		table.insert( res, mw.text.tag( 'div', { style = style, title = tooltip, }, img ) )&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
	local function drawYScale()&lt;br /&gt;
		local function drawSingle( gi, color, width, yticks, single )&lt;br /&gt;
			local yscale = yscales[gi]&lt;br /&gt;
			local _, top, ordermag = roundup( yscale * 0.999 )&lt;br /&gt;
			local numnotches = yticks &amp;gt;= 0 and yticks or&lt;br /&gt;
					(top &amp;lt;= 1.5 and top * 4&lt;br /&gt;
					or top &amp;lt; 4  and top * 2&lt;br /&gt;
					or top)&lt;br /&gt;
			local valStyleStr =&lt;br /&gt;
				single and 'position:absolute;height=20px;text-align:right;vertical-align:middle;width:%spx;top:%spx;padding:0 2px'&lt;br /&gt;
				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'&lt;br /&gt;
			local notchStyleStr = 'position:absolute;height=1px;min-width:5px;top:%spx;left:%spx;border:1px solid %s;'&lt;br /&gt;
			for i = 1, numnotches do&lt;br /&gt;
				local val = i / numnotches * yscale&lt;br /&gt;
				local y = chartHeight - calcHeights( gi, 1, val )&lt;br /&gt;
				local div = mw.text.tag( 'div', { style = string.format( valStyleStr, width - 10, y - 10, color ) }, mw.getContentLanguage():formatNum( tonumber( val ) or 0 ) )&lt;br /&gt;
				table.insert( res, div )&lt;br /&gt;
				div = mw.text.tag( 'div', { style = string.format( notchStyleStr, y, width - 4, color ) }, '' )&lt;br /&gt;
				table.insert( res, div )&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		if scalePerGroup then&lt;br /&gt;
			local colWidth = 80&lt;br /&gt;
			local colStyle = &amp;quot;position:absolute;height:%spx;min-width:%spx;left:%spx;border-right:1px solid %s;color:%s&amp;quot;&lt;br /&gt;
			for gi = 1, numGroups do&lt;br /&gt;
				local left = ( gi - 1 ) * colWidth&lt;br /&gt;
				local color = colors[gi] or defcolor&lt;br /&gt;
				table.insert( res, mw.text.tag( 'div', { style = string.format( colStyle, chartHeight, colWidth, left, color, color ) } ) )&lt;br /&gt;
				drawSingle( gi, color, colWidth, yticks )&lt;br /&gt;
				table.insert( res, '&amp;lt;/div&amp;gt;' )&lt;br /&gt;
			end&lt;br /&gt;
		else&lt;br /&gt;
			drawSingle( 1, 'black', scaleWidth, yticks, true )&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local function drawXlegends()&lt;br /&gt;
		local setOffset, setWidth&lt;br /&gt;
		local legendDivStyleFormat = &amp;quot;position:absolute;left:%spx;top:10px;min-width:%spx;max-width:%spx;text-align:center;vertical-align:top;&amp;quot;&lt;br /&gt;
		local tickDivstyleFormat = &amp;quot;position:absolute;left:%spx;height:10px;width:1px;border-left:1px solid black;&amp;quot;&lt;br /&gt;
		for i = 1, numValues do&lt;br /&gt;
			if not nulOrWhitespace( xlegends[i] ) then&lt;br /&gt;
				setOffset, setWidth = groupBounds( i )&lt;br /&gt;
				-- setWidth = 0.85 * setWidth&lt;br /&gt;
				table.insert( res, mw.text.tag( 'div', { style = string.format( legendDivStyleFormat, setOffset + 5, setWidth - 10, setWidth - 10 ) }, xlegends[i] or '' ) )&lt;br /&gt;
				table.insert( res, mw.text.tag( 'div', { style = string.format( tickDivstyleFormat, setOffset + setWidth / 2 ) }, '' ) )&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local function drawChart()&lt;br /&gt;
		table.insert( res, mw.text.tag( 'div', { class = 'chart noresize', style = string.format( 'margin-top:1em;max-width:%spx;', width ) } ) )&lt;br /&gt;
		table.insert( res, mw.text.tag( 'div', { style = string.format(&amp;quot;position:relative;min-height:%spx;min-width:%spx;max-width:%spx;&amp;quot;, height, width, width ) } ) )&lt;br /&gt;
&lt;br /&gt;
		table.insert( res, mw.text.tag( 'div', { style = string.format(&amp;quot;float:right;position:relative;min-height:%spx;min-width:%spx;max-width:%spx;border-left:1px black solid;border-bottom:1px black solid;&amp;quot;, chartHeight, chartWidth, chartWidth ) } ) )&lt;br /&gt;
		local acum = stack and accumulateTooltip and {}&lt;br /&gt;
		for gi, group in pairs( values ) do&lt;br /&gt;
			for i, val in ipairs( group ) do&lt;br /&gt;
				if acum then acum[i] = ( acum[i] or 0 ) + val end&lt;br /&gt;
				drawbar( gi, i, val, acum and acum[i] )&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		table.insert( res, '&amp;lt;/div&amp;gt;' )&lt;br /&gt;
		table.insert( res, mw.text.tag( 'div', { style = string.format(&amp;quot;position:absolute;height:%spx;min-width:%spx;max-width:%spx;&amp;quot;, chartHeight, scaleWidth, scaleWidth, scaleWidth ) } ) )&lt;br /&gt;
		drawYScale()&lt;br /&gt;
		table.insert( res, '&amp;lt;/div&amp;gt;' )&lt;br /&gt;
		table.insert( res, mw.text.tag( 'div', { style = string.format( &amp;quot;position:absolute;top:%spx;left:%spx;width:%spx;&amp;quot;, chartHeight, scaleWidth, chartWidth ) } ) )&lt;br /&gt;
		drawXlegends()&lt;br /&gt;
		table.insert( res, '&amp;lt;/div&amp;gt;' )&lt;br /&gt;
		table.insert( res, '&amp;lt;/div&amp;gt;' )&lt;br /&gt;
		createGroupList( res, groupNames, colors )&lt;br /&gt;
		table.insert( res, '&amp;lt;/div&amp;gt;' )&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	extractParams()&lt;br /&gt;
	validate()&lt;br /&gt;
	calcHeightLimits()&lt;br /&gt;
	drawChart()&lt;br /&gt;
	return table.concat( res, &amp;quot;\n&amp;quot; )&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
return {&lt;br /&gt;
	['bar-chart'] = barChart,&lt;br /&gt;
	[keywords.barChart] = barChart,&lt;br /&gt;
	[keywords.pieChart] = pieChart,&lt;br /&gt;
}&lt;/div&gt;</summary>
		<author><name>en&gt;Andrybak</name></author>
	</entry>
</feed>