schrodinger.application.matsci.smarts_visualizer_gui module

Visualization of SMARTS patterns inspired by smarts plus website

Atoms are drawn as colored circles. Non-element primitives (ring membership, H count, connectivity, etc.) appear as labeled entries in a dashed annotation box attached to the atom circle. Bonds are drawn as styled lines between atoms.

Copyright Schrodinger, LLC. All rights reserved.

class schrodinger.application.matsci.smarts_visualizer_gui.BondInfo(offset, signs)

Bases: tuple

offset

Alias for field number 0

signs

Alias for field number 1

class schrodinger.application.matsci.smarts_visualizer_gui.LineStyle

Bases: IntEnum

Line style for pens and drawing helpers.

SOLID = 0
DOTTED = 1
DASHED = 2
class schrodinger.application.matsci.smarts_visualizer_gui.AnnotationParam(center_x: float, center_y: float, out_dir: int, primitives: object, node_data: dict, node_idx: int, pixel_positions: dict, is_stereo_rendered: bool, ring_dir: tuple = None, ring_size_dir: tuple = None, h_dir: tuple = None, conn_dir: tuple = None, recursive_dir: tuple = None, unknown_dir: tuple = None)

Bases: object

Holds common rendering state shared by the per-primitive annotation renderer methods.

Parameters:
  • center_x (float) – Atom circle center X

  • center_y (float) – Atom circle center Y

  • out_dir (int) – Default annotation direction away from neighbours

  • primitives (AtomPrimitives) – Parsed atom primitives

  • node_data (dict) – Node attribute dict from the graph. Keys are NODE_LABEL, NODE COLOR, and NODE_PRIMITIVES and values as SMARTS atom label, QtGui.QColor element color, and AtomPrimitives respectively

  • node_idx (int) – Node index in the graph

  • pixel_positions (dict) – Mapping from node index as key and pixel coordinates values

  • is_stereo_rendered (bool) – Whether stereo bonds control H-count hashing

center_x: float
center_y: float
out_dir: int
primitives: object
node_data: dict
node_idx: int
pixel_positions: dict
is_stereo_rendered: bool
ring_dir: tuple = None
ring_size_dir: tuple = None
h_dir: tuple = None
conn_dir: tuple = None
recursive_dir: tuple = None
unknown_dir: tuple = None
__init__(center_x: float, center_y: float, out_dir: int, primitives: object, node_data: dict, node_idx: int, pixel_positions: dict, is_stereo_rendered: bool, ring_dir: tuple = None, ring_size_dir: tuple = None, h_dir: tuple = None, conn_dir: tuple = None, recursive_dir: tuple = None, unknown_dir: tuple = None) → None
class schrodinger.application.matsci.smarts_visualizer_gui.KeyEntryParams(pos_x: float, pos_y: float, font: QFont)

Bases: object

Parameters for drawing a legend key entry (generic symbol key row).

Parameters:
  • pos_x (float) – Horizontal position for the entry

  • pos_y (float) – Vertical position for the entry

  • font (QtGui.QFont) – Font for the description label

pos_x: float
pos_y: float
font: QFont
__init__(pos_x: float, pos_y: float, font: QFont) → None
class schrodinger.application.matsci.smarts_visualizer_gui.GlyphParams(pos_x: float, pos_y: float, prims: AtomPrimitives)

Bases: object

Parameters for drawing a mini atom glyph annotation in the legend.

Parameters:
  • pos_x (float) – X-coordinate of the atom center

  • pos_y (float) – Y-coordinate of the atom center

  • prims (AtomPrimitives) – Structured primitives for the atom

pos_x: float
pos_y: float
prims: AtomPrimitives
__init__(pos_x: float, pos_y: float, prims: AtomPrimitives) → None
class schrodinger.application.matsci.smarts_visualizer_gui.DrawBondParams(start_x: float, start_y: float, end_x: float, end_y: float, offset_x: float = 0.0, offset_y: float = 0.0, bond_type: str = '', unit_x: float = 0.0, unit_y: float = 0.0)

Bases: object

Parameters for drawing a bond line or legend bond entry.

Parameters:
  • start_x (float) – Start X position

  • start_y (float) – Start Y position

  • end_x (float) – End X position

  • end_y (float) – End Y position

  • offset_x (float) – Horizontal offset applied to both endpoints

  • offset_y (float) – Vertical offset applied to both endpoints

  • bond_type (str) – SMARTS bond token for legend entries

  • unit_x (float) – Unit bond-direction X component

  • unit_y (float) – Unit bond-direction Y component

start_x: float
start_y: float
end_x: float
end_y: float
offset_x: float = 0.0
offset_y: float = 0.0
bond_type: str = ''
unit_x: float = 0.0
unit_y: float = 0.0
__init__(start_x: float, start_y: float, end_x: float, end_y: float, offset_x: float = 0.0, offset_y: float = 0.0, bond_type: str = '', unit_x: float = 0.0, unit_y: float = 0.0) → None
schrodinger.application.matsci.smarts_visualizer_gui.get_bond_line_style(bond_label)

Return the line style for a SMARTS bond label.

Parameters:

bond_label (str) – SMARTS bond token

Return type:

LineStyle

Returns:

Dotted for aromatic bonds, otherwise solid

schrodinger.application.matsci.smarts_visualizer_gui.make_pen(color, width=1.5, style=LineStyle.SOLID)

Construct a QPen with the given color, width, and line style.

Parameters:
  • color (QtGui.QColor) – Pen color

  • width (float) – Pen width in pixels

  • style (LineStyle) – Line style (SOLID, DOTTED, or DASHED)

Return type:

QtGui.QPen

Returns:

Configured QPen instance

schrodinger.application.matsci.smarts_visualizer_gui.resolve_pen(painter, pen=None, color=None, pen_thickness=1.5, fill_color=None)

Resolve and apply a QPen on painter.

If pen is given it is used as-is. Otherwise a QPen is built from color and pen_thickness (defaulting to PEN_STANDARD). When neither pen nor color is given but fill_color is, NoPen is applied so the fill renders without an outline. Always returns the applied pen (or None) so callers can branch if needed.

Parameters:
  • painter (QtGui.QPainter) – Active QPainter

  • pen (QtGui.QPen or None) – Explicit pen to use unchanged

  • color (QtGui.QColor or None) – Pen color

  • pen_thickness (float) – Pen width (used only when pen is None)

  • fill_color (QtGui.QColor or None) – If given and no pen/color available, apply NoPen

Return type:

QtGui.QPen or None

Returns:

The QPen that was applied, or None

schrodinger.application.matsci.smarts_visualizer_gui.make_font(size, bold=False, family='Sans', painter=None)

Construct a QFont with the given size and weight, optionally applying it to a painter immediately.

Parameters:
  • size (int) – Point size

  • bold (bool) – Whether to use bold weight

  • family (str) – Font family name

  • painter (QtGui.QPainter or None) – If provided, painter.setFont is called with the new font

Return type:

QtGui.QFont

Returns:

Configured QFont instance

schrodinger.application.matsci.smarts_visualizer_gui.make_triangle_path(px_1, py_1, px_2, py_2, px_3, py_3)

Build a closed QtGui.QPainterPath triangle from three vertex coordinates.

Parameters:
  • px_1 (float) – X coordinate of vertex 1

  • py_1 (float) – Y coordinate of vertex 1

  • px_2 (float) – X coordinate of vertex 2

  • py_2 (float) – Y coordinate of vertex 2

  • px_3 (float) – X coordinate of vertex 3

  • py_3 (float) – Y coordinate of vertex 3

Return type:

QtGui.QPainterPath

Returns:

Closed triangle path

schrodinger.application.matsci.smarts_visualizer_gui.compute_unit_vector(d_params)

Compute the unit direction vector and Euclidean distance between the start and end points of a DrawBondParams instance.

Parameters:

d_params (DrawBondParams) – Bond line parameters

Return type:

tuple(float, float, float) or None

Returns:

(unit_x, unit_y, length) or None if length < GEOMETRY_EPSILON

schrodinger.application.matsci.smarts_visualizer_gui.draw_line(painter, d_params, pen=None, color=None, pen_thickness=1.5)

Draw a line from (start_x+offset_x, start_y+offset_y) to (end_x+offset_x, end_y+offset_y).

If pen is provided, it is set before drawing. Otherwise if color is given, make_pen(color, pen_thickness) is used

Parameters:
  • painter (QtGui.QPainter) – Active QPainter

  • d_params (DrawEntryParams) – Bond line parameters

  • pen (QtGui.QPen or None) – Optional pen to set before drawing

  • color (QtGui.QColor or None) – Line color for auto-generated pen

  • pen_thickness (float) – Pen width (used only when pen is None)

schrodinger.application.matsci.smarts_visualizer_gui.draw_text(painter, text, pos_x=None, pos_y=None, rect=None, rect_radius=None, flags=AlignmentFlag.AlignCenter, pen=None, font=None, color=None, font_size=None, bold=False)

Draw text at a point (pos_x, pos_y) or inside rect using flags.

If rect is None and rect_radius is provided, a centered square rect is constructed automatically around (pos_x, pos_y).

If pen is provided, it is set before drawing. Otherwise if color is given, make_pen(color, PEN_STANDARD) is used.

If font is provided, it is set before drawing. Otherwise if font_size is given, make_font(font_size) is used.

