App Domain Pathway Prediction (#47)

Co-authored-by: Tim Lorsbach <tim@lorsba.ch>
Reviewed-on: enviPath/enviPy#47
This commit is contained in:
2025-08-19 02:53:56 +12:00
parent 3308d47071
commit c3c1d4f5cf
9 changed files with 424 additions and 178 deletions

View File

@ -638,3 +638,147 @@ function fillPRCurve(modelUri, onclick){
});
}
function handleAssessmentResponse(depict_url, data) {
var inside_app_domain = "<a class='list-group-item'>This compound is " + (data["assessment"]["inside_app_domain"] ? "inside" : "outside") + " the Applicability Domain derived from the chemical (PCA) space constructed using the training data." + "</a>";
var functionalGroupsImgSrc = null;
var reactivityCentersImgSrc = null;
if (data['assessment']['node'] !== undefined) {
functionalGroupsImgSrc = "<img width='400' src='" + data['assessment']['node']['image'] + "'>";
reactivityCentersImgSrc = "<img width='400' src='" + data['assessment']['node']['image'] + "'>"
} else {
functionalGroupsImgSrc = "<img width='400' src=\"" + depict_url + "?smiles=" + encodeURIComponent(data['assessment']['smiles']) + "\">";
reactivityCentersImgSrc = "<img width='400' src=\"" + depict_url + "?smiles=" + encodeURIComponent(data['assessment']['smiles']) + "\">"
}
tpl = `<div class="panel panel-default panel-heading list-group-item" style="background-color:silver">
<h4 class="panel-title">
<a id="app-domain-assessment-functional-groups-link" data-toggle="collapse" data-parent="#app-domain-assessment" href="#app-domain-assessment-functional-groups">Functional Groups Covered by Model</a>
</h4>
</div>
<div id="app-domain-assessment-functional-groups" class="panel-collapse collapse">
<div class="panel-body list-group-item">
${inside_app_domain}
<p></p>
<div id="image-div" align="center">
${functionalGroupsImgSrc}
</div>
</div>
</div>
<div class="panel panel-default panel-heading list-group-item" style="background-color:silver">
<h4 class="panel-title">
<a id="app-domain-assessment-reactivity-centers-link" data-toggle="collapse" data-parent="#app-domain-assessment" href="#app-domain-assessment-reactivity-centers">Reactivity Centers</a>
</h4>
</div>
<div id="app-domain-assessment-reactivity-centers" class="panel-collapse collapse">
<div class="panel-body list-group-item">
<div id="image-div" align="center">
${reactivityCentersImgSrc}
</div>
</div>
</div>`
var transformations = '';
for (t in data['assessment']['transformations']) {
transObj = data['assessment']['transformations'][t];
var neighbors = '';
for (n in transObj['neighbors']) {
neighObj = transObj['neighbors'][n];
var neighImg = "<img width='100%' src='" + transObj['rule']['url'] + "?smiles=" + encodeURIComponent(neighObj['smiles']) + "'>";
var objLink = `<a class='list-group-item' href="${neighObj['url']}">${neighObj['name']}</a>`
var neighPredProb = "<a class='list-group-item'>Predicted probability: " + neighObj['probability'].toFixed(2) + "</a>";
var pwLinks = '';
for (pw in neighObj['related_pathways']) {
var pwObj = neighObj['related_pathways'][pw];
pwLinks += "<a class='list-group-item' href=" + pwObj['url'] + ">" + pwObj['name'] + "</a>";
}
var expPathways = `
<div class="panel panel-default panel-heading list-group-item" style="background-color:silver">
<h4 class="panel-title">
<a id="transformation-${t}-neighbor-${n}-exp-pathway-link" data-toggle="collapse" data-parent="#transformation-${t}-neighbor-${n}" href="#transformation-${t}-neighbor-${n}-exp-pathway">Experimental Pathways</a>
</h4>
</div>
<div id="transformation-${t}-neighbor-${n}-exp-pathway" class="panel-collapse collapse">
<div class="panel-body list-group-item">
${pwLinks}
</div>
</div>
`
if (pwLinks === '') {
expPathways = ''
}
neighbors += `
<div class="panel panel-default panel-heading list-group-item" style="background-color:silver">
<h4 class="panel-title">
<a id="transformation-${t}-neighbor-${n}-link" data-toggle="collapse" data-parent="#transformation-${t}" href="#transformation-${t}-neighbor-${n}">Analog Transformation on ${neighObj['name']}</a>
</h4>
</div>
<div id="transformation-${t}-neighbor-${n}" class="panel-collapse collapse">
<div class="panel-body list-group-item">
${objLink}
${neighPredProb}
${expPathways}
<p></p>
<div id="image-div" align="center">
${neighImg}
</div>
</div>
</div>
`
}
var panelName = null;
var objLink = null;
if (transObj['is_predicted']) {
panelName = `Predicted Transformation by ${transObj['rule']['name']}`;
objLink = `<a class='list-group-item' href="${transObj['edge']['url']}">${transObj['edge']['name']}</a>`
} else {
panelName = `Potential Transformation by applying ${transObj['rule']['name']}`;
objLink = `<a class='list-group-item' href="${transObj['rule']['url']}">${transObj['rule']['name']}</a>`
}
var predProb = "<a class='list-group-item'>Predicted probability: " + transObj['probability'].toFixed(2) + "</a>";
var timesTriggered = "<a class='list-group-item'>This rule has triggered " + transObj['times_triggered'] + " times in the training set</a>";
var reliability = "<a class='list-group-item'>Reliability: " + transObj['reliability'].toFixed(2) + " (" + (transObj['reliability'] > data['ad_params']['reliability_threshold'] ? "&gt" : "&lt") + " Reliability Threshold of " + data['ad_params']['reliability_threshold'] + ") </a>";
var localCompatibility = "<a class='list-group-item'>Local Compatibility: " + transObj['local_compatibility'].toFixed(2) + " (" + (transObj['local_compatibility'] > data['ad_params']['local_compatibilty_threshold'] ? "&gt" : "&lt") + " Local Compatibility Threshold of " + data['ad_params']['local_compatibilty_threshold'] + ")</a>";
var transImg = "<img width='100%' src='" + transObj['rule']['url'] + "?smiles=" + encodeURIComponent(data['assessment']['smiles']) + "'>";
var transformation = `
<div class="panel panel-default panel-heading list-group-item" style="background-color:silver">
<h4 class="panel-title">
<a id="transformation-${t}-link" data-toggle="collapse" data-parent="#transformation-${t}" href="#transformation-${t}">${panelName}</a>
</h4>
</div>
<div id="transformation-${t}" class="panel-collapse collapse">
<div class="panel-body list-group-item">
${objLink}
${predProb}
${timesTriggered}
${reliability}
${localCompatibility}
<p></p>
<div id="image-div" align="center">
${transImg}
</div>
<p></p>
${neighbors}
</div>
</div>
`
transformations += transformation;
}
res = tpl + transformations;
$("#appDomainAssessmentResultTable").append(res);
}

