Aller au contenu

Module:Population

Une page de Wikipédia, l'encyclopédie libre.
Ceci est une version archivée de cette page, en date du 17 août 2020 à 09:17 et modifiée en dernier par Zolo (discuter | contributions). Elle peut contenir des erreurs, des inexactitudes ou des contenus vandalisés non présents dans la version actuelle.

 Documentation[créer] [purger]
local p = {}


--
-- Les modules et sous-modules dont on aura besoin
--
local wd = require "Module:Wikidata"

-- le module démographie
p.demographie = require("Module:Démographie")
-- le module chartes
p.chartes = require("Module:Chartes")

-- on charge les sous-modules
p.constantes = require("Module:Population de France/Constantes")
p.sources = require("Module:Population de France/Sources") -- à simplifier pour avoir juste une liste de textes
p.notes = require("Module:Population de France/Notes")
p.donnees = require("Module:Population de France/Données")
p.outils = require("Module:Population de France/Outils")
p.intro = require("Module:Population de France/Introductions")

local function getData(qid) -- récupère le fichier où sont stockés les données pour une page ou un élément Wikidata
	local filename = wd.formatStatements{entity = qid, property = 'P4179', numval = 1}

	if not (qid and filename) then
		return p.outils.err_nodata("tableau", donnees, filename or "pas de fichier")
	end

	return filename, mw.ext.data.get(filename)
end

local function getIdAndName(id, name)
	if (not id) then -- si pas d'id Wikidata, prendre celui de la page active
		id = mw.wikibase.getEntityIdForTitle(name or  mw.title.getCurrentTitle().subpageText)
	end
	if (not name) then
		name = wd.getLabel(name) or mw.title.getCurrentTitle().subpageText
	end
	return id, name
end

local function analyseData(data)  -- définit la signification des différents champs de données du fichier
	local fields = data.schema.fields
	local popfield, datefield, methodfield, criterionfield, sourcefield, sourceurlfield

	for num, j in ipairs(fields) do
		if string.find(fields[num].name, "P585") then
			datefield = num
		elseif string.find(fields[num].name, "P1082") then
			popfield = num
		elseif string.find(fields[num].name, "P1082") then
			popfield = num
		elseif string.find(fields[num].name, "P459") then
			methodfield = num
		elseif string.find(fields[num].name, "P1013") then
			criterionfield = num
		elseif string.find(fields[num].name, "S248") then
			sourcefield = num
		elseif string.find(fields[num].name, "S248") then
			sourceurlfield = num
		end
	end
	
	-- exits if no field for population or date
	if (popfield * datefield == 0) then
		return error("data could not be parsed correctly") -- FIXME
	end
	return {population = popfield, date = datefield, method = methodfield, criterion = criterionfield, source = sourcefield, sourcefield = sourceurlfield}
end

local function getYear(data)
	local d = data[datefield]
	d = tonumber(d) -- enlève le "+" de départ éventuel
	d = tostring(d)
	return mw.ustring.sub(d, 1, 4)
end


local function keepValFR(val, fieldnames)
		-- recencement, on garde
	local method = val[fieldnames.method]
	local d = val[fieldnames.date]
	if (method == "Q39825") then
		return true
	end	
	
	-- interpolation or exptrapolation du recencement quinquennal, on rejette
	if (method == "Q744069") or (method == "Q187631") then
		return false
	end

	-- enquête pour les communes de plus de 10 000 habs
	-- on garde 2006, 2011 et 2016
	if (method == "Q98415788") then
		local year = getYear(d)
		if (d == "2006") or (d == "2011") or (d == "2016") then
			return true
		end
	end
	return true -- autres méthodes, erreurs ?
end
	
local function keepVal(data, fieldnames, country)
	if true or country == "Q142" then -- France
		return keepValFR(data, fieldnames)
	end
	return true -- on garde par défaut
end

local tableFormat = {
	-- on prépare les paramètres à fournir au module Démographie
	["largeur_tableau"] = "48em",
	["taille_police"] = "95%",
	["marge_interlignes"] = "10px",
	["hauteur_lignes"] = "110%",
	["population_fond"] = "#F9F9F9",
	["style_notes"] = "centré",
}

