Module:Graph: Difference between revisions

Content deleted Content added
updated to latest version from w:de:Module:Graph
latest version: formattable text marks also extended to bar charts
Line 1:
-- version 2016-01-0609 _PLEASE UPDATE when modifying anything_
local p = {}
 
Line 28:
 
local function isTable(t) return type(t) == "table" end
 
local function copy(x)
if type(x) == "table" then
local result = {}
for key, value in pairs(x) do result[key] = copy(value) end
return result
else
return x
end
end
 
function p.map(frame)
Line 409 ⟶ 419:
}
}
 
if radiusScale then
chartvis.properties.enter.outerRadius.scale = radiusScale.name
Line 522 ⟶ 533:
end
 
local function getTextMarks(chartvis, chartType, outerRadius, scales, radiusScale, yType, showValues)
local textmarksproperties
if chartType == "pierect" then
textmarksproperties =
{
x = { scale = chartvis.properties.enter.x.scale, field = chartvis.properties.enter.x.field },
y = { scale = chartvis.properties.enter.y.scale, field = chartvis.properties.enter.y.field, offset = -(tonumber(showValues.offset) or -4) },
--dx = { scale = chartvis.properties.enter.x.scale, band = true, mult = 0.5 }, -- for horizontal text
dy = { scale = chartvis.properties.enter.x.scale, band = true, mult = 0.5 }, -- for vertical text
align = { },
baseline = { value = "middle" },
fill = { },
angle = { value = -90 },
fontSize = { value = tonumber(showValues.fontsize) or 11 }
}
if properties.y.offset >= 0 then
properties.align.value = "right"
properties.fill.value = showValues.fontcolor or "white"
else
properties.align.value = "left"
properties.fill.value = showValues.fontcolor or "black"
end
elseif chartType == "pie" then
properties =
{
x = { group = "width", mult = 0.5 },
y = { group = "height", mult = 0.5 },
radius = { offset = tonumber(showValues.offset) or -4 },
theta = { field = "layout_mid" },
fill = { value = showValues.fontcolor or "black" },
baseline = { },
angle = { },
fontSize = { value = tonumber(showValues.fontsize) or math.ceil(outerRadius / 10) }
}
if (showValues.angle or "midangle") == "midangle" then
properties.align = { value = "center" }
properties.angle = { field = "layout_mid", mult = 180.0 / math.pi }
 
if properties.radius.offset >= 0 then
properties.baseline.value = "bottom"
else
if not showValues.fontcolor then properties.fill.value = "white" end
properties.baseline.value = "top"
end
elseif tonumber(showValues.angle) then
-- qunatize scale for aligning text left on right half-circle and right on left half-circle
local alignScale = { name = "align", type = "quantize", domainMin = 0.0, domainMax = math.pi * 2, range = { "left", "right" } }
table.insert(scales, alignScale)
 
properties.align = { scale = alignScale.name, field = "layout_mid" }
properties.angle = { value = tonumber(showValues.angle) }
properties.baseline.value = "middle"
if not tonumber(showValues.offset) then properties.radius.offset = 4 end
end
 
if radiusScale then
properties.radius.scale = radiusScale.name
properties.radius.field = radiusScale.___domain.field
else
properties.radius.value = outerRadius
end
end
 
if properties then
if showValues.format then
local template = "datum.y"
if yType == "integer" or yType == "number" then template = template .. "|number:'" .. showValues.format .. "'"
elseif yType == "date" then template = template .. "|time:" .. showValues.format .. "'"
end
properties.text = { template = "{{" .. template .. "}}" }
else
properties.text = { field = "y" }
end
 
local textmarks =
{
type = "text",
from = { data = "chart", transform = { { field = "y", type = "pie" } } },
properties =
{
enter = properties
{
x = { group = "width", mult = 0.5 },
y = { group = "height", mult = 0.5 },
radius = { offset = -4 },
theta = { field = "layout_mid" },
fill = { value = "white" },
align = { value = "center" },
baseline = { value = "top" },
text = { field = "y" },
angle = { field = "layout_mid", mult = 180.0 / math.pi },
fontSize = { value = math.ceil(outerRadius / 10) }
}
}
}
if chartvis.from then textmarks.from = copy(chartvis.from) end
if radiusScale then
 
textmarks.properties.enter.radius.scale = radiusScale.name
return textmarks
textmarks.properties.enter.radius.field = radiusScale.___domain.field
else
textmarks.properties.enter.radius.value = outerRadius
end
end
return textmarks
end
 
local function getAxes(xTitle, xFormatxAxisFormat, xType, yTitle, yFormatyAxisFormat, yType, chartType)
local xAxis, yAxis
if chartType ~= "pie" then
if xType == "integer" and not xFormatxAxisFormat then xFormatxAxisFormat = "d" end
xAxis =
{
Line 565 ⟶ 630:
scale = "x",
title = xTitle,
format = xFormatxAxisFormat
}
 
if yType == "integer" and not yFormatyAxisFormat then yFormatyAxisFormat = "d" end
yAxis =
{
Line 574 ⟶ 639:
scale = "y",
title = yTitle,
format = yFormatyAxisFormat
}
end
Line 619 ⟶ 684:
local yMax = frame.args.yAxisMax
-- override x and y axis label formatting
local xFormatxAxisFormat = frame.args.xAxisFormat
local yFormatyAxisFormat = frame.args.yAxisFormat
-- show legend with given title
local legendTitle = frame.args.legend
Line 688 ⟶ 753:
local yscale = getYScale(chartType, stacked, yMin, yMax, yType)
table.insert(scales, yscale)
 
 
local colorScale = getColorScale(colors, chartType, #x, #y)
Line 711 ⟶ 775:
-- text marks
local textmarks
if showValues then textmarks = getTextMarks(chartType, outerRadius, radiusScale) end
if type(showValues) == "string" then -- deserialize as table
local keyValues = mw.text.split(showValues, "%s*,%s*")
showValues = {}
for _, kv in ipairs(keyValues) do
local key, value = mw.ustring.match(kv, "^%s*(.-)%s*:%s*(.-)%s*$")
if key then showValues[key] = value end
end
end
 
local chartmarks = chartvis
if chartmarks.marks then chartmarks = chartmarks.marks[1] end
textmarks = getTextMarks(chartmarks, chartType, outerRadius, scales, radiusScale, yType, showValues)
if chartmarks ~= chartvis then
table.insert(chartvis.marks, textmarks)
textmarks = nil
end
end
 
-- axes
local xAxis, yAxis = getAxes(xTitle, xFormatxAxisFormat, xType, yTitle, yFormatyAxisFormat, yType, chartType)
 
-- legend