Introduction
The OpenEye Python Cookbook is a collection of solutions and practical examples for solving cheminformatics and molecule modeling problems using various OpenEye toolkits.
To install OpenEye’s Python package, please see instructions in the Getting Started with OpenEye Python section of the main OpenEye documentation.
We expect that you are familiar with at least some Python and have used OpenEye toolkits before. The main purpose of this documentation is to illustrate that by combining various OpenEye toolkits you can solve a wide range of cheminformatics and molecular modeling problems.
The OpenEye Toolkit Ecosystem
Installation
The oecookbook package requires that you have a valid OpenEye license.
The OpenEye Python Cookbook can be installed via pip using either conda or uv. The oecookbook will install the required dependencies for you, including the compatible OpenEye toolkits.
See also
Conda
> conda create --name oecookbook python=3.12
> conda activate oecookbook
> pip install --extra-index-url https://pypi.anaconda.org/openeye/simple oecookbook
UV
> uv venv oecookbook
> source oecookbook/bin/activate
> uv pip install --extra-index-url https://pypi.anaconda.org/openeye/simple oecookbook
Integration Testing
The OpenEye Python Cookbook ship with a simple set of integration tests to make sure all the libraries function as intended. The test suite is not as exhaustive as the test suite used internally, it is just meant to ensure the OpenEye Python Toolkits infrastructure is working as intended.
Note
Running the integration test requires scripttest and pytest packages.
These packages will be installed on-the-fly, if necessary.
Again using conda or virtualenv environments will ensure that these packages will
not be installed into the global Python environment.
> oecookbook_package_test
Note
Test might fail if you do not have a valid OpenEye license for a specific toolkit or if your license has expired.
Available Scripts
> find_scripts --help
> find_scripts
Outline of Recipes
Each recipe in this documentation is divided into the following sections:
Problem - brief description of the problem you are trying to solve
Ingredients - the list of the OpenEye toolkits you need to solve this problem
Difficulty Level - each recipe is put into one of the following categories:
Download - most recipes provide a self-contained Python script that you can download and run
Download code
Source Code - complete source code listing for the recipe
peptide2img
#!/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. """Depict peptide.""" import argparse import enum import io import json import os import pathlib import sys import rich.console from openeye import oechem, oedepict, oegrapheme from PIL import Image from rich_argparse import HelpPreviewAction, RichHelpFormatter __SCRIPT_NAME__ = pathlib.Path(__file__).absolute().stem __SCRIPT_DESC__ = "Depict peptide." __SCRIPT_TOOLKITS__ = ["oechem", "oedepict", "oegrapheme"] __SCRIPT_KEYWORDS__ = ["HELM", "monomer", "peptide", "peptide-informatics", "depiction"] __SCRIPT_CATEGORIES__ = ["depiction", "peptide-informatics"] class DepictionStyle(enum.Enum): """Utility enum class for peptide depiction style.""" MonomerHighlight = "highlight" MonomerGraph = "graph" def __str__(self) -> str: """Convert to string representation.""" return self.value class InteractiveEffect(enum.Enum): """Utility enum class for peptide interactive effect.""" none = "none" hover = "hover" toggle = "toggle" def __str__(self) -> str: """Convert to string representation.""" return self.value def parse_options() -> argparse.Namespace: """Set up command line options.""" parser = argparse.ArgumentParser( add_help=True, formatter_class=RichHelpFormatter, description="[yellow]" + __SCRIPT_DESC__ + " Supported image formats: svg, png" + "[/yellow]", ) # input options input_group = parser.add_argument_group("Input peptide") exclusive_input_group = input_group.add_mutually_exclusive_group(required=True) exclusive_input_group.add_argument( "--helm", metavar="HELM", type=str, required=False, help="input HELM string", ) exclusive_input_group.add_argument( "--smiles", metavar="SMILES", type=str, required=False, help="input SMILES string", ) exclusive_input_group.add_argument( "--mol", metavar="MOL-FILE", type=str, required=False, help="input molecule file (oeb, sdf, fasta)", ) monomers_group = parser.add_argument_group("Monomer set options") _add_monomer_collection(monomers_group) image_group = parser.add_argument_group("Image options") image_group.add_argument( "--image", type=str, required=False, metavar="IMAGE-FILE", help="output image file (PNG, SVG) (required: %(required)s) -- if no output is provided the image will be displayed on the screen", ) image_group.add_argument( "--width", type=int, default=800, help="width of output image (default: %(default)s)", ) image_group.add_argument( "--height", type=int, default=600, help="height of output image (default: %(default)s)", ) depiction_group = parser.add_argument_group("Depiction options") depiction_group.add_argument( "--style", type=DepictionStyle, default=DepictionStyle.MonomerGraph, choices=list(DepictionStyle), help="peptide depiction style (default: %(default)s)", ) depiction_group.add_argument( "--highlight-backbone", default=False, action="store_true", help="highlight backbone atoms (default: %(default)s)", ) depiction_group.add_argument( "--label-backbone-atoms", default=False, action="store_true", help="label backbone atoms (default: %(default)s)", ) depiction_group.add_argument( "--interactive", type=InteractiveEffect, default=InteractiveEffect.none, choices=list(InteractiveEffect), help="monomers of HELM graph depicted on mouse over or click (SVG-only feature) (default: %(default)s)", ) depiction_group.add_argument( "--algorithmic-layout", default=False, action="store_true", help="use algorithmic layout for coordinate generation in highlight mode (default: %(default)s)", ) parser.add_argument("--help-image", action=HelpPreviewAction) return parser.parse_args() def main() -> int: """Depict peptide.""" args = parse_options() console = rich.console.Console() monomers = _get_monomer_collection(args) code_set = monomers.GetPrimaryCodeSet() if args.code_set is None else args.code_set if not monomers.HasCodeSet(code_set): console.print( f"[red]Warning: invalid code set `{code_set}. available sets are: {monomers.GetCodeSets()}`![/red]" ) return os.EX_DATAERR _check_image_file(args) mol: oechem.OEMolBase | None = _get_molecule(args, monomers, console) if not mol: # error message already printed return os.EX_DATAERR if not args.helm: oechem.OEDetectMonomers(mol, monomers, code_set) if args.highlight_backbone or args.label_backbone_atoms: oechem.OEPerceivePeptideBackbone(mol) if oechem.OECount(mol, oechem.OEIsMonomerGroup()) == 0: console.print("[red]Warning: No monomer is detected in input molecule![/red]") return os.EX_DATAERR image = oedepict.OEImage(args.width, args.height) match args.style: case DepictionStyle.MonomerHighlight: depict_monomer_highlight( image, mol, args.algorithmic_layout, args.highlight_backbone, args.label_backbone_atoms, ) case DepictionStyle.MonomerGraph: interactive = args.interactive if args.image is None or pathlib.Path(args.image).suffix != ".svg": interactive = InteractiveEffect.none if not depict_monomer_graph(image, mol, code_set, interactive): console.print("[red]Failed to draw monomer graph![/red]") return os.EX_DATAERR case _: console.print("[red]Unknown depiction style![/red]") return os.EX_DATAERR oedepict.OEDrawCurvedBorder(image, oedepict.OELightGreyPen, 10) if args.image: oedepict.OEWriteImage(args.image, image) else: _img = Image.open(io.BytesIO(oedepict.OEWriteImageToBytes("png", image))) _img.show() return os.EX_OK def depict_monomer_graph( image: oedepict.OEImage, mol: oechem.OEMolBase, code_set: str, interactive: InteractiveEffect, ) -> bool: """Depict peptide in monomer graph style.""" opts = oegrapheme.OEMonomerGraphDisplayOptions() opts.SetMonomerColorFunctor(OEAnalogColor(code_set)) if interactive == InteractiveEffect.toggle: opts.SetInteractiveEffect(oedepict.OEInteractiveEffect_Toggle) opts.SetMonomerScale(0.33) elif interactive == InteractiveEffect.hover: opts.SetInteractiveEffect(oedepict.OEInteractiveEffect_Hover) if not oegrapheme.OEDrawMonomerGraph(image, mol, opts): return False if interactive != InteractiveEffect.none: oedepict.OEAddInteractiveIcon(image, oedepict.OEIconLocation_Default, 0.5) return True def depict_monomer_highlight( image: oedepict.OEImageBase, mol: oechem.OEMolBase, algorithmic_layout: bool, highlight_backbone: bool, label_backbone_atoms: bool, ) -> None: """Depict the monomer with highlights for the backbone and labels for backbone atoms.""" prep_opts = oedepict.OEPrepareDepictionOptions() if algorithmic_layout: prep_opts.SetOptimizeMacrocycles(True) oedepict.OEPrepareDepiction(mol, prep_opts) highlight_opts = oegrapheme.OEHighlightMonomerDisplayOptions( image.GetWidth(), image.GetHeight(), oedepict.OEScale_AutoScale ) highlight_opts.SetTitleLocation(oedepict.OETitleLocation_Hidden) highlight_opts.SetAtomStereoStyle(oedepict.OEAtomStereoStyle_Display_All) highlight_opts.SetHighlightUnspecifiedStereo(True) if label_backbone_atoms: highlight_opts.SetAtomPropertyFunctor(BackboneLabel()) disp = oedepict.OE2DMolDisplay(mol, highlight_opts) oegrapheme.OEHighlightMonomers(disp, highlight_opts) if highlight_backbone: backbone = oechem.OEAtomBondSet() for atom in disp.GetMolecule().GetAtoms(): if oechem.OEGetPDBAtomIndex(atom) in [ oechem.OEPDBAtomName_C, oechem.OEPDBAtomName_O, oechem.OEPDBAtomName_OXT, oechem.OEPDBAtomName_CA, oechem.OEPDBAtomName_CB, oechem.OEPDBAtomName_CG, oechem.OEPDBAtomName_N, ]: backbone.AddAtom(atom) for bond in disp.GetMolecule().GetBonds(): if backbone.HasAtom(bond.GetBgn()) and backbone.HasAtom(bond.GetEnd()): backbone.AddBond(bond) if backbone.NumBonds() > 0: line_width = 2.0 highlight = oedepict.OEHighlightByColor(oechem.OEDarkSalmon) highlight.SetLineWidthScale(line_width) oedepict.OEAddHighlighting(disp, highlight, backbone) oedepict.OERenderMolecule(image, disp) class BackboneLabel(oedepict.OEDisplayAtomPropBase): """Functor that assigns backbone label to displayed atoms.""" def __init__(self) -> None: """Initialize functor.""" oedepict.OEDisplayAtomPropBase.__init__(self) def __call__(self, atom: oechem.OEAtomBase) -> str: """Assign label.""" if oechem.OEGetPDBAtomIndex(atom) not in [ oechem.OEPDBAtomName_C, oechem.OEPDBAtomName_O, oechem.OEPDBAtomName_OXT, oechem.OEPDBAtomName_CA, oechem.OEPDBAtomName_CB, oechem.OEPDBAtomName_CG, oechem.OEPDBAtomName_N, ]: return "" return atom.GetName() def CreateCopy(self): # noqa: ANN201, N802 """Copy constructor.""" return BackboneLabel().__disown__() 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", ) arg_group.add_argument( "--code-set", type=str, metavar="CODE-SET", required=False, default=None, help="code-set, if not specified primary code-set is used", ) 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 _get_molecule( args: argparse.Namespace, monomers: oechem.OEMonomerSet, console: rich.console.Console, ) -> oechem.OEMolBase | None: mol = oechem.OEGraphMol() if args.smiles: if not oechem.OEParseSmiles(mol, args.smiles): console.print(f"[red]Failed to parse SMILES: `{args.smiles}`[/red]") return None elif args.helm: result = oechem.OEHelmParsingResult() if not oechem.OEHelmToMol(mol, args.helm, monomers, result): console.print(f"[red]Failed to parse HELM: `{args.helm}`[/red]") console.print(f"[red]Warning: {result.GetWarning()}[/red]") console.print(args.helm, markup=False, highlight=False) console.print("[red]" + "-" * result.GetErrorPosition() + "^[/red]") return None elif args.mol: ifs = oechem.oemolistream(args.mol) if not oechem.OEReadMolecule(ifs, mol): console.print(f"[red]Failed to read molecule from '{args.mol}'[/red]") return None return mol if mol.IsValid() else None class OEAnalogColor(oegrapheme.OEMonomerColorBase): """Functor that assigns color to monomer based on its analog.""" def __init__(self, code_set: str) -> None: """Initialize functor.""" oegrapheme.OEMonomerColorBase.__init__(self) self._code_set = code_set self._colors_by_code: dict[str, oechem.OEColor] = {} def __call__(self, monomer: oechem.OEMonomerData) -> oechem.OEColor: """Assign color to monomer.""" code: str = monomer.GetCode(self._code_set) if code in self._colors_by_code: return self._colors_by_code[code] color_hex = _get_monomer_analog_color(monomer) color = oechem.OEColor(color_hex) self._colors_by_code[code] = color return color def CreateCopy(self) -> oegrapheme.OEMonomerColorBase: # noqa: N802 """Copy constructor.""" copy = OEAnalogColor(self._code_set) return copy.__disown__() def _get_monomer_analog_color(monomer: oechem.OEMonomerData) -> str: # noqa: PLR0911 if monomer.GetPolymerType() != oechem.OEPolymerType_Peptide: return "#000000" analog = oechem.OEGetStandardAnalog(monomer.GetCanonicalSmiles()) if analog == oechem.OEResidueIndex_UNK: return "#AAAAAA" match analog: case oechem.OEResidueIndex_CYS | oechem.OEResidueIndex_MET: return "#e4e488" case ( oechem.OEResidueIndex_ALA | oechem.OEResidueIndex_GLY | oechem.OEResidueIndex_ILE | oechem.OEResidueIndex_LEU | oechem.OEResidueIndex_PRO | oechem.OEResidueIndex_VAL ): return "#c09071" case ( oechem.OEResidueIndex_PHE | oechem.OEResidueIndex_TRP | oechem.OEResidueIndex_TYR ): return "#5faf5f" case oechem.OEResidueIndex_ASP | oechem.OEResidueIndex_GLU: return "#e0ac70" case ( oechem.OEResidueIndex_ARG | oechem.OEResidueIndex_HIS | oechem.OEResidueIndex_LYS ): return "#85b4e6" case oechem.OEResidueIndex_SER | oechem.OEResidueIndex_THR: return "#ff8787" case oechem.OEResidueIndex_ASN | oechem.OEResidueIndex_GLN: return "#5493EA" return "#AAAAAA" def _check_image_file(args: argparse.Namespace) -> None: # script will terminate if there is some issues if not args.image: # image will be displayed on the screen return ext = pathlib.Path(args.image).suffix[1:].upper() if not oedepict.OEIsRegisteredImageFile(ext): oechem.OEThrow.Fatal("Unknown image output type!") ofs = oechem.oeofstream() if not ofs.open(args.image): oechem.OEThrow.Fatal("Cannot open output image file!") 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())
Solution - focused code snippets with detailed explanations of how the problem is solved
Usage - examples demonstrating how to run and use the provided Python script
Discussion - additional context and alternative code snippets for related problems
See Also - links and references to other OpenEye toolkit manuals