function p.tableau_m(param)
	-- le nom de la cible (param. nom ou titre page)
	
	local id, name =  getIdAndName(param["wikidata"], param["nom"])
	
	-- récupération et vérification des données
	local datafile, data = getData(id, name)
	local fieldnames = analyseData(data)
	local country = wd.formatStatements{entity = id, property = "P17", numval = 1, displayformat = "raw"}

	-- couleur (on passe par Chartes avec un "truc" pour commune nouvelle)
	local dest = tableFormat
	if (data["division"] == "commune nouvelle") then
		dest["annees_fond"] = p.chartes.charte_m("geographie", "secondaire", "commune", true)
	else
		dest["annees_fond"] = p.chartes.charte_m("geographie", "secondaire", data["division"], true)
	end

	-- le titre du tableau
	dest["titre"] = (param["titre"] or p.constantes.titre_tableau)
	.. " &nbsp;<small>[&#8202;[[:c:Data:" .. datafile .. "|modifier]]&#8202;]</small>"

	-- notes FIXME
	local tmp = p.notes.notes(data, vnom)
	if ((tmp ~= nil) and (mw.text.trim(tmp) ~= "")) then
		dest["notes"] = tmp
	end

	-- sources FIXME
	tmp = p.sources.sources(data)
	if ((tmp ~= nil) and (mw.text.trim(tmp) ~= "")) then
		dest["sources"] = tmp
	end
	-- récupération des chiffres 
	for i, j in ipairs(data.data) do
		if ( keepVal(j, fieldnames, country) or i == #data.data) then -- on garde les données correspondant au critères + la plus récente
			local annee = tonumber(j[fieldnames["date"]])-- A ADAPTER POUR LE CAS OU LA DATE COMPORTE LE MOIS OU LE JOUR
			dest[annee] = j[fieldnames["population"]]
		end
	end


	-- on effectue l'appel terminal et on retourne (et on ajoute la catégorie)
	return p.demographie.demographie_m(dest) .. p.constantes.cat_usage
end


	-- fonction "wrapper" pour la précédente, pour appel depuis un modèle
	function p.tableau(frame)
		local param = {}
		-- deux paramètres : nom et titre
		param["nom"] = p.outils.nettoie(frame.args["nom"] or frame:getParent().args["nom"] or nil)
		param["titre"] = p.outils.nettoie(frame.args["titre"] or frame:getParent().args["titre"] or nil)

	-- on appelle la vraie fonction
	return p.tableau_m(param)
end

--[[
  Fonction créant une introduction de population de commune
--]]

function p.introduction_m(param)
	local resu
	local nom = param["nom"] or mw.title.getCurrentTitle().subpageText
	local donnees = getData(nom)

	-- on charge les données associées à la commune
	local data, wlm = p.donnees.charge_donnees(nom)
	if (type(wlm) == "number") then
		return p.outils.err_nodata("introduction", donnees, wlm)
	end
	if (data["division"] == "fraction cantonale") then
		return p.outils.err_nodata("introduction", donnees, 6) -- pas d'intro pour ça
	end

	resu = p.intro.introduction(data)

	return resu
end

-- fonction "wrapper" pour la fonction précédente, pour appel depuis un modèle
function p.introduction(frame)
	local pframe = frame:getParent()
	local param = {}
	-- récupération de l'unique paramètre (nom)
	param["nom"] = p.outils.nettoie(frame.args["nom"] or pframe.args["nom"] or nil)
	return p.introduction_m(param)
end


-- fonction de tri utilisée par la fonction suivante
-- tri sur la valeur du 1er élément des éléments
function p.sort_par_annee(el1, el2)
	if (el1[1] < el2[1]) then
		return true
	end
		return false
end

--[[
  Fonction créant un graphique de population de commune
--]]
function p.graphique_m(param)
	local resu
	local qid, name = getIdAndName(param["id"], param["nom"])
	if not (name and qid) then
		return error("quelle page ?") -- FIXME
	end

	local data = getData(qid, name)
	if not (data) then
		return p.outils.err_nodata("graphique", data, filename or "pas de fichier")
	end

	-- seuil (nombre de données) à afficher
	param["seuil"] = tonumber(param["seuil"])
	if ((param["seuil"] == nil) or (param["seuil"] <= 0)) then
		param["seuil"] = 5 -- valeur par défaut
	end


	local graphLayout = {
	-- "Histogramme population manuel" étant un modèle, on fabrique la structure d'appel
	-- ici il faudrait modifier "couleur-barres" qui devrait dépendre de la charte…
		["largeur"] = 710,
		["hauteur"] = 340,
		["couleur-fond"] = "rgb(1,1,1)"
	}



	prm = {  }
	local cb
	if (data["division"] == "commune nouvelle") then
		cb = p.chartes.charte_m("geographie", "primaire", "commune", true)
	else
		cb = p.chartes.charte_m("geographie", "primaire", data["division"], true)
	end
	cb = p.outils.color2rgb(cb)
	if (cb == nil) then
		prm["couleur-barres"] = "rgb(0.7,0.9,0.7)" -- couleur "par défaut"
	else
		prm["couleur-barres"] = "rgb(" .. cb .. ")"
	end

	prm["nom"] = param["nom"]
	prm["titre"] = param["titre"] or p.constantes.titre_graphique
	prm["max"] = data["popmax"]
	-- parcours des données
	local tmp = {}
	for annee, pop in pairs(data) do
		if (type(annee) == "number") then
		-- est-ce qu'on garde l'année ?
		if (p.outils.test_annee(annee, data) and (type(pop["pop"]) == "number") and (pop["pop"] > 0)) then
			table.insert(tmp, { annee, pop["pop"] })
		end
	end
end

	-- tri des éléments
	table.sort(tmp, p.sort_par_annee)
	-- on insert année / valeur dans l'ordre (histogramme pop… a besoin des données dans l'ordre)
	local nb = 1
	local nbp = 0
	for k, v in pairs(tmp) do
		if (v[2] > 0) then
			prm[nb] = v[1]
			prm[nb+1] = v[2]
			nb = nb + 2
			nbp = nbp + 1  -- nombre de barres (réel)
		end
	end
	-- si pas assez de données on ne traite pas
	if (nbp < param["seuil"]) then
		return ""  -- on retourne "rien"
	end

	prm["nombre"] = nbp
	prm["sources"] = p.sources.sources_graphique(data)

