Modul:Graf počtu obyvatel

Z Wikipedie, otevřené encyklopedie
require 'Modul:No globals'

local p = {}

local lang = mw.language.getContentLanguage()
local getArgs = require('Modul:Arguments').getArgs

local TableTools = require('Modul:TableTools')
local Wikidata = require('Modul:Wikidata')
local Formatters = require('Modul:Wikidata/Formatters')

local function getIndexedData(id, property)
	local statements = Wikidata.getStatements{
		id = id,
		property = property,
		rank = 'valid',
		withqualifier = 'P585'
	}
	local numbers_raw = {}
	for _, statement in ipairs(statements) do
		local n = Formatters.getRawValue(statement.mainsnak, {})
		for _, qualifier in ipairs(statement.qualifiers.P585) do
			local d = Formatters.getRawValue(qualifier, {})
			if d and d.year then
				numbers_raw[d.year] = n
			end
		end
	end
	return numbers_raw
end

local function getKeys(rows)
	local keys = {}
	for _, v in pairs(rows) do
		for key in pairs(v) do
			keys[key] = true
		end
	end
	return keys
end

local function formatNumOrNothing(num)
	num = tonumber(num)
	if num then
		return lang:formatNum(num)
	else
		return ''
	end
end

local function createTable(data,sep)
	local popTables={}
	local divided={}
	local i,j=0,sep
	for _,v in pairs(data) do
		if j == sep then 
			i=i+1
			divided[i]={}
			j=0
		end
		j=j+1
		divided[i][j] = v
	end
	for _, t in pairs(divided) do
		local keys = getKeys(t)
		local popTable = mw.html.create( 'table' )
		local thead = popTable
			:css( 'display', 'inline-block' )
			:css( 'vertical-align', 'top' )
			:addClass( 'wikitable' )
			:tag( 'tr' )
		thead:tag( 'th' ):wikitext( 'Rok' )
		if keys.population then
			thead:tag( 'th' ):wikitext( 'Obyvatelé' )
		end
		if keys.houses then
			thead:tag( 'th' ):wikitext( 'Domy' )
		end
		for _, v in pairs(t) do
			local tr = popTable:tag( 'tr' )
			  :tag( 'th' )
			  :wikitext( v.year )
			  :done()
			if keys.population then
				tr:tag( 'td' )
				  :css( 'text-align', 'right' )
				  :wikitext( formatNumOrNothing(v.population) )
			end
			if keys.houses then
				tr:tag( 'td' )
				  :css( 'text-align', 'right' )
				  :wikitext( formatNumOrNothing(v.houses) )
			end
		end
		table.insert(popTables,tostring(popTable))
	end
	return table.concat(popTables)
end

local function drawGraph(indexed_data, opts)
	local data = {}
	local x_fields = {}
	local y_fields = {}
	for key, values in pairs(indexed_data) do
		table.insert(data, { name = key, values = values })
		table.insert(x_fields, { data = key, field = 'x' })
		table.insert(y_fields, { data = key, field = 'y' })
	end
	local json = {
		version = 2,
		width = opts.width, height = opts.height,
		data = data,
		scales = {
			{
				name = "x",
				type = "linear",
				domain = { fields = x_fields },
				range = "width",
				zero = false,
				nice = true
			},
			{
				name = "y",
				range = "height",
				nice = true,
				domain = { fields = y_fields }
			}
		},
		axes = {
			{ type = "x", scale = "x", tickcount = 20, format = "d", grid = true },
			{ type = "y", scale = "y", format = "2d", grid = true }
		},
		marks = {
			{
				type = "line",
				from = { data = "population" },
				properties = {
					enter = {
						x = { scale = "x", field = "x" },
						y = { scale = "y", field = "y" },
						strokeWidth = { value = 5 },
						stroke = { value = "steelblue" }
					}
				}
			},
			{
				type = "line",
				from = { data = "houses" },
				properties = {
					enter = {
						x = { scale = "x", field = "x" },
						y = { scale = "y", field = "y" },
						strokeWidth = { value = 5 },
						stroke = { value = "orange" }
					}
				}
			}
		}
	}
	if opts.labels == "ano" then
		table.insert(json["marks"],
			{
				type = "text",
				from = { data = "table" },
				properties = {
					enter = {
						x = { scale = "x", field = "x" },
						y = { scale = "y", field = "y" },
						fill = { value = "#000" },
						align = { value = "left" },
						baseline = { value = "top" },
						dy = { value = -13 },
						text = { field = "y" }
					}
				}
			}
		)
	end
	return tostring(mw.html.create("div")
		:css("display","inline-block")
		:css("vertical-align","top")
		:wikitext(mw.getCurrentFrame():extensionTag("graph", mw.text.jsonEncode(json))))
end

function p.main(frame)
	local args
	if type(frame) ~= 'table' then
		args = { id = frame }
	else
		args = getArgs(frame)
	end

	local opts = {
		width = tonumber(args["width"]) or 430,
		height = tonumber(args["height"]) or 200,
		labels = args["labels"],
	}
	local property = args["property"] or 'P1082'
	local from = tonumber(args["from"])
	local to = tonumber(args["to"])
	local skip = tonumber(args["skip"]) or 1
	local zalamovat = tonumber(args["zalamovat"])

	local keys = {}
	keys.population = property
	if args.domy == 'ano' then
		keys.houses = 'P4080'
	end

	local indexed_data = {}
	local dates = {}
	for key, property in pairs(keys) do
		indexed_data[key] = getIndexedData(args.id, property)
		for d in pairs(indexed_data[key]) do
			dates[d] = true
		end
	end
	dates = TableTools.keysToList(dates, true)
	if #dates < 1 then
		return ''
	end
	local data = {}
	local tabular = {}
	local last
	for _, d in ipairs(dates) do
		if (not(from) or (d >= from))
		  and (not(to) or (d <= to))
		  and (not(last) or ((d-last)>=skip)) then
			local t = { year = d }
			for key in pairs(keys) do
				local val = indexed_data[key][d]
				if val then
					if not data[key] then
						data[key] = {}
					end
					table.insert(data[key], { x = d, y = val })
					t[key] = val
				end
			end
			table.insert(tabular, t)
			last = d
		end
	end

	local output = {}
	output[1] = args["nadpis"] or '<div style="font-weight:bold">Vývoj počtu obyvatel</div><div><small>Data pocházejí z datové položky Wikidat</small></div>'
	local graphPos, tabPos
	if args["tabulka"] == "nad" then
		tabPos = 2
		output[3] = "<br/>"
		graphPos = 4
	elseif (args["tabulka"] == "pod") then
		graphPos = 2
		output[3] = "<br/>"
		tabPos = 4
	elseif (args["tabulka"] == "před") then
		tabPos = 2
		graphPos = 3
	elseif (args["tabulka"] == "za") then
		graphPos = 2
		tabPos = 3
	else
		graphPos = 2
	end
	output[graphPos] = drawGraph(data, opts)
	if tabPos then output[tabPos] = createTable(tabular, zalamovat) end
	return table.concat(output)
end

return p