Module:Model: Difference between revisions
From MaRDI portal
EloiFerrer (talk | contribs) No edit summary |
EloiFerrer (talk | contribs) No edit summary |
||
| Line 152: | Line 152: | ||
-- Convert the JSON results into a Lua table | -- Convert the JSON results into a Lua table | ||
local fieldOrder = {" | local fieldOrder = {"item", "itemLabel"} | ||
local dataTable = helper.convertJsonToTableOrdered(jsonResults, fieldOrder) | local dataTable = helper.convertJsonToTableOrdered(jsonResults, fieldOrder) | ||
Revision as of 11:26, 13 August 2025
Documentation for this module may be created at Module:Model/doc
-- Required modules for SPARQL queries and HTML table generation
-- Module for executing SPARQL queries
local sparql = require('SPARQL')
-- Required module containing helper methods
local helper = require('Module:HelperMethods')
-- MediaWiki library for logging and utilities
local mw = require('mw')
local json = require("mw.text")
-- Main table to hold all functions
local p = {}
------------------------------- Helper Functions -------------------------------
function p.convertJsonToTable(jsonResults)
local resultsTable = {}
if jsonResults and jsonResults.results and jsonResults.results.bindings then
local bindings = jsonResults.results.bindings
for j=0, #bindings do
local row = {}
for key, value in pairs(bindings[j]) do
table.insert(row, value.value)
end
table.insert(resultsTable, row)
end
end
return resultsTable
end
------------------------------- Helper Functions -------------------------------
-- Function to get Computational Tasks
function p.getComputationalTasks(frame)
local entityId = frame.args[1]
-- Validate input parameter
if not entityId or entityId == '' then
return "Error: No entity ID provided"
end
-- Constructing the SPARQL query with dynamic entity entityId
-- P147: used by property id
-- P146: series ordinal property id
local sparqlQuery = [[
PREFIX entityId: <https://portal.mardi4nfdi.de/entity/]] .. entityId .. [[>
SELECT ?URL ?Label ?Ordinal
WHERE {
entityId: p:P147 ?statement.
?statement ps:P147 ?URL.
OPTIONAL { ?statement pq:P146 ?Ordinal. }
?URL rdfs:label ?Label.
}
ORDER BY ASC(xsd:integer(COALESCE(?Ordinal, 9999)))
]]
-- local sparqlQuery = [[
-- PREFIX entityId: <https://portal.mardi4nfdi.de/entity/]] .. entityId .. [[>
-- SELECT ?URL ?URLLabel ?nextURL ?nextURLLabel
-- WHERE {
-- entityId: p:P147 ?statement.
-- ?statement ps:P147 ?URL.
-- OPTIONAL { ?statement pq:P146 ?Ordinal. }
-- OPTIONAL { ?statement pq:P581 ?nextURL. }
-- SERVICE wikibase:label {
-- bd:serviceParam wikibase:language "[AUTO_LANGUAGE],en". }
-- }
-- ORDER BY ASC(xsd:integer(COALESCE(?Ordinal, 9999)))
-- ]]
-- Executing the SPARQL query and retrieving results in JSON format
local jsonResults = sparql.runQuery(sparqlQuery)
-- Validate results
if not jsonResults or not jsonResults.results or not jsonResults.results.bindings then
return "No computational task found"
end
local computationalTasks = {}
-- Get the number of computational tasks
local totalCompTasks = #jsonResults.results.bindings
-- Loop through the bindings
for index = 0, totalCompTasks do
local item = jsonResults.results.bindings[index]
if not item.Label.value then
return "Error: Missing item.Label.value"
elseif not item.URL.value then
return "Error: Missing item.URL.value"
else
local label = item.Label.value
local url = item.URL.value
local numericId = url:match("Q(%d+)")
local urlRendered = "https://portal.mardi4nfdi.de/wiki/Task:" .. numericId
local labelWithUrl = string.format('[%s %s]', tostring(urlRendered), tostring(label))
local ordinal = item.Ordinal and item.Ordinal.value or nil
local prefix = ordinal and (ordinal .. ". ") or ""
table.insert(computationalTasks, "| " .. prefix .. labelWithUrl)
-- if item.nextURL then
-- local nexturl = item.nextURL.value
-- local nextnumericId = nexturl:match("Q(%d+)")
-- local nextLabel = item.nextURLLabel.value
-- local nexturlRendered = "https://portal.mardi4nfdi.de/wiki/Task:" .. nextnumericId
-- local nextLabelWithUrl = string.format('[%s %s]', tostring(nexturlRendered), tostring(nextLabel))
-- table.insert(computationalTasks, "| " .. labelWithUrl .. " followed by " .. nextLabelWithUrl)
-- else
-- table.insert(computationalTasks, "| " .. labelWithUrl)
-- end
end
end
-- Construct the Wikitext table
local wikitextTable = "{| class='wikitable'\n" .. table.concat(computationalTasks, "\n|-\n") .. "\n|}"
return wikitextTable
end
-- Function to get full list of Models
function p.getModels(frame)
local height = frame.args[1] or '400px' -- Default height if not specified
local width = frame.args[2] or '800px' -- Default width if not specified
-- Q68663 refers to mathematical model
-- Q6534265 refers to MathModDB community
local sparqlQuery = [[
SELECT ?item ?itemLabel
WHERE {
?item wdt:P31 wd:Q68663;
wdt:P1495 wd:Q6534265 .
?item rdfs:label ?itemLabel .
FILTER(LANG(?itemLabel) = "en")
}
ORDER BY ASC(?itemLabel)
]]
local jsonResults = sparql.runQuery(sparqlQuery)
-- Handle error in SPARQL query execution
if jsonResults and jsonResults.error then
mw.log("Error in SPARQL query: " .. tostring(jsonResults.error))
return nil
end
if not jsonResults then
return "Could not fetch data."
end
if helper.countElementsInBindings(jsonResults.results.bindings) == 0 then
return "No records found."
end
-- Convert the JSON results into a Lua table
local fieldOrder = {"item", "itemLabel"}
local dataTable = helper.convertJsonToTableOrdered(jsonResults, fieldOrder)
-- Create and return HTML table from the data
local headers = {"Model"}
local htmlTable = helper.createHtmlTableWithMergedCols(dataTable, headers, {{1, 2}})
-- Create a parent container for the table
local parentContainer = mw.html.create('div')
:addClass('parent-container')
:css('width', width)
local heading = mw.html.create('h2')
:wikitext('List of mathematical models')
-- Add the table and chart to the parent container
parentContainer
:node(htmlTable)
:node(heading)
return tostring(parentContainer)
end
-- Function to get Formulations with Quantities
function p.getFormulationsWithQuantities(frame)
local entityId = frame.args[1]
-- Validate input parameter
if not entityId or entityId == '' then
return "Error: No entity ID provided"
end
-- Constructing the SPARQL query with dynamic entity entityId
-- P1560: contains property id
-- P989: defining formula property id
local sparqlQuery = [[
PREFIX entityId: <https://portal.mardi4nfdi.de/entity/]] .. entityId .. [[>
SELECT ?Formula ?defining_formulation ?IDFormula
WHERE {
entityId: wdt:P1560 ?IDFormula.
OPTIONAL { ?IDFormula rdfs:label ?Formula. }
OPTIONAL { ?IDFormula wdt:P989 ?defining_formulation. }
}
]]
-- Executing the SPARQL query and retrieving results in JSON format
local jsonResults = sparql.runQuery(sparqlQuery)
-- Validate results
if not jsonResults or not jsonResults.results or not jsonResults.results.bindings then
return "\"No mathematical expressions found.\""
end
-- local resultTable = p.convertJsonToTable(jsonResults)
-- return "<pre>" .. mw.text.nowiki(json.jsonEncode(resultTable)) .. "</pre>"
-- local jsonString = mw.text.jsonEncode(jsonResults)
-- return "<pre>" .. mw.text.nowiki(jsonString) .. "</pre>"
return p.extractDefiningFormulationsWithQuantities(jsonResults)
end
-- Function to extract Formulations with Quantities
function p.extractDefiningFormulationsWithQuantities(jsonResults)
local frame = mw.getCurrentFrame()
-- Table to store formulations
local formulations = {}
-- Table to store quantity symbol and name id
local quantitySymbolNameIdPairs = {}
local jsonString = mw.text.jsonEncode(jsonResults)
-- Decode the JSON string into a Lua table
local data = mw.text.jsonDecode(jsonString)
-- Get the number of mathematical formulations
local totalFormulations = #data.results.bindings
if totalFormulations > 0 then
-- Loop through the bindings
for index = 1, totalFormulations do
local item = data.results.bindings[index]
local equationLabel = item.Formula.value
local equationIDURL = item.IDFormula.value
local equationID = equationIDURL:match(".*/(.-)$") or equationIDURL -- Extracts the part after the last '/'
local numericId = equationID:sub(2) -- remove "Q" to get "6674540"
local urlRendered = "https://portal.mardi4nfdi.de/wiki/Formula:" .. numericId
local equationWithUrl = string.format('[%s %s]', tostring(urlRendered), tostring(equationLabel))
local equation = mw.wikibase.getEntity(equationID)
-- P989 refers to property defining formula
local definingFormula = equation:getBestStatements('P989')
if definingFormula and #definingFormula > 0 then
local value = definingFormula[1].mainsnak.datavalue.value
mathTag = frame:extensionTag{
name = "math",
content = value
}
-- width is set below to 1200px
-- the percentage below refer to 40% of 1200px and 60% of 1200px to define width
-- for the first and the second column accordingly
table.insert(formulations,
string.format('| style="width:40%%;" | %s || style="width:60%%;" | %s', equationWithUrl, mathTag))
else
table.insert(formulations, "| " .. equationWithUrl)
end
quantitySymbolNameIdPairs = p.extractQuantities(equationID)
if type(quantitySymbolNameIdPairs) == "table" then
-- Accessing the stored pairs
for i, pair in ipairs(quantitySymbolNameIdPairs) do
local pairFirstValue = pair[1]
local pairFirstValue = mw.text.decode(pairFirstValue or "")
local quantitySymbolMathTag = frame:extensionTag{
name = "math",
content = pairFirstValue
}
-- Construct the Portal URL
local url = "https://portal.mardi4nfdi.de/wiki/Quantity:"
local numericId = pair[3]:sub(2) -- remove "Q" to get "6674540"
local fullUrl = url .. numericId
local labelWithUrl = string.format('[%s %s]', tostring(fullUrl), tostring(pair[2]))
table.insert(formulations, "| " .. quantitySymbolMathTag .. " symbol represents " .. labelWithUrl)
end
table.insert(formulations, "| " .. " " )
else
-- Error: extractQuantities did not return a table"
end
end
-- Construct the Wikitext table
local wikitextTable = [[
{| class="wikitable" style="table-layout: fixed; width: 1200px;"
]] .. table.concat(formulations, "\n|-\n") .. "\n|}"
return wikitextTable
else
return "No mathematical expressions found."
end
end
function p.extractQuantities(qid)
-- Property ID for in defining formula
local pidInDefiningFormula = "P983"
-- Property ID for the (qualifier) symbol represents
local pidSymbolRepresents = "P984"
-- Attempt to retrieve entity data
local entity = mw.wikibase.getEntity(qid)
if not entity or not entity.claims[pidInDefiningFormula] then
return "No formulation found"
end
local inDefiningFormulaClaims = entity.claims[pidInDefiningFormula]
local count = 0
-- Table to store pairs of quantity symbol and quantity name
local quantitySymbolNameIdPairs = {}
for _ in pairs(inDefiningFormulaClaims or {}) do
count = count + 1
-- Get the quantity symbol
local quantitySymbol = inDefiningFormulaClaims[count].mainsnak.datavalue.value
if not quantitySymbol then
return "No valid symbol found"
end
quantity = inDefiningFormulaClaims[count].qualifiers[pidSymbolRepresents][1].datavalue.value.text
quantityId = inDefiningFormulaClaims[count].qualifiers[pidSymbolRepresents][1].datavalue.value.id
local quantityName = mw.wikibase.label(quantityId)
-- Insert pair into the table
table.insert(quantitySymbolNameIdPairs, {quantitySymbol, quantityName, quantityId})
end
return quantitySymbolNameIdPairs
end
function p.getImageWithLegend(frame)
-- Property ID for the local image
local pidLocalImage = "P1640"
-- Property ID for the (qualifier) media legend
local pidMediaLegend = "P401"
local defaultLegend = "No legend available."
local entityId = frame.args[1]
-- Validate input parameter
if not entityId or entityId == '' then
return "Error: No entity ID provided"
end
-- Attempt to retrieve entity data
local entity = mw.wikibase.getEntity(entityId)
local imageClaims = entity.claims[pidLocalImage]
local imageStrings = {}
if imageClaims and type(imageClaims) == "table" then
local numClaims = #imageClaims
-- Loop through the image claims
for index = 1, numClaims do
-- Extract the image filename
local imageFilename = imageClaims[index].mainsnak.datavalue.value
local imageLegend = imageClaims[index].qualifiers[pidMediaLegend][1].datavalue.value.text
-- Add this image line to the list
table.insert(imageStrings, string.format("[[File:%s|thumb|470px|%s]]", imageFilename, imageLegend))
if index < numClaims then
-- spacer column
table.insert(imageStrings, ' ')
end
end
-- Combine all image cells into one row of a wikitable
local imageTable = '{| class="wikitable"\n| ' .. table.concat(imageStrings, ' || ') .. '\n|}'
return imageTable .. "\n\n"
else
return " "
end
end
-- Function to get specialized Research Models
function p.getSpecializedModels(frame)
local entityId = frame.args[1]
-- Validate input parameter
if not entityId or entityId == '' then
return "Error: No entity ID provided"
end
-- Constructing the SPARQL query with dynamic entity entityId
-- P1684: specialized by property id
local sparqlQuery = [[
PREFIX entityId: <https://portal.mardi4nfdi.de/entity/]] .. entityId .. [[>
SELECT ?URL ?Label
WHERE {
entityId: wdt:P1684 ?URL.
?URL rdfs:label ?Label
}
]]
-- Executing the SPARQL query and retrieving results in JSON format
local jsonResults = sparql.runQuery(sparqlQuery)
-- Validate results
if not jsonResults or not jsonResults.results or not jsonResults.results.bindings then
return "No specialized research fields found"
end
local specializedModels = {}
-- Get the number of specialized research fields
local totalSpecModels = #jsonResults.results.bindings
-- Loop through the bindings
for index = 0, totalSpecModels do
local item = jsonResults.results.bindings[index]
if not item.Label.value then
return "Error: Missing item.Label.value"
elseif not item.URL.value then
return "Error: Missing item.URL.value"
else
local label = item.Label.value
local url = item.URL.value
local numericId = url:match("Q(%d+)")
local urlRendered = "https://portal.mardi4nfdi.de/wiki/Model:" .. numericId
local labelWithUrl = string.format('[%s %s]', tostring(urlRendered), tostring(label))
table.insert(specializedModels, "| " .. labelWithUrl)
end
end
-- Construct the Wikitext table
local wikitextTable = "{| class='wikitable'\n" .. table.concat(specializedModels, "\n|-\n") .. "\n|}"
return wikitextTable
end
return p