forked from enviPath/enviPy
App Domain Pathway Prediction (#47)
Co-authored-by: Tim Lorsbach <tim@lorsba.ch> Reviewed-on: enviPath/enviPy#47
This commit is contained in:
@ -895,9 +895,10 @@ class SearchManager(object):
|
|||||||
|
|
||||||
class SNode(object):
|
class SNode(object):
|
||||||
|
|
||||||
def __init__(self, smiles: str, depth: int):
|
def __init__(self, smiles: str, depth: int, app_domain_assessment: dict = None):
|
||||||
self.smiles = smiles
|
self.smiles = smiles
|
||||||
self.depth = depth
|
self.depth = depth
|
||||||
|
self.app_domain_assessment = app_domain_assessment
|
||||||
|
|
||||||
def __hash__(self):
|
def __hash__(self):
|
||||||
return hash(self.smiles)
|
return hash(self.smiles)
|
||||||
@ -1040,7 +1041,7 @@ class SPathway(object):
|
|||||||
def depth(self):
|
def depth(self):
|
||||||
return max([v.depth for v in self.smiles_to_node.values()])
|
return max([v.depth for v in self.smiles_to_node.values()])
|
||||||
|
|
||||||
def _get_nodes_for_depth(self, depth: int):
|
def _get_nodes_for_depth(self, depth: int) -> List[SNode]:
|
||||||
if depth == 0:
|
if depth == 0:
|
||||||
return self.root_nodes
|
return self.root_nodes
|
||||||
|
|
||||||
@ -1051,7 +1052,7 @@ class SPathway(object):
|
|||||||
|
|
||||||
return sorted(res, key=lambda x: x.smiles)
|
return sorted(res, key=lambda x: x.smiles)
|
||||||
|
|
||||||
def _get_edges_for_depth(self, depth: int):
|
def _get_edges_for_depth(self, depth: int) -> List[SEdge]:
|
||||||
res = []
|
res = []
|
||||||
for e in self.edges:
|
for e in self.edges:
|
||||||
for n in e.educts:
|
for n in e.educts:
|
||||||
@ -1076,15 +1077,44 @@ class SPathway(object):
|
|||||||
new_tp = False
|
new_tp = False
|
||||||
if substrates:
|
if substrates:
|
||||||
for sub in substrates:
|
for sub in substrates:
|
||||||
|
|
||||||
|
if sub.app_domain_assessment is None:
|
||||||
|
if self.prediction_setting.model:
|
||||||
|
if self.prediction_setting.model.app_domain:
|
||||||
|
app_domain_assessment = self.prediction_setting.model.app_domain.assess(sub.smiles)[0]
|
||||||
|
|
||||||
|
if self.persist is not None:
|
||||||
|
n = self.snode_persist_lookup[sub]
|
||||||
|
|
||||||
|
assert n.id is not None, "Node has no id! Should have been saved already... aborting!"
|
||||||
|
node_data = n.simple_json()
|
||||||
|
node_data['image'] = f"{n.url}?image=svg"
|
||||||
|
app_domain_assessment['assessment']['node'] = node_data
|
||||||
|
|
||||||
|
n.kv['app_domain_assessment'] = app_domain_assessment
|
||||||
|
n.save()
|
||||||
|
|
||||||
|
sub.app_domain_assessment = app_domain_assessment
|
||||||
|
|
||||||
|
|
||||||
candidates = self.prediction_setting.expand(self, sub)
|
candidates = self.prediction_setting.expand(self, sub)
|
||||||
|
# candidates is a List of PredictionResult. The length of the List is equal to the number of rules
|
||||||
for cand_set in candidates:
|
for cand_set in candidates:
|
||||||
if cand_set:
|
if cand_set:
|
||||||
new_tp = True
|
new_tp = True
|
||||||
|
# cand_set is a PredictionResult object that can consist of multiple candidate reactions
|
||||||
for cand in cand_set:
|
for cand in cand_set:
|
||||||
cand_nodes = []
|
cand_nodes = []
|
||||||
|
# candidate reactions can have multiple fragments
|
||||||
for c in cand:
|
for c in cand:
|
||||||
if c not in self.smiles_to_node:
|
if c not in self.smiles_to_node:
|
||||||
self.smiles_to_node[c] = SNode(c, sub.depth + 1)
|
# For new nodes do an AppDomain Assessment if an AppDomain is attached
|
||||||
|
app_domain_assessment = None
|
||||||
|
if self.prediction_setting.model:
|
||||||
|
if self.prediction_setting.model.app_domain:
|
||||||
|
app_domain_assessment = self.prediction_setting.model.app_domain.assess(c)[0]
|
||||||
|
|
||||||
|
self.smiles_to_node[c] = SNode(c, sub.depth + 1, app_domain_assessment)
|
||||||
|
|
||||||
node = self.smiles_to_node[c]
|
node = self.smiles_to_node[c]
|
||||||
cand_nodes.append(node)
|
cand_nodes.append(node)
|
||||||
@ -1097,18 +1127,30 @@ class SPathway(object):
|
|||||||
if len(substrates) == 0 or from_node is not None:
|
if len(substrates) == 0 or from_node is not None:
|
||||||
self.done = True
|
self.done = True
|
||||||
|
|
||||||
# Check if we need to write back data to database
|
# Check if we need to write back data to the database
|
||||||
if new_tp and self.persist:
|
if new_tp and self.persist:
|
||||||
self._sync_to_pathway()
|
self._sync_to_pathway()
|
||||||
# call save to update internal modified field
|
# call save to update the internal modified field
|
||||||
self.persist.save()
|
self.persist.save()
|
||||||
|
|
||||||
def _sync_to_pathway(self):
|
def _sync_to_pathway(self) -> None:
|
||||||
logger.info("Updating Pathway with SPathway")
|
logger.info("Updating Pathway with SPathway")
|
||||||
|
|
||||||
for snode in self.smiles_to_node.values():
|
for snode in self.smiles_to_node.values():
|
||||||
if snode not in self.snode_persist_lookup:
|
if snode not in self.snode_persist_lookup:
|
||||||
n = Node.create(self.persist, snode.smiles, snode.depth)
|
n = Node.create(self.persist, snode.smiles, snode.depth)
|
||||||
|
|
||||||
|
if snode.app_domain_assessment is not None:
|
||||||
|
app_domain_assessment = snode.app_domain_assessment
|
||||||
|
|
||||||
|
assert n.id is not None, "Node has no id! Should have been saved already... aborting!"
|
||||||
|
node_data = n.simple_json()
|
||||||
|
node_data['image'] = f"{n.url}?image=svg"
|
||||||
|
app_domain_assessment['assessment']['node'] = node_data
|
||||||
|
|
||||||
|
n.kv['app_domain_assessment'] = app_domain_assessment
|
||||||
|
n.save()
|
||||||
|
|
||||||
self.snode_persist_lookup[snode] = n
|
self.snode_persist_lookup[snode] = n
|
||||||
|
|
||||||
for sedge in self.edges:
|
for sedge in self.edges:
|
||||||
@ -1130,7 +1172,6 @@ class SPathway(object):
|
|||||||
self.sedge_persist_lookup[sedge] = e
|
self.sedge_persist_lookup[sedge] = e
|
||||||
|
|
||||||
logger.info("Update done!")
|
logger.info("Update done!")
|
||||||
pass
|
|
||||||
|
|
||||||
def to_json(self):
|
def to_json(self):
|
||||||
nodes = []
|
nodes = []
|
||||||
|
|||||||
@ -912,7 +912,8 @@ class Pathway(EnviPathModel, AliasMixin, ScenarioMixin):
|
|||||||
'reaction_probability': link['reaction_probability'],
|
'reaction_probability': link['reaction_probability'],
|
||||||
'scenarios': link['scenarios'],
|
'scenarios': link['scenarios'],
|
||||||
'source': node_url_to_idx[link['start_node_urls'][0]],
|
'source': node_url_to_idx[link['start_node_urls'][0]],
|
||||||
'target': pseudo_idx
|
'target': pseudo_idx,
|
||||||
|
'app_domain': link.get('app_domain', None)
|
||||||
}
|
}
|
||||||
adjusted_links.append(new_link)
|
adjusted_links.append(new_link)
|
||||||
|
|
||||||
@ -927,7 +928,8 @@ class Pathway(EnviPathModel, AliasMixin, ScenarioMixin):
|
|||||||
'reaction_probability': link['reaction_probability'],
|
'reaction_probability': link['reaction_probability'],
|
||||||
'scenarios': link['scenarios'],
|
'scenarios': link['scenarios'],
|
||||||
'source': pseudo_idx,
|
'source': pseudo_idx,
|
||||||
'target': node_url_to_idx[target]
|
'target': node_url_to_idx[target],
|
||||||
|
'app_domain': link.get('app_domain', None)
|
||||||
}
|
}
|
||||||
adjusted_links.append(new_link)
|
adjusted_links.append(new_link)
|
||||||
|
|
||||||
@ -1044,6 +1046,8 @@ class Node(EnviPathModel, AliasMixin, ScenarioMixin):
|
|||||||
return '{}/node/{}'.format(self.pathway.url, self.uuid)
|
return '{}/node/{}'.format(self.pathway.url, self.uuid)
|
||||||
|
|
||||||
def d3_json(self):
|
def d3_json(self):
|
||||||
|
app_domain_data = self.get_app_domain_assessment_data()
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"depth": self.depth,
|
"depth": self.depth,
|
||||||
"url": self.url,
|
"url": self.url,
|
||||||
@ -1053,6 +1057,10 @@ class Node(EnviPathModel, AliasMixin, ScenarioMixin):
|
|||||||
"name": self.default_node_label.name,
|
"name": self.default_node_label.name,
|
||||||
"smiles": self.default_node_label.smiles,
|
"smiles": self.default_node_label.smiles,
|
||||||
"scenarios": [{'name': s.name, 'url': s.url} for s in self.scenarios.all()],
|
"scenarios": [{'name': s.name, 'url': s.url} for s in self.scenarios.all()],
|
||||||
|
"app_domain": {
|
||||||
|
'inside_app_domain': app_domain_data['assessment']['inside_app_domain'] if app_domain_data else None,
|
||||||
|
'uncovered_functional_groups': False,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@ -1078,6 +1086,32 @@ class Node(EnviPathModel, AliasMixin, ScenarioMixin):
|
|||||||
def as_svg(self):
|
def as_svg(self):
|
||||||
return IndigoUtils.mol_to_svg(self.default_node_label.smiles)
|
return IndigoUtils.mol_to_svg(self.default_node_label.smiles)
|
||||||
|
|
||||||
|
def get_app_domain_assessment_data(self):
|
||||||
|
data = self.kv.get('app_domain_assessment', None)
|
||||||
|
|
||||||
|
if data:
|
||||||
|
rule_ids = dict()
|
||||||
|
for e in Edge.objects.filter(start_nodes__in=[self]):
|
||||||
|
for r in e.edge_label.rules.all():
|
||||||
|
rule_ids[str(r.uuid)] = e
|
||||||
|
|
||||||
|
|
||||||
|
for t in data['assessment']['transformations']:
|
||||||
|
if t['rule']['uuid'] in rule_ids:
|
||||||
|
t['is_predicted'] = True
|
||||||
|
t['edge'] = rule_ids[t['rule']['uuid']].simple_json()
|
||||||
|
|
||||||
|
return data
|
||||||
|
|
||||||
|
|
||||||
|
def simple_json(self, include_description=False):
|
||||||
|
res = super().simple_json()
|
||||||
|
name = res.get('name', None)
|
||||||
|
if name == 'no name':
|
||||||
|
res['name'] = self.default_node_label.name
|
||||||
|
|
||||||
|
return res
|
||||||
|
|
||||||
|
|
||||||
class Edge(EnviPathModel, AliasMixin, ScenarioMixin):
|
class Edge(EnviPathModel, AliasMixin, ScenarioMixin):
|
||||||
pathway = models.ForeignKey('epdb.Pathway', verbose_name='belongs to', on_delete=models.CASCADE, db_index=True)
|
pathway = models.ForeignKey('epdb.Pathway', verbose_name='belongs to', on_delete=models.CASCADE, db_index=True)
|
||||||
@ -1090,19 +1124,44 @@ class Edge(EnviPathModel, AliasMixin, ScenarioMixin):
|
|||||||
return '{}/edge/{}'.format(self.pathway.url, self.uuid)
|
return '{}/edge/{}'.format(self.pathway.url, self.uuid)
|
||||||
|
|
||||||
def d3_json(self):
|
def d3_json(self):
|
||||||
return {
|
edge_json = {
|
||||||
'name': self.name,
|
'name': self.name,
|
||||||
'id': self.url,
|
'id': self.url,
|
||||||
'url': self.url,
|
'url': self.url,
|
||||||
'image': self.url + '?image=svg',
|
'image': self.url + '?image=svg',
|
||||||
'reaction': {'name': self.edge_label.name, 'url': self.edge_label.url } if self.edge_label else None,
|
'reaction': {'name': self.edge_label.name, 'url': self.edge_label.url } if self.edge_label else None,
|
||||||
'reaction_probability': self.kv.get('probability'),
|
'reaction_probability': self.kv.get('probability'),
|
||||||
# TODO
|
|
||||||
'start_node_urls': [x.url for x in self.start_nodes.all()],
|
'start_node_urls': [x.url for x in self.start_nodes.all()],
|
||||||
'end_node_urls': [x.url for x in self.end_nodes.all()],
|
'end_node_urls': [x.url for x in self.end_nodes.all()],
|
||||||
"scenarios": [{'name': s.name, 'url': s.url} for s in self.scenarios.all()],
|
"scenarios": [{'name': s.name, 'url': s.url} for s in self.scenarios.all()],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for n in self.start_nodes.all():
|
||||||
|
app_domain_data = n.get_app_domain_assessment_data()
|
||||||
|
|
||||||
|
if app_domain_data:
|
||||||
|
for t in app_domain_data['assessment']['transformations']:
|
||||||
|
if 'edge' in t and t['edge']['uuid'] == str(self.uuid):
|
||||||
|
passes_app_domain = (
|
||||||
|
t['local_compatibility'] >= app_domain_data['ad_params']['local_compatibility_threshold']
|
||||||
|
) and (
|
||||||
|
t['reliability'] >= app_domain_data['ad_params']['reliability_threshold']
|
||||||
|
)
|
||||||
|
|
||||||
|
edge_json['app_domain'] = {
|
||||||
|
'passes_app_domain': passes_app_domain,
|
||||||
|
'local_compatibility': t['local_compatibility'],
|
||||||
|
'local_compatibility_threshold': app_domain_data['ad_params']['local_compatibility_threshold'],
|
||||||
|
'reliability': t['reliability'],
|
||||||
|
'reliability_threshold': app_domain_data['ad_params']['reliability_threshold'],
|
||||||
|
'times_triggered': t['times_triggered'],
|
||||||
|
}
|
||||||
|
|
||||||
|
break
|
||||||
|
|
||||||
|
return edge_json
|
||||||
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def create(pathway, start_nodes: List[Node], end_nodes: List[Node], rule: Optional[Rule] = None, name: Optional[str] = None,
|
def create(pathway, start_nodes: List[Node], end_nodes: List[Node], rule: Optional[Rule] = None, name: Optional[str] = None,
|
||||||
description: Optional[str] = None):
|
description: Optional[str] = None):
|
||||||
@ -1136,6 +1195,14 @@ class Edge(EnviPathModel, AliasMixin, ScenarioMixin):
|
|||||||
def as_svg(self):
|
def as_svg(self):
|
||||||
return self.edge_label.as_svg if self.edge_label else None
|
return self.edge_label.as_svg if self.edge_label else None
|
||||||
|
|
||||||
|
def simple_json(self, include_description=False):
|
||||||
|
res = super().simple_json()
|
||||||
|
name = res.get('name', None)
|
||||||
|
if name == 'no name':
|
||||||
|
res['name'] = self.edge_label.name
|
||||||
|
|
||||||
|
return res
|
||||||
|
|
||||||
|
|
||||||
class EPModel(PolymorphicModel, EnviPathModel):
|
class EPModel(PolymorphicModel, EnviPathModel):
|
||||||
package = models.ForeignKey('epdb.Package', verbose_name='Package', on_delete=models.CASCADE, db_index=True)
|
package = models.ForeignKey('epdb.Package', verbose_name='Package', on_delete=models.CASCADE, db_index=True)
|
||||||
@ -1463,6 +1530,7 @@ class MLRelativeReasoning(EPModel):
|
|||||||
|
|
||||||
return res
|
return res
|
||||||
|
|
||||||
|
|
||||||
class ApplicabilityDomain(EnviPathModel):
|
class ApplicabilityDomain(EnviPathModel):
|
||||||
model = models.ForeignKey(MLRelativeReasoning, on_delete=models.CASCADE)
|
model = models.ForeignKey(MLRelativeReasoning, on_delete=models.CASCADE)
|
||||||
|
|
||||||
@ -1614,7 +1682,7 @@ class ApplicabilityDomain(EnviPathModel):
|
|||||||
'model': self.model.simple_json(),
|
'model': self.model.simple_json(),
|
||||||
'num_neighbours': self.num_neighbours,
|
'num_neighbours': self.num_neighbours,
|
||||||
'reliability_threshold': self.reliability_threshold,
|
'reliability_threshold': self.reliability_threshold,
|
||||||
'local_compatibilty_threshold': self.local_compatibilty_threshold,
|
'local_compatibility_threshold': self.local_compatibilty_threshold,
|
||||||
},
|
},
|
||||||
'assessment': {
|
'assessment': {
|
||||||
'smiles': smiles,
|
'smiles': smiles,
|
||||||
|
|||||||
@ -58,7 +58,7 @@ def predict(pw_pk: int, pred_setting_pk: int, limit: Optional[int] = None, node_
|
|||||||
spw.predict_step(from_depth=level)
|
spw.predict_step(from_depth=level)
|
||||||
level += 1
|
level += 1
|
||||||
|
|
||||||
# break in case we are in incremental model
|
# break in case we are in incremental mode
|
||||||
if limit != -1:
|
if limit != -1:
|
||||||
if level >= limit:
|
if level >= limit:
|
||||||
break
|
break
|
||||||
|
|||||||
@ -1454,6 +1454,7 @@ def package_pathway_node(request, package_uuid, pathway_uuid, node_uuid):
|
|||||||
]
|
]
|
||||||
|
|
||||||
context['node'] = current_node
|
context['node'] = current_node
|
||||||
|
context['app_domain_assessment_data'] = json.dumps(current_node.get_app_domain_assessment_data())
|
||||||
|
|
||||||
return render(request, 'objects/node.html', context)
|
return render(request, 'objects/node.html', context)
|
||||||
|
|
||||||
|
|||||||
144
static/js/pps.js
144
static/js/pps.js
@ -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'] ? ">" : "<") + " 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'] ? ">" : "<") + " 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);
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,4 +1,4 @@
|
|||||||
console.log("loaded")
|
console.log("loaded pw.js")
|
||||||
|
|
||||||
|
|
||||||
function predictFromNode(url) {
|
function predictFromNode(url) {
|
||||||
@ -144,6 +144,16 @@ function draw(pathway, elem) {
|
|||||||
function node_popup(n) {
|
function node_popup(n) {
|
||||||
popupContent = "<a href='" + n.url +"'>" + n.name + "</a><br>";
|
popupContent = "<a href='" + n.url +"'>" + n.name + "</a><br>";
|
||||||
popupContent += "Depth " + n.depth + "<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>"
|
popupContent += "<img src='" + n.image + "' width='"+ 20 * nodeRadius +"'><br>"
|
||||||
if (n.scenarios.length > 0) {
|
if (n.scenarios.length > 0) {
|
||||||
popupContent += '<b>Half-lives and related scenarios:</b><br>'
|
popupContent += '<b>Half-lives and related scenarios:</b><br>'
|
||||||
@ -162,6 +172,18 @@ function draw(pathway, elem) {
|
|||||||
|
|
||||||
function edge_popup(e) {
|
function edge_popup(e) {
|
||||||
popupContent = "<a href='" + e.url +"'>" + e.name + "</a><br>";
|
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"] ? ">" : "<") + " 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"] ? ">" : "<") + " Local Compatibility Threshold of " + e.app_domain["local_compatibility_threshold"] + ")<br>";
|
||||||
|
adcontent += "</p>";
|
||||||
|
}
|
||||||
|
popupContent += adcontent;
|
||||||
|
|
||||||
popupContent += "<img src='" + e.image + "' width='"+ 20 * nodeRadius +"'><br>"
|
popupContent += "<img src='" + e.image + "' width='"+ 20 * nodeRadius +"'><br>"
|
||||||
if (e.reaction_probability) {
|
if (e.reaction_probability) {
|
||||||
popupContent += '<b>Probability:</b><br>' + e.reaction_probability.toFixed(3) + '<br>';
|
popupContent += '<b>Probability:</b><br>' + e.reaction_probability.toFixed(3) + '<br>';
|
||||||
@ -233,13 +255,12 @@ function draw(pathway, elem) {
|
|||||||
.enter().append("line")
|
.enter().append("line")
|
||||||
// Check if target is pseudo and draw marker only if not pseudo
|
// Check if target is pseudo and draw marker only if not pseudo
|
||||||
.attr("class", d => d.target.pseudo ? "link_no_arrow" : "link")
|
.attr("class", d => d.target.pseudo ? "link_no_arrow" : "link")
|
||||||
// .on("mouseover", (event, d) => {
|
.attr("marker-end", d => d.target.pseudo ? '' : 'url(#arrow)')
|
||||||
// tooltip.style("visibility", "visible")
|
|
||||||
// .text(`Link: ${d.source.id} → ${d.target.id}`)
|
// add element to links array
|
||||||
// .style("top", `${event.pageY + 5}px`)
|
link.each(function(d) {
|
||||||
// .style("left", `${event.pageX + 5}px`);
|
d.el = this; // attach the DOM element to the data object
|
||||||
// })
|
});
|
||||||
// .on("mouseout", () => tooltip.style("visibility", "hidden"));
|
|
||||||
|
|
||||||
pop_add(link, "Reaction", edge_popup);
|
pop_add(link, "Reaction", edge_popup);
|
||||||
|
|
||||||
@ -255,16 +276,6 @@ function draw(pathway, elem) {
|
|||||||
.on("click", function (event, d) {
|
.on("click", function (event, d) {
|
||||||
d3.select(this).select("circle").classed("highlighted", !d3.select(this).select("circle").classed("highlighted"));
|
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
|
// Kreise für die Knoten hinzufügen
|
||||||
node.append("circle")
|
node.append("circle")
|
||||||
@ -280,5 +291,10 @@ function draw(pathway, elem) {
|
|||||||
.attr("width", nodeRadius * 2)
|
.attr("width", nodeRadius * 2)
|
||||||
.attr("height", nodeRadius * 2);
|
.attr("height", nodeRadius * 2);
|
||||||
|
|
||||||
|
// 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);
|
pop_add(node, "Compound", node_popup);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -269,141 +269,6 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
function handleAssessmentResponse(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 = "<img width='400' src='{% url 'depict' %}?smiles=" + encodeURIComponent(data['assessment']['smiles']) + "'>";
|
|
||||||
var reactivityCentersImgSrc = "<img width='400' src='{% url 'depict' %}?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'] ? ">" : "<") + " 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'] ? ">" : "<") + " 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);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
function handlePredictionResponse(data) {
|
function handlePredictionResponse(data) {
|
||||||
res = "<table class='table table-striped'>"
|
res = "<table class='table table-striped'>"
|
||||||
res += "<thead>"
|
res += "<thead>"
|
||||||
@ -498,7 +363,7 @@
|
|||||||
success: function (data, textStatus) {
|
success: function (data, textStatus) {
|
||||||
try {
|
try {
|
||||||
$("#appDomainLoading").empty();
|
$("#appDomainLoading").empty();
|
||||||
handleAssessmentResponse(data);
|
handleAssessmentResponse("{% url 'depict' %}", data);
|
||||||
console.log(data);
|
console.log(data);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log("Error");
|
console.log("Error");
|
||||||
|
|||||||
@ -69,7 +69,18 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{% if app_domain_assessment_data %}
|
||||||
|
<div id="appDomainAssessmentResultTable"></div>
|
||||||
|
<script>
|
||||||
|
$(document).ready(function () {
|
||||||
|
handleAssessmentResponse("{% url 'depict' %}", {{ app_domain_assessment_data|safe }})
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
{% endblock content %}
|
{% endblock content %}
|
||||||
|
|||||||
@ -4,16 +4,22 @@
|
|||||||
|
|
||||||
<script src="https://d3js.org/d3.v7.min.js"></script>
|
<script src="https://d3js.org/d3.v7.min.js"></script>
|
||||||
<style>
|
<style>
|
||||||
svg {
|
#vizdiv {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 600px;
|
height: 600px;
|
||||||
|
background: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pwsvg {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
color: red;
|
color: red;
|
||||||
}
|
}
|
||||||
|
|
||||||
.link {
|
.link {
|
||||||
stroke: #999;
|
stroke: #999;
|
||||||
stroke-opacity: 0.6;
|
stroke-opacity: 0.6;
|
||||||
marker-end: url(#arrow);
|
//marker-end: url(#arrow);
|
||||||
}
|
}
|
||||||
|
|
||||||
.link_no_arrow {
|
.link_no_arrow {
|
||||||
@ -31,6 +37,31 @@
|
|||||||
stroke-width: 1.5px;
|
stroke-width: 1.5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.inside_app_domain {
|
||||||
|
fill: green;
|
||||||
|
stroke: green;
|
||||||
|
stroke-width: 1.5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.outside_app_domain {
|
||||||
|
fill: red;
|
||||||
|
stroke: red;
|
||||||
|
stroke-width: 1.5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.passes_app_domain {
|
||||||
|
stroke: green;
|
||||||
|
stroke-width: 1.5px;
|
||||||
|
stroke-opacity: 0.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fails_app_domain {
|
||||||
|
stroke: red;
|
||||||
|
stroke-width: 1.5px;
|
||||||
|
stroke-opacity: 0.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
.highlighted {
|
.highlighted {
|
||||||
stroke: red;
|
stroke: red;
|
||||||
stroke-width: 3px;
|
stroke-width: 3px;
|
||||||
@ -80,8 +111,7 @@
|
|||||||
<ul class="nav navbar-nav">
|
<ul class="nav navbar-nav">
|
||||||
<li class="dropdown requiresWritePerm">
|
<li class="dropdown requiresWritePerm">
|
||||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button"
|
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button"
|
||||||
aria-haspopup="true"
|
aria-haspopup="true" aria-expanded="false">
|
||||||
aria-expanded="false">
|
|
||||||
<span class="glyphicon glyphicon-edit"></span>
|
<span class="glyphicon glyphicon-edit"></span>
|
||||||
Edit
|
Edit
|
||||||
<span class="caret"></span></a>
|
<span class="caret"></span></a>
|
||||||
@ -91,11 +121,26 @@
|
|||||||
{% endblock %}
|
{% endblock %}
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
|
{% if pathway.setting.model.app_domain %}
|
||||||
|
<li class="dropdown">
|
||||||
|
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button"
|
||||||
|
aria-haspopup="true" aria-expanded="false">
|
||||||
|
<span class="glyphicon glyphicon-eye-open"></span>
|
||||||
|
View
|
||||||
|
<span class="caret"></span></a>
|
||||||
|
<ul id="editingList" class="dropdown-menu">
|
||||||
|
<li>
|
||||||
|
<a class="button" id="app-domain-toggle-button">
|
||||||
|
<i id="app-domain-toggle-button" class="glyphicon glyphicon-eye-open"></i> App Domain View</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<ul class="nav navbar-nav navbar-right">
|
<ul class="nav navbar-nav navbar-right">
|
||||||
<li>
|
<li>
|
||||||
<a role="button" data-toggle="modal" onclick="goFullscreen('pwcontent')">
|
<a role="button" data-toggle="modal" onclick="goFullscreen('vizdiv')">
|
||||||
<span class="glyphicon glyphicon-fullscreen"></span>
|
<span class="glyphicon glyphicon-fullscreen"></span>
|
||||||
Fullscreen
|
Fullscreen
|
||||||
</a>
|
</a>
|
||||||
@ -126,16 +171,24 @@
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
<div id="vizdiv">
|
<div id="vizdiv" >
|
||||||
<svg width="2000" height="2000">
|
<svg id="pwsvg">
|
||||||
{% if debug %}
|
{% if debug %}
|
||||||
<rect width="100%" height="100%" fill="aliceblue"/>
|
<rect width="100%" height="100%" fill="aliceblue"/>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<defs>
|
<defs>
|
||||||
<marker id="arrow" viewBox="0 0 10 10" refX="43" refY="5" markerWidth="6" markerHeight="6"
|
<marker id="arrow" viewBox="0 0 10 10" refX="43" refY="5" markerWidth="6" markerHeight="6"
|
||||||
orient="auto-start-reverse">
|
orient="auto-start-reverse" markerUnits="userSpaceOnUse">
|
||||||
<path d="M 0 0 L 10 5 L 0 10 z" fill="#999"/>
|
<path d="M 0 0 L 10 5 L 0 10 z" fill="#999"/>
|
||||||
</marker>
|
</marker>
|
||||||
|
<marker id="arrow_passes_app_domain" viewBox="0 0 10 10" refX="43" refY="5" markerWidth="6" markerHeight="6"
|
||||||
|
orient="auto-start-reverse" markerUnits="userSpaceOnUse">
|
||||||
|
<path d="M 0 0 L 10 5 L 0 10 z" fill="green"/>
|
||||||
|
</marker>
|
||||||
|
<marker id="arrow_fails_app_domain" viewBox="0 0 10 10" refX="43" refY="5" markerWidth="6" markerHeight="6"
|
||||||
|
orient="auto-start-reverse" markerUnits="userSpaceOnUse">
|
||||||
|
<path d="M 0 0 L 10 5 L 0 10 z" fill="red"/>
|
||||||
|
</marker>
|
||||||
</defs>
|
</defs>
|
||||||
<g id="zoomable"></g>
|
<g id="zoomable"></g>
|
||||||
</svg>
|
</svg>
|
||||||
@ -160,7 +213,7 @@
|
|||||||
<a id="pathwaySettingLink" data-toggle="collapse" data-parent="#pathwayAccordion"
|
<a id="pathwaySettingLink" data-toggle="collapse" data-parent="#pathwayAccordion"
|
||||||
href="#pathwaySetting">Setting</a></h4>
|
href="#pathwaySetting">Setting</a></h4>
|
||||||
</div>
|
</div>
|
||||||
<div id="pathwaySetting" class="panel-collapse collapse in">
|
<div id="pathwaySetting" class="panel-collapse collapse">
|
||||||
<div class="panel-body list-group-item" id="pathwaySettingContent">
|
<div class="panel-body list-group-item" id="pathwaySettingContent">
|
||||||
<table class="table table-bordered table-hover">
|
<table class="table table-bordered table-hover">
|
||||||
<tr style="background-color: rgba(0, 0, 0, 0.08);">
|
<tr style="background-color: rgba(0, 0, 0, 0.08);">
|
||||||
@ -246,6 +299,8 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script>
|
<script>
|
||||||
|
// Globla switch for app domain view
|
||||||
|
var appDomainViewEnabled = false;
|
||||||
|
|
||||||
function goFullscreen(id) {
|
function goFullscreen(id) {
|
||||||
var element = document.getElementById(id);
|
var element = document.getElementById(id);
|
||||||
@ -267,6 +322,51 @@
|
|||||||
// TODO fix somewhere else...
|
// TODO fix somewhere else...
|
||||||
var newDesc = transformReferences($('#DescriptionContent')[0].innerText);
|
var newDesc = transformReferences($('#DescriptionContent')[0].innerText);
|
||||||
$('#DescriptionContent').html(newDesc);
|
$('#DescriptionContent').html(newDesc);
|
||||||
|
|
||||||
|
|
||||||
|
$('#app-domain-toggle-button').on('click', function () {
|
||||||
|
// glyphicon glyphicon-eye-close
|
||||||
|
// glyphicon glyphicon-eye-open
|
||||||
|
appDomainViewEnabled = !appDomainViewEnabled;
|
||||||
|
|
||||||
|
if (appDomainViewEnabled) {
|
||||||
|
$('#app-domain-toggle-button > i').removeClass('glyphicon-eye-open');
|
||||||
|
$('#app-domain-toggle-button > i').addClass('glyphicon-eye-close');
|
||||||
|
nodes.forEach((x) => {
|
||||||
|
if(x.app_domain) {
|
||||||
|
if (x.app_domain.inside_app_domain) {
|
||||||
|
d3.select(x.el).select("circle").classed("inside_app_domain", true);
|
||||||
|
} else {
|
||||||
|
d3.select(x.el).select("circle").classed("outside_app_domain", true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
links.forEach((x) => {
|
||||||
|
if(x.app_domain) {
|
||||||
|
if (x.app_domain.passes_app_domain) {
|
||||||
|
d3.select(x.el).attr("marker-end", d => d.target.pseudo ? "" : "url(#arrow_passes_app_domain)");
|
||||||
|
d3.select(x.el).classed("passes_app_domain", true);
|
||||||
|
} else {
|
||||||
|
d3.select(x.el).attr("marker-end", d => d.target.pseudo ? "" : "url(#arrow_fails_app_domain)");
|
||||||
|
d3.select(x.el).classed("fails_app_domain", true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
$('#app-domain-toggle-button > i').removeClass('glyphicon-eye-close');
|
||||||
|
$('#app-domain-toggle-button > i').addClass('glyphicon-eye-open');
|
||||||
|
nodes.forEach((x) => {
|
||||||
|
d3.select(x.el).select("circle").classed("inside_app_domain", false);
|
||||||
|
d3.select(x.el).select("circle").classed("outside_app_domain", false);
|
||||||
|
});
|
||||||
|
links.forEach((x) => {
|
||||||
|
d3.select(x.el).attr("marker-end", d => d.target.pseudo ? "" : "url(#arrow)");
|
||||||
|
d3.select(x.el).classed("passes_app_domain", false);
|
||||||
|
d3.select(x.el).classed("fails_app_domain", false);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
Reference in New Issue
Block a user