Source code for biggr_maps.pathway
from typing import Any, Dict, List, Optional, Tuple
from biggr_maps.map import Map, AutoReaction, MetaboliteNode, MidMarkerNode, Node
import math
[docs]
def alternating_pathways_sides(
map: Map,
node1: Node,
node2: Node,
mid_markers: List[MidMarkerNode],
spacing: float = 200,
centered: bool = True,
):
dx = node2.x - node1.x
dy = node2.y - node1.y
distance = math.sqrt(dx**2 + dy**2)
center_point = (node1.x + dx/2, node1.y + dy/2)
normal = (-dy/distance, dx/distance)
i = 1 if centered else 0
while True:
side = i%2
f = (i//2)
if not centered:
f += 0.5
mid_marker_xy = (
center_point[0] + (1 if side else -1) * f * spacing * normal[0],
center_point[1] + (1 if side else -1) * f * spacing * normal[1],
)
if not any(math.sqrt((mid_marker_xy[0] - node.x)**2 + (mid_marker_xy[1] - node.y)**2) < spacing*0.99 for node in mid_markers):
return mid_marker_xy
i += 1
[docs]
def place_reaction_on_backbone(
map: Map,
name: str,
bigg_id: str,
reaction_info: List[Tuple[float, MetaboliteNode]],
placement_f = alternating_pathways_sides,
add_metabolite_opts = None,
additional_mid_markers: Optional[List[MidMarkerNode]] = None,
**kwargs
):
if add_metabolite_opts is None:
add_metabolite_opts = {}
backbone_nodes = [
(coeff, n) for coeff, n in reaction_info if n.identifier in map.nodes
]
while len(backbone_nodes) > 1:
if (backbone_nodes[0][0] > 0) == (backbone_nodes[1][0] > 0):
backbone_nodes.pop(1)
else:
break
if len(backbone_nodes) < 2:
raise ValueError(
f"Two metabolite nodes should be present in the map already, found {len(backbone_nodes)}."
)
if (backbone_nodes[0][0] > 0) == (backbone_nodes[1][0] > 0):
raise ValueError(f"The two nodes appear at the same side of the reaction.")
if backbone_nodes[0][0] > 0:
plus_node = backbone_nodes[0][1]
minus_node = backbone_nodes[1][1]
else:
plus_node = backbone_nodes[1][1]
minus_node = backbone_nodes[0][1]
angle = math.atan2(plus_node.y - minus_node.y, plus_node.x - minus_node.x)
# mid_marker = MidMarkerNode(
# plus_node.x + (minus_node.x - plus_node.x) / 2,
# plus_node.y + (minus_node.y - plus_node.y) / 2,
# )
mid_markers = [node for node in map.nodes.values() if node.node_type == "midmarker"]
if additional_mid_markers is not None:
mid_markers.extend(additional_mid_markers)
mid_marker = MidMarkerNode(*placement_f(map, plus_node, minus_node, mid_markers))
reaction = AutoReaction(
name=name, bigg_id=bigg_id, mid_marker=mid_marker, angle=angle, **kwargs
)
for coeff, met in reaction_info:
reaction.add_metabolite(met, coeff, **add_metabolite_opts)
return reaction