Module:PersonResearchOutcomesList
From MaRDI portal
Documentation for this module may be created at Module:PersonResearchOutcomesList/doc
-- Required module containing helper methods
local helper = require('Module:HelperMethods')
-- Required modules for SPARQL queries and HTML table generation
local sparql = require('SPARQL')
local mwHtml = require('mw.html')
-- Main table to hold all functions
local p = {}
-- Shared function to run the SPARQL query and return the data table
function p.fetchData(target1)
local baseUrl = mw.site.server
local sparqlQuery = [[
PREFIX target1: <https://portal.mardi4nfdi.de/entity/]] .. target1 .. [[>
PREFIX wdt: <https://portal.mardi4nfdi.de/prop/direct/>
PREFIX wd: <https://portal.mardi4nfdi.de/entity/>
SELECT
?publication_date ?work ?workLabel
?workUrl
(REPLACE(STR(?work), "^.*/", "") AS ?qid)
?item_type
?item_type_label
?zbmath_de_number
?journalLabel
?arxivId
?fullWorkUrl
WHERE {
?work wdt:P16 target1: .
VALUES ?allowedValues { wd:Q5976449 wd:Q5976450 wd:Q5984635 wd:Q6534216 }
?work wdt:P1460 ?allowedValues.
OPTIONAL {
?work wdt:P28 ?publication_datetime .
}
OPTIONAL {
?work wdt:P170 ?last_updated .
}
BIND(COALESCE(xsd:date(?publication_datetime), xsd:date(?last_updated), "N/A") AS ?publication_date)
OPTIONAL {
?work wdt:P1460 ?item_type .
BIND(REPLACE(STR(?item_type), "^.*/(Q[0-9]+)$", "$1") AS ?item_type_short)
BIND(IF(?item_type_short = "Q5976449", "Paper",
IF(?item_type_short = "Q5984635", "Dataset",
IF(?item_type_short = "Q6534216", "Workflow",
IF(?item_type_short = "Q5976450", "Software", "Other")))) AS ?item_type_label)
BIND(CONCAT(
IF(?item_type_short = "Q5976449", "]] .. baseUrl .. [[/wiki/Publication:",
IF(?item_type_short = "Q5984635", "]] .. baseUrl .. [[/wiki/Dataset:",
IF(?item_type_short = "Q6534216", "]] .. baseUrl .. [[/wiki/Workflow:",
IF(?item_type_short = "Q5976450", "]] .. baseUrl .. [[/wiki/Software:", "]] .. baseUrl .. [[/wiki/")))),
REPLACE(STR(?work), "^.*/Q", "")
) AS ?workUrl)
}
OPTIONAL {
?work wdt:P1451 ?zbmath_de_number .
}
OPTIONAL {
?work wdt:P200 ?journal .
}
OPTIONAL {
?work wdt:P21 ?arxivId .
}
OPTIONAL {
?work wdt:P205 ?fullWorkUrl .
}
SERVICE wikibase:label { bd:serviceParam wikibase:language "[AUTO_LANGUAGE],en". }
}
ORDER BY DESC(?publication_date)
]]
local jsonResults = sparql.runQuery(sparqlQuery)
if jsonResults and jsonResults.error then
mw.log("Error in SPARQL query: " .. tostring(jsonResults.error))
return nil
end
if not jsonResults then
return nil
end
if helper.countElementsInBindings(jsonResults.results.bindings) == 0 then
return nil
end
local fieldOrder = {"workUrl", "workLabel", "work", "publication_date", "qid", "item_type", "item_type_label", "zbmath_de_number", "journalLabel", "arxivId", "fullWorkUrl"}
return helper.convertJsonToTableOrdered(jsonResults, fieldOrder)
end
-- Entry point: returns only the publications table
function p.buildTableFromSparql(frame)
local target1 = frame.args[1]
if not target1 or target1 == '' then
return "No records found"
end
local dataTable = p.fetchData(target1)
if not dataTable then
return "No records found."
end
-- Replace URL labels (missing titles) with a readable fallback
for _, row in ipairs(dataTable) do
if row[2] and string.find(row[2], "https://") then
local zbmath_de_number = row[8] or nil
row[2] = helper.titleNotAvailableStr(zbmath_de_number)
end
end
-- Build table manually so we can add journal as second line
local tbl = mwHtml.create('table')
:addClass('wikitable sortable')
:attr('border', '1')
-- Header row
local header = tbl:tag('tr')
header:tag('th'):wikitext('Publication')
header:tag('th'):wikitext('Date of Publication')
header:tag('th'):wikitext('Type')
-- Data rows
-- fieldOrder: 1=workUrl, 2=workLabel, 3=work, 4=publication_date,
-- 5=qid, 6=item_type, 7=item_type_label, 8=zbmath_de_number, 9=journalLabel, 10=arxivId
for _, row in ipairs(dataTable) do
local url = row[1] or ""
local label = row[2] or ""
local date = row[4] or ""
local typeLabel = row[7] or ""
local rawJournal = row[9] or ""
local rawArxiv = row[10] or ""
local journal = mw.text.trim(tostring(rawJournal)):gsub(" ", ""):gsub(" ", "")
local arxivId = mw.text.trim(tostring(rawArxiv)):gsub(" ", ""):gsub(" ", "")
-- Treat URL-valued journal labels as empty
if journal:match("^https?://") then
journal = ""
end
-- Fall back to "arXiv preprint" if no journal but arXiv ID exists
if journal == "" and arxivId ~= "" then
journal = "(available as arXiv preprint)"
end
-- Also check P205 full work URL for arxiv.org
if journal == "" then
local fullWorkUrl = mw.text.trim(tostring(row[11] or ""))
if fullWorkUrl:find("://arxiv.org", 1, true) then
journal = "(available as arXiv preprint)"
end
end
-- Build publication cell content: linked title + optional journal line
local titleLink = "[" .. url .. " " .. label .. "]"
local cellContent = titleLink
if journal ~= "" and not string.find(journal, "https://") then
journal = journal:gsub("\\&", "&"):gsub("&", "&")
cellContent = cellContent .. "<br/><small><i>" .. journal .. "</i></small>"
end
local tr = tbl:tag('tr')
tr:tag('td'):wikitext(cellContent)
tr:tag('td'):wikitext(date)
tr:tag('td'):wikitext(typeLabel)
end
return mw.getCurrentFrame():preprocess(tostring(tbl))
end
-- Entry point: returns only the histogram chart
function p.buildChartFromSparql(frame)
local target1 = frame.args[1]
if not target1 or target1 == '' then
return nil
end
local height = frame.args[2] or '350px'
local width = frame.args[3] or '100%'
local dataTable = p.fetchData(target1)
if not dataTable then
return nil
end
local histogramChart = helper.generateHistogramChartFromTable(dataTable, 4)
-- Modern styling overrides
histogramChart.data.datasets[1].backgroundColor = 'rgba(192, 82, 42, 0.75)'
histogramChart.data.datasets[1].borderColor = 'rgba(192, 82, 42, 1)'
histogramChart.data.datasets[1].borderWidth = 0
histogramChart.data.datasets[1].borderRadius = 5
histogramChart.data.datasets[1].hoverBackgroundColor = 'rgba(192, 82, 42, 1)'
histogramChart.data.datasets[1].label = 'Publications'
histogramChart.options = {
responsive = true,
maintainAspectRatio = false,
layout = {
padding = { right = 0, left = 0 }
},
plugins = {
legend = { display = false }
},
scales = {
x = {
grid = { display = false },
ticks = { color = '#888', font = { size = 12 } },
offset = true
},
y = {
beginAtZero = true,
grid = { color = 'rgba(0,0,0,0.06)', drawBorder = false },
ticks = { color = '#888', font = { size = 12 }, precision = 0 }
}
}
}
local histogramChartJson = mw.text.jsonEncode(histogramChart)
local chartContainer = mw.html.create('div')
:addClass('wikiChartContainer')
:css('height', height)
:css('width', width)
:attr('data-chartdata', histogramChartJson)
return tostring(chartContainer)
end
-- Legacy entry point: original combined output (table + heading + chart)
-- Kept for backwards compatibility
function p.buildTableAndChartFromSparql(frame)
local target1 = frame.args[1]
if not target1 or target1 == '' then
return "No records found"
end
local height = frame.args[2] or '400px'
local width = frame.args[3] or '800px'
local dataTable = p.fetchData(target1)
if not dataTable then
return "No records found."
end
local headers = {"Publication", "Date of Publication", "Type"}
local htmlTable = helper.createHtmlTableWithMergedCols(dataTable, headers, {{1, 2}, {4}, {6, 7}})
local histogramChart = helper.generateHistogramChartFromTable(dataTable, 4)
local histogramChartJson = mw.text.jsonEncode(histogramChart)
local chartContainer = mw.html.create('div')
:addClass('wikiChartContainer')
:css('height', height)
:css('width', width)
:attr('data-chartdata', histogramChartJson)
local heading = mw.html.create('h2')
:wikitext('Research outcomes over time')
local parentContainer = mw.html.create('div')
:addClass('parent-container')
:css('width', width)
:node(htmlTable)
:node(heading)
:node(chartContainer)
return tostring(parentContainer)
end
return p