Jump to content

Module:Chart/sandbox

From Wikipedia, the free encyclopedia
--[[ keywords are used for languages: they are the names of the actual parameters of the template]]localkeywords={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 translatelocaldefColors=mw.loadData("Module:Chart/Default colors")localhideGroupLegendslocalfunctionnulOrWhitespace(s)returnnotsormw.text.trim(s)==''endlocalfunctioncreateGroupList(tab,legends,cols)if#legends>1andnothideGroupLegendsthentable.insert(tab,mw.text.tag('div'))locallist={}localspanStyle="padding:0 1em;background-color:%s;border:1px solid %s;margin-right:1em;-webkit-print-color-adjust:exact;"forgi=1,#legendsdolocalspan=mw.text.tag('span',{style=string.format(spanStyle,cols[gi],cols[gi])},'&nbsp;')..' '..legends[gi]table.insert(list,mw.text.tag('li',{},span))endtable.insert(tab,mw.text.tag('ul',{style="width:100%;list-style:none;column-width:12em;"},table.concat(list,'\n')))table.insert(tab,'</div>')endendlocalfunctionpieChart(frame)localres,imslices,args={},{},frame.argslocalradiuslocalvalues,colors,names,legends,links={},{},{},{},{}localdelimiter=args.delimiteror':'locallang=mw.getContentLanguage()localfunctiongetArg(s,def,subst,with)localresult=args[keywords[s]]ordefor''ifsubstandwiththenresult=string.gsub(result,subst,with)endreturnresultendlocalfunctionanalyzeParams()localfunctionaddSlice(i,slice)localvalue,name,color,link=unpack(mw.text.split(slice,'%s*'..delimiter..'%s*'))values[i]=tonumber(lang:parseFormattedNumber(value))orerror(string.format('Slice %d: "%s", first item("%s") could not be parsed as a number',i,valueor'',slice))colors[i]=notnulOrWhitespace(color)andcolorordefColors[i*2]names[i]=nameor''links[i]=linkendradius=getArg('radius',150)hideGroupLegends=notnulOrWhitespace(args[keywords.hideGroupLegends])localslicesStr=getArg('slices')localprefix=getArg('unitsPrefix','','_',' ')localsuffix=getArg('unitsSuffix','','_',' ')localpercent=args[keywords.percent]localsum=0locali=0forsliceinstring.gmatch(slicesStror'',"%b()")doi=i+1addSlice(i,string.match(slice,'^%(%s*(.-)%s*%)$'))endfork,vinpairs(args)dolocalind=string.match(k,'^'..keywords.slice..'%s+(%d+)$')ifindthenaddSlice(tonumber(ind),v)endendfor_,valinipairs(values)dosum=sum+valendfori,valueinipairs(values)dolocaladdprec=percentandstring.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]orstring.format('[[#noSuchAnchor|%s]]',legends[i]))endendlocalfunctionaddRes(...)for_,vinpairs({...})dotable.insert(res,v)endendlocalfunctioncreateImageMap()addRes('{{#tag:imagemap|','Image:Circle frame.svg{{!}}'..(radius*2)..'px')addRes(unpack(imslices))addRes('desc none','}}')endlocalfunctiondrawSlice(i,q,start)localcolor=colors[i]localangle=start*2*math.pilocalsin,cos=math.abs(math.sin(angle)),math.abs(math.cos(angle))localwsin,wcos=sin*radius,cos*radiuslocals1,s2,w1,w2,w3,w4,borderifq==1thenborder='left'w1,w2,w3,w4=0,0,wsin,wcoss1,s2='bottom','left'elseifq==2thenborder='bottom'w1,w2,w3,w4=0,wcos,wsin,0s1,s2='bottom','right'elseifq==3thenborder='right'w1,w2,w3,w4=wsin,wcos,0,0s1,s2='top','right'elseborder='top'w1,w2,w3,w4=wsin,0,0,wcoss1,s2='top','left'endlocalstyle=string.format('border:solid transparent;position:absolute;%s:%spx;%s:%spx;width:%spx;height:%spx',s1,radius,s2,radius,radius,radius)ifstart<=(q-1)*0.25thenstyle=string.format('%s;border:0;background-color:%s',style,color)elsestyle=string.format('%s;border-width:%spx %spx %spx %spx;border-%s-color:%s',style,w1,w2,w3,w4,border,color)endaddRes(mw.text.tag('div',{style=style},''))endlocalfunctioncreateSlices()localfunctioncoordsOfAngle(angle)return(100+math.floor(100*math.cos(angle)))..' '..(100-math.floor(100*math.sin(angle)))endlocalsum,start=0,0for_,valueinipairs(values)dosum=sum+valueendfori,valueinipairs(values)dolocalpoly={'poly 100 100'}localstartC,endC=start/sum,(start+value)/sumlocalstartQ,endQ=math.floor(startC*4+1),math.floor(endC*4+1)forq=startQ,math.min(endQ,4)dodrawSlice(i,q,startC)endforangle=startC*2*math.pi,endC*2*math.pi,0.02dotable.insert(poly,coordsOfAngle(angle))endtable.insert(poly,coordsOfAngle(endC*2*math.pi)..' 100 100 '..links[i])table.insert(imslices,table.concat(poly,' '))start=start+values[i]endendanalyzeParams()if#values==0thenerror("no slices found - can't draw pie chart")endaddRes(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)-- legendsaddRes('</div>')-- close containing divreturnframe:preprocess(table.concat(res,'\n'))endlocalfunctionbarChart(frame)localres={}localargs=frame.args-- can be changed to frame:getParent().argslocalvalues,xlegends,colors,tooltips,yscales={},{},{},{},{}localgroupNames,unitsSuffix,unitsPrefix,links={},{},{},{}localwidth,height,yticks,stack,delimiter=500,350,-1,false,args.delimiteror':'localchartWidth,chartHeight,defcolor,scalePerGroup,accumulateTooltiplocalnumGroups,numValueslocalscaleWidthlocalfunctionvalidate()localfunctionasGroups(name,tab,toDuplicate,emptyOK)if#tab==0andnotemptyOKthenerror("must supply values for "..keywords[name])endif#tab==1andtoDuplicatethenfori=2,numGroupsdotab[i]=tab[1]endendif#tab>0and#tab~=numGroupsthenerror(keywords[name]..' must contain the same number of items as the number of groups, but it contains '..#tab..' items and there are '..numGroups..' groups')endend-- 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() resultchartHeight=height-80numGroups=#valuesnumValues=#values[1]defcolor=defcoloror'blue'colors[1]=colors[1]ordefcolorscaleWidth=scalePerGroupand80*numGroupsor100chartWidth=width-scaleWidthasGroups('unitsPrefix',unitsPrefix,true,true)asGroups('unitsSuffix',unitsSuffix,true,true)asGroups('colors',colors,true,true)asGroups('groupNames',groupNames,false,false)ifstackandscalePerGroupthenerror(string.format('Illegal settings: %s and %s are incompatible.',keywords.stack,keywords.scalePerGroup))endforgi=2,numGroupsdoif#values[gi]~=numValuesthenerror(keywords.group.." "..gi.." does not have same number of values as "..keywords.group.." 1")endendif#xlegends~=numValuesthenerror('Illegal number of '..keywords.xlegend..'. Should be exactly '..numValues)endendlocalfunctionextractParams()localfunctiontestone(keyword,key,val,tab)locali=keyword==keyand0orkey:match(keyword.."%s+(%d+)")ifnotithenreturnendi=tonumber(i)orerror("Expect numerical index for key "..keyword.." instead of '"..key.."'")ifi>0thentab[i]={}endforsinmw.text.gsplit(val,'%s*'..delimiter..'%s*')dotable.insert(i==0andtabortab[i],s)endreturntrueendfork,vinpairs(args)doifk==keywords.widththenwidth=tonumber(v)ifnotwidthorwidth<200thenerror('Illegal width value (must be a number, and at least 200): '..v)endelseifk==keywords.heightthenheight=tonumber(v)ifnotheightorheight<200thenerror('Illegal height value (must be a number, and at least 200): '..v)endelseifk==keywords.stackthenstack=trueelseifk==keywords.yticksthenyticks=tonumber(v)or-1elseifk==keywords.scalePerGroupthenscalePerGroup=trueelseifk==keywords.defcolorthendefcolor=velseifk==keywords.accumulateTooltipthenaccumulateTooltip=notnulOrWhitespace(v)elseifk==keywords.hideGroupLegendsthenhideGroupLegends=notnulOrWhitespace(v)elseforkeyword,tabinpairs({group=values,xlegend=xlegends,colors=colors,tooltip=tooltips,unitsPrefix=unitsPrefix,unitsSuffix=unitsSuffix,groupNames=groupNames,links=links,})doiftestone(keywords[keyword],k,v,tab)thenbreakendendendendendlocalfunctionroundup(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.localordermag=10^math.floor(math.log10(x))localnormalized=x/ordermaglocaltop=normalized>=1.5and(math.floor(normalized+1))or1.5returnordermag*top,top,ordermagendlocalfunctioncalcHeightLimits()-- if limits were passed by user, use them, otherwise calculate. for "stack" there's only one limet.ifstackthenlocalsums={}for_,groupinpairs(values)dofori,valinipairs(group)dosums[i]=(sums[i]or0)+valendendlocalsum=math.max(unpack(sums))fori=1,#valuesdoyscales[i]=sumendelsefori,groupinipairs(values)doyscales[i]=math.max(unpack(group))endendfori,scaleinipairs(yscales)doyscales[i]=roundup(scale*0.9999)endifnotscalePerGroupthenfori=1,#valuesdoyscales[i]=math.max(unpack(yscales))endendendlocalfunctiontooltip(gi,i,val)iftooltipsandtooltips[gi]andnotnulOrWhitespace(tooltips[gi][i])thenreturntooltips[gi][i],trueendlocalgroupName=mw.text.killMarkers(notnulOrWhitespace(groupNames[gi])andgroupNames[gi]..': 'or'')localprefix=unitsPrefix[gi]orunitsPrefix[1]or''localsuffix=unitsSuffix[gi]orunitsSuffix[1]or''returnstring.gsub(groupName..prefix..mw.getContentLanguage():formatNum(tonumber(val)or0)..suffix,'_',' '),falseendlocalfunctioncalcHeights(gi,i,val)localbarHeight=math.floor(val/yscales[gi]*chartHeight+0.5)-- add half to make it "round" instead of "trunc"localtop,base=chartHeight-barHeight,0ifstackthenlocalrawbase=0forj=1,gi-1dorawbase=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.endifbarHeight<2thenbarHeight=2-- Otherwise the template would try to create a bar with a negative heightendreturnbarHeight,top-baseendlocalfunctiongroupBounds(i)localsetWidth=math.floor(chartWidth/numValues)localsetOffset=(i-1)*setWidthreturnsetOffset,setWidthendlocalfunctioncalcx(gi,i)localsetOffset,setWidth=groupBounds(i)ifstackornumGroups==1thenlocalbarWidth=math.min(38,math.floor(0.8*setWidth))returnsetOffset+(setWidth-barWidth)/2,barWidthendsetWidth=0.85*setWidthlocalbarWidth=math.floor(0.75*setWidth/numGroups)localleft=setOffset+math.floor((gi-1)/numGroups*setWidth)returnleft,barWidthendlocalfunctiondrawbar(gi,i,val,ttval)ifval=='0'thenreturnend-- do not show single line (borders....) if value is 0, or rather, '0'. see talkpagelocalcolor,tooltip,custom=colors[gi]ordefcoloror'blue',tooltip(gi,i,ttvalorval)localleft,barWidth=calcx(gi,i)localbarHeight,top=calcHeights(gi,i,val)-- borders so it shows up when printinglocalstyle=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)locallink=links[gi]andlinks[gi][i]or''localimg=notnulOrWhitespace(link)andstring.format('[[File:Transparent.png|1000px|link=%s|%s]]',link,customandtooltipor'')or''table.insert(res,mw.text.tag('div',{style=style,title=tooltip,},img))endlocalfunctiondrawYScale()localfunctiondrawSingle(gi,color,width,yticks,single)localyscale=yscales[gi]local_,top,ordermag=roundup(yscale*0.999)localnumnotches=yticks>=0andyticksor(top<=1.5andtop*4ortop<4andtop*2ortop)localvalStyleStr=singleand'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'localnotchStyleStr='position:absolute;height=1px;min-width:5px;top:%spx;left:%spx;border:1px solid %s;'fori=1,numnotchesdolocalval=i/numnotches*yscalelocaly=chartHeight-calcHeights(gi,1,val)localdiv=mw.text.tag('div',{style=string.format(valStyleStr,width-10,y-10,color)},mw.getContentLanguage():formatNum(tonumber(val)or0))table.insert(res,div)div=mw.text.tag('div',{style=string.format(notchStyleStr,y,width-4,color)},'')table.insert(res,div)endendifscalePerGroupthenlocalcolWidth=80localcolStyle="position:absolute;height:%spx;min-width:%spx;left:%spx;border-right:1px solid %s;color:%s"forgi=1,numGroupsdolocalleft=(gi-1)*colWidthlocalcolor=colors[gi]ordefcolortable.insert(res,mw.text.tag('div',{style=string.format(colStyle,chartHeight,colWidth,left,color,color)}))drawSingle(gi,color,colWidth,yticks)table.insert(res,'</div>')endelsedrawSingle(1,'black',scaleWidth,yticks,true)endendlocalfunctiondrawXlegends()localsetOffset,setWidthlocallegendDivStyleFormat="position:absolute;left:%spx;top:10px;min-width:%spx;max-width:%spx;text-align:center;vertical-align:top;"localtickDivstyleFormat="position:absolute;left:%spx;height:10px;width:1px;border-left:1px solid black;"fori=1,numValuesdoifnotnulOrWhitespace(xlegends[i])thensetOffset,setWidth=groupBounds(i)-- setWidth = 0.85 * setWidthtable.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)},''))endendendlocalfunctiondrawChart()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)}))localacum=stackandaccumulateTooltipand{}forgi,groupinpairs(values)dofori,valinipairs(group)doifacumthenacum[i]=(acum[i]or0)+valenddrawbar(gi,i,val,acumandacum[i])endendtable.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>')endextractParams()validate()calcHeightLimits()drawChart()returntable.concat(res,"\n")endreturn{['bar-chart']=barChart,[keywords.barChart]=barChart,[keywords.pieChart]=pieChart,}
close