Module:Chart
Aller à la navigation
Aller à la recherche
Module Lua invoqué par le modèle {{Graph}}
-- Module:Chart
local p = {}
local function split(str, sep)
local result = {}
if not str or str == '' then return result end
for part in (str .. sep):gmatch("(.-)" .. sep) do
table.insert(result, mw.text.trim(part))
end
return result
end
local defaultColors = {
'#ffbf7f','#1f77b4','#2ca02c','#d62728',
'#9467bd','#8c564b','#e377c2','#ff7f0e'
}
local function getColor(colorList, index)
local c = colorList[index]
if c and c ~= '' then return mw.text.trim(c) end
return defaultColors[((index - 1) % #defaultColors) + 1]
end
function p.chart(frame)
local args = frame:getParent().args
for k, v in pairs(frame.args) do
if not args[k] or args[k] == '' then args[k] = v end
end
local chartType = mw.text.trim(args['type'] or 'line')
if chartType == 'rect' then chartType = 'bar' end
local stacked = false
if chartType == 'stackedrect' then
chartType = 'bar'
stacked = true
end
local isSymbol = (mw.text.trim(args['type'] or '') == 'symbol')
if isSymbol then chartType = 'scatter' end
local indexAxis = (mw.text.trim(args['orientation'] or '') == 'horizontal') and 'y' or 'x'
local width = tonumber(args['width']) or 400
local height = tonumber(args['height']) or 200
local legend = mw.text.trim(args['legend'] or '')
local align = mw.text.trim(args['align'] or 'center')
local chartTitle = mw.text.trim(args['title'] or '')
local xTitle = mw.text.trim(args['xAxisTitle'] or '')
local yTitle = mw.text.trim(args['yAxisTitle'] or '')
local showValues = (args['showValues'] ~= nil)
local yScaleLog = (mw.text.trim(args['yScaleType'] or '') == 'log')
local tension = (mw.text.trim(args['interpolate'] or '') == 'monotone') and 0.4 or 0
local xAxisAngle = tonumber(args['xAxisAngle'] or 0) or 0
local yAxisMax = tonumber(args['yAxisMax'] or nil)
local xLabels = split(mw.text.trim(args['x'] or ''), ',')
local colorList = split(mw.text.trim(args['colors'] or ''), ',')
--Construction des datasets
local datasets = {}
local jsDatasets = {}
--type Symbol (ou "scatter", nuage de points)
if isSymbol then
-- scatter nécessite de combiner x et y en paires {x, y}
local i = 1
while true do
local yRaw = mw.text.trim(args['y' .. i] or '')
if yRaw == '' then break end
local yVals = split(yRaw, ',')
local points = {}
for j, yv in ipairs(yVals) do
local xv = xLabels[j]
table.insert(points, {
x = tonumber(xv) or xv,
y = tonumber(yv) or 0
})
end
table.insert(jsDatasets, {
label = mw.text.trim(args['y' .. i .. 'Title'] or args['legend' .. i] or ''),
data = points,
borderColor = getColor(colorList, i),
backgroundColor = getColor(colorList, i),
pointRadius = 5,
})
i = i + 1
end
end
--autres types (line, rect, stackedrect, pie)
if not isSymbol then
local ySimple = mw.text.trim(args['y'] or '')
if ySimple ~= '' then
local nums = {}
for _, v in ipairs(split(ySimple, ',')) do
table.insert(nums, tonumber(v) or 0)
end
table.insert(datasets, {
label = mw.text.trim(args['yTitle'] or ''),
data = nums,
color = getColor(colorList, 1),
tension = tension,
})
end
local i = 1
while true do
local yRaw = mw.text.trim(args['y' .. i] or '')
if yRaw == '' then break end
local nums = {}
for _, v in ipairs(split(yRaw, ',')) do
table.insert(nums, tonumber(v) or 0)
end
table.insert(datasets, {
label = mw.text.trim(args['y' .. i .. 'Title'] or ''),
data = nums,
color = getColor(colorList, i),
tension = tension,
})
i = i + 1
end
if #datasets == 0 then
return '<span class="error">Module:Chart — paramètre y manquant</span>'
end
if chartType == 'pie' then
local bgColors = {}
for j = 1, #datasets[1].data do
table.insert(bgColors, getColor(colorList, j))
end
table.insert(jsDatasets, {
label = datasets[1].label,
data = datasets[1].data,
backgroundColor = bgColors,
})
else
for _, ds in ipairs(datasets) do
table.insert(jsDatasets, {
label = ds.label,
data = ds.data,
borderColor = ds.color,
backgroundColor = ds.color,
tension = ds.tension,
fill = false,
})
end
end
end
local scales
if chartType ~= 'pie' then
local yScale = {
type = yScaleLog and 'logarithmic' or 'linear',
title = { display = (yTitle ~= ''), text = yTitle },
}
if yAxisMax then
yScale.max = yAxisMax
end
scales = {
x = {
title = { display = (xTitle ~= ''), text = xTitle },
ticks = { maxRotation = -xAxisAngle, minRotation = -xAxisAngle },
},
y = yScale,
}
if indexAxis == 'y' then
scales.x, scales.y = scales.y, scales.x
end
end
local config = {
type = chartType,
labels = xLabels,
datasets = jsDatasets,
showLegend = (legend ~= ''),
showValues = showValues,
align = align,
indexAxis = indexAxis,
scales = scales,
chartTitle = chartTitle,
stacked = stacked,
}
local configJson = mw.text.jsonEncode(config)
local uid = 'mwchart-' .. tostring(math.random(100000, 999999))
--transforme en <chart> interprété par WikirougeHooks
return frame:extensionTag{
name = 'chart',
content = configJson,
args = {
id = uid,
width = tostring(width),
height = tostring(height),
align = align,
}
}
end
return p