Parameters:
  • painter (QtGui.QPainter) – Active QPainter

  • text (str) – The text string to draw

  • pos_x (float or None) – X coordinate for point-based or centered-rect drawing

  • pos_y (float or None) – Y coordinate for point-based or centered-rect drawing

  • rect (QtCore.QRectF or None) – Rectangle for rect-based drawing

  • rect_radius (float or None) – Half side of auto-generated centered rect

  • flags (int) – Alignment flags used with rect

  • pen (QtGui.QPen or None) – Optional pen to set before drawing

  • font (QtGui.QFont or None) – Optional font to set before drawing

  • color (QtGui.QColor or None) – Optional color for auto-generated pen

  • font_size (int or None) – Optional font size for auto-generated font

  • bold (bool) – Use bold weight for auto-generated font

schrodinger.application.matsci.smarts_visualizer_gui.draw_circle(painter, c_x=None, c_y=None, radius=None, rect=None, pen=None, color=None, fill_color=None, pen_thickness=1.5)

Draw a circle centered at (c_x, c_y) with radius, or using rect.

If rect is provided, the circle is inscribed in that rectangle. Otherwise the center-point form is used.

If pen is provided, it is set before drawing. Otherwise if color is given, make_pen(color, pen_thickness) is used.

Parameters:
  • painter (QtGui.QPainter) – Active QPainter

  • c_x (float or None) – Center X coordinate

  • c_y (float or None) – Center Y coordinate

  • radius (float or None) – Circle radius

  • rect (QtCore.QRectF or None) – Bounding rectangle for the circle

  • pen (QtGui.QPen or None) – Optional pen to set before drawing

  • color (QtGui.QColor or None) – Optional color for auto-generated pen

  • fill_color (QtGui.QColor or None) – Optional fill color for the circle interior. Pass None for stroke-only outline (no fill).

  • pen_thickness (float) – Pen width used when pen is None and color is given

schrodinger.application.matsci.smarts_visualizer_gui.draw_colored_label_rect(painter, rect, fill_color, label, font_size, border_color=None, pen_thickness=1.5)

Draw a filled label rectangle with contrasting centered text.

Parameters:
  • painter (QtGui.QPainter) – Active QPainter

  • rect (QtCore.QRectF) – Bounding rectangle for the label

  • fill_color (QtGui.QColor) – Background color for the rectangle

  • label (str) – Text to render in the rectangle

  • font_size (int) – Label text size

  • border_color (QtGui.QColor or None) – Optional outline color; defaults to fill_color

  • pen_thickness (float) – Outline width

schrodinger.application.matsci.smarts_visualizer_gui.draw_path(painter, path, color=None, pen_thickness=1.5, pen=None, fill_color=None)

Stroke and optionally fill a QPainterPath.

If pen is not provided, make_pen(color, pen_thickness) is used.

Parameters:
  • painter (QtGui.QPainter) – Active QPainter

  • path (QtGui.QPainterPath) – Pre-built painter path to draw

  • color (QtGui.QColor or None) – Line color for auto-generated pen

  • pen_thickness (float) – Pen width (used only when pen is None)

  • pen (QtGui.QPen or None) – Explicit pen; overrides color and pen_thickness

  • fill_color (QtGui.QColor or None) – If a QColor, fills the path interior. Pass None for stroke-only outline (no fill).

schrodinger.application.matsci.smarts_visualizer_gui.build_element_color_structure()

Build a structure with one atom per element (atomic numbers 1 through mm.MMELEMENTS_MAX), used for ASL evaluation in color-scheme lookup.

Atom at 1-based index anum has atomic number anum.

Return type:

Structure

Returns:

Structure with one atom per element

schrodinger.application.matsci.smarts_visualizer_gui.load_element_colors()

Load Maestro’s element color scheme into an atomic-number-to-QColor mapping by evaluating each rule’s ASL against a one-atom-per-element probe structure.

Return type:

dict(int, QtGui.QColor)

Returns:

Mapping from atomic number to QColor

schrodinger.application.matsci.smarts_visualizer_gui.get_atom_color(atomic_num)

Return the QColor for the given atomic number.

Parameters:

atomic_num (int) – Atomic number (0 for wildcard)

Return type:

QtGui.QColor

Returns:

Element color

schrodinger.application.matsci.smarts_visualizer_gui.build_element_symbols()

Build the complete set of element symbols recognised in SMARTS, sourced from the Schrodinger infrastructure element list (1–MMELEMENTS_MAX) plus the lowercase aromatic SMARTS forms (e.g. c, n) and the wildcard *.

Return type:

set(str)

Returns:

Set of valid element/wildcard tokens

schrodinger.application.matsci.smarts_visualizer_gui.split_respecting_parens(text, sep)

Split text on the single character sep, ignoring occurrences inside parentheses.

Parameters:
  • text (str) – String to split

  • sep (str) – Single separator character

Return type:

list(str)

Returns:

List of substrings

schrodinger.application.matsci.smarts_visualizer_gui.negate_label(value, negated)

Return the SMARTS-style negated display label for a value.

Parameters:
  • value (object) – Value to format

  • negated (bool) – Whether the value should be prefixed with ‘!’

Return type:

str

Returns:

‘!value’ if negated, else str(value)

schrodinger.application.matsci.smarts_visualizer_gui.split_negation(token)

Split a leading ‘!’ negation marker from a SMARTS token.

Parameters:

token (str) – SMARTS token, possibly prefixed with ‘!’

Return type:

tuple(bool, str)

Returns:

Whether the token was negated, and the token with ‘!’ removed

class schrodinger.application.matsci.smarts_visualizer_gui.BasePrimitive

Bases: object

Base class for atom primitives

SCALAR_ATTR = None
SCALAR_RE = None
parse(core, negated)

Parse the primitive from the SMARTS token.

The default implementation uses the class-level SCALAR_ATTR and SCALAR_RE to match core and store (int(value), negated). Subclasses that need different logic should override this method.

Parameters:
  • core (str) – SMARTS token core string

  • negated (bool) – whether the token was negated

Return type:

bool

Returns:

True if token was consumed

hasData()

Return True if this primitive has any data.

Return type:

bool

Returns:

True if any data was parsed

needsAnnotationSlot()

Return True if this primitive is drawn as an annotation outside the atom circle. By default we assume that primitives are drawn on the atom circle.

Return type:

bool

Returns:

True if this primitive is drawn outside the atom circle

featureKey()

Return a feature key if this primitive has multiple options.

Return type:

str or None

Returns:

FEATURE_OR_LIST if multiple options, else None

description(**kwargs)

Return a description string for this primitive, or None if it is drawn on the atom circle.

Return type:

str or None

Returns:

Description string or None

class schrodinger.application.matsci.smarts_visualizer_gui.Element

Bases: BasePrimitive