-- précaution
	if (nbp == 0) then
		p.outils.err_nodata("graphique", donnees, 7, true)
	end

-- on "appelle" le modèle
	return mw.getCurrentFrame():expandTemplate{ title = 'Histogramme population manuel', args = prm }
end

-- fonction "wrapper" pour la fonction précédente, pour appel depuis un modèle
function p.graphique(frame)
	local pframe = frame:getParent()
	local param = {}
	-- récupération des paramètre (nom et titre)
	param["nom"] = p.outils.nettoie(frame.args["nom"] or pframe.args["nom"] or nil)
	param["titre"] = p.outils.nettoie(frame.args["titre"] or pframe.args["titre"] or nil)
	param["seuil"] = p.outils.nettoie(frame.args["seuil"] or pframe.args["seuil"] or nil)
	return p.graphique_m(param)
end


--[[
  Retourne la dernière population (ou la dernière date) pour la commune "nom" (ou courante)
  Si prm[1] est vide retourne la population, sans formatage
  Si prm[1] vaut "date", retourne la date
  Si prm[1] vaut "nombre", idem premier cas mais avec formatage du nombre
  Si prm[1] vaut "table", retourne une table avec l'année en 1er élément et le nombre en 2e élément
--]]
function p.derniere_population_m(prm)
	local nom = prm["nom"] or mw.title.getCurrentTitle().subpageText
	local data = getData(nil, nom)
	if data then
		return mw.language.getContentLanguage():formatNum(tmp[2])
	end
end

-- fonction "wrapper" pour la fonction précédente, pour appel depuis un modèle
function p.derniere_population(frame)
	local pframe = frame:getParent()
	local param = {}
	-- récupération des paramètre (nom et titre)
	param["nom"] = p.outils.nettoie(frame.args[2] or pframe.args[2] or nil)
	param["type"] = frame.args[1] or pframe.args[1] or nil
	return p.derniere_population_m(param)
end