View File

@ -1,4 +1,4 @@
console.log("loaded")
console.log("loaded pw.js")
function predictFromNode(url) {
@ -144,6 +144,16 @@ function draw(pathway, elem) {
function node_popup(n) {
popupContent = "<a href='" + n.url +"'>" + n.name + "</a><br>";
popupContent += "Depth " + n.depth + "<br>"
if (appDomainViewEnabled) {
if(n.app_domain != null) {
popupContent += "This compound is " + (n.app_domain['inside_app_domain'] ? "inside" : "outside") + " the Applicability Domain derived from the chemical (PCA) space constructed using the training data." + "<br>"
if (n.app_domain['uncovered_functional_groups']) {
popupContent += "Compound contains functional groups not covered by the training set <br>"
}
}
}
popupContent += "<img src='" + n.image + "' width='"+ 20 * nodeRadius +"'><br>"
if (n.scenarios.length > 0) {
popupContent += '<b>Half-lives and related scenarios:</b><br>'
@ -162,6 +172,18 @@ function draw(pathway, elem) {
function edge_popup(e) {
popupContent = "<a href='" + e.url +"'>" + e.name + "</a><br>";
if(e.app_domain){
adcontent = "<p>";
if(e.app_domain["times_triggered"]) {
adcontent += "This rule triggered " + e.app_domain["times_triggered"] + " times in the training set<br>";
}
adcontent += "Reliability " + e.app_domain["reliability"].toFixed(2) + " (" + (e.app_domain["reliability"] > e.app_domain["reliability_threshold"] ? "&gt" : "&lt") + " Reliability Threshold of " + e.app_domain["reliability_threshold"] + ")<br>";
adcontent += "Local Compatibility " + e.app_domain["local_compatibility"].toFixed(2) + " (" + (e.app_domain["local_compatibility"] > e.app_domain["local_compatibility_threshold"] ? "&gt" : "&lt") + " Local Compatibility Threshold of " + e.app_domain["local_compatibility_threshold"] + ")<br>";
adcontent += "</p>";
}
popupContent += adcontent;
popupContent += "<img src='" + e.image + "' width='"+ 20 * nodeRadius +"'><br>"
if (e.reaction_probability) {
popupContent += '<b>Probability:</b><br>' + e.reaction_probability.toFixed(3) + '<br>';
@ -233,13 +255,12 @@ function draw(pathway, elem) {
.enter().append("line")
// Check if target is pseudo and draw marker only if not pseudo
.attr("class", d => d.target.pseudo ? "link_no_arrow" : "link")
// .on("mouseover", (event, d) => {
// tooltip.style("visibility", "visible")
// .text(`Link: ${d.source.id} → ${d.target.id}`)
// .style("top", `${event.pageY + 5}px`)
// .style("left", `${event.pageX + 5}px`);
// })
// .on("mouseout", () => tooltip.style("visibility", "hidden"));
.attr("marker-end", d => d.target.pseudo ? '' : 'url(#arrow)')
// add element to links array
link.each(function(d) {
d.el = this; // attach the DOM element to the data object
});
pop_add(link, "Reaction", edge_popup);
@ -255,16 +276,6 @@ function draw(pathway, elem) {
.on("click", function (event, d) {
d3.select(this).select("circle").classed("highlighted", !d3.select(this).select("circle").classed("highlighted"));
})
// .on("mouseover", (event, d) => {
// if (d.pseudo) {
// return
// }
// tooltip.style("visibility", "visible")
// .text(`Node: ${d.id} Depth: ${d.depth}`)
// .style("top", `${event.pageY + 5}px`)
// .style("left", `${event.pageX + 5}px`);
// })
// .on("mouseout", () => tooltip.style("visibility", "hidden"));
// Kreise für die Knoten hinzufügen
node.append("circle")
@ -280,5 +291,10 @@ function draw(pathway, elem) {
.attr("width", nodeRadius * 2)
.attr("height", nodeRadius * 2);
pop_add(node, "Compound", node_popup);
// add element to nodes array
node.each(function(d) {
d.el = this; // attach the DOM element to the data object
});
pop_add(node, "Compound", node_popup);
}