API¶
Overview¶
This page describes the API of Indigo library and its rendering plugin. The API allows developers to integrate Indigo into their C/Java/C#/Python projects. Please note that Indigo is under active development, and can always post your comments and suggestions to our team.
Basics¶
System¶
Indigo acts like a state machine that consists of:
- Objects
- Configuration settings
- Error handling facility
It is possible to use more than one Indigo instance at a time. In plain
C API, the “active” instance can be switched with indigoSetSession
call, while in Python, Java, and C#, the instance is represented as an
object of class Indigo
.
The objects that belong to the Indigo state machine are represented as
integer handles in the C API, while in Python, Java, and C# they are
wrapped by the IndigoObject
class.
Access to configuration settings is done via indigoSetOption***
functions in the C API, while in Python, Java, and C# a number of
Indigo.setOption
methods can accomplish it.
Error handling in C is done via return codes, indigoGetLastError
,
and indigoSetErrorHandler
. In Python, Java, and C#, as soon as some
Indigo function terminates with an error, an IndigoException
is
thrown.
Several library instances may be created to act simultaneously and independently. However, each instance requires a certain amount of memory, and thus it is recommended to have as few instances as possible.
It is allowable to have multiple Indigo instances within one program and even in different threads. However, using a single Indigo instance across multiple threads is prohibited.
From now on, only the Python, Java, and C# interfaces are explained. For those who are interested in plain C interface, please read the C API page.
Indigo Constructor¶
Java:
import com.epam.indigo.*;
...
Indigo indigo = new Indigo();
C#:
using com.epam.indigo;
....
Indigo indigo = new Indigo();
Python:
from indigo import *
...
indigo = Indigo()
Python will assume the Indigo binaries stored in the lib
directory
in the directory where indigo.py
is located. In C# and Java, the
binaries are unpacked automatically into the system temporary folder.
Getting the Version String¶
You can use the Indigo.version
method to get the string containing
the Indigo library version number.
Java:
System.out.println("Indigo version " + indigo.version());
C#:
System.Console.WriteLine("Indigo version " + indigo.version());
Python:
print "Indigo version " + indigo.version()
Molecules¶
Loading Molecules and Query Molecules¶
The Indigo
object provides methods for loading molecules and query
molecules
from: strings, byte[]
buffers, and files. The input format is
detected automatically, except for SMARTS expressions, for which there
are special methods.
Java and C#:
IndigoObject mol1 = indigo.loadMolecule("ONc1cccc1");
IndigoObject mol2 = indigo.loadMoleculeFromFile("structure.mol");
IndigoObject qmol1 = indigo.loadQueryMolecule("C1-C-C-C-1");
IndigoObject qmol2 = indigo.loadQueryMoleculeFromFile("query.mol");
IndigoObject qmol3 = indigo.loadSmarts("[N,n,O;!H0]");
IndigoObject qmol4 = indigo.loadSmartsFromFile("query.sma");
Python: the same with the IndigoObject
omitted.
Instrumenting Molecules¶
You can programmatically add atoms and bonds to a molecule. Atoms can be
added with the addAtom
method of the molecule. This method accepts
an atom symbol (a string) — an element from the periodic table, or a
pseudoatom. Similarly, bonds can be added by calling addBond
method
of an atom. This method accepts another atom and the order of the new
bond. You can also create an empty molecule by calling the
createMolecule
method.
Java and C#:
IndigoObject mol = indigo.createMolecule();
IndigoObject atom1 = mol.addAtom("C");
IndigoObject atom2 = mol.addAtom("C");
IndigoObject atom3 = mol.addAtom("C");
IndigoObject atom4 = mol.addAtom("C");
IndigoObject atom5 = mol.addAtom("C");
IndigoObject atom6 = mol.addAtom("N");
IndigoObject bond1 = atom1.addBond(atom2, 2);
IndigoObject bond2 = atom2.addBond(atom3, 2);
IndigoObject bond3 = atom3.addBond(atom4, 1);
IndigoObject bond4 = atom4.addBond(atom5, 2);
IndigoObject bond5 = atom5.addBond(atom6, 1);
IndigoObject bond6 = atom6.addBond(atom1, 2);
You can programmatically construct a query molecule via
createQueryMolecule
method.
Java and C#:
IndigoObject qmol = indigo.createQueryMolecule()
IndigoObject a1 = qmol.addAtom("C")
IndigoObject a2 = qmol.addAtom("[#6]")
a2.addBond(a1, 1)
Python: the same with the IndigoObject
omitted.
You can reset existing atom keeping its connections and stereo
configuration using IndigoObject.resetAtom
method. It accepts string
representation of an atom in the SMILES (or SMARTS for the queries)
notation:
a.resetAtom("N")
To add R-sites or convert existing atom into R-site you can use
addRSite
and setRSite
methods:
atom = mol.addRSite("R3")
atom2.setRSite("R4")
Instrumenting Query Atoms¶
Each atom and bond in the query molecule represents as a logic expression of various properties. Indigo support almost all constraints from the SMARTS specification. To alter existing constraints you can use the following methods:
addConstraint(type, value)
— adds a specified constraint using logicaland
operation.addConstraintNot(type, value)
— adds a negation of a constraintaddConstraintOr(type, value)
— adds a constraint using logicalor
operation.removeConstraints(type)
— removed all constraints with a specified type.
The following self-explaining integer constraint types are supported:
- “atomic-number”
- “charge”
- “isotope”
- “radical”
- “valence”
- “connectivity”
- “total-bond-order”
- “hydrogens”
- “substituents”
- “ring”
- “smallest-ring-size”
- “ring-bonds”
- “rsite-mask”
- “rsite”
Other constraints:
- “aromaticity” = “aliphatic” or “aromatic”
- “smarts” — any single-atom SMARTS expression
Code example:
query = indigo.createQueryMolecule()
atom = q.addAtom("")
atom.addConstraint("substituents", "3")
atom.addConstraintNot("atomic-number", "16")
atom.addConstraint("smarts", "[$([#6]=[N+]=[N-]),$([#6-]-[N+]#[N])]")
Merging Molecules¶
You can merge one molecule into another using the merge
method of a
molecule. This method accepts a molecule that is to be merged into the
first molecule, and returns a “mapping” object. You can call the
mapAtom
method of the mapping object to know what is the (new) atom
of the first molecule that was transferred from the second molecule.
Java and C#:
IndigoObject mol = indigo.loadMolecule("c1ccccc1");
IndigoObject mol2 = indigo.loadMolecule("ON");
IndigoObject mapping = mol.merge(mol2);
mapping.mapAtom(mol2.getAtom(0)).addBond(mol.getAtom(3), 1);
Python: the same with the IndigoObject
omitted.
Removing Atoms and Bonds from Molecules¶
You can call the IndigoObject.remove
method on an atom or a bond to
remove it from the molecule it belongs to. Also, if you want to remove
many atoms at once, you can call IndigoObject.removeAtoms
method,
providing to it an array of indices of atoms that you want to remove.
Submolecules¶
The IndigoObject.createSubmolecule
method is applicable to a
molecule or a query molecule. It accepts an array of atom indices and
returns a new molecule containing the given atoms copied from the
molecule, and the bonds between them.
Similarly, the IndigoObject.createEdgeSubmolecule
method accepts two
arrays — atom indices and bond indices — and returns a new molecule
containing the given atoms and bonds copied from the molecule.
Indigo allows to create a reference on a submolecule of a molecule with
method IndigoObject.getSubmolecule
. Such molecule can be later used
for finding layout of a molecule part.
Accessing Atoms and Bonds¶
The following methods can be applied to a molecule or query molecule:
getAtom
— returns the atom by the given index.getBond
— returns the bond by the given index.iterateAtoms
— returns an iterator over atoms, including pseudoatoms and R-sites.iteratePseudoatoms
— returns an iterator over pseudoatoms.iterateRSites
— returns an iterator over R-sites.iterateBonds
— returns an iterator over bonds.
Getting the Properties of Atoms and Bonds¶
The following methods of a molecule’s atom can be called to obtain information:
atomicNumber
— returns zero if the atomic number is undefined or ambiguous. (happens only on queries). This method can not be applied to R-sites or pseudoatoms.isotope
— returns the isotope value or zero if the atomic number is undefined or ambiguous.degree
— returns explicit atom degree.charge
— returns the charge value ornull
if the charge is undefined (can happens only on queries).explicitValence
— returns the explicit valence ornull
if there is no explicit valence.radicalElectrons
— returns the number of radical electrons ornull
if the radical is undefined (can happen only on queries).countHydrogens
— returns the total number of hydrogens connected to the atom (explicit+implicit). Can returnnull
on query atoms where the number of hydrogens is not definitely known.countImplicitHydrogens
— returns the number of implicit hydrogens connected to the atom. Not applicable to query atoms.valence
— returns the valence of the atom. Not applicable to query atoms.isPseudoatom
— returnstrue
if the atom is a pseudoatom,false
otherwise.isRSite
— returnstrue
if the atom is a pseudoatom,false
otherwise.symbol
— returns a string containing the atom symbol. It is either a symbol the periodic table (“C”, “Na”), or a pseudoatom label (“Res”), or an R-site mark (“R1”).xyz
—returns an array of threefloat
numbers, which define the position of the atom.singleAllowedRGroup
— R-Group index allowed on R-Site (usually there is a single allowed index). This method can be applied exclusively to R-sites.
The following IndigoObject
methods can be applied to molecule’s
bonds:
bondOrder
— returns 1/2/3 if the bond is a single/double/triple bond. Returns 4 if the bond is an aromatic bond. Returns zero if the bond is ambiguous (query bond).source
— the atom from which the bond is goingdestination
— the atom to which the bond is goingtopology
— returns Indigo.RING or Indigo.CHAIN, depending on whether the bond is a ring bond or not. Returns zero if the bond is ambiguous (query bond).
Modifying Atoms and Bonds¶
The following methods of a molecule’s atom can be called to modify the atom:
resetCharge
resetExplicitValence
resetIsotope
resetRadical
setCharge
— accepts an integer charge valuesetIsotope
— accepts an integer isotope valuesetXYZ
— accepts three float numbers (X, Y, Z)setAttachmentPoint
— accepts an integer index of the attachment point (usually 1 or 2).setBondOrder
— accepts an integer value (1/2/3/4 for single/double/triple/aromatic)
Accessing Neighbor Atoms¶
With iterateNeighbors
method you can access the neighbors atoms of
an atom. Also, these “neighbor” objects respond to the bond
method,
which returns the bond connecting the atom with the neighbor.
Java:
for (IndigoObject atom : mol.iterateAtoms())
{
System.out.printf("atom %d: %d neighbors\n", atom.index(), atom.degree());
for (IndigoObject nei : atom.iterateNeighbors())
System.out.printf("neighbor atom %d is connected by bond %d\n", nei.index(), nei.bond().index());
}
foreach (IndigoObject atom in mol.iterateAtoms())
{
System.Console.WriteLine("atom {0}: {1} neighbors\n", atom.index(), atom.degree());
foreach (IndigoObject nei in atom.iterateNeighbors())
System.Console.WriteLine("neighbor atom {0} is connected by bond {1}\n", nei.index(), nei.bond().index());
}
Python:
for atom in mol.iterateAtoms():
print "atom %d: %d neighbors" % (atom.index(), atom.degree())
for nei in atom.iterateNeighbors():
print "neighbor atom %d is connected by bond %d\n" % (nei.index(), nei.bond().index())
Accessing R-Groups¶
Note: This section applies exclusively to query molecules.
The iterateRGroups
method iterates over a query molecule’s R-groups.
Each of the R-groups has a collection of possible “R-group fragments”,
which in turn can be accessed via the iterateRGroupFragments
method.
Java:
for (IndigoObject rg : mol.iterateRGroups())
{
System.out.println("RGROUP #" + rg.index());
for (IndigoObject frag : rg.iterateRGroupFragments())
{
System.out.println(" FRAGMENT #" + rg.index());
System.out.println(frag.molfile());
}
}
C#:
foreach (IndigoObject rg in mol.iterateRGroups())
{
System.Console.WriteLine("RGROUP #" + rg.index());
foreach (IndigoObject frag in rg.iterateRGroupFragments())
{
System.Console.WriteLine(" FRAGMENT #" + rg.index());
System.Console.WriteLine(frag.molfile());
}
}
Python:
for rg in mol.iterateRGroups():
print "RGROUP #" + rg.index()
for frag in rg.iterateRGroupFragments():
print " FRAGMENT #" + rg.index()
print frag.molfile()
Expand abbreviations¶
The expandAbbreviations
function converts input structure using the abbreviations dictionary into the expanded form. By default, Indigo uses the following structures list:
Name | Expansion |
---|---|
CO2 | [*:2]OC([*:1])=O |
Ph | *C1=CC=CC=C1 |
CO | [*:1]C([*:2])=O |
SO2 | [*:1]S(=O)(=O)[*:2] |
Me | *C |
Et | *CC |
Boc | CC(C)(C)OC([*])=O |
Bz | [*]C(=O)C1=CC=CC=C1 |
Cbz | [*]C(=O)OCC1=CC=CC=C1 |
Ac | CC(=O)[*] |
NO2 | [O-][N+]([*])=O |
NO | *N=O |
CN | [*]C#N |
CHO | [*]C=O |
N3 | [*]N=[N+]=[N-] |
C2H5O | [*]OCC |
C6H11 | [*]C1CCCCC1 |
PMB | COC1=CC=C(C[*])C=C1 |
Bn | [*]CC1=CC=CC=C1 |
Ms | CS([*])(=O)=O |
Cys | SC[C@H](N[*:1])C([*:2])=O |
Pr | *CCC |
Ts | CC1=CC=C(C=C1)S([*])(=O)=O |
t-Bu | CC(C)(C)[*] |
Bu | CCCC[*] |
Tf | FC(F)(F)S([*])(=O)=O |
Tos | CC1=CC=C(C=C1)S([*])(=O)=O |
FMOC | [*]C(=O)OCC1C2=CC=CC=C2C2=C1C=CC=C2 |
SO3- | [O-]S([*])(=O)=O |
SO3H | [OH]S([*])(=O)=O |
O- | *[O-] |
NH3+ | *[NH3+] |
SiPr | CC(C)S[*] |
iPr | CC(C)[*] |
CHOH | OC([*:1])[*:2] |
Python:
mol = indigo.loadMolecule("molfile_with_alias.mol")
mol.expandAbbreviations()
Saving Molecules¶
IndigoObject.smiles
, when applied to a molecule, returns a SMILES
string. Similarly, IndigoObject.molfile
returns a string with a
Molfile, while IndigoObject.cml
returns a string with CML
representation. IndigoObject.saveMolfile
and
IndigoObject.saveCml
methods save Molfile and CML to disk.
Java:
System.out.println(mol1.molfile());
System.out.println(mol2.smiles());
qmol1.saveMolfile("query.mol");
C#:
System.Console.WriteLine(mol1.molfile());
System.Console.WriteLine(mol2.smiles());
qmol1.saveMolfile("query.mol");
Python:
print mol1.molfile()
print mol2.smiles()
qmol1.saveMolfile("query.mol")
Reactions¶
Loading Reactions and Query Reactions¶
Java and C#:
IndigoObject rxn1 = indigo.loadReaction("[I-].[Na+].C=CCBr>>[Na+].[Br-].C=CCI");
IndigoObject rxn2 = indigo.loadReactionFromFile("reaction.rxn");
IndigoObject qrxn1 = indigo.loadQueryReaction("CBr>>CCl");
IndigoObject qrxn2 = indigo.loadQueryReactionFromFile("query.rxn");
IndigoObject rs = indigo.loadReactionSmarts("[C$(CO)]>>[C$(CN)]");
IndigoObject rs2 = indigo.loadReactionSmartsFromFile("query.sma");
Python: the same with the IndigoObject
omitted.
Instrumenting Reactions¶
The Indigo.createReaction
method returns an empty reaction. The
Indigo.createQueryReaction
method returns an empty query reaction.
The IndigoObject.addReactant
, IndigoObject.addProduct
, and
IndigoObject.addCatalyst
methods can then be used to fill it up.
Java and C#:
IndigoObject rxn = indigo.createReaction();
rxn.addReactant(mol1);
rxn.addReactant(mol2);
rxn.addProduct(indigo.loadMolecule("ClC1CCCCC1));
Python: the same with the IndigoObject
omitted.
Accessing Reactions¶
Reactions respond to the following IndigoObject
methods:
IndigoObject.iterateReactants
— enumerates reactantsIndigoObject.iterateProducts
— enumerates productsIndigoObject.iterateCatalysts
— enumerates catalystsIndigoObject.iterateMolecules
— enumerates reactants, products, and catalysts, in no particular orderIndigoObject.countReactants
— returns the number of reactantsIndigoObject.countProducts
— returns the number of productsIndigoObject.countCatalysts
— returns the number of catalystsIndigoObject.countMolecules
— returns the total number of molecules in the reaction
You can also call the IndigoObject.remove
method of the reaction
molecule to remove it from the reaction.
Java:
System.out.println(rxn.countMolecules());
for (IndigoObject item : rxn.iterateReactants())
System.out.println(item.molfile());
for (IndigoObject item : rxn.iterateCatalysts())
item.remove();
C#:
System.Console.WriteLine(rxn.countMolecules());
foreach (IndigoObject item in rxn.iterateReactants())
System.Console.WriteLine(item.molfile());
foreach (IndigoObject item in rxn.iterateCatalysts())
item.remove();
Python:
print rxn.countMolecules()
for item in rxn.iterateReactants():
print item.molfile()
for item in rxn.iterateCatalysts():
item.remove();
Saving Reactions¶
The IndigoObject.smiles
, when applied to a reaction, returns a
reaction SMILES string. Similarly, the IndigoObject.rxnfile
returns
a string with an Rxnfile. The IndigoObject.saveRxnfile
method saves
the Rxnfile to disk.
Java:
System.out.println(rxn.smiles());
System.out.println(rxn.rxnfile());
rxn.saveRxnfile("reaction.rxn");
C#:
System.Console.WriteLine(rxn.smiles());
System.Console.WriteLine(rxn.rxnfile());
rxn.saveRxnfile("reaction.rxn");
Python:
print rxn.smiles()
print rxn.rxnfile()
rxn.saveRxnfile("reaction.rxn")
Reacting Centers¶
Reacting centers include bonds that are involved in the reaction. Indigo supports the following types of reacting centers:
Indigo.RC_NOT_CENTER
Indigo.RC_UNMARKED
Indigo.RC_CENTER
Indigo.RC_UNCHANGED
Indigo.RC_MADE_OR_BROKEN
Indigo.RC_ORDER_CHANGED
These values are bit flags, and can be combined.
IndigoObject.reactingCenter
and IndigoObject.setReactingCenter
are the getter and setter of the bond reacting center property.
Python:
print("reacting centers:")
for m in rxn.iterateMolecules():
for b in m.iterateBonds():
print(rxn.reactingCenter(b))
for m in rxn.iterateMolecules():
for b in m.iterateBonds():
rxn.setReactingCenter(b, Indigo.RC_CENTER | Indigo.RC_UNCHANGED)
The IndigoObject.correctReactingCenters
method highlights bond
reacting centers according to AAM.
Java, C#, and Python:
rxn.automap("discard");
rxn.correctReactingCenters();
Reaction Atom-to-Atom Mapping¶
The IndigoObject.automap(mode [ignore_option])
method is purposed
for generating reaction atom-to-atom mapping (AAM). The method accepts a
string parameter called mode
. The following modes are available:
discard
: discards the existing mapping entirely and considers only the existing reaction centers (the default)keep
: keeps the existing mapping and maps unmapped atomsalter
: alters the existing mapping, and maps the rest of the reaction but may change the existing mappingclear
: removes the mapping from the reaction
Java, C#, and Python:
rxn.automap("discard");
rxn.saveRxnfile("rxn_aam.rxn");
rxn.automap("clear");
rxn.saveSmiles("rxn_noaam.smi");
The following options can be added after the discard
, keep
or
alter
modes (separated by a space):
ignore_charges
: do not consider atom charges while searchingignore_isotopes
: do not consider atom isotopes while searchingignore_valence
: do not consider atom valence while searchingignore_radicals
: do not consider atom radicals while searching
Python:
rxn.automap("alter ignore_charges")
for in rxn.iterateMolecules():
for atom in mol.iterateAtoms():
print("Atom %d %d" % atom.index(), atom.atomMappingNumber())
rxn.automap("alter ignore_charges ignore_valence")
...
The IndigoObject.clearAAM
method resets current atom-to-atom
mapping. Reaction atom has method IndigoObject.atomMappingNumber
and
IndigoObject.setAtomMappingNumber
to get and set atom-to-atom
mapping manually.
Java, C#, and Python:
rxn.clearAAM();
rxn.saveSmiles("rxn_noaam.smi");
The aam-timeout
indigo integer parameter (time in milliseconds)
corresponds for the AAM algorithm working time. The AAM method returns a
current state solution for a reaction when time is over.
Java, C#, and Python:
indigo.setOption("aam-timeout", 500);
rxn.automap("discard");
rxn.saveSmiles("rxn_time.smi");
Calculating Properties¶
The following IndigoObject
methods can be applied to a molecule or
query molecule:
countAtoms
— returns the number of atoms, including pseudoatoms and R-sites.countPseudoatoms
— returns the number of pseudoatoms.countRSites
— returns the number of R-sites.coundBonds
— returns the number of bonds.grossFormula
— returns a string with the gross formula.molecularWeight
— returns the molecular weight (a floating-point number).mostAbundantMass
— returns the “most abundant isotopes mass” (a floating-point number).monoisotopicMass
— returns the monoisotopic mass (a floating-point number).hasCoord
— returnstrue
if the given molecule has coordinates,false
otherwise.hasZCoord
— returnstrue
if the given molecule has 3D coordinates,false
otherwise.isChiral
— returnstrue
if the molecule was loaded from a Molfile, and if it had the ‘Chiral’ flag set.countHeavyAtoms
— returns the number of atoms in the molecule, excluding hydrogen atoms. Hydrogen isotopes are excluded too.countImplicitHydrogens
— returns the total number of implicit hydrogens in the molecule.countHydrogens
— returns the total number of hydrogens in the molecule (implicit hydrogens included, hydrogen isotopes included).countSSSR
— returns the total number of cycles in the Smallest Set of Smallest Rings (SSSR).
Molecule Validation¶
Molecule validation can be done using the following methods:
checkBadValence
checkAmbiguousH
These functions returns non-empty string description of found issues, or empty string if molecule is correct.
Working with Connected Components¶
You can use the countComponents
method to calculate the number of
connected components in a structure. Via the componentIndex
method,
you can obtain the number of the component to which the given atom
belongs. Also, you can obtain the whole “component” object via the
component
method. You can also iterate over the components using the
iterateComponents
method.
The “component” objects respond to the countAtoms
, countBonds
,
iterateAtoms
, and iterateBonds
calls. However, they can not be
used as molecules. If you want to have a separate molecule representing
a connected component, you should clone
it.
Note: The numbering of the components in zero-based.
Java:
System.out.printf("%d components\n", mol.countComponents());
for (IndigoObject comp : mol.iterateComponents())
{
System.out.println(comp.clone().smiles());
System.out.printf("component %d: %d atoms, %d bonds\n", comp.index(), comp.countAtoms(), comp.countBonds());
for (IndigoObject atom : comp.iterateAtoms())
System.out.println(atom.index());
}
for (IndigoObject atom : mol.iterateAtoms())
System.out.println(atom.componentIndex());
for (IndigoObject atom : mol.component(0).iterateAtoms())
System.out.println(atom.index());
C#:
System.Console.WriteLine("{0} components", mol.countComponents());
foreach (IndigoObject comp in mol.iterateComponents())
{
System.Console.WriteLine(comp.clone().smiles());
System.Console.WriteLine("component {0}: {0} atoms, {0} bonds\n", comp.index(), comp.countAtoms(), comp.countBonds());
foreach (IndigoObject atom in comp.iterateAtoms())
System.Console.WriteLine(atom.index());
}
foreach (IndigoObject atom in mol.iterateAtoms())
System.Console.WriteLine(atom.componentIndex());
foreach (IndigoObject atom in mol.component(0).iterateAtoms())
System.Console.WriteLine(atom.index());
Python:
print mol.countComponents(), 'components'
for comp in mol.iterateComponents():
print comp.clone().smiles()
print "component %d: %d atoms, %d bonds\n", (comp.index(), comp.countAtoms(), comp.countBonds())
for atom in comp.iterateAtoms():
print atom.index()
for atom in mol.iterateAtoms():
print atom.compomentIndex()
for atom in mol.component(0).iterateAtoms():
print atom.index()
Canonical SMILES¶
IndigoObject.canonicalSmiles
method computes the canonical SMILES
(also known as absolute SMILES) string for either molecule or reaction.
Java:
System.out.println(mol.canonicalSmiles());
System.out.println(rxn.canonicalSmiles());
C#:
System.Console.WriteLine(mol.canonicalSmiles());
System.Console.WriteLine(rxn.canonicalSmiles());
Python:
print mol.canonicalSmiles()
print rxn.canonicalSmiles()
Please see the Canonical Smiles for detailed examples
Attachment points¶
Every molecule can have many attachment points. They are grouped by
order - the number of connections. For example, a molecule can have 2
attachment points with order 1, and 3 attachment points with order 2.
The following methods of IndigoObject
for a molecule are available
for working with attachment points:
clearAttachmentPoints
resets all the attachment points.countAttachmentPoints
returns maximal order of attachment points.iterateAttachmentPoints(order)
iterates atoms corresponding to the attachment points with the same specified order.
Python:
count = mol.countAttachmentPoints()
print("%s Number of attachment points: %s" % (offset, count))
for order in range(1, count + 1):
for a in mol.iterateAttachmentPoints(order):
print("%s Index: %d. Order %d" % (offset, a.index(), order))
mol.clearAttachmentPoints()
Layout (2D coordinates)¶
The IndigoObject.layout
method performs the cleanup of the object it
is applied to by computing atoms 2D coordinates.
Java, C#, and Python:
mol.layout();
rxn.layout();
Aromaticity¶
The IndigoObject.aromatize
and IndigoObject.dearomatize
methods
convert molecules/reactions to aromatic and Kekule forms respectively.
Java, C#, and Python:
mol1.dearomatize();
rxn.aromatize();
Implicit and Explicit Hydrogens¶
Indigo does not change the representation of the hydrogens automatically. If the hydrogens in the input structure or reaction are implicit (this is usually the case), Indigo does not add the missing hydrogens to the structure or reaction. If some (or all) of hydrogens in the input are explicitly drawn, Indigo does not remove them.
You can force folding (i.e. removal) or unfolding (i.e. addition) the
hydrogens of a molecule or reaction by calling
IndigoObject.foldHydrogens
and IndigoObject.unfoldHydrogens
methods.
Java, C#, and Python:
mol.unfoldHydrogens();
mol.foldHydrogens();
rxn.unfoldHydrogens();
rxn.foldHydrogens();
Stereochemistry¶
The following methods of IndigoObject
are available for accessing
molecule’s stereo configuration:
countStereocenters
returns the number of the chiral atoms in a moleculeiterateStereocenters
returns an iterator for molecule’s atoms that are stereocenterscountAlleneCenters
returns the number of allene-like stereo fragmentsiterateAlleneCenters
returns an iterator for molecule’s atoms that are centers of allene fragments (the middle ‘C’ in ‘C=C=C’)bondStereo
returns one of the following constants:Indigo.UP
— stereo “up” bondIndigo.DOWN
— stereo “down” bondIndigo.EITHER
— stereo “either” bondIndigo.CIS
— “Cis” double bondIndigo.TRANS
— “Trans” double bond- zero — not a stereo bond of any kind
stereocenterType
returns one of the following constants:Indigo.ABS
— “absolute” stereocenterIndigo.OR
— “or” stereocenterIndigo.AND
— “and” stereocenterIndigo.EITHER
— “any” stereocenter- zero — not a stereocenter
invertStereo
inverts the stereo configuration of an atomresetStereo
resets the stereo configuration of an atom or a bondchangeStereocenterType(newType)
changes current stereocenter type to a specified typeaddStereocenter(type, idx1, idx2, idx3, [idx4])
adds new stereocenter build on a atom pyramid with a specified atom indicesclearStereocenters
resets the chiral configurations of a molecule’s atomsclearAlleneCenters
resets the chiral configurations of a molecule’s allene-like fragmentsclearCisTrans
resets the cis-trans configurations of a molecule’s bonds
The following methods are useful for keeping cis-trans stereochemistry intact when converting to/from SMILES:
resetSymmetricCisTrans
can be called on a molecule loaded from a Molfile or CML. After this call, the cis-trans configurations remain only on nonsymmetric cis-trans bonds. The method returns the number of bonds that have been reset.markEitherCisTrans
can be called prior to saving a molecule loaded from SMILES to Molfile format. It guarantees that the bonds that have no cis-trans configuration in SMILES will not have a cis-trans configuration in the resulting Molfile.
Java:
IndigoObject mol = indigo.loadMolecule("chiral.mol");
System.output.println("%d chiral atoms\n", mol.countStereocenters());
for (IndigoObject atom : mol.iterateStereocenters())
{
System.out.printf("atom %d -- stereocenter type %d\n", atom.index(), atom.stereocenterType());
atom.invertStereo();
}
for (IndigoObject bond : mol.iterateBonds())
if (bond.bondStereo() != 0)
System.out.printf("bond %d -- stereo type %d\n", bond.index(), bond.bondStereo());
System.out.println(mol.smiles());
mol.clearStereocenters();
mol.clearCisTrans();
System.out.println(mol.smiles());
C#:
IndigoObject mol = indigo.loadMolecule("chiral.mol");
System.Console.WriteLine("{0} chiral atoms\n", mol.countStereocenters());
foreach (IndigoObject atom in mol.iterateStereocenters())
{
System.Console.WriteLine("atom {0} -- stereocenter type {1}\n", atom.index(), atom.stereocenterType());
atom.invertStereo();
}
foreach (IndigoObject bond in mol.iterateBonds())
if (bond.bondStereo() != 0)
System.Console.WriteLine("bond {0} -- stereo type {1}\n", bond.index(), bond.bondStereo());
System.Console.WriteLine(mol.smiles());
mol.clearStereocenters();
mol.clearCisTrans();
System.out.println(mol.smiles());
Python:
IndigoObject mol = indigo.loadMolecule("chiral.mol");
print mol.countStereocenters(), "chiral atoms"
for atom in mol.iterateStereocenters():
print "atom", atom.index(), "-- stereocenter type", atom.stereocenterType()
atom.invertStereo();
for bond in mol.iterateBonds():
if bond.bondStereo() != 0:
print "bond", bond.index(), "-- stereo type", bond.bondStereo()
print mol.smiles()
mol.clearStereocenters()
mol.clearCisTrans()
print mol.smiles()
stereocenterGroup
and setStereocenterGroup
method to get/set stereocenter group:
# Load structure
m = indigo.loadMoleculeFromFile('../release-notes/1.1.x/data/stereogroups.mol')
indigo.setOption('render-comment', 'Before')
indigoRenderer.renderToFile(m, 'result_1.png')
for s in m.iterateStereocenters():
print "atom index =", s.index(), "group =", s.stereocenterGroup()
m.getAtom(1).changeStereocenterType(Indigo.OR)
m.getAtom(1).setStereocenterGroup(1)
m.getAtom(5).setStereocenterGroup(1)
indigo.setOption('render-comment', 'Stereocenter groups and types were changed')
indigoRenderer.renderToFile(m, 'result_2.png')
atom index = 1 group = 0
atom index = 2 group = 1
atom index = 5 group = 2
The markStereobonds
method set up/down bond marks if a stereoconfiguration were changed manually, or if it should be reset:
m = indigo.loadMoleculeFromFile('../release-notes/1.1.x/data/stereobonds.mol')
indigo.setOption('render-comment', 'Before')
indigoRenderer.renderToFile(m, 'result_1.png')
m.markStereobonds()
indigo.setOption('render-comment', 'After')
indigoRenderer.renderToFile(m, 'result_2.png')
Enumeration of Submolecules¶
Indigo provides methods to enumerate submolecules of different kinds, namely:
- Smallest Set of Smallest Rings (SSSR) —
iterateSSSR
. - All rings of size within a given interval —
iterateRings
. The method accepts the minimum and maximum amounts of the rings’ atoms. - All subtrees of size within a given interval —
iterateSubtrees
. The method accepts the minimum and maximum amounts of the subtrees’ atoms. - All edge submolecules of size within a given interval —
iterateEdgeSubmolecules
. The method accepts the minimum and maximum amounts of the submolecules’ edges.
The “submolecule” objects returned by these methods respond to the
countAtoms
, countBonds
, iterateAtoms
, and iterateBonds
calls. However, they can not be used as molecules. If you want to have a
separate molecule representing the obtained submolecule, you should
clone
it.
Java:
for (IndigoObject submol : mol.iterateEdgeSubmolecules(1, mol.countBonds())
{
System.out.printf("submolecule #%d: %s\n", submol.index(), submol.clone().smiles());
for (IndigoObject atom : item.iterateAtoms())
System.out.printf("%d ", atom.index());
System.out.printf("\n");
for (IndigoObject bond : item.iterateBonds())
System.out.printf("%d ", bond.index());
System.out.printf("\n");
}
C#:
foreach (IndigoObject item in mol.iterateEdgeSubmolecules(1, mol.countAtoms()))
{
System.Console.WriteLine("{0} {1}", item.index(), item.clone().smiles());
foreach (IndigoObject atom in item.iterateAtoms())
System.Console.Write("{0} ", atom.index());
System.Console.WriteLine();
foreach (IndigoObject bond in item.iterateBonds())
System.Console.Write("{0} ", bond.index());
System.Console.WriteLine();
}
Python:
for submol in mol.iterateEdgeSubmolecules(1, mol.countBonds()):
print "submolecule", submol.index(), ":", submol.clone().smiles()
print [atom.index() for atom in item.iterateAtoms()]
print [bond.index() for bond in item.iterateBonds()]
Enumeration of Tautomers¶
Indigo provides a method to enumerate tautomers of a selected molecule. Currently there are two algorithms to enumerate tautomers: based on InChI code and based on a set of reaction SMARTS rules.
The iterateTautomers
method returns an iterator for tautomers. It accepts a molecule and options as parameters.
There are two possible options: INCHI
to use method based on InChI code, and RSMARTS
to use reaction SMARTS templates:
Java:
for (IndigoObject tautomer : indigo.iterateTautomers(molecule, "RSMARTS")
{
System.out.printf("tautomer %d: %s\n", tautomer.index(), tautomer.clone().smiles());
}
C#:
foreach (IndigoObject item in indigo.iterateTautomers(molecule, "RSMARTS"))
{
System.Console.WriteLine("tautomer {0}: {1}", item.index(), item.clone().smiles());
}
Python:
for tautomer in indigo.iterateTautomers(molecule, 'RSMARTS'):
print "tautomer", tautomer.index(), ":", tautomer.clone().smiles()
Please see the Enumeration of Tautomers for detailed examples
SGroups¶
In a molecule loaded from a Molfile, arbitrary subsets of a its atoms and bonds can be joined in S-groups. There are many kinds of S-groups, Indigo supports all described in the format:
- generic SGroup (GEN)
- abbreviation (superatom) (SUP)
- structure repeating unit (SRU)
- multiple SGroup (MUL)
- data SGroup (DAT)
- monomer SGroup (MON)
- mer SGroup (MER)
- copolymer SGroup (COP)
- crosslink SGroup (CRO)
- modification SGroup (MOD)
- graft SGroup (GRA)
- component SGroup (COM)
- mixture SGroup (MIX)
- formulation SGroup (FOR)
- any polymer SGroup (ANY)
The following methods of IndigoObject
are available for reading
molecule’s groups:
countGenericSGroups
countSuperatoms
countRepeatingUnits
countMultipleGroups
countDataSGroups
iterateGenericSGroups
iterateSuperatoms
iterateRepeatingUnits
iterateMultipleGroups
iterateDataSGroups
getSuperatom(index)
getDataSGroup(index)
The iterator methods return “group” objects. Each “group” object
responds to IndigoObject.iterateAtoms
and
IndigoObject.iterateBonds
methods.
Java:
for (IndigoObject dsg : mol.iterateDataSGroups())
{
System.out.println("data sgroup " + dsg.index());
for (IndigoObject atom : dsg.iterateAtoms())
System.out.println(" atom " + atom.index());
}
C#:
foreach (IndigoObject dsg in mol.iterateDataSGroups())
{
System.Console.WriteLine("data sgroup " + dsg.index());
foreach (IndigoObject atom in dsg.iterateAtoms())
System.Console.WriteLine(" atom " + atom.index());
}
Python:
for dsg in mol.iterateDataSGroups():
print "data sgroup", dsg.index()
for atom in dsg.iterateAtoms():
print atom.index()
You can also add data SGroups to an existing structure using
IndigoObject.addDataSGroup()
method. It returns the added group. By
default, the data SGroup is added in “attached” mode — that is, the data
is attached to each of the group’s atoms. To make the data SGroup
detached, you can call the IndigoObject.setDataSGroupXY
method of
the data SGroup object. To get a description of a data SGroup use method
IndigoObject.description()
.
To add a superatom use IndigoObject.addSuperatom()
method:
mol.addSuperatom(list_with_atom_indices, "Abbreviation")
New set of methods is available for manipulation with S-groups. You can create new S-group using “mapping” object received from matcher:
IndigoObject.createSGroup
Java:
IndigoObject match = indigo.substructureMatcher(mol).match(query);
if (match != null)
{
IndigoObject sgroup = mol.createSGroup("SUP", match, "Asx");
}
C#:
IndigoObject match = indigo.substructureMatcher(mol).match(query);
if (match != null)
{
IndigoObject sgroup = mol.createSGroup("SUP", match, "Asx");
}
Python:
match = indigo.substructureMatcher(mol).match(query)
if match:
sgroup = mol.createSGroup("SUP", match, "Asx")
You can get and set different S-group’s properties using the next methods:
getSGroupType
- returns S-group typegetSGroupIndex
- returns S-group indexsetSGroupData
- accepts S-group data (for S-groups of “DAT” type)setSGroupCoords
accepts S-group coordinates, x and y values (for S-groups of “DAT” type)setSGroupDescription
- accepts S-group data field units or format (for S-groups of “DAT” type)setSGroupFieldName
- accepts S-group data name (for S-groups of “DAT” type)setSGroupQueryCode
- accepts S-group data query code (for S-groups of “DAT” type)setSGroupQueryOper
- accepts S-group data query operation (for S-groups of “DAT” type)setSGroupDisplay
- accepts S-group data display option (for S-groups of “DAT” type)setSGroupLocation
- accepts S-group data display location (for S-groups of “DAT” type)setSGroupTag
- accepts S-group data tag (for S-groups of “DAT” type)setSGroupTagAlign
- accepts S-group data tag alignment (for S-groups of “DAT” type)setSGroupDataType
- accepts S-group data type (for S-groups of “DAT” type)setSGroupXCoord
- accepts S-group x coordinate (for S-groups of “DAT” type)setSGroupYCoord
- accepts S-group y coordinate (for S-groups of “DAT” type)getSGroupClass
- returns S-group class name (for S-groups of “SUP” type)setSGroupClass
- accepts S-group class name (for S-groups of “SUP” type)getSGroupName
- returns S-group label (for S-groups of “SUP” and “SRU” types)setSGroupName
- accepts S-group label (for S-groups of “SUP” and “SRU” types)getSGroupNumCrossBonds
- returns number of crossing bonds for sgroupaddSGroupAttachmentPoint
- accepts attachment point’s description and creates it (for S-groups of “SUP” type)deleteSGroupAttachmentPoint
- accepts attachment point’s index and removes it (for S-groups of “SUP” type)getSGroupDisplayOption
- returns display option for sgroup (for S-groups of “SUP” type)setSGroupDisplayOption
- accepts display option for sgroup (for S-groups of “SUP” type)getSGroupMultiplier
- returns multiplier value for sgroup (for S-groups of “MUL” type)setSGroupMultiplier
- accepts multiplier value for sgroup (for S-groups of “MUL” type)setSGroupBrackets
- accepts bracket style and brackets coordinates for sgroup (for S-groups of “GEN”,”MUL” and “SRU” types)
Note: All properties and its values correspond to Molfile format.
Python examples:
sg.setSGroupClass("AA")
print(sg.getSGroupName())
print(sg.getSGroupClass())
print(sg.getSGroupNumCrossBonds())
print(sg.getSGroupDisplayOption())
sg.setSGroupName("As")
sg.setSGroupDisplayOption(0)
mp = sg.getSGroupMultiplier()
sg.setSGroupMultiplier(mp + 1)
sg.setSGroupBrackets(1, 1.0, 1.0, 1.0, 2.0, 3.0, 1.0, 3.0, 2.0)
sg.setSGroupData("Test Data S-group")
sg.setSGroupCoords(1.0, 1.0)
sg.setSGroupDescription("SGroup Description (FIELDINFO)")
sg.setSGroupFieldName("SGroup (FIELDNAME)")
sg.setSGroupQueryCode("SGroup (QUERYTYPE)")
sg.setSGroupQueryOper("SGroup (QUERYOP)")
sg.setSGroupDisplay("attached")
sg.setSGroupLocation("relative")
sg.setSGroupTag("G")
sg.setSGroupTagAlign(9)
sg.setSGroupDataType("T")
sg.setSGroupXCoord(4.0)
sg.setSGroupYCoord(5.0)
You can find in the IndigoObject
S-groups using different criteria
with corresponding values in S-group properties by type, by name, by class, by atoms or crossing bonds
included in S-group:
findSGroups
- it accepts key and value for search and retuns iterator for collection of found sgroups
Currently available keys are:
SG_TYPE
- find sgroups by typeSG_CLASS
- find sgroups by classSG_LABEL
- find sgroups by nameSG_DISPLAY_OPTION
- find sgroups by display optionSG_BRACKET_STYLE
- find sgroups by bracket styleSG_DATA
- find sgroups which contains corresponding string in data fieldSG_DATA_NAME
- find sgroups by data nameSG_DATA_TYPE
- find sgroups by data typeSG_DATA_DESCRIPTION
- find sgroups by data descriptionSG_DATA_DISPLAY
- find sgroups by data display optionSG_DATA_LOCATION
- find sgroups by data locationSG_DATA_TAG
- find sgroups by data tagSG_QUERY_CODE
- find sgroups by query codeSG_QUERY_OPER
- find sgroups by query operationSG_PARENT
- find sgroups by parent sgroupSG_CHILD
- find sgroups by children sgroupSG_ATOMS
- find sgroups containing list of atomsSG_BONDS
- find sgroups contating list of crossing bonds
Please see the Sgroups search for detailed examples
S-group can be removed from the IndigoObject
using remove
method. In that case just description of
corresponding S-group will be removed (the atoms and bonds remain).
TGroups¶
Indigo supports the hybrid representation (SCSR) for a molecule loaded from a V3000 Molfile. SCSR uses TEMPLATE blocks to represent residues and this representation is widely used for biological sequences.
There are methods for transformation SCSR into full CTAB form and vise versa:
transformSCSRtoCTAB
- transforms SCSR into full CTAB representation (templates are transformed into S-groups)transformCTABtoSCSR
- transforms CTAB into SCSR (accepts templates collection and replaces matched fragments by pseudoatoms and corresponding templates)
Examples of usage these methods are in corresponding Examples section.
Alignment of Atoms¶
The IndigoObject.alignAtoms
method can be used to calculate and
apply the transformation (scale + rotation + translation) of a
molecule so that some subset of its atoms will become as close as
possible to the desired positions. The method accepts an integer array
of atom indices and a float array of desired coordinates (three times
bigger that the array of indices, storing resired x,y,z coordinates for
each atom).
Java:
IndigoObject query = indigo.loadSmarts("[#7]1~[#6]~[#6]~[#7]~[#6]~[#6]2~[#6]~[#6]~[#6]~[#6]~[#6]~1~2");
int[] atoms = new int[query.countAtoms()];
float[] xyz = new float[query.countAtoms() * 3];
for (IndigoObject structure : indigo.iterateSDFile("structures.sdf.gz"))
{
IndigoObject match = indigo.substructureMatcher(structure).match(query);
int i = 0;
if (structure.index() == 0)
for (IndigoObject atom : query.iterateAtoms())
System.arraycopy(match.mapAtom(atom).xyz(), 0, xyz, i++ * 3, 3);
else
{
for (IndigoObject atom : query.iterateAtoms())
atoms[i++] = match.mapAtom(atom).index();
structure.alignAtoms(atoms, xyz);
}
}
C#:
IndigoObject query = indigo.loadSmarts("[#7]1~[#6]~[#6]~[#7]~[#6]~[#6]2~[#6]~[#6]~[#6]~[#6]~[#6]~1~2");
int[] atoms = new int[query.countAtoms()];
float[] xyz = new float[query.countAtoms() * 3];
foreach (IndigoObject structure in indigo.iterateSDFile("structures.sdf.gz"))
{
IndigoObject match = indigo.substructureMatcher(structure).match(query);
int i = 0;
if (structure.index() == 0)
foreach (IndigoObject atom in query.iterateAtoms())
Array.Copy(match.mapAtom(atom).xyz(), 0, xyz, i++ * 3, 3);
else
{
foreach (IndigoObject atom in query.iterateAtoms())
atoms[i++] = match.mapAtom(atom).index();
structure.alignAtoms(atoms, xyz);
}
}
Python:
query = indigo.loadSmarts("[#7]1~[#6]~[#6]~[#7]~[#6]~[#6]2~[#6]~[#6]~[#6]~[#6]~[#6]~1~2");
xyz = []
for structure in indigo.iterateSDFile("structures.sdf.gz"):
match = indigo.substructureMatcher(structure).match(query)
if structure.index() == 0:
for atom in query.iterateAtoms():
xyz.extend(match.mapAtom(atom).xyz())
else:
atoms = []
for atom in query.iterateAtoms():
atoms.append(match.mapAtom(atom).index())
structure.alignAtoms(atoms, xyz);
InChI¶
InChI support is done via IndigoInchi plugin. To work with the InChI plugin in C#/Java/Python wrappers, one needs to create an instance of IndigoInchi, passing an existing Indigo instance to it.
Use IndigoInchi.loadMolecule
method to convert InChI strings to a
molecule, and IndigoInchi.getInchi
method for the reverse operation.
Python:
indigo_inchi = IndigoInchi(indigo);
print(indigo_inchi.version())
m = indigo_inchi.loadMolecule("InChI=1S/C10H20N2O2/c11-7-1-5-2-8(12)10(14)4-6(5)3-9(7)13/h5-10,13-14H,1-4,11-12H2")
print(m.canonicalSmiles())
print(indigo_inchi.getInchi(m))
print(indigo_inchi.getWarning())
m = indigo.loadMolecule("C1CCCCCCC1")
print(indigo_inchi.getInchi(m))
Options¶
You can pass any options supported by the official InChI library via
inchi-options
option:
indigo.setOption("inchi-options", "/DoNotAddH /SUU /SLUUD")
One can use both -
and /
prefix for them:
indigo.setOption("inchi-options", "-DoNotAddH /SUU -SLUUD")
Standardize of Molecule¶
The IndigoObject.standardize
method can be used to the “standardizing”
of the molecule or query (stereo, charges, geometry, valences, atoms and bonds properties)
in accordance with requirements. The list of applied modifications is defined by
options activated in Indigo (full list of available standardize options is described
in the corresponding Options section).
Note: in the case of activation multiple options the order of applied modifications corresponds to the order of the options in the list of available options
Java, C#, and Python:
indigo.setOption("standardize-stereo", true);
indigo.setOption("standardize-charges", true);
mol.standardize();
Ionize of Molecule¶
The IndigoObject.ionize
method can be used for building protonated/deprotonated form
of the molecule in accordance with pH and pH tolerance. pKa model for pKa estimation can be
defined using corresponding Options section).
Java, C#, and Python:
indigo.setOption("pKa-model", "advanced")
indigo.setOption("pKa-model-level", 5)
indigo.setOption("pKa-model-min-level", 2)
mol.ionize(pH, ph_toll)
pKa¶
The IndigoObject.getAcidPkaValue
and IndigoObject.getBasicPkaValue
method can be used for
estimation pKa values for individual atoms in a molecule. pKa model for pKa estimation can be
defined using corresponding Options section).
The IndigoObject.buildPkaModel
method is used for building pKa model based on custom structures
set.
Java, C#, and Python:
level = indigo.buildPkaModel(10, 0.5, 'molecules/PkaModel.sdf')
a_pka = mol.getAcidPkaValue(atom, 5, 2)
b_pka = mol.getBasicPkaValue(atom, 5, 2)
CIP Stereo Descriptors¶
Descriptors calculation is activated by corresponding Indigo option molfile-saving-add-stereo-desc
and descriptors are added into generated mol file as data S-groups with special name field
INDIGO_CIP_DESC
. Setting Indigo option molfile-saving-add-stereo-desc
to 0 (or false) (the
default value) disables descriptors calculation and removes all such data S-groups during corresponding
mol file generation.
Please see the CIP Descriptors for detailed examples.
IO¶
Reading SDF, RDF, CML, multiline SMILES files, CDX (binary)¶
The following methods of the Indigo
class can be used to enumerate
files with multiple molecules/reactions:
iterateSDFile
iterateRDFile
iterateSmilesFile
iterateCMLFile
iterateCDXFile
Java:
for (IndigoObject item : indigo.iterateSDFile("structures.sdf"))
System.out.println(item.grossFormula());
C#:
foreach (IndigoObject item in indigo.iterateSDFile("structures.sdf"))
System.Console.WriteLine(item.grossFormula());
Python:
for item in indigo.iterateSDFile("structures.sdf"):
print item.grossFormula()
Indexed access¶
You can access items from SDF/RDF/CML/SMILES files by index, using the
at
method. The numbering of the items is zero-based.
Java, C#:
IndigoObject reader = indigo.iterateSDFile("structures.sdf");
String s = reader.at(15).smiles()
Python: the same with the IndigoObject
and String
omitted.
Accessing Molecule and Reaction Properties¶
Names¶
Molecule or reaction name is associated with the first line of the Molfile/Rxnfile the molecule/reaction was loaded from. In case it was loaded from SMILES string, the word immediately following the SMILES code is taken.
IndigoObject.name
and IndigoObject.setName
are the getter and
setter of the molecule/reaction name.
Java, C#:
String name = mol2.name();
mol2.setName("another name");
mol2.saveMolfile("mol2.mol");
Python: the same with the IndigoObject
and String
omitted.
SDF/RDF/CDX Properties¶
The following methods are used to get the named properties of the molecule/reaction loaded from an SDF or RDF or CDX file:
IndigoObject.hasProperty
(boolean) — checks if the object has the given property.IndigoObject.getProperty
(string) — returns the value of the given property, or raises an error in case the object does not have it.IndigoObject.removeProperty
— removes the given property from the object, or does nothing in case the object does not have it.- Note: currently CDX annotations are used as CDX properties
Java:
for (IndigoObject item : indigo.iterateSDFile("structures.sdf"))
if (item.hasProperty("cdbregno"))
System.out.println(item.getProperty("cdbregno"));
C#:
foreach (IndigoObject item in indigo.iterateSDFile("structures.sdf"))
if (item.hasProperty("cdbregno"))
System.Console.WriteLine(item.getProperty("cdbregno"));
Python:
for item in indigo.iterateSDFile("structures.sdf"):
if item.hasProperty("cdbregno"):
print item.getProperty("cdbregno")
It is also possible to iterate over all properties of a particular record in SDF or RDF or CDX file.
Java:
for (IndigoObject item : indigo.iterateRDfile("reactions.rdf"))
for (IndigoObject prop : item.iterateProperties())
System.out.println(prop.name() + " : " + prop.rawData())
C#:
foreach (IndigoObject item in indigo.iterateRDfile("reactions.rdf"))
foreach (IndigoObject prop in item.iterateProperties())
System.Console.WriteLine(prop.name() + " : " + prop.rawData())
Python:
for item in indigo.iterateRDFile("reactions.rdf"):
for prop in item.iterateProperties():
print prop.name(), ":", prop.rawData()
Writing SDF Files¶
It is possible to write molecules to SDF files, along with arbitrary properties assigned.
Java and C#:
IndigoObject saver = indigo.writeFile("structures.sdf");
IndigoObject mol = indigo.loadMolecule("C1CCC1");
mol.setName("cyclobutane");
mol.setProperty("id", "8506");
saver.sdfAppend(mol);
mol = indigo.loadMolecule("C(NNN)C");
mol.setProperty("id", "42");
saver.sdfAppend(mol);
Python: the same with the IndigoObject
omitted.
Writing RDF Files¶
Molecules and reactions can be written to an RDF file with the
rdfAppend
method. However, the special rdfHeader
method must be
called exactly once before anything is written into the RDF file.
Java and C#:
IndigoObject f = indigo.writeFile("test.rdf");
f.rdfHeader();
mol.setProperty("WHAT", "a molecule");
rxn.setProperty("WHAT", "a reaction");
f.rdfAppend(mol);
f.rdfAppend(rxn);
Python: the same with the IndigoObject
omitted.
Writing CML Files¶
Molecules can be written to a CML file with the cmlAppend
method.
However, the cmlHeader
method must be called exactly once before
anything is written into the CML file, and the cmlFooter
method must
be called after all the molecules has been written.
Java and C#:
IndigoObject f = indigo.writeFile("structures.cml");
f.cmlHeader();
f.cmlAppend(mol1);
f.cmlAppend(mol2);
f.cmlFooter();
Python: the same with the IndigoObject
omitted.
Writing Multiline SMILES Files¶
Java and C#:
IndigoObject f = indigo.writeFile("test.smi");
f.smilesAppend(mol);
f.smilesAppend(rxn);
Python: the same with the IndigoObject
omitted.
Closing Files¶
The file output stream is closed on the object’s destructor. However,
you may need to close it explicitly. You can use the close
method:
f.close();
You may need to be sure that the file will be closed after some block of
code has finished executing. In Java, you can call the close
method
in finally
block:
IndigoObject f = null;
try
{
f = indigo.writeFile("test.sdf");
f.sdfAppend(mol);
}
finally
{
if (f != null)
f.close();
}
In C#, the “using” statement can make the job easier:
using (IndigoObject f = indigo.writeFile("test.sdf"))
{
f.sdfAppend(mol);
}
In Python, the “with” syntax serves the same purpose:
with indigo.writeFile("test.sdf") as f:
f.sdfAppend(mol)
Generic Interface to Writing Files¶
There is also a generic interface to writing multiple
molecules/reactions in a file. You can create a generic file saver
(IndigoObject.createFileSaver
), specifying the desired format to it,
and then append items to it (IndigoObject.append
), not bothering
about header and footer — the saver will write them for you
automatically.
The IndigoObject.createFileSaver
method accepts the output file name
and a string with the desired format, which is “sdf”, “rdf”, “cml”, or
“smi”.
Java:
IndigoObject saver = null;
try
{
saver = indigo.createFileSaver("reactions.cml", "cml");
saver.append(rxn1);
saver.append(rxn2);
}
finally
{
if (saver != null)
saver.close();
}
C#:
using (IndigoObject saver = indigo.createFileSaver("reactions.cml", "cml"))
{
saver.append(rxn1);
saver.append(rxn2);
}
Python:
with indigo.createFileSaver("reactions.cml", "cml") as saver:
saver.append(rxn1);
saver.append(rxn2);
Writing into a Memory Buffer¶
You can write the SDF or RDF data into a memory buffer instead of a
file. Indigo.writeBuffer
method creates and returns a memory output
stream. After you have finished writing, you can call the toString
method to obtain the written data.
Java, C#:
IndigoObject buf = indigo.writeBuffer();
mol.setProperty("name", "cyclobutane");
buf.sdfAppend(mol);
String s = buf.toString();
Python: the same with the IndigoObject
and String
omitted.
You can also create a generic saver on top of an existing buffer writer
Java, C#:
IndigoObject saver = indigo.createSaver(buf, "cml");
Python: the same with the IndigoObject
omitted.
Serialization¶
You can use the IndigoObject.serialize
method to serialize a
molecule or a reaction into a binary byte array. All molecule and
reaction features are serialized, including atom coordinates,
stereochemistry, bond orientations, highlighting, AAM numbers, etc. To
restore the molecule/reaction back, use the Indigo.unserialize
method.
- Note: groups are not serialized (i.e. polymer brackets and data s-groups will be lost during serialization)
- Note: Molecule/reaction name and SDF properties ate not serialized
Java, C#:
byte[] data = mol.serialize();
...
IndigoObject mol2 = indigo.unserialize(data);
Python: the same with the IndigoObject
omitted.
Match and Similarity¶
Fingerprints¶
The IndigoObject.fingerprint
method works for molecules and
reactions (including query molecules and query reactions) and returns a
fingerprint
object. IndigoObject.toString
and
IndigoObject.toBuffer
methods of that object can be called to obtain
a hex-string representation or a byte array of a fingerprint,
respectively.
The fingerprint
method accepts a string with a requested fingerprint
type. The following fingerprint types are available:
sim
— “Similarity fingerprint”, useful for calculating similarity measures (the default)sub
— “Substructure fingerprint”, useful for substructure screeningsub-res
— “Resonance substructure fingerprint”, useful for resonance substructure screeningsub-tau
— “Tautomer substructure fingerprint”, useful for tautomer substructure screeningfull
— “Full fingerprint”, which has all the mentioned fingerprint types included
The size of the fingerprint can be controlled via a number of fingerprinting options.
Java:
fp1 = mol1.fingerprint("sim");
fp2 = mol2.fingerprint("sim");
String fp1string = fp1.toString();
byte[] fp2bytes = fp1.toBuffer();
Python: the same with IndigoObject
and String
omitted.
The IndigoObject.countBits
method calculates the number of nonzero
bits in a fingerprint. The Indigo.commonBits
method calculates the
number of coincident nonzero bits in two fingerprints.
Java and C#:
int bits1 = fp1.countBits();
int bits2 = fp2.countBits();
int bits12 = indigo.commonBits(fp1, fp2);
Python: the same with the int
omitted.
Molecule and Reaction Similarity¶
The Indigo.similarity
method accepts two molecules, two reactions,
or two fingerprints. It also accepts a “metrics” string and returns a
float value — the similarity measure between the two given items. There
are three available metrics, which are calculated in the following way:
tanimoto
(the default) : c / (a + b - c)tversky <alpha> <beta>
: c / ((a - c) * alpha + (b - c) * beta) (if alpha and beta are omitted, they are taken for alpha = beta = 0.5)euclid-sub
: c / a
Where:
- “a” is the number of nonzero bits in the first fingerprint
- “b” is the number of nonzero bits in the second fingerprint
- “c” is the number of coincident bits in the two fingerprints
Java and C#:
float sim1 = indigo.similarity(fp1, fp2, "tanimoto");
float sim2 = indigo.similarity(rxn1, rxn2, "tversky");
float sim2 = indigo.similarity(mol1, mol2, "tversky 0.1 0.9");
float sim4 = indigo.similarity(mol1, mol2, "euclid-sub");
Python: the same with the float
omitted.
Exact Match¶
The Indigo.exactMatch
method accepts two molecules or reactions and
returns a “mapping” object — the result of the exact match of two given
molecules or reactions. If match is not possible, it returns null
.
If you are interested only in does the match exist or not, you can just
check if the result of the method is null
. Otherwise, please check
below how to work with the
mapping objects.
Note: You can not pass query molecules or reactions to
exactMatch
.
Exact Matching Flags for Molecules¶
The Indigo.exactMatch
method accepts an optional string. In this
string, you can pass the following flags to the matching procedure:
Flag | Comment |
---|---|
ELE |
Distribution of electrons: bond types, atom charges, radicals, valences |
MAS |
Atom isotopes |
STE |
Stereochemistry: chiral centers, stereogroups, and cis-trans bonds |
FRA |
Connected fragments: disallows match of separate ions in salts |
ALL |
All of the above (the most permissive matching) |
TAU |
Tautomer matching (not compatible to other flags) |
NONE |
No conditions (the most flexible kind of search) |
$number |
Maximum allowed RMS value for affine transformation match |
The flags should go in the parameters string separated by space. Each flag specifies a constraint for the matching procedure. The more flags you set, the more restrictive the matching is. You can write the minus sign before the flag to exclude it from the ‘ALL’ flag. For example, ‘ALL -MAS’ means that all the described features except the isotopes must match.
The TAU
flag stands for tautomer matching. It can not be combined
with any other flags. You can see examples of exact matching, affine
transformation
matching,
and exact tautomer
matching
in the Bingo User Manual.
Note: When no flags are specified, the behavior is equivalent to the
ALL
flag.
The $number
, if present, should go after the flags; for example:
ALL 0.1
. The given number
is the maximum allowed
root-mean-square deviation between the atoms of the two molecules,
measured in angstroms. Prior to the calculation of the RMS value, the
optimal affine transformation (translation+rotation+scale) is applied to
one of the molecules to make it as close as possible to the other
molecule.
Note: Affine transformation matching is not possible when the molecule’s atoms do not have coordinates (e.g. the molecule was loaded from SMILES).
Java and C#:
IndigoObject match = indigo.exactMatch(mol1, mol2, "ALL 0.1");
if (match == null) // affine matching has failed?
match = indigo.exactMatch(mol1, mol2);
if (match == null) // exact match has failed, trying to ignore stereochemistry
match = indigo.exactMatch(mol1, mol2, "ALL -STE");
if (match == null) // failed again; trying the most permissive matching
match = indigo.exactMatch(mol1, mol2, "NONE");
Python:
match = indigo.exactMatch(mol1, mol2, "ALL 0.1")
if not match:
match = indigo.exactMatch(mol1, mol2) # equivalent to ALL
if not match:
match = indigo.exactMatch(mol1, mol2, "ALL -STE") # equivalent to "ELE MAS FRA"
if not match:
match = indigo.exactMatch(mol1, mol2, "NONE")
Exact Matching Flags for Reactions¶
When calling the Indigo.exactMatch
method for reactions, you can
pass it the “ELE”, “MAS”, and “STE” flags, which have the same meaning
as in molecule exact matching. You can also pass two reaction-specific
flags:
Flag | Comment |
---|---|
AAM |
Atom-atom mapping |
RCT |
Reacting centers |
Note: FRA
, TAU
, and affine matching are not available for
reactions.
Molecule Substructure Matching¶
The Indigo.substructureMatcher
method accepts a molecule (but not a
query molecule) and returns a “substructure matcher” object. The given
molecule is going to be the “target” molecule for the substructure
match.
Molecule Substructure Matching Flags¶
The Indigo.substructureMatcher
method accepts an optional string, in
which you can specify one of the following flags:
RES
— chemical resonance matching mode (C=N
matchesCN=O
etc). You can read more about the resonance search and see examples on the Bingo User Manual page.TAU
— tautomer matching mode. You can read more about the tautomer substructure search and see examples on the Bingo User Manual page.TAU INCHI
— tautomer matching mode based on InChI code. Read more about the tautomer substructure search and see examples on the Bingo User Manual page.TAU RSMARTS
— tautomer matching mode based on RSMARTS rules. Read more about the tautomer substructure search and see examples on the Bingo User Manual page.
Methods of Substructure Matcher¶
IndigoObject.ignoreAtom
method accepts an atom of the target molecule and marks it as “ignored” for the substructure matcher. No atom of any query will be mapped to this atom.IndigoObject.unignoreAtom
method cancels the effect of theignoreAtom
method for the given atom.IndigoObject.unignoreAllAtoms
method cancels the effect of previousignoreAtom
calls.IndigoObject.match
accepts a query molecule and returns a “mapping” object if the matching has succeeded. If multiple matches are possible, the first one is taken. If no match is possible, it returnsnull
.IndigoObject.countMatches
accepts a query molecule and returns the number or unique matches.IndigoObject.countMatchesWithLimit
works likecountMatches
, but also accepts an additional integer parameter for limiting the number of matches.IndigoObject.iterateMatches
accepts a query molecule and returns an iterator for unique matches (“mapping” objects).
Also, please take a look on some options available for substructure matchers.
Reaction Substructure Matching¶
You can pass a reaction to the Indigo.substructureMatcher
method to
obtain a “reaction substructure matcher” object. It responds to the
IndigoObject.match
method similarly to the molecule matcher. This
method returns a “reaction match” object, or null
if the matching is
not possible.
You can specify optional DAYLIGHT-AAM
flag to the matcher. When this
flag is present, the matching of the atom-atom mapping (reaction AAM) is
following the Daylight’s rules for reaction
SMARTS.
Otherwise, it follows ordinary rules that are normal for matching
Rxnfiles.
Java and C#:
IndigoObject rxn1 = indigo.loadReactionSmarts("[C:1][C:1]>>[C:1]");
IndigoObject rxn2 = indigo.loadReaction("[CH3:7][CH3:8]>>[CH3:7][CH3:8]");
IndigoObject match = indigo.substructureMatcher(rxn2, "DAYLIGHT-AAM").match(rxn1);
Python: the same with the IndigoObject
omitted.
Note: ignoreAtom
, unignoreAtoms
, unignoreAllAtoms
,
countMatches
, countMatchesWithLimit
, and iterateMatches
methods are not supported by reaction substructure matcher.
Converting the Substructure Query to the Aromatic Form¶
If your query is loaded from a Molfile or SMILES and its aromatic rings are represented in Kekule form, you should transform it to aromatic form prior to matching. Otherwise, it will not match the aromatic rings in the target structure.
Java and C#:
IndigoObject query = indigo.loadMoleculeFromFile("kekule.mol");
query.aromatize();
Python: the same with the IndigoObject
omitted.
Note: aromatize
does not have any effect for SMARTS queries (and
should not be called on them).
Optimizing the Substructure Query¶
If you have a complex molecule or reaction SMARTS query, you can “optimize” it in-memory so that the matching performs faster.
Java and C#:
IndigoObject query = indigo.loadSmarts("[$([a;r4,!R1&r3])]1:[$([a;r4,!R1&r3])]:[$([a;r4,!R1&r3])]:[$([a;r4,!R1&r3])]:1");
query.optimize();
Python: the same with the IndigoObject
omitted.
Methods of “mapping” object¶
You can get the detailed information about the succeeded matching via
the returned “mapping” IndigoObject
. It responds to the following
method calls:
IndigoObject.mapAtom
method accepts an atom of the query molecule/reaction and returns the corresponding atom from the target molecule/reaction. In case the query atom is unmapped (this can happen only with explicit hydrogens), it returnsnull
. You can useIndigoObject.index
method to get mapped atom index.IndigoObject.mapBond
method is similar tomapAtom
, but accepts a bond of the query and returns a bond of the target. It can also returnnull
if the bond is unmapped (this can happen only with bonds to explicit hydrogens).IndigoObject.mapMolecule
method is similar tomapAtom
, but accepts a molecule of the query reaction and returns a molecule of the target reaction. It can also returnnull
if the molecule is unmapped (this can happen if a molecule within a query reaction represents explicit hydrogen).IndigoObject.highlightedTarget
method returns a copy of the target molecule/reaction where the matched atoms and bonds are highlighted.
Note: The IndigoObject.mapAtom
and IndigoObject.ignoreAtom
methods accepts only atoms, and not atom indices. Similarly, the
IndigoObject.mapBond
and IndigoObject.mapMolecule
method accepts
only bonds and molecules respectively, and not their indices.
Example 1 (mapping query molecule atoms)¶
Java:
IndigoObject match = indigo.substructureMatcher(mol).match(query);
if (match != null)
{
match.highlightedTarget().saveMolfile("highlighted.mol");
for (IndigoObject atom : qmol2.iterateAtoms())
System.out.printf("atom %d mapped to atom %d\n", atom.index(), match.mapAtom(atom).index());
}
C#:
IndigoObject match = indigo.substructureMatcher(mol).match(query);
if (match != null)
{
match.highlightedTarget().saveMolfile("highlighted.mol");
foreach (IndigoObject atom in qmol2.iterateAtoms())
System.Console.WriteLine("atom {0} mapped to atom {1}", atom.index(), match.mapAtom(atom).index());
}
Python:
match = indigo.substructureMatcher(mol).match(query)
if match:
match.highlightedTarget().saveMolfile("highlighted.mol")
for atom in qmol2.iterateAtoms():
print "atom", atom.index(), "mapped to atom", match.mapAtom(atom).index())
Example 2 (getting the highlighted target molecule)¶
Java:
IndigoObject matcher = indigo.substructureMatcher(mol);
IndigoObject query = indigo.loadSmarts("O=[!C;R]");
System.out.println(matcher.countMatches(query);
for (IndigoObject match : matcher.iterateMatches(query))
System.out.println(match.highlightedTarget().smiles());
C#:
IndigoObject matcher = indigo.substructureMatcher(mol);
IndigoObject query = indigo.loadSmarts("O=[!C;R]");
System.Console.WriteLine(matcher.countMatches(query);
foreach (IndigoObject match in matcher.iterateMatches(query))
System.Console.WriteLine(match.highlightedTarget().smiles());
Python:
matcher = indigo.substructureMatcher(mol)
query = indigo.loadSmarts("O=[!C;R]")
print matcher.countMatches(query)
for match in matcher.iterateMatches(query):
print match.highlightedTarget().smiles()
Example 3 (exact match between reactions)¶
Java:
IndigoObject match = indigo.exactMatch(rxn1, rxn2, "ALL -AAM");
if (match != null)
{
for (IndigoObject mol : rxn1.iterateMolecules())
{
System.out.println("molecule #" + mol.index());
for (IndigoObject atom : mol.iterateAtoms())
if (match.mapAtom(atom) != null)
System.out.printf("atom #%d matched\n", atom.index());
for (IndigoObject bond : mol.iterateBonds())
if (match.mapBond(atom) != null)
System.out.printf("bond #%d matched\n", bond.index());
}
}
C#:
IndigoObject match = indigo.exactMatch(rxn1, rxn2, "ALL -AAM");
if (match != null)
{
foreach (IndigoObject mol in rxn1.iterateMolecules())
{
System.Console.writeLine("molecule #" + mol.index());
foreach (IndigoObject atom in mol.iterateAtoms())
if (match.mapAtom(atom) != null)
System.Console.WriteLine("atom #{0} matched\n", atom.index());
foreach (IndigoObject bond in mol.iterateBonds())
if (match.mapBond(bond) != null)
System.Console.WriteLine("bond #{0} matched\n", bond.index());
}
}
Python:
match = indigo.exactMatch(rxn1, rxn2, "ALL -AAM")
if match:
foreach mol in rxn1.iterateMolecules():
print "molecule #" + mol.index();
for atom in mol.iterateAtoms():
if match.mapAtom(atom):
print "atom #", atom.index(), "matched"
for bond in mol.iterateBonds():
if match.mapBond(bond):
print "bond #", bond.index(), "matched"
Tautomer Matching Rules¶
- By default, any chains that satisfy basic conditions of tautomerism,
are considered tautomeric by he tautomer matcher. You can restrict
the tautomer matching by enabling conditions for boundary atoms in
tautomeric chains. Each rule consists of two conditions, for two
boundary atoms of the chain. The rules are numbered (1,2,…), and
the numbers can be used in matcher’s parameter string after the
TAU
specifier (TAU R1 R2
). The more rules you specify, the more flexibility you receive in the search; but when you specify no rules at all (TAU
), you get the most flexible search because no rules are checked. Any tautomeric chain is acceptable in this case. You can also useTAU R*
to specify all rules at once. - Some metal bonds and atom charges can replace hydrogen in tautomeric
chains. You can add the HYD word to disable such hydrogen
replacements (
TAU HYD
). - Ring-chain tautomerism is disabled by default. You can add
R-C
to enable it (TAU R-C
).
The following three rules are recommended and are used in examples:
- Each boundary atom in the tautomeric chain must be one of N, O, P, S, As, Se, Sb, Te
- Carbon not from the aromatic ring at one end of the tautomeric chain, and one of N, O, P, S at the other end
- Carbon from the aromatic ring at one end of the tautomeric chain and one of N, O at the other end
Customizing the rules¶
Indigo
provides thee methods to customize the rules:
clearTautomerRules
, setTautomerRule
, and removeTautomerRule
.
There are no rules by default. The Indigo.setTautomerRule
method
accepts an ID number of the rule (must be from 1 to 32), and two strings
(for two bound atoms of the chain), containing allowed elements are
separated by commas. ‘1’ at the beginning means an aromatic atom, and
‘0’ means an aliphatic (non-aromatic) atom.
The three rules defined above can be set in the following way:
Java and C#:
indigo.setTautomerRule(1, "N,O,P,S,As,Se,Sb,Te", "N,O,P,S,As,Se,Sb,Te");
indigo.setTautomerRule(2, "0C", "N,O,P,S");
indigo.setTautomerRule(3, "1C", "N,O");
IndigoObject mol1 = indigo.loadQueryMolecule("OC1=CC=CNC1");
IndigoObject mol2 = indigo.loadMolecule("O=C1CNCC2=CC=CC=C12");
IndigoObject matcher = indigo.substructureMatcher(mol2, "TAU R2");
IndigoObject match = matcher.match(mol1);
Python: the same with IndigoObject
omitted
Highlighting Atoms and Bonds¶
The IndigoObject.highlight
and IndigoObject.unhighlight
methods
can be applied to an atom or a bond. Also, the
IndigoObject.unhighlight
method can be applied to a molecule or
reaction to dismiss the highlighting on the whole molecule or reaction.
You can check if object is highlighted using
IndigoObject.isHighlighted
method.
The following example shows how to highlight the matched atoms and bonds on a substructure matcher’s target, along with explicit hydrogens attached to the matched atoms.
Java:
IndigoObject matcher = indigo.substructureMatcher(target);
IndigoObject match = matcher.match(query);
for (IndigoObject item : query.iterateAtoms())
{
IndigoObject atom = match.mapAtom(item);
atom.highlight();
for (IndigoObject nei : atom.iterateNeighbors())
{
if (!nei.isPseudoatom() && !nei.isRSite() && nei.atomicNumber() == 1)
{
nei.highlight();
nei.bond().highlight();
}
}
}
for (IndigoObject bond : query.iterateBonds())
match.mapBond(bond).highlight();
System.out.println(target.smiles());
target.unhighlight();
System.out.println(target.smiles());
C#:
IndigoObject matcher = indigo.substructureMatcher(target);
IndigoObject match = matcher.match(query);
foreach (IndigoObject qatom in query.iterateAtoms())
{
IndigoObject atom = match.mapAtom(qatom);
atom.highlight();
foreach (IndigoObject nei in atom.iterateNeighbors())
{
if (!nei.isPseudoatom() && !nei.isRSite() && nei.atomicNumber() == 1)
{
nei.highlight();
nei.bond().highlight();
}
}
}
foreach (IndigoObject bond in query.iterateBonds())
match.mapBond(bond).highlight();
System.Console.WriteLine(target.smiles());
target.unhighlight();
System.Console.WriteLine(target.smiles());
Python:
matcher = indigo.substructureMatcher(target)
match = matcher.match(query)
for qatom in query.iterateAtoms():
atom = match.mapAtom(qatom)
atom.highlight()
for nei in atom.iterateNeighbors():
if not nei.isPseudoatom() and not nei.isRSite() and nei.atomicNumber() == 1:
nei.highlight()
nei.bond().highlight()
for bond in query.iterateBonds():
match.mapBond(bond).highlight()
print target.smiles()
target.unhighlight()
print target.smiles()
Rendering¶
Rendering in Indigo is done by the IndigoRenderer
plugin which is
included in the Indigo distribution. The plugin is available for C (as a
separate dynamic library), and has wrappers for all supported languages.
To work with the rendering plugin in C#/Java/Python wrappers, one needs
to create an instance of IndigoRenderer
, passing an existing
Indigo
instance to it.
Java and C#:
IndigoRenderer renderer = new IndigoRenderer(indigo);
A large number of options can be set for
the rendering plugin. They are set via the ordinary Indigo
instance.
One of the options is obligatory: render-output-format
tells which
format the image should be rendered to.
The IndigoRenderer.renderToBuffer
accepts an IndigoObject
and
returns a byte buffer with PNG, SVG, or PDF image (on the Windows
platform, EMF format is supported too). Similarly, the
IndigoRenderer.renderToFile
method saves the image to a file.
Java and C#:
indigo.setOption("render-output-format", "png");
indigo.setOption("render-margins", 10, 10);
mol1.layout();
indigo.setOption("render-comment", "N-Hydroxyaniline")
renderer.renderToFile(mol1, "mol.png");
indigo.setOption("render-output-format", "svg");
byte[] svg = renderer.renderToBuffer(rxn);
Python: the same with the byte[]
omitted.
Rendering Multiple Items to Grid¶
IndigoRenderer.renderGridToFile
and
IndigoRenderer.renderGridToBuffer
methods can be used to render
multiple molecules or reactions at once. The rendered items are placed
in grid specified by its number of columns. Some
options are available for placing
titles under (or above) the items.
Java:
IndigoObject arr = indigo.createArray();
for (IndigoObject item : indigo.iterateSDFile("structures.sdf"))
arr.arrayAdd(item);
renderer.renderGridToFile(collection, null, 4, "structures.png");
C#:
IndigoObject arr = indigo.createArray();
foreach (IndigoObject item in indigo.iterateSDFile("structures.sdf"))
arr.arrayAdd(item);
renderer.renderGridToFile(collection, null, 4, "structures.png");
Python:
arr = indigo.createArray();
for item in indigo.iterateSDFile("structures.sdf"):
arr.arrayAdd(item);
renderer.renderGridToFile(collection, None, 4, "structures.png")
The second parameter of the IndigoRenderer.renderGridToFile
and
IndigoRenderer.renderGridToBuffer
methods is optional. You can
specify it only for molecules, not for reactions. If this parameter is
not null
, it has to be an integer array whose number of elements is
equal to the number of given molecules. Each element of this array is
the index of the “reference atom” in the corresponding molecule. The
rendering is then done in such a way that the reference atoms are
grid-aligned. You can see the examples of this at
CTR.
Win32 and .NET Support¶
In the .NET API, additional IndigoRenderer
methods are available for
working with Win32 HDC and System.Drawing
objects directly:
void renderToHDC (IndigoObject item, IntPtr hdc, bool printing)
Bitmap renderToBitmap (IndigoObject item)
Metafile renderToMetafile (IndigoObject item)
Scaffold Detection and R-Group Decomposition¶
Scaffold Detection¶
The Indigo.extractCommonScaffold(mode [max_iterations])
method
searches MCS scaffold for given molecules array and returns an
extraction result. The method accepts a string parameter called
mode
. The following modes are available:
exact
: searches MCS using the exact algorithm.approx
: searches MCS using the approximate algorithm
There is an optional integer parameter (iteration limit) followed by the mode. The default value for the exact algorithm is 0 (infinite) and for the approximate algorithm is 1000.
Indigo searches MCS in terms of a largest induced molecule1 subgraph
isomorphic to an induced molecule2 subgraph. Largest means that a result
subgraph can not be extended by the adding a vertex (atom). E.g. there
are three possible mcs for the molecules ‘NCOCCCS’ and ‘NCCOCCS’ which
can not be extended: ‘CCOC’, ‘NC’ and ‘CCS’. Indigo stores all the
intermediate subgraphs, which can be a result MCS. Thus, after a
searching is finished, there is an array (all the solutions) of
submolecules available. In the end, the result molecules array is sorted
by the following rule: maximize rings number; if two molecules contain
equal ring number, then maximize bonds number. The result sorted
molecules array (all the maximum common submolecules) can be iterated by
the allScaffolds()
method. The IndigoObject.allScaffolds()
method returns an array object.
Java:
IndigoObject arr = indigo.createArray();
for (IndigoObject item : indigo.iterateSDFile("structures.sdf"))
arr.arrayAdd(item);
IndigoObject scaf = indigo.extractCommonScaffold(arr, "exact");
if (scaf != null) {
System.out.println("max scaffold: " + scaf.smiles());
for(IndigoObject scaffold: scaf.allScaffolds().iterateArray())
System.out.println("current scaffold: " + scaffold.smiles());
}
C#:
IndigoObject arr = indigo.createArray();
foreach (IndigoObject item in indigo.iterateSDFile("structures.sdf"))
arr.arrayAdd(item);
IndigoObject scaf = indigo.extractCommonScaffold(arr, "approx 2000");
if (scaf != null) {
System.Console.WriteLine("max scaffold: " + scaf.smiles());
for(IndigoObject scaffold: scaf.allScaffolds().iterateArray())
System.Console.WriteLine("current scaffold: " + scaffold.smiles());
}
Python:
arr = indigo.createArray();
for item in indigo.iterateSDFile("structures.sdf"):
arr.arrayAdd(item);
scaf = indigo.extractCommonScaffold(arr, "exact 1000");
if scaf:
print "max scaffold:" + scaf.smiles()
for scaffold in scaf.allScaffolds().iterateArray():
print "current scaffold:" + scaffold.smiles()
R-Group Decomposition¶
The R-Group decomposition algorithm separates given molecule into a
scaffold (matches the given query molecule) and R-Groups. To start
working with the algorithm you need to create a Decomposer
object.
The Indigo.createDecomposer
method accepts a query molecule and
returns the Decomposer
object. During a decomposition the
Decomposer
object builds a common scaffold with all R-Groups
gathered together(so named full scaffold
). The scaffold matches
every passed molecule and together with calculated R-Groups restores
initial molecules. Once the Decomposer
object is created, you can
pass molecules into and perform the decomposition. The method
IndigoObject.decomposeMolecule
returns a DecompositionItem
object. The method accepts molecule. User can get the calculated results
by accessing the DecompositionItem
object. The following methods are
used to get the results:
The IndigoObject.decomposedMoleculeWithRGroups
returns molecule
separated into a scaffold with R-Groups (DecompositionItem
object).
The IndigoObject.decomposedMoleculeHighlighte
returns molecule with
a highlighted scaffold (DecompositionItem
object). The
IndigoObject.decomposedMoleculeScaffold
returns the full scaffold
(Decomposer
object) or a submolecule which matches the given query
(DecompositionItem
object).
Java, C#:
IndigoObject deco = indigo.createDecomposer(scaf);
IndigoObject deco_item1 = decomposer.decomposeMolecule(mol1);
deco_item1.decomposedMoleculeWithRGroups().saveMolfile("molrgoups1.mol");
deco_item1.decomposedMoleculeHighlighted().saveMolfile("highlighted1.mol");
deco_item1.decomposedMoleculeScaffold().saveMolfile("scaffold1.mol");
IndigoObject deco_item2 = decomposer.decomposeMolecule(mol2);
deco_item2.decomposedMoleculeWithRGroups().saveMolfile("molrgoups2.mol");
deco_item2.decomposedMoleculeHighlighted().saveMolfile("highlighted2.mol");
deco_item2.decomposedMoleculeScaffold().saveMolfile("scaffold2.mol");
IndigoObject scaffold = deco.decomposedMoleculeScaffold();
scaffold.saveMolfile("full_scaffold.mol");
Python:
deco = indigo.createDecomposer(scaf);
deco_item1 = decomposer.decomposeMolecule(mol1);
deco_item1.decomposedMoleculeWithRGroups().saveMolfile("molrgoups1.mol");
deco_item1.decomposedMoleculeHighlighted().saveMolfile("highlighted1.mol");
deco_item1.decomposedMoleculeScaffold().saveMolfile("scaffold1.mol");
deco_item2 = decomposer.decomposeMolecule(mol2);
deco_item2.decomposedMoleculeWithRGroups().saveMolfile("molrgoups2.mol");
deco_item2.decomposedMoleculeHighlighted().saveMolfile("highlighted2.mol");
deco_item2.decomposedMoleculeScaffold().saveMolfile("scaffold2.mol");
scaffold = deco.decomposedMoleculeScaffold();
scaffold.saveMolfile("full_scaffold.mol");
Note: There are possible situations when a given query molecule does not match a next decomposition molecule. An exception is raised in that case.
The DecompositionItem
objects supports iterating matches since a
given query scaffold can have several embeddings. The
IndigoObject.iterateDecompositions
returns the DecompositionItem
iterator. The full scaffold can be completed by an appropriate match.
The IndigoObject.addDecomposition
(Decomposer
object )method
accepts a DecompositionItem
object and adds the current match to the
full scaffold. The following example shows the usage with iterating all
matches:
Python:
...
# iterate over all the structures
for smiles in structures:
# handle current molecule and handle exceptions
try:
item = deco.decomposeMolecule(indigo.loadMolecule(smiles))
# iterate over all the decompositions
for q_match in item.iterateDecompositions()
# get decomposed molecules (current match)
rg_mol = q_match.decomposedMoleculeWithRGroups()
# add current match
deco.addDecomposition(q_match)
except Exception,e:
# error handlers
Note: There are two different types of input queries: - user defined molecule with RGroups - simple query molecule, which can be passed from the Scaffold Detection
In the first case the full scaffold equals to the user defined molecule
itself and it can not be changed during the RGroup Decomposition. In the
second case the full scaffold should be generated by the library, and it
will be returned by the decomposedMoleculeScaffold
method. You can
load scaffold from a molfile. The SMILES format is not supported at the
moment.
The following example shows the usage user-defined scaffold:
Python:
# prepare query scaffold (e.g. '(R1)C1CCCC(R2)C1')
scaffold = indigo.loadQueryMoleculeFromFile("query_mol")
# init decomposition
deco = indigo.createDecomposer(scaffold)
# load molecule
mol = indigo.loadMolecule('NC1CCCC(O)C1')
# create deco item
item = deco.decomposeMolecule(indigo.loadMolecule(smiles))
# iterate over all the decompositions
for q_match in item.iterateDecompositions()
# get decomposed molecule (current match)
rg_mol = q_match.decomposedMoleculeWithRGroups()
# print molfile
print(rg_mol.molfile())
In the example above there will be two matches: (R1)C1CCCC(R2)C1, R1=OH, R2=NH2 (R1)C1CCCC(R2)C1, R1=NH2, R2=OH
Note: the following code is deprecated:
Java:
IndigoObject deco = indigo.decomposeMolecules(scaf, arr);
deco.decomposedMoleculeHighlighted().saveMolfile("highlighted.mol");
IndigoObject scaffold = deco.decomposedMoleculeScaffold();
for (IndigoObject item : deco.iterateDecomposedMolecules())
System.out.println(item.decomposedMoleculeWithRGroups().molfile());
C#:
IndigoObject deco = indigo.decomposeMolecules(scaf, arr);
deco.decomposedMoleculeHighlighted().saveMolfile("highlighted.mol");
IndigoObject scaffold = deco.decomposedMoleculeScaffold();
foreach (IndigoObject item in deco.iterateDecomposedMolecules())
System.Console.WriteLine(item.decomposedMoleculeWithRGroups().molfile());
Python:
deco = indigo.decomposeMolecules(scaf, arr);
deco.decomposedMoleculeHighlighted().saveMolfile("highlighted.mol");
scaffold = deco.decomposedMoleculeScaffold();
for item in deco.iterateDecomposedMolecules():
print item.decomposedMoleculeWithRGroups().molfile()
Reaction Products Enumeration¶
General API for the combinatorial chemistry capabilities of Indigo. More examples can be found here. Also some examples available at options page.
Java:
IndigoObject reaction = indigo.loadQueryReaction("Cl[C:1]([*:3])=O.[OH:2][*:4]>>[*:4][O:2][C:1]([*:3])=O");
IndigoObject monomers_table = indigo.createArray();
monomers_table.arrayAdd(indigo.createArray());
monomers_table.at(0).arrayAdd(indigo.loadMolecule("CC(Cl)=O"));
monomers_table.at(0).arrayAdd(indigo.loadMolecule("OC1CCC(CC1)C(Cl)=O"));
monomers_table.arrayAdd(indigo.createArray());
monomers_table.at(1).arrayAdd(indigo.loadMolecule("O[C@H]1[C@H](O)[C@@H](O)[C@H](O)[C@@H](O)[C@@H]1O"));
IndigoObject output_reactions = indigo.reactionProductEnumerate(reaction, monomers_table);
Python:
reaction = indigo.loadQueryReaction("Cl[C:1]([*:3])=O.[OH:2][*:4]>>[*:4][O:2][C:1]([*:3])=O")
monomers_table = indigo.createArray()
monomers_table.arrayAdd(indigo.createArray())
monomers_table.at(0).arrayAdd(indigo.loadMolecule("CC(Cl)=O"))
monomers_table.at(0).arrayAdd(indigo.loadMolecule("OC1CCC(CC1)C(Cl)=O"))
monomers_table.arrayAdd(indigo.createArray())
monomers_table.at(1).arrayAdd(indigo.loadMolecule("O[C@H]1[C@H](O)[C@@H](O)[C@H](O)[C@@H](O)[C@@H]1O"))
output_reactions = indigo.reactionProductEnumerate(reaction, monomers_table)
indigo.setOption("render-comment", "Results")
rxn_array = indigo.createArray();
for elem in output_reactions.iterateArray():
rxn = elem.clone();
rxn_array.arrayAdd(rxn)
indigoRenderer.renderGridToFile(rxn_array, None, 2, 'result_rpe.png')
Reaction-based Molecule Transformations¶
Usage examples are available here.
Java:
IndigoObject reaction = indigo.loadQueryReaction("[*+:1][*-:2]>>[*:2]=[*:1]");
IndigoObject molecule = indigo.loadMolecule("[O-][C+]1CCCC1[N+]([O-])=O");
indigo.transform(reaction, molecule);
System.out.println(molecule.smiles());
Python:
reaction = indigo.loadQueryReaction("[*+:1][*-:2]>>[*:2]=[*:1]")
molecule = indigo.loadMolecule("[O-][C+]1CCCC1[N+]([O-])=O")
indigo.transform(reaction, molecule)
print(molecule.smiles())
O=N(C1CCCC1=O)=O