if yType == "number" or yType == "integer" then
h_annoLine = numericArray(h_annoLineString)  
else
h_annoLine = stringArray(h_annoLineString)  
end
h_annoLabel = stringArray(h_annoLabelString)
end  
-- pie chart radiuses
local innerRadius = tonumber(.args.innerRadius) or tonumber(.args.innerradius) or 0
local outerRadius = math.min(graphwidth, graphheight)
-- format JSON output
local formatJson = .args.formatjson  
-- get x values
local x
x, xType, xMin, xMax = deserializeXData(.args.x, xType, xMin, xMax)  
-- get y values (series)
local yValues = {}
local seriesTitles = {}
for name, value in pairs(.args) do
local yNum
if name == "y" then yNum = 1 else yNum = tonumber(string.match(name, "^y(%d+)$")) end
if yNum then
yValues[yNum] = value
-- name the series: default is "y<number>". Can be overwritten using the "y<number>Title" parameters.
seriesTitles[yNum] = .args["y" .. yNum .. "Title"] or .args["y" .. yNum .. "title"] or name
end
end
local y
y, yType, yMin, yMax = deserializeYData(yValues, yType, yMin, yMax)  
-- create data tuples, consisting of series index, x value, y value
local data
if chartType == "pie" then
-- for pie charts the second second series is merged into the first series as radius values
data = convertXYToSingleSeries(x, y, xType, yType, { "y", "r" })
else
data = convertXYToManySeries(x, y, xType, yType, seriesTitles)
end  
-- configure stacked charts
local stacked = false
local stats
if string.sub(chartType, 1, 7) == "stacked" then
chartType = string.sub(chartType, 8)
if #y > 1 then -- ignore stacked charts if there is only one series
stacked = true
-- aggregate data by cumulative y values
stats =
{
name = "stats", source = "chart", transform =
{
{
type = "aggregate",
groupby = { "x" },
summarize = { y = "sum" }
}
}
}
end
end  
-- add annotations to data
local vannoData, hannoData  
if v_annoLine then
vannoData = { name = "v_anno", format = { type = "json", parse = { x = xType } }, values = {} }
for i = 1, #v_annoLine do
local item = { x = v_annoLine[i], label = v_annoLabel[i] }
table.insert(vannoData.values, item)
end
end
if h_annoLine then
hannoData = { name = "h_anno", format = { type = "json", parse = { y = yType } }, values = {} }
for i = 1, #h_annoLine do
local item = { y = h_annoLine[i], label = h_annoLabel[i] }
table.insert(hannoData.values, item)
end
end  
-- create scales
local scales = {}  
local xscale = getXScale(chartType, stacked, xMin, xMax, xType, xScaleType)
table.insert(scales, xscale)
local yscale = getYScale(chartType, stacked, yMin, yMax, yType, yScaleType)
table.insert(scales, yscale)  
local colorScale = getColorScale(colors, chartType, #x, #y)
table.insert(scales, colorScale)  
local alphaScale = getAlphaColorScale(colors, y)
table.insert(scales, alphaScale)  
local lineScale
if (linewidths) and (chartType == "line") then
lineScale = getLineScale(linewidths, chartType)
table.insert(scales, lineScale)
end  
local radiusScale
if chartType == "pie" and #y > 1 then
radiusScale = getValueScale("r", 0, outerRadius)
table.insert(scales, radiusScale)
end  
-- decide if lines (strokes) or areas (fills) should be drawn
local colorField
if chartType == "line" then colorField = "stroke" else colorField = "fill" end  
-- create chart markings
local chartvis = getChartVisualisation(chartType, stacked, colorField, #y, innerRadius, outerRadius, linewidth, alphaScale, radiusScale, lineScale, interpolate)
local marks = { chartvis }  
-- text marks
if showValues then
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
local textmarks = getTextMarks(chartmarks, chartType, outerRadius, scales, radiusScale, yType, showValues)
if chartmarks ~= chartvis then
table.insert(chartvis.marks, textmarks)
else
table.insert(marks, textmarks)
end
end  
-- grids
if xGrid then
if xGrid == "0" then xGrid = false
elseif xGrid == 0 then xGrid = false
elseif xGrid == "false" then xGrid = false
elseif xGrid == "n" then xGrid = false
else xGrid = true
end
end
if yGrid then
if yGrid == "0" then yGrid = false
elseif yGrid == 0 then yGrid = false
elseif yGrid == "false" then yGrid = false
elseif yGrid == "n" then yGrid = false
else yGrid = true
end
end  
-- symbol marks
if showSymbols and chartType ~= "rect" then
local chartmarks = chartvis
if chartmarks.marks then chartmarks = chartmarks.marks[1] end  
if type(showSymbols) == "string" then
if showSymbols == "" then showSymbols = true
else showSymbols = numericArray(showSymbols)
end
else
showSymbols = tonumber(showSymbols)
end  
-- custom size
local symSize
if type(showSymbols) == "number" then
symSize = tonumber(showSymbols*showSymbols*8.5)
elseif type(showSymbols) == "table" then
symSize = {}
for k, v in pairs(showSymbols) do
symSize[k]=v*v*8.5 -- "size" acc to Vega syntax is area of symbol
end
else
symSize = 50
end
-- symSizeScale
local symSizeScale = {}
if type(symSize) == "table" then
symSizeScale = getSymSizeScale(symSize)
table.insert(scales, symSizeScale)
end  
-- custom shape
if stringArray(symbolsShape) and #stringArray(symbolsShape) > 1 then symbolsShape = stringArray(symbolsShape) end  
local symShape = " "  
if type(symbolsShape) == "string" and shapes[symbolsShape] then
symShape = shapes[symbolsShape]
elseif type(symbolsShape) == "table" then
symShape = {}
for k, v in pairs(symbolsShape) do
if symbolsShape[k] and shapes[symbolsShape[k]] then
symShape[k]=shapes[symbolsShape[k]]
else
symShape[k] = "circle"
end
end
else
symShape = "circle"
end
-- symShapeScale
local symShapeScale = {}
if type(symShape) == "table" then
symShapeScale = getSymShapeScale(symShape)
table.insert(scales, symShapeScale)
end  
-- custom stroke
local symStroke
if (type(symbolsStroke) == "number") then
symStroke = tonumber(symbolsStroke)
-- TODO symStroke serialization
-- elseif type(symbolsStroke) == "table" then
-- symStroke = {}
-- for k, v in pairs(symbolsStroke) do
-- symStroke[k]=symbolsStroke[k]
-- --always draw x with stroke
-- if symbolsShape[k] == "x" then symStroke[k] = 2.5 end
--always draw x with stroke
-- if symbolsNoFill[k] then symStroke[k] = 2.5 end
-- end
else
symStroke = 0
--always draw x with stroke
if symbolsShape == "x" then symStroke = 2.5 end
--always draw x with stroke
if symbolsNoFill then symStroke = 2.5 end
end  
-- TODO -- symStrokeScale
-- local symStrokeScale = {}
-- if type(symStroke) == "table" then
-- symStrokeScale = getSymStrokeScale(symStroke)
-- table.insert(scales, symStrokeScale)
-- end  
local symbolmarks = getSymbolMarks(chartmarks, symSize, symShape, symStroke, symbolsNoFill, alphaScale)
if chartmarks ~= chartvis then
table.insert(chartvis.marks, symbolmarks)
else
table.insert(marks, symbolmarks)
end
end  
local vannolines, vannolabels, hannolines, hannolabels = getAnnoMarks(chartmarks, persistentGrey, persistentGrey, 0.75)
if vannoData then
table.insert(marks, vannolines)
table.insert(marks, vannolabels)
end
if hannoData then
table.insert(marks, hannolines)
table.insert(marks, hannolabels)
end  
-- axes
local xAxis, yAxis = getAxes(xTitle, xAxisFormat, xAxisAngle, xType, xGrid, yTitle, yAxisFormat, yType, yGrid, chartType)  
-- legend
local legend
if legendTitle and tonumber(legendTitle) ~= 0 then legend = getLegend(legendTitle, chartType, outerRadius) end
-- construct final output object
local output =
{
version = 2,
width = graphwidth,
height = graphheight,
data = { data },
scales = scales,
axes = { xAxis, yAxis },
marks = marks,
legends = { legend }
}
if vannoData then table.insert(output.data, vannoData) end
if hannoData then table.insert(output.data, hannoData) end
if stats then table.insert(output.data, stats) end  
local flags
if formatJson then flags = mw.text.JSON_PRETTY end
return mw.text.jsonEncode(output, flags)
end  
function p.mapWrapper