chemparseplot.plot.rings#

Primitive rings and the bridges between them, drawn with xyzrender.

The rings are the ones pydseams.yoda.ringNetwork returns for the neighbour list this module builds. xyzrender can also paint hull="rings" from its own bond perception. That detector is not used here. The hulls, the dashed bridges, and the optional query markers are a picture of the list handed to ringNetwork.

The neighbour list is not periodic. A distance cutoff is a number the caller measures between the longest bond and the shortest nonbonded contact. Passing the ice default of 3.5 angstrom builds a different graph. The command is rgpycrumbs geom plt-rings, a PEP 723 script the rgpycrumbs dispatcher runs under uv. rgpycrumbs geom plt-rings-track applies the same census to every frame of a trajectory. A hop is a change of terminal ring, identified by its atom set. The integer ringNetwork returns for one frame is not that identity. A query coordinate is the caller’s Wannier centre. The label is not the coordinate that enters a mean square displacement.

Module Contents#

Classes#

RingReport

Rings and the complement of their edges, for one neighbour list.

Assignment

Nearest ring centroid or junction midpoint for one query point.

Sample

One query on one frame, after rings have been matched by atom set.

Trajectory

Labels, junction visits, and terminal-ring hops for every query.

Functions#

_import_pydseams

_import_xyzrender

_as_edges

_adjacency

_nlist

Row format ringNetwork reads: the vertex, then its neighbours.

_girth

Length of a shortest cycle through uv, or None when uv is a bridge.

_ring_edges

report_from_bonds

Enumerate primitive rings of an explicit neighbour list.

bonds_within_cutoff

Heavy-atom pairs at a positive distance of at most cutoff angstrom.

ring_report

Primitive rings of an explicit bond list or of a heavy-atom cutoff.

_owners

assign_points

Label each query by the nearest ring centroid or junction midpoint.

read_structure

Read an XYZ (no bonds) or a V2000 SDF (bonds included).

_read_xyz

_read_sdf

_write_xyz

_one_indexed

render_primitive_rings

Draw one hull per primitive ring and a dashed stroke on each junction.

format_report

One plain-text table of the census, the junctions, and the labels.

_owner_atoms

_backbone_ranks

Order ring centroids along their leading axis.

_ring_adjacency

Rings that share an atom, or that a junction joins.

_ring_distance

_chain_value

align_trajectory

Match each frame’s labels by atom set and count terminal-ring hops.

track_queries

Label query points on each frame and count terminal-ring hops.

read_xyz_frames

Every frame of a multi-structure XYZ. Columns past x, y, z are ignored.

read_frames

One SDF frame with its bonds, or every frame of an XYZ without bonds.

read_query_frames

Query coordinates with shape (frame, point, 3).

load_trajectory

Track query frames on a molecule file.

format_trajectory

Hop counts and the terminal-ring coordinate of each query.

write_trajectory_csv

One row per query per frame.

chain_of_pentagons

Flat pentagons joined by one bridge each. Coordinates are angstrom.

Data#

API#

chemparseplot.plot.rings.RING_COLOURS#

