Source code for synkit.Vis.epd.models
from __future__ import annotations
"""Simple data models for mechanism visualization."""
from dataclasses import dataclass
from typing import Any, Dict, Iterable, List, Mapping, Sequence, Tuple
from .constants import transition_family
[docs]
@dataclass(frozen=True)
class Transition:
"""Minimal transition record used by the visualizer.
:param kind: Transition kind, e.g. ``'LP-/B+'`` or ``'B-/B+'``.
:type kind: str
:param src: Source atom/bond tuple.
:type src: Tuple[int, ...]
:param dst: Destination atom/bond tuple.
:type dst: Tuple[int, ...]
:param data: Auxiliary metadata such as ``shared_atom``.
:type data: Dict[str, Any]
"""
kind: str
src: Tuple[int, ...]
dst: Tuple[int, ...]
data: Dict[str, Any]
[docs]
def transition_from_epd_step(step: Any) -> Transition:
"""Normalize one SynKit EPD step into a drawable transition.
:param step: Transition-like object. Supported forms are ``Transition``,
a mapping with ``kind``, ``src`` and ``dst`` keys, or an ``epd_lw``
row of ``[typed_action, source, target]``.
:type step: Any
:return: Drawable transition with typed action preserved in ``data``.
:rtype: Transition
:raises ValueError: If the step cannot be interpreted.
Example
-------
.. code-block:: python
from synkit.Vis.epd import transition_from_epd_step
step = ["LP-/Sigma+", [1], [1, 2]]
transition = transition_from_epd_step(step)
assert transition.kind == "LP-/B+"
assert transition.data["typed_kind"] == "LP-/Sigma+"
"""
if isinstance(step, Transition):
return step
if isinstance(step, Mapping):
raw_kind = step.get("kind")
src = step.get("src")
dst = step.get("dst")
data = dict(step.get("data", {}) or {})
elif (
isinstance(step, Sequence)
and not isinstance(step, (str, bytes))
and len(step) >= 3
):
raw_kind, src, dst = step[:3]
data = {}
else:
raise ValueError(f"Unsupported EPD transition step: {step!r}")
if raw_kind is None or src is None or dst is None:
raise ValueError(f"Incomplete EPD transition step: {step!r}")
raw_kind = str(raw_kind)
family = transition_family(raw_kind)
if family != raw_kind:
data.setdefault("typed_kind", raw_kind)
return Transition(
kind=family,
src=tuple(int(x) for x in src),
dst=tuple(int(x) for x in dst),
data=data,
)
[docs]
def transitions_from_epd(epd: Iterable[Any]) -> List[Transition]:
"""Normalize SynKit ``epd_lw`` data for the mechanism visualizer.
:param epd: Iterable of EPD transition steps.
:type epd: Iterable[Any]
:return: List of normalized transitions.
:rtype: List[Transition]
Example
-------
.. code-block:: python
from synkit.Vis.epd import transitions_from_epd
epd_lw = [
["LP-/Sigma+", [1], [1, 2]],
["Sigma-/LP+", [2, 3], [3]],
]
transitions = transitions_from_epd(epd_lw)
"""
return [transition_from_epd_step(step) for step in epd]