Ugrás a tartalomhoz

Modul:Forgalomdiagram

Ellenőrzött
A Wikipédiából, a szabad enciklopédiából

Forgalomdiagram[mi ez?] • [dokumentáció: mutat, szerkeszt] • [tesztek: létrehozás]

local getArgs = require('Modul:Arguments').getArgs
local p = {}
local property = 'P3872'

local json = {
	version = 2,
	width = 400, height = 200,
	data = {
		{
			name = "table",
			values = {}
		}
	},
	scales = {
		{
			name = "x",
			type = "ordinal",
			range = "width",
			domain = { data = "table", field= "x" }
		},
		{
			name = "y",
			range = "height",
			nice = true,
			domain = { data = "table", field = "y" }
		}
	},
	axes = {
		{ type = "x", scale = "x" },
		{ type = "y", scale = "y" }
	},
	marks = {
		{
			type = "rect",
			from = { data = "table" },
			properties = {
				enter = {
					x = { scale = "x", field = "x" },
					width = { scale = "x", band = true, offset = -1},
					y = { scale = "y", field = "y" },
					y2 = { scale = "y", value = 0 }
				},
				update = {
					fill = { value = "steelblue" }
				},
				hover = {
					fill = { value = "red" }
				}
			}
		},
		{
			type = "text",
			from = { data = "table" },
			properties = {
				enter = {
					x = { scale = "x", field = "x" },
					dx = { scale = "x", band = true, mult = 0.5 },
					y = { scale = "y", field = "y" },
					fill = { value = "#000" },
					align = { value = "center" },
					baseline = { value = "top" },
					dy = { value = -13 },
					text = { field = "y_form" }
				}
			}
		}
	}
}

local function getStatements(id)
	local entity = mw.wikibase.getEntity(id)
	if not entity then
		return nil
	end
	if not entity.claims or not entity.claims[property] then
		return nil
	end
	local statements = entity.claims[property]
	return statements
end

local function prepareStatements(statements)
	local Time
	local numbers_raw = {}
	local years = {}
	local dates = {}
	local ranks = { normal = 1, preferred = 2 }
	local function processStatement(statement)
		local snak = statement.mainsnak
		if not snak or snak.snaktype ~= 'value' then
			return
		end
		local rank = ranks[statement.rank]
		if not rank then
			return
		end
		local n = tonumber(snak.datavalue.value.amount)
		local d = nil
		if statement.qualifiers and statement.qualifiers.P585 then  -- dátum
			if not Time then
				Time = require('Modul:Time')
			end
			d = Time.newFromWikidataValue(statement.qualifiers.P585[1].datavalue.value)
		end
		if d and d.precision >= Time.PRECISION.YEAR then
			years[d.year] = true
			local month = d.precision >= Time.PRECISION.MONTH and d.month or 0
			local day = d.precision >= Time.PRECISION.DAY and d.day or 0
			local monthday = month * 100 + day
			if not numbers_raw[d.year] or numbers_raw[d.year].precision > d.precision then
				-- prefer yearly/monthly data over sum of monthly/daily as the latter can have “gaps”
				numbers_raw[d.year] = { number = n, precision = d.precision, monthdays = { [monthday] = rank } }
			elseif numbers_raw[d.year].precision == d.precision then
				if not numbers_raw[d.year].monthdays[monthday] then
					numbers_raw[d.year].monthdays[monthday] = rank
					numbers_raw[d.year].number = numbers_raw[d.year].number + n
				elseif numbers_raw[d.year].monthdays[monthday] < rank then
					numbers_raw[d.year].monthdays[monthday] = rank
					numbers_raw[d.year].number = n
				else
					-- We already have data for this date with at least as high rank
					-- as the new. Just keep the previous one; either one can be good,
					-- so don’t do useless operations.
				end
			end
		end
	end
	for _, statement in pairs(statements) do
		processStatement(statement)
	end
	for y, _ in pairs(years) do
		table.insert(dates, y)
	end
	if #dates < 1 then
		return nil
	end
	table.sort(dates)
	local numbers = {}
	if #dates <= 10 then
		for _, v in ipairs(dates) do
			table.insert(numbers, { tostring(v), numbers_raw[v].number } )
		end
	else
		local n = #dates - 1
		for i = 0, 9 do
			local j = math.floor(i * n / 9 + 0.5) + 1
			local year = dates[j]
			table.insert(numbers, {tostring(year), numbers_raw[year].number})
		end
		if numbers_raw[dates[n + 1]].number >= 1000000 then
			json.marks[2].properties.enter.angle = { value = -45 }
		end
	end
	return numbers
end

local function drawGraph(data, float)
	local lang = mw.language.getContentLanguage()
	for _, v in pairs(data) do
		local d, n = v[1], v[2]
		local n_form = tostring(n)
		if n >= 10000 then
			n_form = lang:formatNum(n)
		end
		table.insert(json.data[1].values, { x = d, y = n, y_form = n_form })
	end
	return tostring(mw.html.create("div")
		:css("display", "inline-block")  -- style hotfix
		:css("max-width", "100%")
		:css("overflow-x", "auto") -- too wide on mobile
		:css("float", float) -- optional
		:wikitext(mw.getCurrentFrame():extensionTag("graph", mw.text.jsonEncode(json)))
	)
end

local function wikitable(frame, data)
	local ret = '{| class="wikitable"\n'
	for _, v in ipairs(data) do
		ret = ret .. '|-\n|' .. v[1] .. '||' .. frame:expandTemplate { title = 'számt', args = { v[2] }} .. '\n'
	end
	ret = ret .. '|}'
	return ret
end

function p.main(frame)
	local args = {}
	if type(frame) ~= 'table' then
		args = { id = frame }
	else
		args = getArgs(frame)
	end
	if args.property then
		property = args.property
	end
	local statements = getStatements(args.id)
	if type(statements) ~= 'table' then
		return nil
	end
	statements = prepareStatements(statements)
	if type(statements) ~= 'table' then
		return nil
	end
	if #statements < 3 then
		return wikitable(frame, statements)
	end
	return frame:callParserFunction('#tag', { 'templatestyles', '', src = 'Népességdiagram alt1/style.css' }) ..
		require('Modul:Népességdiagram alt1').dijagram(statements, {
			property = property,
			entityId = args.id or mw.wikibase.getEntityIdForCurrentPage(),
			naslov = 'Utasforgalom',
			yAxisTitle = 'Utasok száma'
		})
end

return p