Модуль:Wikidata/Population
Для документации этого модуля может быть создана страница Модуль:Wikidata/Population/doc
local WDS = require('Module:WikidataSelectors');
local p = {};
local DEFAULT_COLUMNS = 4;
local DEFAULT_WIDTH = 700;
local DEFAULT_HEIGHT = 300;
local COLLAPSE_IF_ROWS_MORE_THAN = 11;
local TABLE_COLLAPSIBLE_HEADER = "Статистика численности населения с %s по %s";
local TABLE_COLUMN_HEADER_YEAR = "Год";
local TABLE_COLUMN_HEADER_POPULATION = "Численность";
local function deepcopy(orig)
local orig_type = type(orig)
local copy
if orig_type == 'table' then
copy = {}
for orig_key, orig_value in next, orig, nil do
copy[deepcopy(orig_key)] = deepcopy(orig_value)
end
setmetatable(copy, deepcopy(getmetatable(orig)))
else -- number, string, boolean, etc
copy = orig
end
return copy
end
local function formatPopulationPropertyImpl( context, options )
if ( not context ) then error( 'context not specified' ); end;
if ( not options ) then error( 'options not specified' ); end;
if ( not options.entity ) then error( 'options.entity missing' ); end;
local claims = context.selectClaims( options, options.property );
if (claims == nil) then
return nil --TODO error?
end
for i, j in ipairs(claims) do
if ( not j.qualifiers.P585[1]) then return nil end --проверка на наличие момента времени
end
local comparator = function(o1, o2)
local t1 = context.parseTimeFromSnak( o1.qualifiers.P585[1] );
local t2 = context.parseTimeFromSnak( o2.qualifiers.P585[1] );
return t1 < t2;
end
table.sort( claims, comparator )
return claims;
end
function p.formatPopulationPropertyForGraph( context, options )
local claims = formatPopulationPropertyImpl( context, options );
-- Обход всех заявлений утверждения и с накоплением оформленых предпочтительных
-- заявлений в таблице
local formattedClaims = {}
local count = 0;
local csv = 'year,month,day,population';
if ( not claims ) then
return '';
end
for i, claim in ipairs(claims) do
-- уточняем даты: для года до середины, для месяца до 15-го числа
local p585Value = claim.qualifiers.P585[1].datavalue.value;
local p585Precision = p585Value.precision;
local p585Time = p585Value.time;
if ( p585Precision == 10 ) then
-- Set 15-th day of month
p585Time = mw.ustring.gsub(p585Time, "\-[0-9]+T", "-15T");
elseif ( p585Precision == 9 ) then
-- Set to 1-st of July
p585Time = mw.ustring.gsub(p585Time, "\-[0-9]+\-[0-9]+T", "-07-01T");
end
local year, month, day = mw.ustring.gmatch( p585Time, "(\-?[0-9]+)\-([0-9]+)\-([0-9]+)T" )(1);
local value = string.gsub( claim.mainsnak.datavalue.value.amount, '^%+', '' );
local line = year .. ',' .. month .. ',' .. day .. ',' .. value;
csv = csv .. '\\n' .. line;
count = count + 1;
end
if ( count == 0 ) then
return '';
end
local graphData = '{ "version": 2, "width": ' .. DEFAULT_WIDTH .. ', "height": ' .. DEFAULT_HEIGHT .. ', "data": [ { "name": "table", "values": "';
graphData = graphData .. csv;
graphData = graphData .. '","format": { "parse": {"year": "integer", "month": "integer", "day": "integer", "population": "integer"}, "type": "csv" },'
graphData = graphData .. '"transform": [{ "type": "formula", "field": "date", "expr": "datetime(datum.year,datum.month-1,datum.day)" }] } ],';
graphData = graphData .. '"scales": [{ "name": "x", "type": "time", "range": "width", "nice": "year", "domain": {"data": "table", "field": "date"} },';
graphData = graphData .. '{ "name": "y", "type": "linear", "range": "height", "domain": {"data": "table", "field": "population"} } ],';
graphData = graphData .. '"axes": [ {"type": "x", "scale": "x", "ticks": 10}, {"type": "y", "scale": "y", "ticks": 5, "grid": true, "orient": "right", "format": "d"} ],';
graphData = graphData .. '"marks": [{ "type": "area", "from": {"data": "table"}, "properties": { "enter": {';
graphData = graphData .. '"x": {"scale": "x", "field": "date"}, "y": {"scale": "y", "value": 0}, "y2": {"scale": "y", "field": "population"}, ';
graphData = graphData .. '"fill": {"value": "#99B2CC"}, "fillOpacity": {"value": 0.35}, "interpolate": {"value": "monotone"}}}},';
graphData = graphData .. '{ "type": "line", "from": {"data": "table"}, "properties": { "enter": {';
graphData = graphData .. '"x": {"scale": "x", "field": "date"}, "y": {"scale": "y", "field": "population"},';
graphData = graphData .. '"stroke": {"value": "#99B2CC"}, "strokeWidth": {"value": 3}, "interpolate": {"value": "monotone"}}}},';
graphData = graphData .. '{"type": "symbol","from": {"data": "table"},"properties": {"enter": {';
graphData = graphData .. '"x": {"scale": "x", "field": "date"},"y": {"scale": "y", "field": "population"},"stroke": {"value": "#99B2CC"},"fill": {"value": "#fff"},"size": {"value": 10}}}}]}';
local result = options.frame:extensionTag( 'graph', graphData );
local columns = options.columns or DEFAULT_COLUMNS;
local perColumn = math.ceil( count / columns );
if ( perColumn > COLLAPSE_IF_ROWS_MORE_THAN ) then
return result;
else
-- side-by-side display
return '<div style="display: inline-block; vertical-align: bottom;">' .. result .. '</div>';
end
end
function p.formatPopulationClaimForGraph( context, options, statement )
local time = context.parseTimeFromSnak( statement.qualifiers.P585[1] );
local value = string.gsub( statement.mainsnak.datavalue.value.amount, '^%+', '' );
return os.date("*t", time / 1000).year .. ',' .. value;
end
function p.formatPopulationPropertyForTable( context, options )
local claims = formatPopulationPropertyImpl( context, options );
-- Обход всех заявлений утверждения и с накоплением оформленых предпочтительных
-- заявлений в таблице
local formattedClaims = {}
local firstTime = false;
local lastTime = '';
local count = 0;
if ( not claims ) then
return '';
end
for i, claim in ipairs(claims) do
-- обрезаем выводимую дату до года
claim = deepcopy( claim );
if ( claim.qualifiers.P585[1].datavalue.value.precision > 9 ) then
claim.qualifiers.P585[1].datavalue.value.precision = 9;
end
local time = context.formatSnak( options, claim.qualifiers.P585[1] );
local value = context.formatSnak( options, claim.mainsnak );
if ( not firstTime ) then firstTime = time end;
lastTime = time;
local line = '\n|-\n! ' .. time
line = line .. '\n| style="text-align: right; border-right: none;padding-right: 0;" | ' .. value;
line = line .. '\n| style="text-align: left; border-left: none;padding-left: 0;" | ' .. context.formatRefs( options, claim );
table.insert( formattedClaims, line )
count = count + 1;
end
if ( count == 0 ) then
return '';
end
local columns = options.columns or DEFAULT_COLUMNS;
if ( count < columns ) then
local out = '{| class="wikitable" \n|-\n! ' .. TABLE_COLUMN_HEADER_YEAR .. ' !! colspan=2 | ' .. TABLE_COLUMN_HEADER_POPULATION .. '\n|-';
for i, formattedClaim in ipairs(formattedClaims) do
out = out .. '\n' .. formattedClaim;
end
out = out .. '\n|}';
return out;
end
local out = '';
local perColumn = math.ceil( count / columns );
if ( perColumn > COLLAPSE_IF_ROWS_MORE_THAN ) then
local caption = mw.ustring.format( TABLE_COLLAPSIBLE_HEADER, firstTime, lastTime );
out = out .. '{| class="collapsible collapsed" |\n';
out = out .. '! colspan=' .. columns .. ' | ' .. caption .. '\n';
out = out .. '|-';
else
out = out .. '{| style="display: inline-block; vertical-align: bottom;" cellpadding=5 |';
end
for i, formattedClaim in ipairs(formattedClaims) do
if ( i % perColumn == 1 ) then
out = out .. '\n| align="center" valign="top" | \n{| class="wikitable" \n|-\n! ' .. TABLE_COLUMN_HEADER_YEAR .. ' !! colspan=2 | ' .. TABLE_COLUMN_HEADER_POPULATION .. '\n|-';
end
out = out .. '\n' .. formattedClaim;
if ( i % perColumn == 0 ) then
out = out .. '\n|}';
end
end
if ( count % perColumn ~= 0 ) then
out = out .. '\n|}';
end
out = out .. '\n|}';
return out
end
function p.formatPopulationClaimForTable( context, options, statement )
return '';
end
return p;