Edge Rewrite
// HTMLRewriter · presentation

This page was redesigned at the edge.

Cloudflare fetched the original article and streamed it through HTMLRewriter to apply an entirely new visual system without rebuilding the source page.

Jump to content

Module:WikidataChart

From Wikipedia, the free encyclopedia

local defaultFormat = {
	[0] = "Y",				-- precision: billion years
	[1] = "Y",				-- precision: hundred million years
	[2] = "Y",				-- precision: ten million years
	[3] = "Y",				-- precision: million years
	[4] = "Y",				-- precision: hundred thousand years
	[5] = "Y",				-- precision: ten thousand years
	[6] = "Y",				-- precision: millennium
	[7] = "Y",				-- precision: century
	[8] = "Y",				-- precision: decade
	[9]  = "Y",				-- precision: year
	[10] = "M Y",			-- precision: month
	[11] = "j F Y",			-- precision: day
	[12] = "j F Y ga",		-- precision: hour
	[13] = "j F Y g:ia",	-- precision: minute
	[14] = "j F Y g:i:sa"	-- precision: second
}

local p = {}

function p.plot(frame)
	local property = frame.args[1] or error("Wikidata property to chart required")
	local xQualifier = frame.args[2] or error("Wikidata qualifier for x axis required")
	local yIds = mw.text.split(frame.args["pageIds"] or "", ",", true)
	local xStart = frame.args["xStart"]
	local xEnd = frame.args["xEnd"]
	local precision = tonumber(frame.args["precision"])
	local xAxisFormat = defaultFormat[precision or 9]	
	
	-- Collect data
	local series = { captions = {}, points = {} }
	for seriesIdx, id in ipairs(yIds) do
		if id == "" then id = nil end
		local entity = mw.wikibase.getEntity(id)
		
		local labels = entity.labels or {}
		series.captions[seriesIdx] = (labels.en or labels.de or {}).value or id

		local property = entity.claims[property]
		for _, item in ipairs(property) do
			if item.qualifiers and item.qualifiers[xQualifier] and item.qualifiers[xQualifier][1] then
				local qualifier = item.qualifiers[xQualifier][1]
				if qualifier.snaktype ~= "value" or qualifier.datatype ~= "time" then
					error("'xQualifier' parameter must be a time")
				end
				local x = applyPrecision(mw.text.trim(qualifier.datavalue.value.time, "+"), precision)
				
				if (not xStart or x >= xStart) and (not xEnd or string.sub(x, 1, #xEnd) <= xEnd) and qualifier.datavalue.value.precision >= (precision or 0) then
					local mainsnak = item.mainsnak
					if mainsnak.snaktype ~= "value" or mainsnak.datatype ~= "quantity" then
						error("'property' parameter must be numeric")
					end
					local y = tonumber(mainsnak.datavalue.value.amount)
	
					if not series.points[x] then series.points[x] = {} end
					series.points[x][seriesIdx] = y
				end
			end
		end
	end

	-- Sort x values
	local xValues = {}
	for k in pairs(series.points) do table.insert(xValues, k) end
	table.sort(xValues)

    -- default values, can be overwritten
	local chartArgs =
	{
		type = "line",
		xType = "date",
		x = table.concat(xValues, ","),
		yType = "number",
		
		-- these are not supported anymore with new chart extension as of now..
--		xAxisTitle = mw.wikibase.label(xQualifier),		
--		yAxisTitle = mw.wikibase.label(property)
	}
	-- Set legends / series titles
	for seriesIdx, caption in ipairs(series.captions) do
		chartArgs["y" .. seriesIdx] = ""
		chartArgs["y" .. seriesIdx .. "Title"] = caption
	end
	-- Set values
	local seriesCount = #series.captions
	for _, x in ipairs(xValues) do
		yValues = series.points[x]
		for seriesIdx = 1, seriesCount do
			chartArgs["y" .. seriesIdx] = chartArgs["y" .. seriesIdx] .. "," .. (yValues[seriesIdx] or "")
		end
	end
	-- Remove separators at the beginning
	for seriesIdx, _ in ipairs(series.captions) do
		chartArgs["y" .. seriesIdx] = mw.ustring.sub(chartArgs["y" .. seriesIdx], 2)
	end
	-- Transfer diagram parameters (all parameters that start with chart_ are transferred directly to the Graph module without a prefix)
	for k, v in pairs(frame.args) do
		local chartParam = string.match(k, "^chart_(.+)")
		if chartParam then chartArgs[chartParam] = v end
	end

 	
	--workaround, to better show dates since the extension doesn't support them yet properly
	if chartArgs["xType"]=="date" then
		xValuesCutted = {}
		for _, k in pairs(xValues) do
			table.insert(xValuesCutted,string.sub( k, 1, 10))
		end
		chartArgs["x"] = table.concat(xValuesCutted, ",")
	end
	-- if number, use precision to round (default 9=years)
	if chartArgs["xType"]=="number" then
		xValuesCutted = {}
		for _, k in pairs(xValues) do
			table.insert(xValuesCutted,mw.getContentLanguage():formatDate(xAxisFormat, k))
		end
		chartArgs["x"] = table.concat(xValuesCutted, ",")
	end
	
	-- create the plot
	local resultplot
	resultplot = mw.getCurrentFrame():expandTemplate {
		title = 'Template:ChartDirect',
		args = chartArgs
		}
		
	return resultplot
end

function p.plotWrapper(frame)
	return p.plot(frame:getParent())
end

function applyPrecision(date, precision)
	if not precision then precision = math.huge end

	local _, _, year, month, day, hour, minute, second, timezone = string.find(date, "^(.?%d+)-(%d+)-(%d+)T(%d+):(%d+):(%d+)(.+)$")
	if precision < 14 then second = "00" end
	if precision < 13 then minute = "00" end
	if precision < 12 then hour = "00" end
	if precision < 11 or day == "00" then day = "01" end
	if precision < 10 or month == "00" then month = "01" end
	return year .. "-" .. month .. "-" .. day .. "T" .. hour .. ":" .. minute .. ":" .. second .. timezone
end

return p