User:TiagoLubiana/cell-ontology.js
Note: After publishing, you may have to bypass your browser's cache to see the changes.
- Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
- Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
- Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5.
// ==UserScript==
// @name Cell Ontology and UBERON Request Helper
// @namespace http://tampermonkey.net/
// @version 1.7
// @description Enhance Wikidata pages with quick access to formatted cell ontology and UBERON term requests
// @author You
// @match https://www.wikidata.org/wiki/Q*
// @grant none
// ==/UserScript==
(function() {
'use strict';
// Helper functions
function getItemId() {
return location.pathname.replace('/wiki/', '');
}
// Ensure OOjs UI is loaded
mw.loader.using('oojs-ui-core').done(function() {
$(function() {
// Only run this in the main namespace
if (mw.config.get('wgNamespaceNumber') === 0) {
const itemId = mw.config.get('wbEntityId'); // Get the current item ID
Promise.all([isSubclassOfCell(itemId), isSubclassOfAnatomicalEntity(itemId)]).then(([isCell, isAnatomicalEntity]) => {
if (isCell) {
addNTRButton(itemId, 'CL', createCLNTRBody);
addImageButton(itemId);
} else if (isAnatomicalEntity) {
addNTRButton(itemId, 'UBERON', createUberonNTRBody);
}
});
}
});
});
async function isSubclassOfCell(item) {
const query = `
ASK {
wd:${item} wdt:P279* wd:Q7868 .
}
`;
const url = 'https://query.wikidata.org/sparql?query=' + encodeURIComponent(query) + '&format=json';
try {
const response = await fetch(url);
const data = await response.json();
return data.boolean;
} catch (error) {
console.error('Error checking subclass of cell:', error);
return false;
}
}
async function isSubclassOfAnatomicalEntity(item) {
const query = `
ASK {
wd:${item} wdt:P279* wd:Q27043950 .
}
`;
const url = 'https://query.wikidata.org/sparql?query=' + encodeURIComponent(query) + '&format=json';
try {
const response = await fetch(url);
const data = await response.json();
return data.boolean;
} catch (error) {
console.error('Error checking subclass of anatomical entity:', error);
return false;
}
}
function addNTRButton(itemId, ontology, createNTRBody) {
var button = new OO.ui.ButtonWidget({
label: `Add a NTR to ${ontology}`,
flags: ['progressive'] // Optional: adds a visual cue that this is a primary action
});
button.on('click', function() {
fetchAndFormatData(itemId, ontology).then(result => displayFormattedResult(result, ontology, createNTRBody));
});
$('.mw-indicators').append(button.$element);
}
function addImageButton(itemId) {
var imageButton = new OO.ui.ButtonWidget({
label: 'Add image to CL',
flags: ['progressive'] // Optional: adds a visual cue that this is a primary action
});
imageButton.on('click', function() {
createImageIssueForCL(itemId);
});
$('.mw-indicators').append(imageButton.$element);
}
// Function to fetch image data
async function fetchCLIdAndImage(item) {
const query = `
SELECT ?cl_id ?image ?label WHERE {
wd:${item} wdtn:P7963 ?cl_id .
wd:${item} rdfs:label ?label .
FILTER(LANG(?label) = "en")
OPTIONAL { wd:${item} wdt:P18 ?image. }
}
`;
const url = 'https://query.wikidata.org/sparql?query=' + encodeURIComponent(query) + '&format=json';
try {
const response = await fetch(url);
const data = await response.json();
console.log('Data:', data.results.bindings);
return data.results.bindings;
} catch (error) {
console.error('Error fetching CL ID and image data:', error);
return [];
}
}
async function createImageIssueForCL(item) {
const results = await fetchCLIdAndImage(item);
if (results.length === 1 && results[0].image) {
// Construct the KGCL command
const kgclCommand = `\`\`\`
Hey ontobot! apply: - create edge ${results[0].cl_id.value} <http://xmlns.com/foaf/0.1/depicted_by> "${results[0].image.value}"^^xsd:anyURI
\`\`\``;
// Construct GitHub issue body
const body = `
**Request to add a new image axiom with KGCL**
**Wikidata item:** [${results[0].label.value}](https://www.wikidata.org/entity/${item})
**CL ID:** ${results[0].cl_id.value}
**Image URL:** ${results[0].image.value}
${kgclCommand}
**Additional notes or concerns:**
This request was autogenerated from Wikidata.
`;
const url = newGithubIssueUrl({
user: 'obophenotype',
repo: 'cell-ontology',
body: body,
title: `[KGCL] New Image Axiom Request for ${results[0].label.value}`,
labels: [`KGCL`, `ontobot`, `image+axiom+request`, `from+wikidata`]
});
window.open(url, '_blank');
} else if (results.length !== 1) {
alert('No unique CL match found for this item on Wikidata.');
} else {
alert('No image found for this item on Wikidata.');
}
}
async function fetchAndFormatData(item, ontology) {
const query = `
SELECT ?itemLabel (GROUP_CONCAT(DISTINCT ?itemAltLabel; separator = ", ") AS ?aliases)
(SAMPLE(?referenceTitle) AS ?referenceTitle) (SAMPLE(?pubMedID) AS ?pubMedID)
(GROUP_CONCAT(DISTINCT ?superclassLabel;separator=", ") AS ?superclasses)
(SAMPLE(?superclassUberonId) AS ?superclassUberonId)
(GROUP_CONCAT(DISTINCT ?clId;separator=", ") AS ?clIds)
(GROUP_CONCAT(DISTINCT ?anatomicalLocationLabel;separator=", ") AS ?anatomicalLocations)
(SAMPLE(?anatomicalUberonId) AS ?anatomicalUberonId)
?wikipediaUrl
WHERE {
BIND(wd:${item} AS ?item)
OPTIONAL { ?item skos:altLabel ?itemAltLabel. FILTER(LANG(?itemAltLabel) = "en") }
?item p:P31 ?statement.
?statement ps:P31 ?whatever.
OPTIONAL {
?statement prov:wasDerivedFrom ?ref.
?ref pr:P248 ?reference.
?reference rdfs:label ?referenceTitle. FILTER(LANG(?referenceTitle) = "en")
OPTIONAL { ?reference wdt:P698 ?pubMedID. }
}
OPTIONAL {
?item wdt:P279 ?superclass.
?superclass rdfs:label ?superclassLabel. FILTER(LANG(?superclassLabel) = "en")
OPTIONAL { ?superclass wdt:P1554 ?superclassUberonId. }
OPTIONAL { ?superclass wdt:P7963 ?clId. }
}
OPTIONAL {
?item wdt:P927 ?anatomicalLocation.
?anatomicalLocation rdfs:label ?anatomicalLocationLabel. FILTER(LANG(?anatomicalLocationLabel) = "en")
OPTIONAL { ?anatomicalLocation wdt:P1554 ?anatomicalUberonId. }
}
OPTIONAL {
?wikipediaUrl schema:about ?item;
schema:inLanguage "en";
schema:isPartOf <https://en.wikipedia.org/>.
}
SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}
GROUP BY ?itemLabel ?wikipediaUrl
`;
const url = 'https://query.wikidata.org/sparql?query=' + encodeURIComponent(query) + '&format=json';
try {
const response = await fetch(url);
const data = await response.json();
return data.results.bindings[0] || {};
} catch (error) {
console.error('Error fetching data:', error);
return {};
}
}
// Adapted from https://github.com/sindresorhus/new-github-issue-url/tree/main
function newGithubIssueUrl(options = {}) {
let repoUrl = `https://github.com/${options.user}/${options.repo}`;
const url = new URL(`${repoUrl}/issues/new`);
const types = ['body', 'title', 'labels', 'template', 'milestone', 'assignee', 'projects'];
for (const type of types) {
let value = options[type];
if (value === undefined) {
continue;
}
if (type === 'labels' || type === 'projects') {
if (!Array.isArray(value)) {
console.error(`The \`${type}\` option should be an array`);
continue;
}
value = value.join(',');
}
url.searchParams.set(type, value);
}
return url.toString();
}
function displayFormattedResult(result, ontology, createNTRBody) {
const { itemLabel, aliases, referenceTitle, pubMedID, superclasses, superclassUberonId, clIds, anatomicalLocations, anatomicalUberonId, wikipediaUrl } = result;
const item = getItemId();
const wikidataLink = `https://www.wikidata.org/wiki/${item}`;
const clIdsArray = clIds ? clIds.value.split(', ') : [];
const formattedClIds = clIdsArray.map(id => `[${id}](http://purl.obolibrary.org/obo/${id.replace(':', '_')})`).join(', ');
const formattedSuperclassUberonId = superclassUberonId ? `[UBERON:${superclassUberonId.value.replace(':', '_')}](http://purl.obolibrary.org/obo/UBERON_${superclassUberonId.value.replace(':', '_')})` : 'N/A';
const formattedAnatomicalUberonId = anatomicalUberonId ? `[UBERON:${anatomicalUberonId.value.replace(':', '_')}](http://purl.obolibrary.org/obo/UBERON_${anatomicalUberonId.value.replace(':', '_')})` : 'N/A';
const formattedPubMedID = pubMedID ? `[PMID:${pubMedID.value}](https://pubmed.ncbi.nlm.nih.gov/${pubMedID.value})` : '';
const body = createNTRBody({
itemLabel: itemLabel ? itemLabel.value : 'N/A',
aliases: aliases ? aliases.value : 'None',
referenceTitle: referenceTitle ? referenceTitle.value : 'No reference found',
pubMedID: formattedPubMedID,
superclasses: superclasses ? superclasses.value : 'N/A',
superclassUberonId: formattedSuperclassUberonId,
clIds: formattedClIds,
anatomicalLocations: anatomicalLocations ? anatomicalLocations.value : 'N/A',
anatomicalUberonId: formattedAnatomicalUberonId,
wikipediaUrl: wikipediaUrl ? wikipediaUrl.value : 'No reference found',
wikidataLink: wikidataLink
});
const url = newGithubIssueUrl({
user: 'obophenotype',
repo: ontology === 'CL' ? 'cell-ontology' : 'uberon',
body: body,
title: `[NTR] New Term Request: ${itemLabel ? itemLabel.value : ''}`,
labels: [`new+term+request`, `from+wikidata`]
});
window.open(url, '_blank');
}
function createCLNTRBody({itemLabel, aliases, referenceTitle, pubMedID, superclasses, clIds, anatomicalLocations, anatomicalUberonId, wikipediaUrl, wikidataLink}) {
return `**Preferred term label**
*${itemLabel}*
**Synonyms**
${aliases}
**Definition**
A ${superclasses} that... **FILL HERE**
References:
${referenceTitle}
${pubMedID}
${wikipediaUrl}
**Parent cell type term**
${superclasses}
CL IDs: ${clIds}
**Anatomical structure where the cell type is found**
${anatomicalLocations}
Uberon IDs: ${anatomicalUberonId}
**Your ORCID**
https://orcid.org/0000-0003-2473-2313
**Additional notes or concerns**
The draft for this request was autogenerated from Wikidata. For more details, see the [Wikidata item](${wikidataLink}) or the [source script](https://www.wikidata.org/wiki/User:TiagoLubiana/cell-ontology.js).
`;
}
function createUberonNTRBody({itemLabel, aliases, referenceTitle, pubMedID, superclasses, superclassUberonId, anatomicalLocations, anatomicalUberonId, wikipediaUrl, wikidataLink}) {
return `**Preferred term label:**
*${itemLabel}*
**Synonyms**
${aliases}
**Definition**
${pubMedID}
**Parent term**
${superclasses}
UBERON ID: ${superclassUberonId}
**Anatomical structure where the term is found**
${anatomicalLocations}
UBERON ID: ${anatomicalUberonId}
**Your nano-attribution**
https://orcid.org/0000-0003-2473-2313
**Link back to Wikidata item**
${wikidataLink}
`;
}
})();