🆕 Print Monomer Set Information to Console
Problem
You want to inspect the monomers in either OEChem TK’s built-in monomer sets
or a custom monomer set defined in a json file.
See also
OEChem TK Built-in Monomer Sets section
Ingredients
|
Difficulty Level
🌶️
Download
Source Code
monomers2console
#!/usr/bin/env python3
# (C) 2026 Cadence Design Systems, Inc. (Cadence)
# All rights reserved.
# TERMS FOR USE OF SAMPLE CODE The software below ("Sample Code") is
# provided to current licensees or subscribers of Cadence products or
# SaaS offerings (each a "Customer").
# Customer is hereby permitted to use, copy, and modify the Sample Code,
# subject to these terms. Cadence claims no rights to Customer's
# modifications. Modification of Sample Code is at Customer's sole and
# exclusive risk. Sample Code may require Customer to have a then
# current license or subscription to the applicable Cadence offering.
# THE SAMPLE CODE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED. OPENEYE DISCLAIMS ALL WARRANTIES, INCLUDING, BUT
# NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
# PARTICULAR PURPOSE AND NONINFRINGEMENT. In no event shall Cadence be
# liable for any damages or liability in connection with the Sample Code
# or its use.
"""Print monomers to console."""
import argparse
import json
import os
import pathlib
import sys
import rich.console
import rich.markup
import rich.table
import rich.text
from openeye import oechem
from rich_argparse import HelpPreviewAction, RichHelpFormatter
__SCRIPT_NAME__ = pathlib.Path(__file__).absolute().stem
__SCRIPT_DESC__ = "Print monomers to console."
__SCRIPT_TOOLKITS__ = ["oechem"]
__SCRIPT_KEYWORDS__ = ["monomer", "peptide", "peptide-informatics"]
__SCRIPT_CATEGORIES__ = ["peptide-informatics"]
def parse_options() -> argparse.Namespace:
"""Set up command line options."""
parser = argparse.ArgumentParser(
add_help=True,
formatter_class=RichHelpFormatter,
description="[yellow]" + __SCRIPT_DESC__ + "[/yellow]",
)
monomers_group = parser.add_argument_group("Monomer set options")
_add_monomer_collection(monomers_group)
parser.add_argument("--help-image", action=HelpPreviewAction)
parser.add_argument(
"--save-console-svg",
default=False,
action="store_true",
help=f"run command and capture console output in {__SCRIPT_NAME__}.svg file",
)
return parser.parse_args()
def main() -> int:
"""Print monomers to console."""
args = parse_options()
monomers = _get_monomer_collection(args)
console = rich.console.Console(record=args.save_console_svg)
console.print(monomers)
if args.save_console_svg:
console.save_svg(f"{__SCRIPT_NAME__}.svg", title="output")
return os.EX_OK
class MonomerSetParameter: # noqa: PLW1641
"""Utility class to handle both built-in and user defined monomer sets."""
def __init__(self) -> None: # noqa: D107
self._monomer_sets = ["Standard", "OpenEye", "JSON-FILENAME"]
def __repr__(self) -> str: # noqa: D105
return ",".join(self._monomer_sets)
def __eq__(self, param: object) -> bool: # noqa: D105
if not isinstance(param, str):
return False
if param in ["Standard", "OpenEye"]:
return True
console = rich.console.Console()
monomer_set_filepath = pathlib.Path(param)
if (
not monomer_set_filepath.exists()
or monomer_set_filepath.suffix.lower() != ".json"
):
console.print(f"[red]Invalid monomer set file '{param}' ![/red]")
return False
try:
with monomer_set_filepath.open("r") as json_file:
json.load(json_file)
except json.JSONDecodeError as e:
console.print(f"[red]Invalid monomer set file '{param}' ![/red]")
console.print(f"[red]Error decoding JSON: {e} ![/red]")
return False
return True
def _add_monomer_collection(arg_group: argparse._ArgumentGroup) -> None:
arg_group.add_argument(
"-m",
"--monomers",
type=str,
default="Standard",
choices=[MonomerSetParameter()],
help="built-in monomer-set type or json file of monomers",
)
def _get_monomer_collection(args: argparse.Namespace) -> oechem.OEMonomerSet:
monomers = oechem.OEMonomerSet()
match args.monomers:
case "Standard":
oechem.OELoadStandardMonomerSet(monomers)
case "OpenEye":
oechem.OELoadOpenEyeMonomerSet(monomers)
case _:
oechem.OEReadMonomerSet(monomers, args.monomers)
return monomers
def monomer_set_rich_console(
self, # noqa: ANN001
console: rich.console.Console,
options: rich.console.ConsoleOptions,
) -> rich.console.RenderResult:
"""Rich representation of the monomer set."""
primary_code_set = self.GetPrimaryCodeSet()
code_sets: list[str] = [
primary_code_set,
*[c for c in self.GetCodeSets() if c != primary_code_set],
]
columns: list[tuple[str, str, str]] = [ # (header, justified, footer
("idx", "right", "Total"),
*[(c, "left", f"{self.NumMonomers(c)}") for c in code_sets],
*[(str(r), "right", "") for r in range(1, 4)],
("polymer", "center", ""),
("monomer", "center", ""),
("amino types", "center", ""),
("analogue", "center", ""),
("SMILES", "left", ""),
]
table = rich.table.Table(
title=f"[bold]Number of monomers: {self.NumMonomers()} Version={self.GetVersion()} [/bold]",
show_footer=True,
)
for header, justify, footer in columns:
table.add_column(header, justify=justify, footer=footer) # type: ignore[arg-type]
for idx, monomer in enumerate(self.GetMonomers()):
codes: list[rich.text.Text] = [
(
rich.text.Text(
monomer.GetCode(code_set),
style=(
""
if code_set != "PDB"
else f"link https://www.rcsb.org/ligand/{monomer.GetCode(code_set)}"
),
)
if monomer.HasCode(code_set)
else rich.text.Text("-", style="dim")
)
for code_set in code_sets
]
polymer_type = oechem.OEPolymerTypeToString(monomer.GetPolymerType())
row_data = [
str(idx + 1),
*codes,
*[_get_r_group_repr(monomer, r) for r in range(1, 4)],
polymer_type,
_get_monomer_type_repr(monomer),
_get_amino_acid_type_repr(monomer),
_get_standard_analog_repr(monomer),
f"{rich.markup.escape(monomer.GetSmiles())}",
]
table.add_row(*row_data)
yield from table.__rich_console__(console, options)
def _get_r_group_repr(monomer: oechem.OEMonomer, rgroup_idx: int) -> rich.text.Text:
if not monomer.HasRGroup(rgroup_idx):
return rich.text.Text("")
if monomer.GetPolymerType() == oechem.OEPolymerType_Peptide:
match rgroup_idx:
case 1:
return rich.text.Text("R1", style="bold rgb(100,120,240)")
case 2:
return rich.text.Text("R2", style="bold rgb(240,100,120)")
case 3:
return rich.text.Text("R3", style="bold rgb(45,110,40)")
return rich.text.Text(f"R{rgroup_idx}", style="bold rgb(240,140,80)")
def _get_monomer_type_repr(monomer: oechem.OEMonomer) -> rich.text.Text:
if monomer.GetMonomerType() == oechem.OEMonomerType_Backbone:
return rich.text.Text("backbone")
if (
monomer.GetMonomerType() == oechem.OEMonomerType_Terminal
and monomer.IsNTerminal()
):
return rich.text.Text("🅝", style="bold white") + rich.text.Text(
"-terminal", style="not bold"
)
if (
monomer.GetMonomerType() == oechem.OEMonomerType_Terminal
and monomer.IsCTerminal()
):
return rich.text.Text("🅒", style="bold white") + rich.text.Text(
"-terminal", style="not bold"
)
return rich.text.Text("N/A", style="bold on red")
def _get_amino_acid_type_repr(monomer: oechem.OEMonomer) -> rich.text.Text:
amino_acid_type = monomer.GetAminoAcidType()
amino_acid_dict = {
oechem.OEAminoAcidType_Alpha: "α", # noqa: RUF001
oechem.OEAminoAcidType_Beta: "β",
oechem.OEAminoAcidType_Gamma: "γ", # noqa: RUF001
oechem.OEAminoAcidType_Delta: "δ",
oechem.OEAminoAcidType_NMethylated: "N-me",
oechem.OEAminoAcidType_AlphaMethylated: "α-me", # noqa: RUF001
oechem.OEAminoAcidType_BetaMethylated: "β-me",
}
amino_types = []
for amino, amino_repr in amino_acid_dict.items():
if amino_acid_type & amino == amino:
amino_types.append(amino_repr)
return rich.text.Text(",".join(amino_types), style="bold")
def _get_standard_analog_repr(monomer: oechem.OEMonomer) -> rich.text.Text:
if monomer.GetPolymerType() != oechem.OEPolymerType_Peptide:
return rich.text.Text("-", style="bold")
analog = oechem.OEGetStandardAnalog(monomer.GetCanonicalSmiles())
if analog == oechem.OEResidueIndex_UNK:
return rich.text.Text("-", style="bold")
return rich.text.Text(oechem.OEGetAminoAcidCode(analog), style="bold")
oechem.OEMonomerSet.__rich_console__ = monomer_set_rich_console # type: ignore[attr-defined]
setattr(main, "__SCRIPT_NAME__", __SCRIPT_NAME__)
setattr(main, "__SCRIPT_DESC__", __SCRIPT_DESC__)
setattr(main, "__SCRIPT_TOOLKITS__", __SCRIPT_TOOLKITS__)
setattr(main, "__SCRIPT_KEYWORDS__", __SCRIPT_KEYWORDS__)
setattr(main, "__SCRIPT_CATEGORIES__", __SCRIPT_CATEGORIES__)
if __name__ == "__main__":
sys.exit(main())
Usage
See Download section to download the script.
> monomers2console --help
By default, the monomers2console script loads OEChem TK’s
built-in Standard monomer set and prints out its 20 standard amino acid
information.
> monomers2console
- --monomers OpenEye
OEChem TK’s built-in OpenEye monomer-set can be loaded with the --monomers OpenEye
parameter.
> monomers2console --monomers OpenEye
- --monomers JSON-MONOMER-FILE
The following example shows how to output a custom monomer set
defined in a json file
(custom-monomers.json)
> monomers2console --monomers custom-monomers.json
See also in OEChem TK manual
API
OEAminoAcidType namespace
OEMonomerSet class
OEMonomerType namespace
OEPolymerType namespace
OEReadMonomerSet function