Module:Parliament diagram
Documentation for this module may be created at Module:Parliament diagram/doc
require('strict') local p = {} local getArgs = require('Module:Arguments').getArgs local errorCategory = '[[Category:Compilation error of the Parliamentary diagram template]]' local getColor = require('Module:Political party').fetch local dimx = 175 local dimr = 50 local dimc = 40 local limite = 2000 local bgcolor = "#fff" -- Error handler using xpcall, format the error local function errhandler(msg) local cat = mw.title.getCurrentTitle().namespace == 0 and errorCategory or '' return string.format('<span class="error">%s</span>%s', msg, cat) end -- create a single array from string local function agg(a,...) local args = {...} for _, s in ipairs(args) do table.insert(a, s) end end -- get the party color from Module:Party color -- a = party; b = optional color local function color(a,b) local c = '#CCC' if (b) then c = b else c = getColor({a, "color"}) end if string.sub(c,1,5) == '#' then c = "#" .. string.sub(c, 6, 11) end return c end -- create circles local function values(n) local totals= {4, 17, 36, 65, 100, 144, 196, 255, 322, 398, 480, 571, 670, 776, 891, 1013, 1143, 1281, 1427, 1580, 1743, 1911, 2089} local dots = 0 local benches = 1 local jj,rr,aa -- searches for the amount of benches needed to show all the dots while (n > totals[benches]) do benches = benches + 1 end local dd = dimr/benches -- distance between the arches dimc = 0.7*dimr/benches -- size of the circles local list = {} -- list of dots -- calculate angle and radius of each dot for rg=0,benches-2 do rr = dimx - dd*(2*rg+1) -- radius jj = math.floor((n/totals[benches])*math.pi/(2*math.asin(dd/rr)))+1 --n° dots if (jj==1) then dots = dots + 1 list[dots] = {0.5, rr} else for ps=0,jj-1 do aa = ps/(jj-1) dots = dots + 1 list[dots] = {aa,rr} end end end -- dots left to place on an internal arch jj=n-dots rr= dimx - dd*(2*benches-1) -- radius if (jj==1) then dots = dots + 1 list[dots] = {1/2, rr} else for ps=0,jj-1 do aa=ps/(jj-1) dots = dots + 1 list[dots] = {aa,rr} end end -- order dots per increasing angle from the center table.sort(list, function(a,b) return ((a[1]<b[1]) or (a[1]==b[1] and a[2]<b[2])) end) return list end -- create the parliamentary arch function p._parliament(args) local ss = {} local ss2 = {} local data = {} local num = 1 local totalDots = 0 local cap = args.caption or '' local show = tonumber(args.show) or 0 while (args['n'..num]) do if (tonumber(args['n'..num])) then data[num] = { n = args['n'..num] and tonumber(args['n'..num]), c = color(args['p'..num] or '', args['c'..num]), b = args['b'..num] or '-', p = args['p'..num] or 'Serie '..num } totalDots = totalDots + data[num].n num = num+1 else error(string.format('Invalid value for n%d', num),2) end end num = num - 1 if (totalDots>limite) then error('Number of dots superior to the limit') elseif (totalDots<1) then error('No dots are indicated') end local dots = values(totalDots) local width = 2*dimx local height = dimx+dimc local scale = 1.0 if (args['background']) then bgcolor = args['background'] end if (args['width'] and tonumber(args['width'])) then width = tonumber(args['width']) scale = width/(2*dimx) height = (dimx+dimc)*scale elseif (args['height'] and tonumber(args['height'])) then height = tonumber(args['height']) scale = height/(dimx+dimc) width = 2*dimx*scale elseif (totalDots<29) then width = 280 scale = width/(2*dimx) height = (dimx+dimc)*scale elseif (totalDots<101) then width = 300 scale = width/(2*dimx) height = (dimx+dimc)*scale elseif (totalDots<281) then width = 350 scale = width/(2*dimx) height = (dimx+dimc)*scale end -- TEMPORARY FIX WHILE THE GRAPH EXTENSION IS DISABLED -- local seats_diagram = require('Module:Seats_diagram') args.width = width if true then return tostring(seats_diagram._parliament(args)) end --------------------------------------------------------- local graph = { version = 2, width = width, height = height, padding = "no", background = bgcolor, data = { }, scales = { { name = "x", type = "linear", range = "width", zero = true, domainMin = 0, domainMax = 2*dimx }, { name = "y", type = "linear", range = "height", zero = true, domainMin = 0, domainMax = dimx + dimc } }, marks = { } } local ee = 0 local values for i=1,num do values = {} for j=1,data[i].n do ee = ee + 1 values[j] = { px = dimx-dots[ee][2]*math.cos(math.pi*dots[ee][1]), py = dimc+dots[ee][2]*math.sin(math.pi*dots[ee][1]), } end graph['data'][i] = { name = "tab"..i, values = values } graph['marks'][i] = { type = "symbol", from = {data = "tab"..i }, properties = { enter = { x = {scale = "x",field = "px"}, y = {scale = "y",field = "py"}, fill = {value = data[i].c}, size = {value = (2*dimc*scale)^2} } } } if (data[i].b ~= "-") then local bl = data[i].b if string.sub(bl,1,5) == '#' then bl = "#" .. string.sub(bl, 6, 11) end graph['marks'][i]['properties']['enter']['stroke'] = {value = bl} graph['marks'][i]['properties']['enter']['strokeWidth'] = {value = 1} end end graph['marks'][num+1] = { type = "text", properties = { enter = { x = {scale = "x",value=dimx}, y = {scale = "y",value=dimc+8}, align = {value = "center"}, fill = {value = "#000"}, font = {value = "Helvetica"}, fontSize = { value = 36*scale }, fontWeight = { value = "bold" }, text = {value = totalDots } } } } agg(ss, mw.getCurrentFrame():extensionTag('graph', mw.text.jsonEncode(graph))) if (cap ~= '') then agg(ss,string.format('<p style="font-size:90%%; margin-left:10px">%s</p>',cap)) end if show == 1 then for i=1,num do agg(ss2,string.format('<span style="display:inline-block;border:solid grey 1px;background:%s;width:1em;height:1em"> </span> %s', data[i].c, data[i].n)) end agg(ss,'<p style="font-size:90%; margin-left:10px">') agg(ss,table.concat(ss2," · ")) agg(ss,'</p>') elseif show ==2 then for i=1,num do agg(ss2,string.format('<span style="display:inline-block;border:solid grey 1px;background:%s;width:1em;height:1em"> </span> %s %s', data[i].c, data[i].p, data[i].n)) end agg(ss,'<p style="font-size:90%; margin-left:10px">') agg(ss,table.concat(ss2,"<br/>")) agg(ss,'</p>') end if args['debug'] then return mw.text.jsonEncode(graph) else return table.concat(ss) end end function p.parliament(frame) return select(2, xpcall(function() return p._parliament(getArgs(frame, { parentOnly = true })) end, errhandler)) end return p