Module:Neuchâtel fossil cast
Jump to navigation
Jump to search
Lua
CodeDiscussionEditHistoryLinksLink count Subpages:DocumentationTestsResultsSandboxLive code All modules
Code behind {{Neuchâtel fossil cast}}
Usage
{{#invoke:Neuchâtel fossil cast|function_name}}
Code
--[[
= Module:Neuchâtel fossil cast =
Authors and maintainers:
* User:Jarekt
* User:Harej
]]
require('strict') -- used for debugging purposes as it detects cases of unintended global variables
local getLabel = require("Module:Wikidata label")._getLabel -- used for creation of name based on Wikidata
local labels = require("Module:I18n/artwork") -- internationalization of labels
local core = require('Module:Core')
local art = require('Module:Wikidata art')
local qualifierDate = require("Module:Wikidata date")._qualifierDate -- used for processing of date qualifiers
local institution = require("Module:Institution")._institution
local creator = require("Module:Creator")._creator
local information = require("Module:Information")._information
local p = {}
-- ===========================================================================
-- === Assemble wikidata query tools used by other modules ===================
-- ===========================================================================
-- ===========================================================================
local function getEntityLabel(entity, userLang)
local label
-- build language fallback list
local langList = mw.language.getFallbacksFor(userLang)
table.insert(langList, 1, userLang)
-- get label
for _, lang in ipairs(langList) do -- loop over language fallback list looking for label in the specific language
label = entity:getLabel(lang)
if label then break end -- label found and we are done
end
label = label or entity.id -- fallback value
return '[[:d:'.. entity.id ..'|'.. label ..']]'
end
-------------------------------------------------------------------------------
local function getBestProperties(entity, prop)
return core.parseStatements(entity:getBestStatements( prop ), nil)
end
-------------------------------------------------------------------------------
local function getProperty(entity, prop)
return (core.parseStatements(entity:getBestStatements( prop ), nil) or {nil})[1]
end
-------------------------------------------------------------------------------
local function getItemProperty(item, prop)
return (core.parseStatements(mw.wikibase.getBestStatements( item, prop ), nil) or {nil})[1]
end
-------------------------------------------------------------------------------
local function getItemProperties(item, prop)
return core.parseStatements(mw.wikibase.getBestStatements( item, prop ), nil)
end
-------------------------------------------------------------------------------
local function getPropertyByQual(entity, prop, qualID, qvalue, lang)
local Res = {}
if entity.claims and entity.claims[prop] then
for k, statement in ipairs( entity:getBestStatements( prop )) do
if (statement.mainsnak.snaktype == "value" and statement.qualifiers and statement.qualifiers[qualID]) then
local snak = statement.qualifiers[qualID][1]
if (snak.snaktype == "value" and snak.datatype == 'wikibase-item' and snak.datavalue.value.id == qvalue) then
return statement.mainsnak.datavalue.value
end
end
end
end
return ''
end
-------------------------------------------------------------------------------
local function getPropertyWithQual(entity, prop, qualifiers, lang)
local Res = {}
if entity.claims and entity.claims[prop] then
for k, statement in ipairs( entity:getBestStatements( prop )) do
local res, val = {}, nil -- table with fields: key, value, P... (qualifiers)
if (statement.mainsnak.snaktype == "value") then
val = statement.mainsnak.datavalue.value
if val.id then
val = val.id
elseif val.text then
res.value_lang = val.language
val = val.text
end
else
val = statement.mainsnak.snaktype
end
res.value = val
for iQual, qual in ipairs( qualifiers ) do
if statement.qualifiers and statement.qualifiers[qual] then
local snak = statement.qualifiers[qual][1]
if (snak.snaktype == "value" and snak.datatype == 'wikibase-item') then
val = snak.datavalue.value.id
elseif (snak.snaktype == "value" and snak.datatype == 'string') then
val = snak.datavalue.value
elseif (snak.snaktype == "value" and snak.datatype == 'time') then
val = qualifierDate(snak, lang).str
else
val = nil
end
res[qual] = val
end
end
table.insert(Res, res)
end
end
return Res
end
--------------------------------------------------------------------
local function scientific_name(item, lang)
-- Extract P225 (scientific name) and associated qualifiers: Extract P405 (discoverer) and P574 (time of discovery)
local taxon_info = {}
local name
local entity = mw.wikibase.getEntity(item)
local edit_str = core.editAtWikidata(item, 'P225') -- taxon name (P225)
local props = getPropertyWithQual(entity, 'P225', {'P405', 'P574'}, lang) -- P405 axon author, P574 year of taxon publication
for _, prop in ipairs(props) do
local val = '[[d:' .. item .. '|' .. prop.value .. ']]'
val = val or core.getLabel(item, lang)
if prop.P405 then
name = getItemProperty(prop.P405, 'P835') or getItemProperty(prop.P405, 'P734') -- author citation (zoology) or last name
if (name) then
name = '[[d:' .. prop.P405 .. '|' .. name .. ']]'
else
name = core.getLabel(prop.P405, lang)
end
taxon_info.discoverer = core.getLabel(prop.P405, lang)
end
if (name and prop.P574) then
taxon_info.specimen = "''" .. val .. "'' (".. name .. ', ' .. prop.P574 .. ')' .. edit_str
else
taxon_info.specimen = "''" .. val .. "''"
end
taxon_info.discovery_time = prop.P574
end
return taxon_info
end
--------------------------------------------------------------------
local function taxonChain(item, endRank)
local rank, visited_items = nil, {}
for iter = 1,10 do -- at maximum only 10 iterations are allowed
visited_items[item] = true -- early detection of loops
item = getItemProperty(item, 'P171')
if (not item) then
break -- stopping criteria: item is missing "parent taxon" property
end
rank = getItemProperty(item, 'P105')
if visited_items[item] or (rank==endRank) then
break -- stopping criteria: loop is detected or end-rank was found
end
end
if item and rank==endRank then
return item
end
end
--------------------------------------------------------------------
local function get_classification(item, lang)
local val = core.getLabel(item, lang)
local X = {}
local taxons = {'Q35409', 'Q37517', 'Q36602'} -- family -> class -> order
for _,taxon in ipairs(taxons) do
local item = taxonChain(item, taxon) -- find family
if item then
local id = core.getLabel(taxon, lang)
local lab = core.getLabel(item, lang)
table.insert(X, id .. ': ' .. lab )
else
break
end
end
if #X>0 then
return val .. ' (' .. table.concat(X,', ') .. ')'
else
return val
end
end
--------------------------------------------------------------------
local function timeChain(item, endStage)
local inst, item1
local ok = false
for _, item in ipairs(getItemProperties(item, 'P361')) do
if item ~= 'Q63463770' then -- not "ICS Standard Global Chronostratigraphic (Geochronologic) Scale"
item1 = item
ok = true
break
end
end
if (not ok) then
return nil
end
return item1
-- for _, inst in ipairs(getItemProperties(item, 'P31')) do
-- if inst == endStage then
-- return item
-- end
-- end
end
--------------------------------------------------------------------
local function timeChain2(item, endStage)
local ok = false
for _, item in ipairs(getItemProperties(item, 'P361')) do
if item ~= 'Q63463770' then -- not "ICS Standard Global Chronostratigraphic (Geochronologic) Scale"
ok = true
break
end
end
if (ok) then
return item
end
end
--------------------------------------------------------------------
local function timeChain1(item, endStage)
local rank, visited_items, ok, item1
visited_items = {}
for iter = 1,10 do -- at maximum only 10 iterations are allowed
ok = false
visited_items[item] = true -- early detection of loops
for _, item in ipairs(getItemProperties(item, 'P361')) do
if item ~= 'Q63463770' then -- not "ICS Standard Global Chronostratigraphic (Geochronologic) Scale"
ok = true
break
end
end
if (not ok) or visited_items[item] then
break -- stopping criteria: item is missing "part of" property, or a loop is detected
end
for _, item1 in ipairs(getItemProperties(item, 'P31')) do
if item1 == endStage then
return item
end
end
end
end
-- ===========================================================================
-- === Template specific code ================================================
-- ===========================================================================
local function read_cast_from_wikidata(cast_qid, data, lang)
-- the photographs are of fossil cast of specimens of organisms
local X, id
if not cast_qid then
return data
end
local entity = mw.wikibase.getEntity(cast_qid)
data.name = getEntityLabel(entity, lang) -- copy labels of the item to the top line
X = art.get_accession_number(entity, lang)
data.id = X.str -- wikitext version of the accession number
id = getProperty(entity, 'P195')
if id then
id = getItemProperty(id, 'P127')
if id=='Q121092336' then
id = 'Q3330885'
end
if id then
data.institution = institution({wikidata=id, lang=lang, collapse = 'collapsed'})
end
end
return data
end
-- ===========================================================================
local function read_specimen_from_wikidata(specimen_qid, data, lang)
local X, id, id1, val
if not specimen_qid then
return data
end
local entity = mw.wikibase.getEntity(specimen_qid)
X = art.get_creator(entity, 'P61', lang)
data.discoverer = X.str
data.references = art.get_references(entity, lang)
-- object_type
local props = getPropertyWithQual(entity, 'P31', {'P642'})
local edit_str = core.editAtWikidata(entity.id, 'P31', lang)
for _, prop in ipairs(props) do
data.type_status = core.getLabel(prop.value, lang) .. edit_str
if prop.P642 then -- Get taxon information via specimen
data.classification = get_classification(prop.P642, lang)
local taxon_info = scientific_name(prop.P642, lang)
data.specimen = taxon_info.specimen
data.discoverer = taxon_info.discoverer
data.discovery_time = taxon_info.discovery_time
end
end
-- discovery_place
id = getProperty(entity, 'P189')
if id then
id1 = getItemProperty(id, 'P17') -- country of discovery_place
val = core.getLabel(id, lang)
edit_str = core.editAtWikidata(entity.id, 'P189', lang)
if id1 then
data.discovery_place = val .. ' (' .. core.getLabel(id1, lang) .. ')' .. edit_str
elseif id then
data.discovery_place = val .. edit_str
end
end
-- time period (P2348)
-- TODO: output "Late Jurassic (period: Jurassic, epoch: Mesozoic)" seems to be in wrong order (pertiod then epoch). Why?
X ={}
local stages = {epoch='Q754897', period='Q392928'}
id = getProperty(entity, 'P2348')
if id then
val = core.getLabel(id, lang)
edit_str = core.editAtWikidata(entity.id, 'P2348', lang)
for _,stage in pairs(stages) do
id = timeChain(id, stage)
if id then
table.insert(X, core.getLabel(stage, lang) .. ': ' .. core.getLabel(id, lang))
else
break
end
end
if #X>0 then
data.time_period = val .. ' (' .. table.concat(X,', ') .. ')' ..edit_str
else
data.time_period = val .. edit_str
end
end
return data
end
-- ===========================================================================
local function header_insert(data, cast_qid, lang)
local field, tag, cell1, cell2, id
local top, results = {}, {}
if data.name then
table.insert(top, string.format('<span class="fn" id="artwork"><bdi>%s\n</bdi></span>', data.name ) )
table.insert(top, string.format('[[File:Wikidata-logo.svg|20px|wikidata:%s|link=wikidata:%s]]', cast_qid, cast_qid) )
table.insert(top, string.format('[[File:Wikidata-Reasonator_small_logo.svg|5px|reasonator:%s|link=https://reasonator.toolforge.org/test/?q=%s]]', cast_qid, cast_qid) )
cell1 = mw.ustring.format('<th colspan="2" style="background-color:#ccf; font-weight:bold; border:1px solid #aaa" lang="%s" text-align="center">%s</th>\n', lang, table.concat(top, ' '))
field = mw.ustring.format('<tr>\n%s\n</tr>\n\n', cell1)
table.insert(results, field)
end
return table.concat(results)
end
-- ===========================================================================
local function fossil_insert(data, cast_qid, lang)
local field, tag, cell1, cell2, id
-- field specific preferences
local params = {
{field='type_status' , tag='status'},
{field='specimen' , tag='specimen'},
{field='classification' , tag='Q11398'},
{field='time_period' , tag='P2348'},
{field='age' , tag='Q568683'},
{field='epoch' , tag='Q754897'},
{field='period' , tag='Q392928'},
{field='discoverer' , tag='wm-license-information-author', id='fileinfotpl_aut'},
{field='discovery_time' , tag='time_of_description'},
{field='discovery_place', tag='place_of_discovery', id='fileinfotpl_art_discovery_place'},
{field='institution' , tag='Q2668072', id='fileinfotpl_art_gallery'},
{field='id' , tag='wm-license-artwork-id', id='wm-license-artwork-id'},
{field='references' , tag='wm-license-artwork-references', id='fileinfotpl_art_references'},
}
local results = {}, {}
for _, param in ipairs(params) do
field = data[param.field]
tag = param.tag
if string.sub(tag,1,10) == 'wm-license' then
tag = mw.message.new( tag ):inLanguage(lang):plain() -- label message in lang language
elseif string.match(tag, "^[QP]%d+$") then
tag = getLabel(tag, lang, "-", "ucfirst")
elseif labels[tag] then
tag = core.langSwitch(labels[tag], lang)
else
tag = '('..tag..'/'..lang..')'
end
-- id = mw.ustring.format('id="%s" ', param.id)
if field then -- skip if no field
cell1 = mw.ustring.format('<td %sclass="fileinfo-paramfield" lang="%s">%s</td>\n', id or '', lang, tag)
cell2 = mw.ustring.format('<td>\n%s</td>', field or '')
field = mw.ustring.format('<tr>\n%s%s\n</tr>\n\n', cell1, cell2)
table.insert(results, field)
end
end
return table.concat(results)
end
-- ===========================================================================
function p.fossil(frame)
local args = core.getArgs(frame)
local lang = args.lang or 'en'
local data = {}
data = read_cast_from_wikidata(args.cast_qid, data, lang)
data = read_specimen_from_wikidata(args.specimen_qid, data, lang)
-- Build the fossil information output
args.other_fields_0 = header_insert(data, args.cast_qid, lang)
args.other_fields_1 = fossil_insert(data, args.cast_qid, lang)
args.strict = false
args.cast_qid = nil
args.specimen_qid = nil
args.permission = frame:expandTemplate{title="Muséum d'histoire naturelle de Neuchâtel"}
local results = information(args)
return results
end
-- ===========================================================================
function p.debug(frame)
local field = frame.args.field
local lang = frame.args.lang
local item = frame.args.item
if field=='scientific_name' then
return p.scientific_name(item, lang) or item
elseif field=='test' then
return 'test'
end
return ''
end
return p