Skip to content

Commit 5dd9595

Browse files
committed
Address some more nits
1 parent 9dd5a80 commit 5dd9595

2 files changed

Lines changed: 24 additions & 11 deletions

File tree

pyglotaran_extras/inspect/kinetic_scheme/_layout.py

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from __future__ import annotations
44

55
import hashlib
6+
import logging
67
from collections import deque
78
from enum import Enum
89
from typing import TYPE_CHECKING
@@ -20,6 +21,9 @@
2021
NodePositions = dict[str, tuple[float, float]]
2122
"""Mapping from node label to (x, y) position in data coordinates."""
2223

24+
_LOGGER = logging.getLogger(__name__)
25+
_SAME_COLUMN_TOLERANCE = 0.3
26+
2327

2428
class LayoutAlgorithm(str, Enum):
2529
"""Available layout algorithms for kinetic scheme visualization.
@@ -667,7 +671,15 @@ def _position_ground_state_nodes(
667671
positions[gs_node.label] = (parent_x, parent_y - ground_state_offset)
668672
else:
669673
# Fallback: place at origin
670-
positions[gs_node.label] = (0.0, -ground_state_offset)
674+
fallback_position = (0.0, -ground_state_offset)
675+
_LOGGER.debug(
676+
"Ground-state fallback positioning used for node '%s': "
677+
"parents=%s, fallback_position=%s",
678+
gs_node.label,
679+
parents,
680+
fallback_position,
681+
)
682+
positions[gs_node.label] = fallback_position
671683

672684

673685
def _avoid_ground_state_arrow_overlap(
@@ -718,7 +730,7 @@ def _avoid_ground_state_arrow_overlap(
718730

719731
# Check if successor is approximately in the same x column
720732
# and below the parent
721-
if abs(sx - px) < 0.3 and sy < py:
733+
if abs(sx - px) < _SAME_COLUMN_TOLERANCE and sy < py:
722734
positions[successor_label] = (sx + nudge, sy)
723735

724736

tests/inspect/kinetic_scheme/test_layout.py

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22

33
from __future__ import annotations
44

5-
import hashlib
6-
75
import pytest
86

97
from pyglotaran_extras.inspect.kinetic_scheme._k_matrix_parser import Transition
@@ -104,10 +102,14 @@ def test_no_overlapping_positions(self) -> None:
104102
positions = compute_layout(graph, LayoutAlgorithm.HIERARCHICAL)
105103

106104
compartment_positions = [positions[n.label] for n in graph.compartment_nodes()]
105+
epsilon = 1e-6
107106
for i, pos_i in enumerate(compartment_positions):
108107
for j, pos_j in enumerate(compartment_positions):
109108
if i != j:
110-
assert pos_i != pos_j
109+
dx = pos_i[0] - pos_j[0]
110+
dy = pos_i[1] - pos_j[1]
111+
distance = (dx * dx + dy * dy) ** 0.5
112+
assert distance > epsilon
111113

112114
def test_deterministic_output(self) -> None:
113115
"""Same input should always produce the same positions."""
@@ -120,12 +122,11 @@ def test_deterministic_output(self) -> None:
120122

121123
def test_node_sort_index_is_deterministic(self) -> None:
122124
"""Node sort index should use deterministic hashing."""
123-
label = "species_2"
124-
digest = hashlib.md5(label.encode(), usedforsecurity=False).digest()
125-
expected = int.from_bytes(digest[:4], "big") / 4294967296.0
126-
actual = _node_sort_index(label)
127-
assert actual == expected
128-
assert 0.0 <= actual < 1.0
125+
species_2_idx = _node_sort_index("species_2")
126+
species_3_idx = _node_sort_index("species_3")
127+
assert 0.0 <= species_2_idx < 1.0
128+
assert 0.0 <= species_3_idx < 1.0
129+
assert species_2_idx != species_3_idx
129130

130131
def test_parallel_nodes_side_by_side(self) -> None:
131132
"""Parallel decay nodes (all isolated) should be on the same row."""

0 commit comments

Comments
 (0)