--[[
  Retourne une phrase décrivant la variation de population de la commune
    courante (ou "nom") ou un pictograme si "type" = "picto"
--]]
function p.variation_texte_m(prm)
	local nom = prm["nom"] or mw.title.getCurrentTitle().subpageText
	local donnees = "Module:Données/" .. nom .. "/évolution population"

	-- on charge les données associées à la commune
	local data, wlm = p.donnees.charge_donnees(nom)
	if (type(wlm) == "number") then
		return p.outils.err_nodata("variation_texte", donnees, wlm, true)
	end

	local txt, sens = p.donnees.variation_texte(data)
	if (txt == nil) then
		return p.outils.err_nodata("variation_texte", donnees, 7, true)
	end
	if (prm["type"] ~= "picto") then
		return txt
	end
-- on crée le pictogramme
	if (sens > 0) then
		return "[[Fichier:Increase2.svg|11px|link=|class=noviewer|" .. txt .. "]]"
	elseif (sens < 0) then
		return "[[Fichier:Decrease2.svg|11px|link=|class=noviewer|" .. txt .. "]]"
	else -- égal
		return "[[fichier:steady.svg|10px|link=|class=noviewer|" .. txt .. "]]"
	end
end

-- fonction "wrapper" pour la fonction précédente, pour appel depuis un modèle
function p.variation_texte(frame)
	local pframe = frame:getParent()
	local param = {}
	-- récupération des paramètre (nom et titre)
	param["nom"] = p.outils.nettoie(frame.args["nom"] or pframe.args["nom"] or nil)
	param["type"] = frame.args["type"] or pframe.args["type"] or nil
	return p.variation_texte_m(param)
end


--[[
  Retourne la densité de la commune. Si "précision" indiquée utilise celle-ci,
  sinon précision 1 par défaut
--]]

function p.densite_m(params)
	local name, id = getIdAndName( params["nom"], params["id"])

	if not id then
		return nil -- or error ?
	end

	-- population et densité par Wikdata. Ou prendre la pop des données tabulaires par cohérence ?
	local pop = wd.formatStatements{entity = id, property = 'P1082', numval = 1, displayformat = "raw"}
	local area = wd.formatStatements{entity = id, property = 'P2046', numval = 1, targetunit = "sqkm", displayformat = "raw", showunit = "-"}
	-- TODO: test supplémentaire pour vérifier que la date et la population portent sur la même date ?

	if not (pop and area) then -- FIXME
		return p.outils.err_nodata("densite", donnees, 7, true)
	end
	pop, area = tonumber(pop), tonumber(area)
	local prc = 1
	if (type(params["précision"]) == "number") then
		prc = params["précision"]
	end


	if (params["format"] ~= nil) then
		return mw.language.getContentLanguage():formatNum(p.outils.round(pop / area, prc))
	else
		return p.outils.round(pop / area, prc)
	end
end

-- fonction "wrapper" pour la fonction précédente, pour appel depuis un modèle
function p.densite(frame)
	local pframe = frame:getParent()
	local param = {}
	-- récupération des paramètre (nom et titre)
	param["nom"] = p.outils.nettoie(frame.args["nom"] or pframe.args["nom"] or nil)
	param["précision"] = tonumber(frame.args["précision"] or pframe.args["précision"] or nil)
	param["format"] = frame.args["format"] or pframe.args["format"] or nil
	return p.densite_m(param)
end


--[[
  Retourne la superficie de la commune.
--]]

function p.superficie_m(prm)
	local nom = prm["nom"] or mw.title.getCurrentTitle().subpageText
	local donnees = "Module:Données/" .. nom .. "/évolution population"

-- on charge les données associées à la commune
local data, wlm = p.donnees.charge_donnees(nom)
	if (type(wlm) == "number") then
		return p.outils.err_nodata("superficie", donnees, wlm, true)
	end

	return (data["superficie"])

end

-- fonction "wrapper" pour la fonction précédente, pour appel depuis un modèle
function p.superficie(frame)
	local pframe = frame:getParent()
	local param = {}
	-- récupération des paramètre (nom et titre)
	param["nom"] = p.outils.nettoie(frame.args["nom"] or pframe.args["nom"] or nil)
	return p.superficie_m(param)
end

return p