forked from enviPath/enviPy
merged pathways
This commit is contained in:
+102
-15
@@ -2071,7 +2071,10 @@ class Pathway(EnviPathModel, AliasMixin, ScenarioMixin, AdditionalInformationMix
|
|||||||
def empty_due_to_threshold(self):
|
def empty_due_to_threshold(self):
|
||||||
return self.kv.get("empty_due_to_threshold", False)
|
return self.kv.get("empty_due_to_threshold", False)
|
||||||
|
|
||||||
def d3_json(self):
|
def merged_d3_json(self):
|
||||||
|
return self.d3_json(merged=True)
|
||||||
|
|
||||||
|
def d3_json(self, merged=False):
|
||||||
# Ideally it would be something like this but
|
# Ideally it would be something like this but
|
||||||
# to reduce crossing in edges do a DFS
|
# to reduce crossing in edges do a DFS
|
||||||
# nodes = [n.d3_json() for n in self.nodes]
|
# nodes = [n.d3_json() for n in self.nodes]
|
||||||
@@ -2079,15 +2082,68 @@ class Pathway(EnviPathModel, AliasMixin, ScenarioMixin, AdditionalInformationMix
|
|||||||
nodes = []
|
nodes = []
|
||||||
processed = set()
|
processed = set()
|
||||||
|
|
||||||
|
structure_to_combined_nodes = dict()
|
||||||
|
node_to_combined_node = dict()
|
||||||
queue = list()
|
queue = list()
|
||||||
for n in self.root_nodes:
|
|
||||||
queue.append(n)
|
|
||||||
|
|
||||||
# Add unconnected nodes
|
class CombinedNode(object):
|
||||||
for n in self.nodes.order_by("url"):
|
|
||||||
if len(n.out_edges.all()) == 0:
|
def __init__(self, representative: "Node"):
|
||||||
if n not in queue:
|
self.representative = representative
|
||||||
queue.append(n)
|
self.nodes = set([self.representative])
|
||||||
|
|
||||||
|
def ids(self):
|
||||||
|
return [n.id for n in self.nodes]
|
||||||
|
|
||||||
|
def d3_json(self):
|
||||||
|
d3_json = self.representative.d3_json()
|
||||||
|
compound = self.representative.default_node_label.compound
|
||||||
|
d3_json["name"] = compound.get_name()
|
||||||
|
d3_json["smiles"] = compound.default_structure.smiles
|
||||||
|
d3_json["node_label_id"] = compound.default_structure.url
|
||||||
|
d3_json["image"] = f"{compound.default_structure.url}?image=svg",
|
||||||
|
d3_json["image_svg"] = IndigoUtils.mol_to_svg(
|
||||||
|
compound.default_structure.molfile
|
||||||
|
if compound.default_structure.molfile is not None
|
||||||
|
and compound.default_structure.molfile.strip()
|
||||||
|
else compound.default_structure.smiles,
|
||||||
|
width=40,
|
||||||
|
height=40,
|
||||||
|
),
|
||||||
|
|
||||||
|
return d3_json
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return f"CombinedNode({self.nodes})"
|
||||||
|
|
||||||
|
if merged:
|
||||||
|
for n in self.nodes:
|
||||||
|
def_struct = n.default_node_label.compound.default_structure
|
||||||
|
if def_struct in structure_to_combined_nodes:
|
||||||
|
structure_to_combined_nodes[def_struct].nodes.add(n)
|
||||||
|
else:
|
||||||
|
cn = CombinedNode(n)
|
||||||
|
structure_to_combined_nodes[def_struct] = cn
|
||||||
|
|
||||||
|
# for n in self.nodes.order_by("url"):
|
||||||
|
# if len(n.out_edges.all()) == 0:
|
||||||
|
# if n not in queue:
|
||||||
|
# queue.append(n)
|
||||||
|
|
||||||
|
for cn in structure_to_combined_nodes.values():
|
||||||
|
for n in cn.nodes:
|
||||||
|
node_to_combined_node[n] = cn
|
||||||
|
|
||||||
|
queue = list(structure_to_combined_nodes.values())
|
||||||
|
else:
|
||||||
|
for n in self.nodes:
|
||||||
|
queue.append(n)
|
||||||
|
|
||||||
|
# Add unconnected nodes
|
||||||
|
for n in self.nodes.order_by("url"):
|
||||||
|
if len(n.out_edges.all()) == 0:
|
||||||
|
if n not in queue:
|
||||||
|
queue.append(n)
|
||||||
|
|
||||||
for i in queue:
|
for i in queue:
|
||||||
processed.add(i)
|
processed.add(i)
|
||||||
@@ -2097,25 +2153,56 @@ class Pathway(EnviPathModel, AliasMixin, ScenarioMixin, AdditionalInformationMix
|
|||||||
processed.add(current)
|
processed.add(current)
|
||||||
nodes.append(current.d3_json())
|
nodes.append(current.d3_json())
|
||||||
|
|
||||||
for e in self.edges.filter(start_nodes=current).order_by("url").distinct():
|
if merged:
|
||||||
|
q = Q(start_nodes__in=current.ids())
|
||||||
|
else:
|
||||||
|
q = Q(start_nodes=current)
|
||||||
|
|
||||||
|
for e in self.edges.filter(q).order_by("url").distinct():
|
||||||
for prod in e.end_nodes.all().order_by("url"):
|
for prod in e.end_nodes.all().order_by("url"):
|
||||||
if prod not in queue and prod not in processed:
|
|
||||||
queue.append(prod)
|
if merged:
|
||||||
|
def_struct = n.default_node_label.compound.default_structure
|
||||||
|
if def_struct in structure_to_combined_nodes:
|
||||||
|
structure_to_combined_nodes[def_struct].nodes.add(n)
|
||||||
|
else:
|
||||||
|
cn = CombinedNode(n)
|
||||||
|
structure_to_combined_nodes[def_struct] = cn
|
||||||
|
if cn not in queue and cn not in processed:
|
||||||
|
queue.append(cn)
|
||||||
|
else:
|
||||||
|
if prod not in queue and prod not in processed:
|
||||||
|
queue.append(prod)
|
||||||
|
|
||||||
# We shouldn't lose or make up nodes...
|
# We shouldn't lose or make up nodes...
|
||||||
if len(nodes) != len(self.nodes):
|
if not merged:
|
||||||
logger.debug(
|
if len(nodes) != len(self.nodes):
|
||||||
f"{self.get_name()}: Num Nodes {len(nodes)} vs. DB Nodes {len(self.nodes)}"
|
logger.debug(
|
||||||
)
|
f"{self.get_name()}: Num Nodes {len(nodes)} vs. DB Nodes {len(self.nodes)}"
|
||||||
|
)
|
||||||
|
|
||||||
links = [e.d3_json() for e in self.edges]
|
links = [e.d3_json() for e in self.edges]
|
||||||
|
|
||||||
# D3 links Nodes based on indices in nodes array
|
# D3 links Nodes based on indices in nodes array
|
||||||
|
combined_node_depth_to_idx = dict()
|
||||||
node_url_to_idx = dict()
|
node_url_to_idx = dict()
|
||||||
for i, n in enumerate(nodes):
|
for i, n in enumerate(nodes):
|
||||||
n["id"] = i
|
n["id"] = i
|
||||||
node_url_to_idx[n["url"]] = i
|
node_url_to_idx[n["url"]] = i
|
||||||
|
|
||||||
|
# Add potential missing mappings
|
||||||
|
if merged:
|
||||||
|
cn_idx_mapping = dict()
|
||||||
|
for n in nodes:
|
||||||
|
for cn in processed:
|
||||||
|
for sub_n in cn.nodes:
|
||||||
|
if n["url"] == sub_n.url:
|
||||||
|
cn_idx_mapping[cn] = n["id"]
|
||||||
|
|
||||||
|
for n in processed:
|
||||||
|
for sub_n in n.nodes:
|
||||||
|
node_url_to_idx[sub_n.url] = cn_idx_mapping[n]
|
||||||
|
|
||||||
adjusted_links = []
|
adjusted_links = []
|
||||||
for link in links:
|
for link in links:
|
||||||
# Check if we'll need pseudo nodes
|
# Check if we'll need pseudo nodes
|
||||||
|
|||||||
@@ -2313,6 +2313,7 @@ def package_pathway(request, package_uuid, pathway_uuid):
|
|||||||
|
|
||||||
context["pathway"] = current_pathway
|
context["pathway"] = current_pathway
|
||||||
context["current_object"] = current_pathway
|
context["current_object"] = current_pathway
|
||||||
|
context["merged"] = request.GET.get("merged", False) == "true"
|
||||||
|
|
||||||
context["breadcrumbs"] = [
|
context["breadcrumbs"] = [
|
||||||
{"Home": s.SERVER_URL},
|
{"Home": s.SERVER_URL},
|
||||||
|
|||||||
@@ -544,8 +544,11 @@
|
|||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
{% if merged %}
|
||||||
|
{{ pathway.merged_d3_json|json_script:"pathway" }}
|
||||||
|
{% else %}
|
||||||
{{ pathway.d3_json|json_script:"pathway" }}
|
{{ pathway.d3_json|json_script:"pathway" }}
|
||||||
|
{% endif %}
|
||||||
<script>
|
<script>
|
||||||
// Global switch for compound names view
|
// Global switch for compound names view
|
||||||
var compoundNamesViewEnabled = false;
|
var compoundNamesViewEnabled = false;
|
||||||
|
|||||||
Reference in New Issue
Block a user