Module:Chart absolute to relative
Lua
CodeDiscussionEditHistoryLinksLink count Subpages:DocumentationTestsResultsSandboxLive code All modules
This module provides utility functions for transforming tabular data sets in chart renderings.
See mw:Extension:Chart/Transforms for more documentation on this transform feature of the Charts system.
See similar module: Module:ChartPercentage
UsageUsage
convert_to_percentage: convert the data to percentages, relative to a base value column
To use as a chart transform:
"transform": {
"module": "Chart absolute to relative",
"function": "convert_to_percentage",
"args": {
"sum_column": "2",
"units": "percent",
"decimals": "2"
}
},
Arguments:
sum_column: column number of the sum value of the row (lua arrays are 1-based arrays)units: percentdecimals: rounding
ExampleExample
- Chart: Data:Germany federal elections/Seat distribution in the Bundestag.chart
- Data: Data:Germany federal elections/Seat distribution in the Bundestag.tab
Code
local p = {}
local function toNumber(x)
if x == nil then return nil end
if type(x) == "number" then return x end
if type(x) ~= "string" then return nil end
local s = x:gsub("%s+", ""):gsub(",", "")
return tonumber(s)
end
local function roundTo(n, decimals)
if n == nil then return nil end
decimals = tonumber(decimals)
if not decimals or decimals < 0 then return n end
local m = 10 ^ decimals
return math.floor(n * m + 0.5) / m
end
local function unitsIsPercent(u)
return u == "percent" or u == "%" or u == "percentage"
end
function p.convert_to_percentage(tab, args)
args = args or {}
if type(tab) ~= "table" or not unitsIsPercent(args.units) then
return tab
end
local N = tonumber(args.sum_column) or tonumber(args.sumcol) or tonumber(args.sum) or 2
local decimals = args.decimals
-- Tabular Data rows
local rows = tab.data
if type(rows) ~= "table" then
rows = tab -- fallback for raw matrix
end
-- Determine column count robustly (prefer schema)
local colCount
if type(tab.schema) == "table" and type(tab.schema.fields) == "table" then
colCount = #tab.schema.fields
else
-- fallback: use first row length (best-effort)
colCount = (type(rows[1]) == "table") and #rows[1] or 0
end
local outData = {}
for r = 1, #rows do
local row = rows[r]
if type(row) == "table" then
local newRow = {}
newRow[1] = row[1] -- year
local sum = toNumber(row[N])
local newCol = 2
for c = 2, colCount do
if c ~= N then
local v = toNumber(row[c])
if v ~= nil and sum ~= nil and sum ~= 0 then
newRow[newCol] = roundTo((v / sum) * 100, decimals)
else
newRow[newCol] = nil
end
newCol = newCol + 1
end
end
outData[#outData + 1] = newRow
else
outData[#outData + 1] = row
end
end
-- Copy original object and replace data
local result = {}
for k, v in pairs(tab) do
result[k] = v
end
result.data = outData
-- Adjust schema.fields (remove column N)
if type(tab.schema) == "table" and type(tab.schema.fields) == "table" then
local oldFields = tab.schema.fields
local newFields = {}
for i = 1, #oldFields do
if i ~= N then
newFields[#newFields + 1] = oldFields[i]
end
end
local newSchema = {}
for k, v in pairs(tab.schema) do
newSchema[k] = v
end
newSchema.fields = newFields
result.schema = newSchema
end
return result
end
return p