Module:Sandbox/Bawolff/graph
Jump to navigation
Jump to search
| File:Ambox warning blue construction.svg | This module is rated as pre-alpha. It is incomplete and may or may not be in active development. Do not use it in article namespace pages. A module remains in pre-alpha until its developer, or another editor who adopts it if it is abandoned for some time, considers the basic structure complete. |
This is a module to make graphs. The goal is for it to be a wikitext only version of {{Graph:Lines}}, but it still has quite a bit to go.
Usage
[edit source]Example:
{{#invoke:Sandbox/Bawolff/graph|draw|data=GDP per capita indexed at 1950 - Maddison Project Data (2018) (OWID 2807).tab}}
makes
Lua error at line 40: attempt to index field 'data' (a nil value).
-- Very experimental. Meant to be a wikitext only replacement for {{Graph:lines}}
local p = {}
local canvas = require( 'Module:Sandbox/Bawolff/canvas' )
local function convertToPixelHoriz( value, minValue, maxValue, minPixel, maxPixel )
return ((value-minValue)/(maxValue-minValue))*(maxPixel-minPixel)+minPixel
end
-- Have to reverse, because 0 is top corner not bottom
local function convertToPixelVert( value, minValue, maxValue, minPixel, maxPixel )
return maxPixel - ((value-minValue)/(maxValue-minValue))*(maxPixel-minPixel) - minPixel
end
local function writeVertical( ctx, text, x, y )
-- TODO this doesn't seem right, maybe module:canvas has a bug.
ctx:save()
local height = ctx:getContextAttributes()['height']
ctx:translate( 0, height )
ctx:rotate( -math.pi/2 )
ctx.textBaseline = 'top'
ctx:fillText( text, y, x )
ctx:restore()
end
function p.draw( frame )
assert( frame.args.tabletype or 'tab' == 'tab', "tabletype not supported" )
local width = frame.args.width or 350
local height = frame.args.height or 250
local ctx = canvas.getContext('2d', { width = width, height = height } )
local vertGutter = frame.args.vertGutter or 40
local horizGutter = frame.args.horizGutter or 25
ctx:moveTo( vertGutter, 0 )
ctx:lineTo( vertGutter, height-horizGutter )
ctx:lineTo( width, height-horizGutter )
-- Main example i am testing with: GDP per capita indexed at 1950 - Maddison Project Data (2018) (OWID 2807).tab
local data = mw.ext.data.get( frame.args.data )
assert( data ~= nil )
-- For now, hardcoded first is which line segment, second is year, third is GDP.
local maxYear = -1000000
local minYear = 1000000000
local maxGDP = -10000000000000
for i, v in ipairs( data.data ) do
if ( v[2] > maxYear ) then
maxYear = math.ceil(v[2])
end
if ( v[2] < minYear ) then
minYear = math.floor(v[2])
end
if ( v[3] > maxGDP ) then
maxGDP = math.ceil(v[3])
end
end
ctx.fillStyle = 'var(--color-base,#202122)'
ctx.font = '10px sans-serif'
ctx.textAlign = 'end'
ctx.textBaseline = 'bottom'
ctx:fillText( '0', vertGutter - 3, height-horizGutter )
ctx.textBaseline = 'top'
ctx:fillText( maxGDP, vertGutter -3, 0 )
ctx.textAlign = 'start'
ctx.textBaseline = 'bottom'
ctx.font = 'bold 12px sans-serif'
writeVertical( ctx, frame.args.yAxis or data.schema.fields[3].title, 0, (height - horizGutter)/2 -15 )
--ctx:fillText( "GDP (nominal)", 0, (height - horizGutter)/2 )
ctx.font = '10px sans-serif'
ctx.textBaseline = 'top'
ctx:fillText( minYear, vertGutter, height - horizGutter + 3 )
ctx.textAlign = 'end'
ctx:fillText( maxYear, width, height - horizGutter + 3 )
ctx.textBaseline = 'bottom'
ctx.font = 'bold 12px sans-serif'
ctx:fillText( frame.args.xAxis or data.schema.fields[2].title, (width-vertGutter)/2+vertGutter+10, height )
-- Because this is hacky, assuming they are ordered by entity, year
local color = { 'red', 'blue', 'orange', 'green', 'purple', "teal" }
local curColor = 0
local curEntity = nil
for i, v in ipairs( data.data ) do
local xPt = convertToPixelHoriz( v[2], minYear, maxYear, vertGutter, width )
local yPt = convertToPixelVert( v[3], 0, maxGDP, horizGutter, height )
if v[1] ~= curEntity then
curEntity = v[1]
curColor = (curColor + 1) % ( #color+1 )
ctx:stroke()
ctx:beginPath()
ctx.strokeStyle = ctx:createWikitextPattern{
background = color[curColor],
class = "calculator-field calculator-hideifzero",
attr = { ["data-calculator-type"] = "passthru", ["data-calculator-formula"] = mw.uri.anchorEncode(curEntity) }
}
ctx:moveTo( xPt, yPt )
else
ctx:lineTo( xPt, yPt )
end
end
ctx:stroke()
return tostring(ctx) .. frame:preprocess('<templatestyles src="Template:Calculator-hideifzero/styles.css"/>')
end
return p