(‘#0072B2’, ‘#E69F00’, ‘#009E73’, ‘#CC79A7’, ‘#D55E00’, ‘#56B4E9’, ‘#F0E442’, ‘#000000’)

chemparseplot.plot.rings.JUNCTION_COLOUR#

‘#C0392B’

class chemparseplot.plot.rings.RingReport#

Rings and the complement of their edges, for one neighbour list.

n_atoms: int#

None

bonds: tuple[tuple[int, int], ...]#

None

rings: tuple[tuple[int, ...], ...]#

None

junctions: tuple[tuple[int, int], ...]#

None

pendants: tuple[tuple[int, int], ...]#

None

other: tuple[tuple[int, int], ...]#

None

depth_gap: tuple[tuple[int, int, int], ...]#

None

property census: dict[int, int]#

Ring counts keyed by size.

class chemparseplot.plot.rings.Assignment#

Nearest ring centroid or junction midpoint for one query point.

query: int#

None

kind: str#

None

owner: int#

None

distance: float#

None

margin: float#

None

chemparseplot.plot.rings._import_pydseams()#
chemparseplot.plot.rings._import_xyzrender()#
chemparseplot.plot.rings._as_edges(bonds: collections.abc.Sequence[tuple[int, int]], n_atoms: int) → tuple[tuple[int, int], ...]#
chemparseplot.plot.rings._adjacency(n_atoms: int, edges: collections.abc.Sequence[tuple[int, int]]) → list[set[int]]#
chemparseplot.plot.rings._nlist(adj: collections.abc.Sequence[set[int]]) → list[list[int]]#

Row format ringNetwork reads: the vertex, then its neighbours.

chemparseplot.plot.rings._girth(adj: list[set[int]], u: int, v: int) → int | None#

Length of a shortest cycle through uv, or None when uv is a bridge.

chemparseplot.plot.rings._ring_edges(rings: collections.abc.Sequence[collections.abc.Sequence[int]]) → tuple[set[tuple[int, int]], set[int]]#
chemparseplot.plot.rings.report_from_bonds(n_atoms: int, bonds: collections.abc.Sequence[tuple[int, int]], *, max_depth: int = 6) → chemparseplot.plot.rings.RingReport#

Enumerate primitive rings of an explicit neighbour list.

max_depth is the largest ring ringNetwork generates. An edge that still lies on a cycle of length 12 or less, and that is absent from the returned rings, is recorded in depth_gap. That absence is truncation. An edge with no cycle is a bridge. A junction is a bridge, or a truncated edge, whose two ends both lie on a returned ring.

chemparseplot.plot.rings.bonds_within_cutoff(symbols: collections.abc.Sequence[str], coords: numpy.ndarray, cutoff: float) → tuple[tuple[int, int], ...]#

Heavy-atom pairs at a positive distance of at most cutoff angstrom.

Hydrogen is left out. On a thiophene the covalent heavy graph and the 3.5 angstrom graph are different molecules, so the cutoff is an argument and not a default.

chemparseplot.plot.rings.ring_report(symbols: collections.abc.Sequence[str], coords: numpy.ndarray, *, bonds: collections.abc.Sequence[tuple[int, int]] | None = None, cutoff: float | None = None, max_depth: int = 6) → chemparseplot.plot.rings.RingReport#

Primitive rings of an explicit bond list or of a heavy-atom cutoff.

chemparseplot.plot.rings._owners(coords: numpy.ndarray, report: chemparseplot.plot.rings.RingReport) → tuple[numpy.ndarray, list[tuple[str, int]]]#
chemparseplot.plot.rings.assign_points(coords: numpy.ndarray, report: chemparseplot.plot.rings.RingReport, queries: numpy.ndarray) → tuple[chemparseplot.plot.rings.Assignment, ...]#

Label each query by the nearest ring centroid or junction midpoint.

The label is a name for the centre. The centre’s own coordinate is what enters a mean square displacement.

chemparseplot.plot.rings.read_structure(path: str | os.PathLike[str]) → tuple[list[str], numpy.ndarray, tuple[tuple[int, int], ...] | None]#

Read an XYZ (no bonds) or a V2000 SDF (bonds included).

chemparseplot.plot.rings._read_xyz(text: str) → tuple[list[str], numpy.ndarray, None]#
chemparseplot.plot.rings._read_sdf(text: str) → tuple[list[str], numpy.ndarray, tuple[tuple[int, int], ...]]#
chemparseplot.plot.rings._write_xyz(path: pathlib.Path, symbols: collections.abc.Sequence[str], coords: numpy.ndarray) → None#
chemparseplot.plot.rings._one_indexed(groups: collections.abc.Sequence[collections.abc.Sequence[int]]) → list[list[int]]#
chemparseplot.plot.rings.render_primitive_rings(symbols: collections.abc.Sequence[str], coords: numpy.ndarray, output: str | os.PathLike[str], *, bonds: collections.abc.Sequence[tuple[int, int]] | None = None, cutoff: float | None = None, max_depth: int = 6, queries: numpy.ndarray | None = None, config: str = 'paton', canvas_size: int = 900) → tuple[chemparseplot.plot.rings.RingReport, tuple[chemparseplot.plot.rings.Assignment, ...]]#

Draw one hull per primitive ring and a dashed stroke on each junction.

Query points, when given, are a second structure drawn in place. They are not aligned onto the molecule. Each is an He marker at the caller’s coordinate, which is the stand-in for a Wannier centre.

chemparseplot.plot.rings.format_report(report: chemparseplot.plot.rings.RingReport, assignments: collections.abc.Sequence[chemparseplot.plot.rings.Assignment] = ()) → str#

One plain-text table of the census, the junctions, and the labels.

class chemparseplot.plot.rings.Sample#

One query on one frame, after rings have been matched by atom set.

frame: int#

None

query: int#

None

kind: str#

None

owner: int#

None

atoms: tuple[int, ...]#

None

chain: float#

None

terminal_atoms: tuple[int, ...] | None#

None

terminal_chain: float | None#

None

distance: float#

None

margin: float#

None

label_hop: bool#

None

block_hop: bool#

None

hop_length: int | None#

None

class chemparseplot.plot.rings.Trajectory#

Labels, junction visits, and terminal-ring hops for every query.

samples: tuple[chemparseplot.plot.rings.Sample, ...]#

None

n_frames: int#

None

n_queries: int#

None

label_hops(query: int | None = None) → int#

Owner changes, including a visit to a junction.

block_hops(query: int | None = None) → int#

Changes of the terminal ring. A junction frame keeps that ring.

neighbor_hops(query: int | None = None) → int#

Block hops whose rings share an atom or a junction in that frame.

junction_frames(query: int | None = None) → int#

Frames whose nearest owner is a bridge between rings.

chemparseplot.plot.rings._owner_atoms(report: chemparseplot.plot.rings.RingReport, kind: str, owner: int) → tuple[int, ...]#
chemparseplot.plot.rings._backbone_ranks(coords: numpy.ndarray, report: chemparseplot.plot.rings.RingReport, previous_axis: numpy.ndarray | None = None) → tuple[dict[int, int], numpy.ndarray | None]#

Order ring centroids along their leading axis.

The stored axis keeps its sign from the previous frame, so a rigid molecule does not reverse the chain coordinate. The rank is still not the identity of a ring. The atom set is.

chemparseplot.plot.rings._ring_adjacency(report: chemparseplot.plot.rings.RingReport) → list[set[int]]#

Rings that share an atom, or that a junction joins.

chemparseplot.plot.rings._ring_distance(adj: collections.abc.Sequence[set[int]], src: int, dst: int) → int | None#
chemparseplot.plot.rings._chain_value(report: chemparseplot.plot.rings.RingReport, ranks: dict[int, int], kind: str, owner: int) → float#
chemparseplot.plot.rings.align_trajectory(frames: collections.abc.Sequence[tuple[chemparseplot.plot.rings.RingReport, tuple[chemparseplot.plot.rings.Assignment, ...], numpy.ndarray]]) → chemparseplot.plot.rings.Trajectory#

Match each frame’s labels by atom set and count terminal-ring hops.

owner on an :class:Assignment is the position of that ring in one call. The same atoms can come back at another position. The canonical owner is the atom set, first seen in frame order.

chemparseplot.plot.rings.track_queries(frames: collections.abc.Sequence[tuple[collections.abc.Sequence[str], numpy.ndarray, collections.abc.Sequence[tuple[int, int]] | None]], queries: numpy.ndarray, *, cutoff: float | None = None, max_depth: int = 6) → chemparseplot.plot.rings.Trajectory#

Label query points on each frame and count terminal-ring hops.

frames is (symbols, coordinates, bonds). Bonds and cutoff follow the same rule as :func:ring_report: one of them, not both. queries has shape (frame, point, 3). A single point per frame may be (frame, 3).

chemparseplot.plot.rings.read_xyz_frames(text: str) → list[tuple[list[str], numpy.ndarray]]#

Every frame of a multi-structure XYZ. Columns past x, y, z are ignored.

chemparseplot.plot.rings.read_frames(path: str | os.PathLike[str]) → list[tuple[list[str], numpy.ndarray, tuple[tuple[int, int], ...] | None]]#

One SDF frame with its bonds, or every frame of an XYZ without bonds.

chemparseplot.plot.rings.read_query_frames(path: str | os.PathLike[str]) → numpy.ndarray#

Query coordinates with shape (frame, point, 3).

chemparseplot.plot.rings.load_trajectory(molecule: str | os.PathLike[str], queries: str | os.PathLike[str], *, cutoff: float | None = None, max_depth: int = 6) → chemparseplot.plot.rings.Trajectory#

Track query frames on a molecule file.

One molecule frame is reused for every query frame. That is a fixed bond graph with a moving centre. Several molecule frames pair with the query frames one to one, and an XYZ molecule then needs cutoff.

chemparseplot.plot.rings.format_trajectory(track: chemparseplot.plot.rings.Trajectory) → str#

Hop counts and the terminal-ring coordinate of each query.

chemparseplot.plot.rings.write_trajectory_csv(path: str | os.PathLike[str], track: chemparseplot.plot.rings.Trajectory) → None#

One row per query per frame.

chemparseplot.plot.rings.chain_of_pentagons(n_rings: int, side: float = 1.4, gap: float = 1.45)#

Flat pentagons joined by one bridge each. Coordinates are angstrom.