Primitive for element constraints: bare symbols (C, c, Cl) and atomic-number tokens (#6).

ELEMENT_RE = re.compile('^#(\\d+)$')
ISOTOPE_RE = re.compile('^\\d+([A-Z][a-z]?|[a-z])$')
__init__()

Initialize with an empty list of atomic elements.

parse(core, negated)

See parent for information.

parseWildcard()

Set this primitive to represent the wildcard atom

hasData()

See parent for information.

featureKey()

Return a feature key if this primitive has multiple elements.

Return type:

str or None

Returns:

FEATURE_OR_LIST if multiple elements, else None

description(**kwargs)

Return None since element symbols are drawn on the atom circle.

Return type:

None

Returns:

None — element description is handled by AtomRenderer

isNegatedOnly()

Return whether the sole element predicate is negated.

Return type:

bool

Returns:

True for predicates such as !C or !#6

isHydrogen()

Return True if the sole element is hydrogen (not negated).

Return type:

bool

Returns:

True if the sole element is hydrogen (not negated)

isAromatic()

Return True if the first element symbol is lowercase (aromatic form).

Return type:

bool

Returns:

True if the first element symbol is lowercase (aromatic form)

getDisplaySymbol()

Return the symbol string to render on the atom circle.

Return type:

str

Returns:

Element symbol, wildcard, or comma-joined OR-list

class schrodinger.application.matsci.smarts_visualizer_gui.Ring

Bases: BasePrimitive

Primitive for ring membership and size constraints: R, R0, Rn, rn.

RING_COUNT_RE = re.compile('^R(\\d+)$')
RING_SIZE_RE = re.compile('^r(\\d+)$')
NO_RING_SIZE = 0
__init__()

Initialize with no ring constraints.

parse(core, negated)

See parent for information.

parseRingNumeric(core, negated, regex, val_attr, negated_attr)

Parse a ring count or ring size numeric constraint.

If the value is NO_RING_SIZE, this sets the membership flag (RING_IN or RING_NOT_IN) instead.

Parameters:
  • core (str) – SMARTS primitive token

  • negated (bool) – Whether the outer SMARTS atom was negated

  • regex (re.Pattern) – Compiled regex that captures the ring value

  • val_attr (str) – Name of the attribute to store the numeric value

  • negated_attr (str) – Name of the boolean attribute for negation

Return type:

bool

Returns:

True if the pattern matched, False otherwise

hasData()

See parent for information.

needsAnnotationSlot()

See parent for information.

featureKey()

See parent for information.

description(**kwargs)

See parent for information.

class schrodinger.application.matsci.smarts_visualizer_gui.HCount

Bases: BasePrimitive

Primitive for hydrogen count constraints: H, H0…H4.

HCOUNT_RE = re.compile('^H(\\d*)$')
__init__()

Initialize with an empty list of hydrogen counts.

parse(core, negated)

See parent for information.

hasData()

See parent for information.

needsAnnotationSlot()

See parent for information.

featureKey()

See parent for information.

formatLabel()

Return the comma-separated hydrogen-count label.

Return type:

str

Returns:

Hydrogen-count values without the SMARTS H prefix

hasPositiveImplicitHydrogen()

Return whether this atom has exactly one positive implicit hydrogen.

Return type:

bool

Returns:

True when H1, rather than a negated or zero-H constraint, is present

description(**kwargs)

See parent for information.

class schrodinger.application.matsci.smarts_visualizer_gui.Connectivity

Bases: BasePrimitive

Primitive for total connectivity constraints: X1…X4.

SCALAR_ATTR = 'connectivity'
SCALAR_RE = re.compile('^X(\\d+)$')
__init__()

Initialize with no connectivity constraint.

hasData()

See parent for information.

needsAnnotationSlot()

See parent for information.

featureKey()

See parent for information.

getRemaining(graph_degree)

Return the number of connections not represented by visible bonds.

Parameters:

graph_degree (int) – Number of visible bonds

Return type:

int

Returns:

Remaining total connections

description(graph_degree=0, **kwargs)

See parent for information.

class schrodinger.application.matsci.smarts_visualizer_gui.Degree

Bases: BasePrimitive

Primitive for heavy-atom degree constraints: D1…D4.

SCALAR_ATTR = 'degree'
SCALAR_RE = re.compile('^D(\\d+)$')
__init__()

Initialize with no degree constraint.

hasData()

See parent for information.

featureKey()

See parent for information.

description(**kwargs)

See parent for information.

class schrodinger.application.matsci.smarts_visualizer_gui.Valence

Bases: BasePrimitive

Primitive for valence constraints: v1…v4.

SCALAR_ATTR = 'valence'
SCALAR_RE = re.compile('^v(\\d+)$')
__init__()

Initialize with no valence constraint.

hasData()
Return type:

bool

Returns:

True if a valence constraint was parsed

featureKey()

See parent for information.

description(**kwargs)

See parent for information.

class schrodinger.application.matsci.smarts_visualizer_gui.Charge

Bases: BasePrimitive

Primitive for formal charge constraints: +, -, +2, etc.

CHARGE_RE = re.compile('^([+\\-])(\\d*)$')
__init__()

Initialize with no charge constraint.

parse(core, negated)

See parent for information.

hasData()

See parent for information.

featureKey()

See parent for information.

formatLabel()

Return the charge label string for display, e.g. ‘+2’, ‘-1’.

Return type:

str

Returns:

Charge label, or empty string if no charge is set

description(**kwargs)

See parent for information.

class schrodinger.application.matsci.smarts_visualizer_gui.Aromatic

Bases: BasePrimitive

Primitive for aromaticity flag constraints: a (aromatic) or A (aliphatic).

__init__()

Initialize with no aromaticity flag.

parse(core, negated)

See parent for information.

hasData()

See parent for information.

isAromatic()

Return whether this primitive explicitly marks the atom aromatic.

Return type:

bool

Returns:

True if the flag is ‘a’ and not negated

featureKey()

See parent for information.

description(**kwargs)

See parent for information.

class schrodinger.application.matsci.smarts_visualizer_gui.Chirality

Bases: BasePrimitive

Primitive for tetrahedral chirality: @ (CCW) or @@ (CW).

__init__()

Initialize with no chirality constraint.

parse(core, negated)

See parent for information. Chirality set by element and not “parsed” from the SMARTS string, so this method always returns False.

setChirality(value)

Set the chirality value directly from the RDKit chiral tag.

Parameters:

value (str) – STEREO_CCW or STEREO_CW

hasData()

See parent for information.

featureKey()

See parent for information.

description(**kwargs)

See parent for information.

class schrodinger.application.matsci.smarts_visualizer_gui.Recursive

Bases: BasePrimitive

Primitive for recursive SMARTS constraints: $(…).

RECURSIVE_RE = re.compile('^\\$\\(')
__init__()

Initialize with an empty list of recursive patterns.

parse(core, negated)

See parent for information.

hasData()

See parent for information.

featureKey()

See parent for information.

description(**kwargs)

See parent for information.

class schrodinger.application.matsci.smarts_visualizer_gui.RecursivePalette

Bases: object

Assign stable identifiers and colors to unique recursive SMARTS strings.

__init__()

Initialize with empty pattern-to-entry mapping and ordered entry list.

getEntry(pattern)

Return the shared palette entry for a recursive SMARTS string.

Parameters:

pattern (str) – Recursive SMARTS predicate

Return type:

dict

Returns:

Entry containing label, pattern, and color

copyPalette()

Return an independent palette with the same entry order and colors.

Return type:

RecursivePalette

Returns:

Independent copy of this palette

schrodinger.application.matsci.smarts_visualizer_gui.extract_recursive_inner(pattern)

Return the SMARTS expression contained by a recursive predicate.

Parameters:

pattern (str) – Recursive SMARTS predicate

Return type:

str

Returns:

Inner SMARTS expression

class schrodinger.application.matsci.smarts_visualizer_gui.AtomPrimitives(raw_smarts)

Bases: object

Container of per-primitive objects parsed from a raw SMARTS atom token.

Each attribute is an instance of the corresponding primitive class. Parsing is delegated to those classes; this class only orchestrates tokenization and provides aggregate query methods.

__init__(raw_smarts)

Initialize by parsing the raw SMARTS atom token.

Parameters:

raw_smarts (str) – Raw atom SMARTS token from atom.GetSmarts()

nonElementPrimitives()

Return primitives that may carry user-visible annotation data.

Excludes element, which is drawn on the circle itself. Chirality is populated externally during bond rendering.

Returns:

Tuple of non-element primitive objects

Return type:

tuple

parse(raw_smarts)

Populate primitive sub-objects by parsing raw_smarts.

Parameters:

raw_smarts (str) – Raw atom SMARTS token

parseToken(token)

Try each primitive class’s parser on a single token, in order, stopping at the first one that recognizes it.

Parameters:

token (str) – Single primitive token, possibly negated with !

hasNonElementPrimitives()

Return True if the atom has any constraint beyond its element.

Used to decide whether to draw the atom circle with an outline (constrained) or without (element-only).

Return type:

bool

Returns:

True if the atom has constraints beyond its element

isRecursiveOnly()

Return whether the atom is represented solely by recursive SMARTS.

A recursive-only atom has no explicit element and no other visible primitive or fallback token. It is rendered as a labeled square so that the recursive predicate, rather than an unexplained wildcard, is the primary atom glyph.

Return type:

bool

Returns:

True when recursive SMARTS is the only atom constraint

countAnnotationSlots()

Return the number of directional annotation slots needed.

Annotations that extend outward from the atom circle (ring, H count, connectivity, ring size) each consume one directional slot.

Return type:

int

Returns:

Number of annotation slots needed

presentFeatures()

Return the set of FEATURE_* keys describing which annotation primitives this atom carries.

Does not include FEATURE_AROMATIC — that depends on element symbol and is determined by SMARTSGraphWidget.isAromaticAtom.

Return type:

set(str)

Returns:

Set of feature keys describing the atom’s primitives

class schrodinger.application.matsci.smarts_visualizer_gui.SmartsNetworkParser(smarts)

Bases: object

Parse a SMARTS string into a NetworkX graph where nodes represent query atoms and edges represent query bonds.

__init__(smarts)

Initialize with a SMARTS string.

Parameters:

smarts (str) – SMARTS pattern to parse

parse()

Build and return the NetworkX graph for the SMARTS pattern.

Return type:

networkx.Graph

Returns:

Graph representing the SMARTS topology

Raises:

ValueError – if the SMARTS string cannot be parsed by RDKit

parseMol()

Parse the SMARTS string into an RDKit molecule and validate it.

Return type:

rdkit.Chem.rdchem.Mol

Returns:

Parsed RDKit molecule

Raises:

ValueError – if SMARTS cannot be parsed or has too many atoms

buildGraph(mol)

Build a NetworkX graph from the RDKit molecule by adding atom nodes and bond edges.

Parameters:

mol (rdkit.Chem.rdchem.Mol) – RDKit molecule

Returns:

NetworkX graph representing the SMARTS topology

Return type:

networkx.Graph

addAtomNodes(graph, mol)

Add atom nodes to the graph.

Parameters:
  • graph (networkx.Graph) – Target graph

  • mol (rdkit.Chem.rdchem.Mol) – Source RDKit molecule

addBondEdges(graph, mol)

Add bond edges to the graph.

Parameters:
  • graph (networkx.Graph) – Target graph

  • mol (rdkit.Chem.rdchem.Mol) – Source RDKit molecule

applyChirality(atom, primitives)

Transfer RDKit chirality tagging onto the AtomPrimitives object.

Parameters:
  • atom (rdkit.Chem.rdchem.Atom) – RDKit atom

  • primitives (AtomPrimitives) – Already-parsed atom primitives

resolveAtomColor(atom, raw_label, primitives)

Determine the display color for an atom based on its element identity.

Parameters:
  • atom (rdkit.Chem.rdchem.Atom) – RDKit atom

  • raw_label (str) – Raw SMARTS label from atom.GetSmarts()

  • primitives (AtomPrimitives) – Already-parsed atom primitives

Returns:

Display color for the atom

Return type:

QtGui.QColor

schrodinger.application.matsci.smarts_visualizer_gui.simplify_detailed_smarts_graph(graph)

Remove explicit hydrogen nodes from a detailed SMARTS display graph.

A heavy atom’s hydrogens are already captured by its total-hydrogen-count primitive, but detailed SMARTS graphs may also carry those same hydrogens as explicit atom nodes. These leaves are redundant for visualization and make the layout substantially harder to read.

Parameters:

graph (networkx.Graph) – Graph built from a detailed SMARTS pattern

Return type:

networkx.Graph

Returns:

Copy of graph without explicit hydrogen nodes

schrodinger.application.matsci.smarts_visualizer_gui.perpendicular_direction(direction)

Return a unit vector perpendicular to direction, preferring the variant with a positive Y component (downward in screen coordinates).

Parameters:

direction (tuple(float, float)) – Unit vector (dx, dy)

Return type:

tuple(float, float)

Returns:

Unit vector perpendicular to direction

class schrodinger.application.matsci.smarts_visualizer_gui.SmartsLayoutEngine(graph)

Bases: object

Compute 2-D positions for graph nodes.

Acyclic chains are laid out in a zigzag (trans) pattern. Acyclic graphs with branches use the longest path as a backbone with branches placed perpendicular. Ring-containing graphs use kamada_kawai_layout. High-degree annotated nodes get neighbors redistributed for annotation room.

__init__(graph)

Initialize the layout engine with the given graph.

Parameters:

graph (networkx.Graph) – NetworkX graph

compute()

Compute 2-D positions for graph nodes.

Return type:

dict

Returns:

Mapping from node index to (x, y) position

disconnectedLayout()

Lay out disconnected components side by side without dropping nodes.

NetworkX’s force-directed layout can omit isolated components from the returned mapping in this rendering path. Computing each connected component independently keeps every graph node addressable and makes the component separation deterministic.

Return type:

dict

Returns:

Mapping from node index to composed component coordinates

getChainOrder()

If graph is an acyclic path (every node has degree <= 2 and there are no cycles), return the ordered list of node indices from one endpoint to the other. Otherwise return None.

Return type:

list(int) or None

Returns:

Ordered list of node indices from one endpoint to the other, or None

redistributeForAnnotations(positions)

Post-process layout positions so that high-degree nodes with annotations have room for their annotation glyphs.

Parameters:

positions (dict) – Mutable mapping from node index to (x, y)

Return type:

dict

Returns:

The updated positions mapping with redistributed neighbor coordinates

getStarHub()

Return the hub node if the graph is a star (one central node where every other node is a leaf with degree 1). Return None otherwise.

Return type:

int or None

Returns:

Hub node index if the graph is a star, otherwise None

starLayout(hub)

Lay out a star graph with the hub at the center and leaves evenly spaced around it in a circle.

Parameters:

hub (int) – Central node index

Return type:

dict

Returns:

Mapping from node index to (x, y) position

branchedZigzagLayout(backbone)

Lay out a graph with a known backbone in zigzag style, placing branch atoms perpendicular to the backbone at their branch points.

The backbone is drawn left-to-right in a zigzag. Branch atoms extend above or below the backbone, alternating sides to minimize overlap.

Parameters:

backbone (list(int)) – Ordered list of node indices along the backbone

Return type:

dict

Returns:

Mapping from node index to (x, y) position

placeBranchDescendants(parent_node, parent_x, parent_y, branch_direction, positions, backbone_set)

Position every non-backbone descendant of a branch node recursively.

Parameters:
  • parent_node (int) – Node index whose children to position

  • parent_x (float) – X-coordinate of the parent node

  • parent_y (float) – Y-coordinate of the parent node

  • branch_direction (int) – +1 for downward, -1 for upward

  • positions (dict) – Position map being built

  • backbone_set (set) – Set of backbone node indices to skip

zigzagLayout(chain_order)

Lay out an ordered chain of nodes in a zigzag (trans) pattern.

Even-indexed atoms sit at y = 0, odd-indexed atoms at y = 0.5, producing the standard chemistry zigzag drawing.

Parameters:

chain_order (list(int)) – Ordered list of node indices

Return type:

dict

Returns:

Mapping from node index to (x, y) position

schrodinger.application.matsci.smarts_visualizer_gui.edge_key(node_a, node_b)

Return a canonical, order-independent key for an undirected edge.

Parameters:
  • node_a (int) – One endpoint of the edge

  • node_b (int) – Other endpoint of the edge

Return type:

tuple(int, int)

Returns:

(min(node_a, node_b), max(node_a, node_b))

schrodinger.application.matsci.smarts_visualizer_gui.compute_position_bounds(coords)

Return the bounding box and coordinate ranges for a set of 2D points.

Degenerate (zero-width or zero-height) ranges are normalized to 1.0 to avoid division by zero when computing scale factors.

Parameters:

coords (iterable(tuple(float, float))) – 2D points to bound

Return type:

tuple(float, float, float, float, float, float)

Returns:

(min_x, max_x, min_y, max_y, range_x, range_y)

class schrodinger.application.matsci.smarts_visualizer_gui.GraphLayoutMapper(graph, positions, width, height, legend_height)

Bases: object

Converts NetworkX layout coordinates to widget pixel coordinates and analyses graph structure (ring membership, stereo assignments).

__init__(graph, positions, width, height, legend_height)

Initialize with the graph, layout positions, and widget dimensions.

Parameters:
  • graph (networkx.Graph) – Parsed SMARTS graph

  • positions (dict) – NetworkX layout positions keyed by node index

  • width (int) – Widget pixel width

  • height (int) – Widget pixel height (excluding legend)

  • legend_height (int) – Pixel height reserved for the legend

layoutToPixel()

Map NetworkX layout coordinates to widget pixel coordinates.

Reserves margins on all sides and space at the bottom for the legend.

Return type:

dict

Returns:

Mapping from node index to (x_px, y_px) tuple

computeRingEdges()

Return the set of edges that are part of a ring.

Each edge is stored as edge_key(u, v) for canonical lookup.

Return type:

set(tuple(int, int))

Returns:

Set of canonical edge keys that belong to a ring

hasMultiBond(node)

Return True if the node has any double or triple bond attached.

Parameters:

node (int) – Node index

Return type:

bool

Returns:

True if the node has any double or triple bond attached

computeStereoAssignments()

Compute which edges should be drawn as wedge or hash bonds, and which atoms should draw their H-count as a hashed wedge.

Rules:

  1. Skip stereo rendering entirely if the chiral center has a double or triple bond (geometry is already constrained).

  2. Ring bonds are always drawn as regular lines (in-plane).

  3. For @@ (CW): the first two non-ring neighbors get solid and hashed wedges respectively. If only one non-ring neighbor exists, the implicit H fills the second slot as a hash.

  4. For @ (CCW): the implicit H gets a hashed wedge (drawn by the hashed-wedge bond is drawn for the H-count line and the second non-ring neighbor gets a solid wedge. If no implicit H, first two non-ring neighbors get solid and hash.

Return type:

tuple(dict, set)

Returns:

A pair of (stereo_map, stereo_h_nodes) where stereo_map maps directed edges to STEREO_WEDGE or STEREO_HASH, and stereo_h_nodes is the set of node indices whose H-count glyph should be drawn as a hashed wedge.

schrodinger.application.matsci.smarts_visualizer_gui.is_aromatic_atom(primitives)

Return True if the atom should be drawn with a dashed (aromatic) outline.

An atom is considered aromatic when its explicit aromatic primitive equals the lower-case aromatic flag and is not negated, or when its element symbol uses lower-case aromatic SMARTS notation.

Parameters:

primitives (AtomPrimitives) – Structured primitives for the atom

Return type:

bool

Returns:

True if the atom should be drawn with a dashed aromatic outline

class schrodinger.application.matsci.smarts_visualizer_gui.BondRenderer(graph)

Bases: object

Draws bond lines between atom pixel positions. Handles single, double, triple, wedge, hash, aromatic, and directional bond styles.

ANY_BOND_COLOR = <PyQt6.QtGui.QColor object>
HEXAGON_RADIUS = 8
BOND_SINGLE_OFFSET = 0.0
SINGLE_BOND_SIGNS = (0,)
DOUBLE_BOND_SIGNS = (-1, 1)
TRIPLE_BOND_SIGNS = (-1, 0, 1)
WAVY_AMPLITUDE = 3.0
WAVY_SEGMENT_DIVISOR = 4
HEXAGON_VERTEX_COUNT = 6
HEXAGON_ANGLE_STEP = 60
HEXAGON_ANGLE_OFFSET = -90
BOND_DOUBLE_OFFSET = 3.0
BOND_TRIPLE_OFFSET = 4.0
PEN_SINGLE_THICKNESS = 2.0
PEN_DOUBLE_THICKNESS = 1.5
PEN_TRIPLE_THICKNESS = 1.2
__init__(graph)

Initialize the bond renderer.

Parameters:

graph (networkx.Graph) – Parsed SMARTS graph

setPainter(painter)

Set the active QPainter and forward to sub-renderers.

Parameters:

painter (QtGui.QPainter) – Active QPainter

drawEdge(painter, d_params, bond_label, stereo=None)

Draw a bond line between two atom positions

Aromatic bonds are drawn as dotted lines. Ring bond negation (!@) is indicated by a small red hexagon at the bond midpoint. Stereo bonds are drawn as filled wedges or hashed wedges emanating from the source (chiral center).

Parameters:
  • painter (QtGui.QPainter) – Active QPainter

  • d_params (DrawBondParams) – Edge params with start_x/y = source, end_x/y = dest

  • bond_label (str) – Bond SMARTS token

  • stereo (str or None) – Stereo bond rendering style

drawBondBody(d_params, bond_label, stereo)

Draw the main bond body, delegating to a stereo-specific renderer when one applies, otherwise falling back to the plain bond renderer.

Parameters:
  • d_params (DrawBondParams) – Bond line parameters

  • bond_label (str) – SMARTS bond token for the edge

  • stereo (str or None) – Stereo rendering override for this edge

drawPlainBond(d_params, bond_label)

Draw a non-stereo bond body, choosing the line style from the SMARTS bond label.

Parameters:
  • d_params (DrawBondParams) – Bond line parameters

  • bond_label (str) – SMARTS bond token for the edge

drawMultiEdge(d_params, pen, bond_info)

Draw a single, double, or triple bond body by offsetting parallel lines perpendicular to the bond axis.

Parameters:
  • d_params (DrawBondParams) – Bond line parameters

  • pen (QtGui.QPen) – Preconfigured pen for the bond

  • bond_info (BondInfo) – Offset and sign configuration

drawDirectionalArrow(d_params, direction)

Draw a small arrowhead at the bond midpoint pointing perpendicular to the bond axis. direction is +1 for up (/) or -1 for down ().

Parameters:
  • d_params (DrawBondParams) – Bond line parameters

  • direction (int) – +1 for up, -1 for down

drawBondAnnotation(d_params, bond_label, hexagon_radius)

Draw the trailing glyph for ring or directional bonds.

Ring bonds (@/!@) get a hexagon at the bond midpoint; directional bonds (//) get a perpendicular arrowhead. Other bond labels add no glyph.

Parameters:
  • d_params (DrawBondParams) – Bond line parameters

  • bond_label (str) – SMARTS bond token for the edge

  • hexagon_radius (float) – Radius of the ring-annotation hexagon

drawWedgeBond(d_params)

Draw a filled solid wedge bond (triangle) from start to end.

The wedge is narrow at the start (chiral center) and widens to WEDGE_BASE_HALF * 2 pixels at the destination.

Parameters:

d_params (DrawBondParams) – Bond line parameters

drawHashBond(d_params, color=<PyQt6.QtGui.QColor object>)

Draw a hashed wedge bond where there are WEDGE_HASH_COUNT equally spaced perpendicular lines that get progressively wider from the chiral center to the neighbor.

Parameters:
  • d_params (DrawBondParams) – Bond line parameters

  • color (QtGui.QColor) – Hash-line color

drawSingleHashBond(d_params, frac, color)

Draw one perpendicular hash line at fractional position and along the bond, with width scaled by the fractional position.

Parameters:
  • d_params (DrawBondParams) – Bond line parameters

  • frac (float) – Fractional position along the bond (0 < frac < 1)

  • color (QtGui.QColor) – Hash-line color

drawHexagonGlyph(d_params, radius, color)

Draw a small hexagon at the midpoint of the bond.

Parameters:
  • d_params (DrawBondParams) – Bond line parameters

  • radius (float) – Hexagon radius

  • color (QtGui.QColor) – Stroke color

drawWavyLine(d_params, color)

Draw a wavy (zigzag) line between two points.

Parameters:
  • d_params (DrawBondParams) – Bond line parameters

  • color (QtGui.QColor) – Line color

class schrodinger.application.matsci.smarts_visualizer_gui.RecursiveGraphRenderer

Bases: object

Draws recursive SMARTS sub-graphs ($(…) patterns) as scaled nested boxes connected by an arrow to the parent atom label.

REC_BOX_FILL = <PyQt6.QtGui.QColor object>
REC_LABEL_HEIGHT = 16
REC_MINI_ATOM_RADIUS = 10
REC_BOX_MARGIN = 16
REC_ARROW_LENGTH = 6
REC_FALLBACK_BOX_GAP = 6
REC_BADGE_GAP = 5
__init__()

Initialize the recursive graph renderer.

setPainter(painter)

Store the active painter for helper methods that reuse it.

Parameters:

painter (QtGui.QPainter) – Active QPainter

drawRecursiveAtom(painter, center_x, center_y, palette_entry, pattern, badge_targets)

Draw a recursive-only atom as a colored labeled square.

Parameters:
  • painter (QtGui.QPainter) – Active QPainter

  • center_x (float) – Atom center X

  • center_y (float) – Atom center Y

  • palette_entry (dict) – Recursive label and color

  • pattern (str) – Recursive SMARTS predicate

  • badge_targets (list) – Mutable click-target collection

drawRecursiveBadge(painter, center_x, center_y, direction, pattern, palette_entry, badge_index, badge_count, badge_targets)

Draw a colored recursive predicate badge attached to an atom.

Parameters:
  • painter (QtGui.QPainter) – Active QPainter

  • center_x (float) – Atom center X

  • center_y (float) – Atom center Y

  • direction (tuple) – Outward annotation direction

  • pattern (str) – Recursive SMARTS predicate

  • palette_entry (dict) – Recursive label and color

  • badge_index (int) – Zero-based badge index

  • badge_count (int) – Number of badges on the atom

  • badge_targets (list) – Mutable click-target collection

drawRecursiveLabelSquare(painter, label_cx, label_cy, label_w, label_h, label_font, label_text)

Draw the black square with a white number that labels a recursive SMARTS glyph on the parent atom.

Parameters:
  • painter (QtGui.QPainter) – Active QPainter

  • label_cx (float) – Square center X

  • label_cy (float) – Square center Y

  • label_w (float) – Square width

  • label_h (float) – Square height

  • label_font (QtGui.QFont) – Font to use for the number

  • label_text (str) – Number string to render

computeRecursiveBoxPos(label_cx, label_cy, label_w, label_h, dir_x, dir_y, sub_box_size)

Compute the top-left (box_x, box_y) position of the sub-graph box for a recursive SMARTS glyph.

When the direction is predominantly horizontal the box is placed to the side of the label; when predominantly vertical it is placed above or below.

Parameters:
  • label_cx (float) – Label square center X

  • label_cy (float) – Label square center Y

  • label_w (float) – Label square width

  • label_h (float) – Label square height

  • dir_x (float) – Direction X component (unit vector)

  • dir_y (float) – Direction Y component (unit vector)

  • sub_box_size (float) – Side length of the sub-graph box

Return type:

tuple(float, float)

Returns:

(box_x, box_y) top-left corner of the sub-graph box

mapSubGraphPositions(sub_positions, box_x, box_y, sub_box_size)

Scale raw sub-graph layout positions to fit inside the sub-graph box.

Each raw position is mapped to a pixel coordinate centerd within the box, preserving aspect ratio and respecting the box margin.

Parameters:
  • sub_positions (dict) – Raw layout positions keyed by node index

  • box_x (float) – Top-left X of the sub-graph box

  • box_y (float) – Top-left Y of the sub-graph box

  • sub_box_size (float) – Side length of the sub-graph box

Return type:

dict

Returns:

Mapping from node index to (x, y) pixel tuples

drawSubGraphEdges(painter, sub_graph, pixel_pos)

Draw all edges of the sub-graph between their mapped pixel positions.

Aromatic bonds are rendered with a dotted line style; all other bonds use a solid fine pen.

Parameters:
  • painter (QtGui.QPainter) – Active QPainter

  • sub_graph (networkx.Graph) – Parsed sub-graph of the recursive SMARTS

  • pixel_pos (dict) – Mapping from node index to (x, y) pixel tuples

drawSubGraphAtoms(painter, sub_graph, pixel_pos, mini_radius)

Draw all atom circles for the sub-graph at their mapped pixel positions.

Aromatic atoms are drawn with a dashed outline; all others use a solid thin outline. Each circle is filled with the node’s element color.

Parameters:
  • painter (QtGui.QPainter) – Active QPainter

  • sub_graph (networkx.Graph) – Parsed sub-graph of the recursive SMARTS

  • pixel_pos (dict) – Mapping from node index to (x, y) pixel tuples

  • mini_radius (float) – Radius in pixels for each mini atom circle

computeArrowShaft(label_cx, label_cy, box_x, box_y, dir_x, dir_y, label_w, sub_box_size)

Compute the start and end points of the arrow shaft connecting the label square to the sub-graph box.

Parameters:
  • label_cx (float) – Label square center X

  • label_cy (float) – Label square center Y

  • box_x (float) – Top-left X of the sub-graph box

  • box_y (float) – Top-left Y of the sub-graph box

  • dir_x (float) – Direction X component (unit vector)

  • dir_y (float) – Direction Y component (unit vector)

  • label_w (float) – Label square width

  • sub_box_size (float) – Side length of the sub-graph box

Return type:

tuple(tuple(float, float), tuple(float, float))

Returns:

(shaft_start, shaft_end) as (x, y) tuples

drawArrowHead(painter, tip_x, tip_y, dir_x, dir_y)

Draw the two wing lines of an arrowhead at the given tip position.

The wing direction is derived from (dir_x, dir_y); if the shaft vector is zero-length, no lines are drawn.

Parameters:
  • painter (QtGui.QPainter) – Active QPainter

  • tip_x (float) – Arrowhead tip X

  • tip_y (float) – Arrowhead tip Y

  • dir_x (float) – Shaft direction X (need not be a unit vector)

  • dir_y (float) – Shaft direction Y (need not be a unit vector)

drawRecursiveArrow(painter, label_cx, label_cy, box_x, box_y, dir_x, dir_y, label_w, sub_box_size)

Draw the connecting arrow from the label square to the sub-graph box.

The arrow shaft runs from the edge of the label square to the nearest face of the sub-graph box, and an arrowhead is drawn at the tip.

Parameters:
  • painter (QtGui.QPainter) – Active QPainter

  • label_cx (float) – Label square center X

  • label_cy (float) – Label square center Y

  • box_x (float) – Top-left X of the sub-graph box

  • box_y (float) – Top-left Y of the sub-graph box

  • dir_x (float) – Direction X component (unit vector)

  • dir_y (float) – Direction Y component (unit vector)

  • label_w (float) – Label square width

  • sub_box_size (float) – Side length of the sub-graph box

drawSubGraphBoxAndLabel(painter, box_x, box_y, sub_box_size, corner_rect, label_font, label_text)

Draw the filled rectangle background of the sub-graph box and the corner label square with its number text.

Parameters:
  • painter (QtGui.QPainter) – Active QPainter

  • box_x (float) – Top-left X of the sub-graph box

  • box_y (float) – Top-left Y of the sub-graph box

  • sub_box_size (float) – Side length of the sub-graph box

  • corner_rect (QtCore.QRectF) – Bounding rect of the corner label square

  • label_font (QtGui.QFont) – Font to use for the corner label text

  • label_text (str) – Number string to render in the corner label

drawRecursiveSubGraph(painter, sub_graph, sub_positions, box_x, box_y, sub_box_size, label_font, label_text, label_w, label_h, dir_x, dir_y, label_cx, label_cy)

Map sub-graph positions into the box, draw edges and mini atom circles, then draw the arrow from the label square to the box.

Also draws a numbered label in the top-left corner of the box and an arrowhead at the tip of the arrow line.

Parameters:
  • painter (QtGui.QPainter) – Active QPainter

  • sub_graph (networkx.Graph) – Parsed sub-graph of the recursive SMARTS

  • sub_positions (dict or None) – Raw layout positions keyed by node index

  • box_x (float) – Top-left X of the sub-graph box

  • box_y (float) – Top-left Y of the sub-graph box

  • sub_box_size (float) – Side length of the sub-graph box

  • label_font (QtGui.QFont) – Font used for the corner label

  • label_text (str) – Number string for the corner label

  • label_w (float) – Label square width

  • label_h (float) – Label square height

  • dir_x (float) – Direction X component (unit vector)

  • dir_y (float) – Direction Y component (unit vector)

  • label_cx (float) – Label square center X

  • label_cy (float) – Label square center Y

drawRecursiveTextFallback(painter, label_cx, label_cy, dir_x, dir_y, pattern, rec_idx, label_w)

Fallback rendering for recursive SMARTS when the inner pattern cannot be parsed as a sub-graph. Draws the pattern text in a dashed box.

Parameters:
  • painter (QtGui.QPainter) – Active QPainter

  • label_cx (float) – Label center X

  • label_cy (float) – Label center Y

  • dir_x (float) – Direction X component

  • dir_y (float) – Direction Y component

  • pattern (str) – Recursive SMARTS pattern text

  • rec_idx (int) – 1-based index

  • label_w (float) – Width of the numbered label

class schrodinger.application.matsci.smarts_visualizer_gui.AtomRenderer(graph, recursive_palette=None)

Bases: object

Draws atom glyphs (circles, element symbols, annotation boxes) and atom index badges for a SMARTS graph.

Parameters:

graph (networkx.Graph) – Parsed SMARTS graph

DEGREE_TEXT_V_OFFSET = 14
UNKNOWN_ANNOTATION_FONT_SIZE = 7
RING_TEXT_DROP = 4
RING_SIZE_SCALE = 0.8
RING_SIZE_OFFSET = 4
HCOUNT_SUBSCRIPT_DROP = 4
CONNECTIVITY_LABEL_DROP = 4
VALENCE_DOT_INSET = 4
VALENCE_DOT_SPACING = 5
VALENCE_DOT_RADIUS = 2
VALENCE_TEXT_DROP = 4
VALENCE_TEXT_GAP = 2
REC_HIGHLIGHT_WIDTH = 2
INDEX_BADGE_COLOR = <PyQt6.QtGui.QColor object>
INDEX_BADGE_FONT_SIZE = 7
INDEX_BADGE_OFFSET_X = 14
INDEX_BADGE_OFFSET_Y = -14
__init__(graph, recursive_palette=None)

Initialize the graph renderer.

Parameters:
  • graph (networkx.Graph) – Parsed SMARTS graph

  • recursive_palette (RecursivePalette or None) – Optional recursive SMARTS palette

setPainter(painter)

Store the active QPainter for use by all drawing methods.

Parameters:

painter (QtGui.QPainter) – Active QPainter

drawRingSizeAnnotation(context, prim)

Render ring-size glyph

Parameters:
  • context (AnnotationParam) – Common annotation rendering state

  • prim (Ring) – Ring primitive instance

drawHCountAnnotation(context, prim)

Draw the H-count glyph.

Parameters:
  • context (AnnotationParam) – Common annotation rendering state

  • prim (HCount) – HCount primitive instance

drawConnectivityAnnotation(context, prim)

Draw the connectivity glyph.

Parameters:
drawDegreeAnnotation(context, prim)

Draw the degree glyph.

Parameters:
  • context (AnnotationParam) – Common annotation rendering state

  • prim (Degree) – Degree primitive instance

drawValenceAnnotation(context, prim)

Draw the valence glyph.

Parameters:
  • context (AnnotationParam) – Common annotation rendering state

  • prim (Valence) – Valence primitive instance

drawChargeAnnotation(context, prim)

Draw the charge glyph.

Parameters:
  • context (AnnotationParam) – Common annotation rendering state

  • prim (Charge) – Charge primitive instance

drawRecursiveAnnotation(context, prim)

Draw a badge for each unique recursive SMARTS predicate.

Parameters:
drawUnknownAnnotation(context, unknown_tokens)

Render unsupported SMARTS predicates as a visible fallback label.

Parameters:
  • context (AnnotationParam) – Common annotation rendering state

  • unknown_tokens (list(str)) – SMARTS predicates not handled semantically

drawAtomGlyph(painter, center, node_data, node_idx=None, pixel_positions=None, is_stereo_rendered=False)

Draw an atom glyph, filled circle with element symbol, with inline annotations (ring circle, H count line, connectivity wavy line) drawn directly on/near the atom.

Annotations are placed in the direction away from neighboring bonds so they don’t overlap.

Parameters:
  • painter (QtGui.QPainter) – Active QPainter

  • center (tuple(float, float)) – Center position (x, y)

  • node_data (dict) – Node attribute dict from the graph. Keys are NODE_LABEL, NODE_COLOR, and NODE_PRIMITIVES with values as SMARTS atom label (str), element color (QtGui.QColor), and parsed constraints (AtomPrimitives) respectively

  • node_idx (int or None) – Node index in the graph (for direction computation)

  • pixel_positions (dict or None) – Mapping from node index as key and pixel coordinates values

  • is_stereo_rendered (bool) – Whether this atom’s stereo bonds are rendered as wedges (controls H-count hashed wedge drawing)

drawAtomIndex(center_x, center_y, index, has_charge=False)

Draw a small numbered badge near the atom circle showing the 1-based match index for substructure searches.

Parameters:
  • center_x (float) – Atom circle center X

  • center_y (float) – Atom circle center Y

  • index (int) – 1-based atom index

  • has_charge (bool) – Whether an upper-right charge glyph is present

drawRecursiveHighlight(center_x, center_y, color, is_recursive_only=False)

Draw the colored outline used to identify atoms in a recursive view.

Parameters:
  • center_x (float) – Atom center X

  • center_y (float) – Atom center Y

  • color (QtGui.QColor) – Recursive predicate color

drawAtomCircle(center_x, center_y, color, primitives, radius=20, outline_width=1.5)

Draw the filled atom circle with an optional outline border.

When the atom has non-element constraints the circle is outlined in dark grey; an aromatic atom uses a dashed outline instead of solid. A plain element-only atom has no border.

Parameters:
  • center_x (float) – Circle center X

  • center_y (float) – Circle center Y

  • color (QtGui.QColor) – Fill color

  • primitives (AtomPrimitives) – Parsed atom primitives

  • radius (float) – Circle radius

  • outline_width (float) – Circle outline width

drawAtomBase(center_x, center_y, primitives, color, radius=20, outline_width=1.5, font_size=10)

Draw the element circle or OR-list pie chart and its symbol.

Parameters:
  • center_x (float) – Circle center X

  • center_y (float) – Circle center Y

  • primitives (AtomPrimitives) – Parsed atom primitives

  • color (QtGui.QColor) – Atom fill color

  • radius (float) – Circle radius

  • outline_width (float) – Circle outline width

  • font_size (int) – Element symbol font size

drawElementSymbol(center_x, center_y, primitives, color, radius=20, font_size=10)

Draw the element symbol text centerd on the atom circle.

The text is white for colored atoms and dark grey for wildcard atoms so it remains legible against the light fill.

Parameters:
  • center_x (float) – Circle center X

  • center_y (float) – Circle center Y

  • primitives (AtomPrimitives) – Parsed atom primitives

  • color (QtGui.QColor) – Atom fill color (used to choose text color)

  • radius (float) – Circle radius

  • font_size (int) – Symbol font size

getNodeDegree(node_idx)

Return the graph degree (number of visible bonds) for a node.

Parameters:

node_idx (int or None) – Node index in the graph

Return type:

int

Returns:

Graph degree of the node, or 0 if not found

computeAnnotationDirection(node_idx, pixel_positions)

Compute the direction (unit vector) in which annotations should be placed for a given atom.

Finds the largest angular gap between neighboring bonds and returns a unit vector bisecting that gap, guaranteeing the annotation is placed in the most open space.

Parameters:
  • node_idx (int or None) – Node index in the graph

  • pixel_positions (dict or None) – Mapping from node index as key and pixel coordinates values

Return type:

tuple(float, float)

Returns:

Unit vector (dx, dy) for annotation direction

getElementSymbol(primitives)

Return the element symbol string to display on the atom circle.

Parameters:

primitives (AtomPrimitives) – AtomPrimitives for the atom

Return type:

str

Returns:

Symbol string (e.g. ‘C’, ‘N’, ‘*’)

drawPieChart(center_x, center_y, element_prim, radius=20)

Draw a pie-chart circle for OR-list atoms, with one wedge per element.

Parameters:
  • center_x (float) – Center X coordinate

  • center_y (float) – Center Y coordinate

  • element_prim (Element) – Element primitive containing the symbol list

  • radius (int) – Circle radius in pixels

drawRingGlyph(center_x, center_y, direction, primitives)

Draw a ring annotation, an open circle overlapping the atom edge in the annotation direction, with bracket text ]n.

Parameters:
  • center_x (float) – Atom center X

  • center_y (float) – Atom center Y

  • direction (tuple(float, float) or None) – Unit vector (dx, dy) for placement direction

  • primitives (AtomPrimitives) – Parsed atom primitives

drawChargeGlyph(center_x, center_y, charge)

Draw charge annotation as text at the upper-right of atom circle.

Parameters:
  • center_x (float) – Atom center X

  • center_y (float) – Atom center Y

  • charge (Charge) – Charge primitive

class schrodinger.application.matsci.smarts_visualizer_gui.LegendRenderer(graph, recursive_palette=None)

Bases: BondRenderer

Builds and renders the SMARTS graph legend: per-atom mini glyphs with descriptions, bond type entries, and the symbol vocabulary key row.

SUBSCRIPT_FONT_SIZE = 6
LEGEND_HEADER_FONT_SIZE = 13
LABEL_LEGEND_HEADER = 'LEGEND'
LABEL_RING_CONSTRAINT = 'R, !R0'
LEGEND_MINI_HEXAGON_RADIUS = 6
REC_LEGEND_WRAP_WIDTH = 28
LEGEND_MARGIN = 24
LEGEND_HEADER_BOX_GAP = 6
LEGEND_BOX_BOTTOM_GAP = 6
LEGEND_INNER_ENTRY_TOP = 12
LEGEND_COL_WIDTH_REDUCTION = 40
LEGEND_SEP_EXTRA = 4
LEGEND_KEY_ROW_GAP = 10
LEGEND_MINI_RADIUS = 14
LEGEND_GLYPH_TOP_OFFSET = 30
LEGEND_BOND_ENTRY_X_END = 55
LEGEND_BOND_TEXT_LEFT = 65
LEGEND_ATOM_TEXT_GAP = 12
MINI_RING_TEXT_GAP = 2
MINI_RING_TEXT_DROP = 4
MINI_HCOUNT_TEXT_INSET = 5
MINI_HCOUNT_TEXT_DROP = 12
MINI_SUBSCRIPT_DROP = 14
MINI_SUBSCRIPT_OFFSET = 4
MINI_CONN_LABEL_PERP = 4
KEY_CENTER_Y_DROP = 18
KEY_ALIPHATIC_TEXT_GAP = 8
KEY_ALIPHATIC_TEXT_DROP = 5
KEY_ALIPHATIC_COLUMN_WIDTH = 110
KEY_AROMATIC_COLUMN_WIDTH = 110
KEY_CONN_WAVY_WIDTH = 25
KEY_CONN_STUB = 8
KEY_CONN_LABEL_INSET = 8
KEY_CONN_LABEL_LIFT = 7
KEY_CONN_DESC_GAP = 14
KEY_CONN_DESC_DROP = 5
KEY_CONN_COLUMN_WIDTH = 110
KEY_HCOUNT_H_INSET = 8
KEY_HCOUNT_H_DROP = 22
KEY_HCOUNT_SUB_INSET = 20
KEY_HCOUNT_SUB_DROP = 24
KEY_HCOUNT_DESC_INSET = 32
KEY_HCOUNT_DESC_DROP = 5
KEY_HCOUNT_COLUMN_WIDTH = 100
KEY_RING_TEXT_INSET = 3
KEY_RING_DESC_GAP = 28
KEY_RING_COLUMN_WIDTH = 140
KEY_RING_FONT_SIZE = 9
BOND_DOUBLE_OFFSET = 2
BOND_TRIPLE_OFFSET = 3
PEN_SINGLE_THICKNESS = 2.0
PEN_DOUBLE_THICKNESS = 1.5
PEN_TRIPLE_THICKNESS = 1.2
__init__(graph, recursive_palette=None)

Initialize the legend renderer and its sub-renderers.

Parameters:
  • graph (networkx.Graph) – Parsed SMARTS graph

  • recursive_palette (RecursivePalette or None) – Optional recursive SMARTS palette

collectPresentFeatures()

Scan the graph to determine which bond types and annotation primitives are actually used, so the legend only shows relevant items.

Return type:

tuple(set(str), set(str))

Returns:

(bond_labels, primitive_keys) present in the graph

drawLegend(painter, width, height, legend_height)

Draw a comprehensive legend with two sections inside a dashed rectangle:

  1. Per-atom entries: each unique atom from the SMARTS is drawn as a mini glyph (colored circle with annotations) alongside a multi-line text description. Bond type entries are also shown.

  2. Generic symbol key: a single row at the bottom explaining the glyph vocabulary (circle, wavy line, H count line, ring circle, etc.).

Parameters:
  • painter (QtGui.QPainter) – Active QPainter

  • width (int) – Widget pixel width

  • height (int) – Widget pixel height

  • legend_height (int) – Pixel height reserved for the legend

buildPerAtomEntries()

Build per-atom legend entries, deduplicated by their rendered SMARTS label and context-dependent description. Recursive-only atoms are represented by dedicated recursive legend entries instead.

Result is cached, since the graph and palette are fixed for the renderer’s lifetime.

Return type:

list(dict)

Returns:

List of dicts with node_data, description, node_idx keys

buildRecursiveEntries()

Build legend entries for unique recursive predicates.

Result is cached, since the graph and palette are fixed for the renderer’s lifetime.

Return type:

list(dict)

Returns:

Recursive legend entries in palette order

countBondLegendEntries(bond_labels)

Return the number of bond entries that will appear in the legend. A default single bond is always included; each additional special bond type present in the pattern adds one more entry.

Parameters:

bond_labels (set(str)) – Set of bond SMARTS tokens present in the graph

Return type:

int

Returns:

Number of bond legend entries to display

buildBondLegendEntries(bond_labels=None)

Build bond-type legend entries for the per-atom legend section.

The result for the graph’s own bond labels (bond_labels=None) is cached, since the graph is fixed for the renderer’s lifetime.

Return type:

list(dict)

Returns:

List of entry dicts, each with bond type and description keys

buildAtomDescription(node_idx, node_data, graph=None)

Build a multi-line human-readable description of an atom for the legend.

Examples: aliphatic O with 1 further hydrogen, aliphatic C, not in a ring.

Parameters:
  • node_idx (int) – Node index in the graph

  • node_data (dict) – Node attribute dict from the graph. Keys are NODE_LABEL, NODE_COLOR, and NODE_PRIMITIVES with values as SMARTS atom label (str), element color (QtGui.QColor), and parsed constraints (AtomPrimitives) respectively

  • graph (networkx.Graph or None) – The graph containing node_idx (defaults to self.graph)

Return type:

str

Returns:

Multi-line human-readable description of the atom for the legend

drawPerAtomEntry(params, entry)

Draw a single per-atom or per-bond legend entry: a mini glyph on the left and multi-line description text on the right.

Parameters:
  • params (KeyEntryParams) – Cell position and font parameters

  • entry (dict) – Entry dict (either atom or bond entry)

drawMiniAtomGlyph(center_x, center_y, node_data, node_idx, radius, graph=None)

Draw a scaled-down atom glyph for the legend, with all the same annotations as the main diagram but at a smaller size.

Parameters:
  • center_x (float) – Circle center X

  • center_y (float) – Circle center Y

  • node_data (dict) – Node attribute dict from the graph. Keys are NODE_LABEL, NODE_COLOR, and NODE_PRIMITIVES with values as SMARTS atom label (str), element color (QtGui.QColor), and parsed constraints (AtomPrimitives) respectively

  • node_idx (int) – Node index in the graph

  • radius (int) – Circle radius in pixels

  • graph (networkx.Graph or None) – The graph containing node_idx (defaults to self.graph)

drawMiniRingGlyph(params, radius)

Draw the ring-membership circle and bracket label for a mini atom glyph in the legend.

Parameters:
  • params (GlyphParams) – Glyph position and primitives

  • radius (int) – Mini atom circle radius

drawMiniHCountGlyph(params, h_dir, radius)

Draw the H-count stub line and text label for a mini atom glyph in the legend.

Parameters:
  • params (GlyphParams) – Glyph position and primitives

  • h_dir (tuple(float, float)) – Unit direction vector (dx, dy) for the stub line

  • radius (int) – Mini atom circle radius

drawMiniConnectivityGlyph(params, conn_dir, radius, node_idx, graph=None)

Draw the connectivity wavy line, straight stub, and count label for a mini atom glyph in the legend.

Parameters:
  • params (GlyphParams) – Glyph position and primitives

  • conn_dir (tuple(float, float)) – Unit direction vector (dx, dy) for the wavy line

  • radius (int) – Mini atom circle radius

  • node_idx (int) – Node index in the graph (used to read graph degree)

  • graph (networkx.Graph or None) – The graph containing node_idx (defaults to self.graph)

drawMiniBond(d_params)

Draw a mini bond legend entry, choosing the line style from the bond type.

Parameters:

d_params (DrawBondParams) – Bond line parameters

drawGenericKeyRow(start_x, start_y)

Draw the generic symbol key row at the bottom of the legend, showing the glyph vocabulary used in the diagram.

Only symbols that appear in the current SMARTS are shown.

Parameters:
  • start_x (float) – Left X position

  • start_y (float) – Top Y position

drawAtomOutlineKeyEntry(params, label, column_width)

Draw an atom-outline key entry and return the updated X cursor.

Parameters:
  • params (KeyEntryParams) – Key entry parameters

  • label (str) – Description text for the atom outline

  • column_width (float) – Horizontal width reserved for the entry

Return type:

float

Returns:

X cursor after this entry (start of next column)

drawConnectivityKeyEntry(params)

Draw the connectivity wavy-line key entry and return the updated X cursor.

Parameters:

params (KeyEntryParams) – Key entry parameters

Return type:

float

Returns:

X cursor after this entry (start of next column)

drawHCountKeyEntry(params)

Draw the H-count vertical-line key entry and return the updated X cursor.

Parameters:

params (KeyEntryParams) – Key entry parameters

Return type:

float

Returns:

X cursor after this entry (start of next column)

drawRingKeyEntry(params)

Draw the ring circle key entry and return the updated X cursor.

Parameters:

params (KeyEntryParams) – Key entry parameters

Return type:

float

Returns:

X cursor after this entry (start of next column)

class schrodinger.application.matsci.smarts_visualizer_gui.GraphState(smarts: str, graph: object, recursive_palette: object, positions: dict, bond_renderer: object, atom_renderer: object, legend_renderer: object)

Bases: object

Bundles all derived objects computed from a SMARTS pattern.

Parameters:
  • smarts (str) – The SMARTS pattern string

  • graph (networkx.Graph) – Parsed networkx graph

  • recursive_palette (RecursivePalette) – Shared recursive palette

  • positions (dict) – Node-to-(x,y) layout positions

  • bond_renderer (BondRenderer) – Bond line renderer

  • atom_renderer (AtomRenderer) – Atom glyph renderer

  • legend_renderer (LegendRenderer) – Legend renderer

smarts: str
graph: object
recursive_palette: object
positions: dict
bond_renderer: object
atom_renderer: object
legend_renderer: object
__init__(smarts: str, graph: object, recursive_palette: object, positions: dict, bond_renderer: object, atom_renderer: object, legend_renderer: object) → None
class schrodinger.application.matsci.smarts_visualizer_gui.SMARTSGraphWidget(smarts, parent=None, layout=None, recursive_palette=None, recursive_highlight_color=None)

Bases: QWidget

Custom widget that draws a SMARTS logic graph using QPainter.

Atoms are rendered as filled circles colored by element type (from Maestro’s element.sch). Non-element primitives appear as labeled entries in dashed annotation boxes. Bonds are drawn as styled lines.

LABEL_NO_ATOMS = 'No atoms'
HINT_FONT_SIZE = 12
LEGEND_HEADER_HEIGHT = 30
LEGEND_KEY_ROW_HEIGHT = 55
LEGEND_PADDING = 20
WIDGET_MIN_WIDTH = 400
WIDGET_MIN_HEIGHT = 300
__init__(smarts, parent=None, layout=None, recursive_palette=None, recursive_highlight_color=None)
Parameters:
  • smarts (str) – SMARTS pattern to visualize

  • parent (QWidget or None) – Parent widget

  • layout (QLayout or None) – Optional layout to add this widget to

  • recursive_palette (RecursivePalette or None) – Palette shared by recursive predicate annotations and dialogs

  • recursive_highlight_color (QtGui.QColor or None) – Color used to mark the atom that owns the recursive predicate

buildGraphState(smarts, palette)

Parse a SMARTS string and build all derived graph objects.

Parameters:
  • smarts (str) – SMARTS pattern to visualize

  • palette (RecursivePalette) – Recursive palette to use

Return type:

GraphState

Returns:

Populated graph state

applyGraphState(state)

Store pre-built graph state on self and compute legend height.

Parameters:

state (GraphState) – Graph state from buildGraphState

setSmarts(smarts)

Replace the current SMARTS pattern and recompute layout and renderers.

Parameters:

smarts (str) – New SMARTS pattern to visualize

collectRecursivePatterns(graph, include_nested=False, seen_patterns=None)

Return recursive predicates in stable first-occurrence order.

Parameters:
  • graph (networkx.Graph) – Graph whose recursive predicates are collected

  • include_nested (bool) – Whether to include recursive predicates nested inside recursive predicates

  • seen_patterns (set(str) or None) – Recursive predicates collected by callers

Return type:

list(str)

Returns:

Unique recursive predicates in discovery order

registerRecursivePatterns(graph, recursive_palette=None, include_nested=False)

Register recursive predicates before legend sizing and painting.

Parameters:
  • graph (networkx.Graph) – Parsed SMARTS graph

  • recursive_palette (RecursivePalette or None) – Palette that receives the discovered predicates

  • include_nested (bool) – Whether to register nested recursive predicates

getRecursivePaletteEntries(include_nested=False)

Return unique recursive palette entries used by this graph.

Parameters:

include_nested (bool) – Whether to include nested recursive predicates

Return type:

list(dict)

Returns:

Recursive entries in graph order

computeLegendHeight(legend_renderer=None)

Compute the total legend height from atom, bond, and recursive entries.

Return type:

int

Returns:

Total pixel height of the legend area

paintEvent(event)

Render the full SMARTS graph: edges, atom glyphs, annotation boxes, and the legend.

Parameters:

event (QtGui.QPaintEvent) – Paint event

drawEdges(painter, pixel_positions, stereo_map)

Draw all graph edges (bonds) with associated stereo annotations.

Parameters:
  • painter (QtGui.QPainter) – Active QPainter

  • pixel_positions (dict) – Mapping from node index as key and pixel coordinates values

  • stereo_map (dict) – Mapping of edge to stereo type

drawAtoms(painter, pixel_positions, stereo_h_nodes)

Draw all atom glyphs including their annotation slots and optional recursive highlight outlines.

Parameters:
  • painter (QtGui.QPainter) – Active QPainter

  • pixel_positions (dict) – Mapping from node index as key and pixel coordinates values

  • stereo_h_nodes (set) – Set of node indices that have implicit-H stereo

drawAtomIndices(pixel_positions)

Draw numeric index badges on each atom when show_indices is enabled.

Parameters:

pixel_positions (dict) – Mapping from node index as key and pixel coordinates values

mousePressEvent(event)

Open the recursive SMARTS dialog when a recursive badge is clicked.

Parameters:

event (QtGui.QMouseEvent) – Qt mouse event

mouseMoveEvent(event)

Show a pointing-hand cursor over recursive SMARTS targets.

Parameters:

event (QtGui.QMouseEvent) – Qt mouse event

leaveEvent(event)

Restore the normal cursor when the pointer leaves the graph.

Parameters:

event (QtCore.QEvent) – Qt leave event

getRecursiveTargetAt(point)

Return the recursive target under a widget point, if any.

Parameters:

point (QtCore.QPointF) – Widget-local mouse position

Return type:

tuple or None

Returns:

(rectangle, pattern, color) or None

openRecursiveDialog(pattern, color)

Open a graph dialog for a recursive predicate.

Parameters:
  • pattern (str) – Recursive SMARTS predicate

  • color (QtGui.QColor) – Predicate highlight color

class schrodinger.application.matsci.smarts_visualizer_gui.SMARTSVisualizerDialog(smarts, parent=None, recursive_palette=None, recursive_highlight_color=None, recursive_label=None)

Bases: SDialog

A modal dialog that displays a SMARTS pattern as a logic graph.

Atoms are drawn as labeled circles colored by element type. Inline annotations show ring membership, H count, valence, connectivity, etc. Bonds are drawn as styled lines between atoms.

__init__(smarts, parent=None, recursive_palette=None, recursive_highlight_color=None, recursive_label=None)
Parameters:
  • smarts (str) – Valid SMARTS pattern to visualize

  • parent (QWidget or None) – Parent widget

  • recursive_palette (RecursivePalette or None) – Palette shared by recursive predicate annotations and dialogs

  • recursive_highlight_color (QtGui.QColor or None) – Color used to mark the atom that owns the recursive predicate

  • recursive_label (str or None) – Label assigned to the recursive predicate

layOut()

Lay out the dialog: SMARTS label at top, graph widget filling the remaining space, and an export button.

updateVisualization()

Update the graph widget with the current SMARTS from the edit field.

onIndexToggled(checked)

Toggle atom index badge visibility on the graph widget.

Parameters:

checked (bool) – Whether the checkbox is checked

exportPng()

Export the current graph visualization as a PNG file.

exportRecursiveSubgraphs(file_path)

Export each recursive sub-pattern as a separate PNG file.

Parameters:

file_path (str) – Path to the main graph’s exported PNG