Molecule Layouts

The previous chapters described how to depict a single molecule in an image. This chapter provides examples for drawing multiple molecular diagrams into the same image.

Depicting Molecules in Arbitrary Position

The OEImageFrame class provides a general framework to display a molecule in a specific region of the image by defining the following parameters:

  • the reference of the parent image
  • the width and height of the generated frame
  • the offset of the frame relative to the top-left corner of its parent (OE2DPoint)

The Listing 1 examples generates an image where the same molecule is depicted in different regions of the image. The molecular diagrams are automatically resized in order to fit into the specific frame, since the corresponding OE2DMolDisplay object is constructed with the width and height of the OEImageFrame object. When the OERenderMolecule function is called, the offset of the OEImageFrame object is added to the coordinates stored in OE2DMolDisplay in order to transfer the molecule into the specific region of the image. The image created by Listing 1 is shown in Figure: Example of using OEImageFrame.

Listing 1: Example of using OEImageFrame

package openeye.docexamples.oedepict;

import openeye.oechem.*;
import openeye.oedepict.*;

public class ImageFrame {
    private static void DrawMolecule(OEImageBase image, OEMolBase mol,
            double width, double height, OE2DPoint offset) {
        OEImageFrame frame = new OEImageFrame(image, width, height, offset);

        oedepict.OEDrawBorder(frame, oedepict.getOELightGreyPen());

        double scale = OEScale.AutoScale;
        OE2DMolDisplayOptions opts = new OE2DMolDisplayOptions(width, height, scale);
        OE2DMolDisplay disp = new OE2DMolDisplay(mol, opts);
        boolean clearBackground = true;
        oedepict.OERenderMolecule(frame, disp, !clearBackground);
    }

    public static void main(String argv[]) {
        OEImage image = new OEImage(400, 400);

        OEGraphMol mol = new OEGraphMol();
        oechem.OESmilesToMol(mol, "C1CC(O)CNC1");
        oedepict.OEPrepareDepiction(mol);

        DrawMolecule(image, mol,  60,  60, new OE2DPoint(50.0,   40.0));
        DrawMolecule(image, mol, 180, 180, new OE2DPoint(180.0, 120.0));
        DrawMolecule(image, mol,  80,  80, new OE2DPoint(300.0,  20.0));
        DrawMolecule(image, mol,  50,  50, new OE2DPoint(150.0, 320.0));
        DrawMolecule(image, mol,  20,  20, new OE2DPoint(360.0, 360.0));

        oedepict.OEWriteImage("ImageFrame.png", image);
    }
}
../_images/ImageFrame.png

Example of using OEImageFrame

See also

Depicting Molecules in Grid

The OEImageGrid class allows molecules to be aligned into rows and columns. After generating an OEImageGrid object by specifying its number of rows and columns, the cells of the grid can be accessed (from left to right, top to bottom order) by calling the OEImageGrid.GetCells method. The image created by Listing 2 is shown in Figure: Example of using OEImageGrid.

Listing 2: Example of using OEImageGrid

package openeye.docexamples.oedepict;

import java.util.ArrayList;
import openeye.oechem.*;
import openeye.oedepict.*;

public class ImageGridSimple {
    public static void main(String args[]) {
        ArrayList<String> smiles = new ArrayList<String>();
        smiles.add("C1CC(C)CCC1");
        smiles.add("C1CC(O)CCC1");
        smiles.add("C1CC(Cl)CCC1");

        OEImage image = new OEImage(200, 200);

        int rows = 2;
        int cols = 2;
        OEImageGrid grid = new OEImageGrid(image, rows, cols);

        OE2DMolDisplayOptions opts = new OE2DMolDisplayOptions(grid.GetCellWidth(),
                grid.GetCellHeight(), 
                OEScale.AutoScale);
        OEImageBaseIter celliter = grid.GetCells();
        for (String smi : smiles) {
            OEGraphMol mol = new OEGraphMol();
            oechem.OESmilesToMol(mol, smi);
            oedepict.OEPrepareDepiction(mol);

            OE2DMolDisplay disp = new OE2DMolDisplay(mol, opts);
            oedepict.OERenderMolecule(celliter.Target(), disp);
            celliter.Increment();
        }

        oedepict.OEWriteImage("ImageGridSimple.svg", image);
    }
}
../_images/ImageGridSimple.png

Example of using OEImageGrid

See also

The cells of an OEImageGrid object are evenly spaced and their dimensions (width and height) are calculated based on the width and height of the grid, its margins and gap parameter set between the cells. The spacing between the cells and the margins of the grid can be modified by calling the following functions:

Warning

After accessing the cells of the OEImageGrid object, the dimensions and position of the cells become immutable and modifying the spacing between the cells or the margin of the grid is not allowed.

The image created by Listing 3 is shown in Figure: Example of customizing OEImageGrid.

Listing 3: Example of customizing OEImageGrid

package openeye.docexamples.oedepict;

import java.util.ArrayList;
import openeye.oechem.*;
import openeye.oedepict.*;

public class ImageGridBoxed {
    private static void DrawCellNumber(OEImageBase cell, int idx) {
        OEFont font = new OEFont();
        font.SetAlignment(OEAlignment.Center);
        double yoffset = font.GetSize();
        double xoffset = font.GetSize();
        cell.DrawText(new OE2DPoint(xoffset, yoffset), Integer.toString(idx), font);
    }

    public static void main(String[] args) {
        ArrayList<String> smiles = new ArrayList<String>();
        smiles.add("C1CC(C)CCC1");
        smiles.add("C1CC(O)CCC1");
        smiles.add("C1CC(Cl)CCC1");

        OEImage image = new OEImage(200, 200);
        image.Clear(oechem.getOELightGrey());

        int rows = 2;
        int cols = 2;
        OEImageGrid grid = new OEImageGrid(image, rows, cols);
        grid.SetMargins(5);
        grid.SetMargin(OEMargin.Left, 30);
        grid.SetCellGap(5);

        OE2DMolDisplayOptions opts = new OE2DMolDisplayOptions(grid.GetCellWidth(),
                grid.GetCellHeight(), 
                OEScale.AutoScale);
        int idx = 0;
        OEImageBaseIter celliter = grid.GetCells();
        for (String smi : smiles) {
            OEGraphMol mol = new OEGraphMol();
            oechem.OESmilesToMol(mol, smi);
            oedepict.OEPrepareDepiction(mol);

            OE2DMolDisplay disp = new OE2DMolDisplay(mol, opts);

            OEImageBase cell = celliter.Target();
            oedepict.OERenderMolecule(cell, disp);
            oedepict.OEDrawBorder(cell, oedepict.getOEBlackPen());
            DrawCellNumber(cell, idx+1);

            celliter.Increment();
            idx += 1;
        }

        oedepict.OEWriteImage("ImageGridBoxed.svg", image);
    }
}
../_images/ImageGridBoxed.png

Example of customizing OEImageGrid

The following example demonstrates how to depict molecules and display data using OEImageGrid. The individual cells of an OEImageGrid object can be accessed by calling the OEImageGrid.GetCell method that returns an image (OEImageBase pointer) on which molecule can be drawn or text can be displayed. The image created by Listing 4 is shown in Figure: Example of depicting molecules and data.

Listing 4: Example of depicting molecules and data

package openeye.docexamples.oedepict;

import java.util.ArrayList;
import openeye.oechem.*;
import openeye.oedepict.*;

public class ImageGridData {
    private static void DrawMoleculeData(OEImageBase cell, OEMolBase mol)
    {
        double gap = cell.GetHeight()/4.0;

        OEFont font = new OEFont();
        font.SetAlignment(OEAlignment.Left);

        String data = "title = " + mol.GetTitle();
        double offset = gap;
        cell.DrawText(new OE2DPoint(0, offset), data, font);

        offset += gap;
        data = "smiles = " + oechem.OEMolToSmiles(mol);
        cell.DrawText(new OE2DPoint(0, offset), data, font);

        offset += gap;
        data = String.format("MW = %.3f", oechem.OECalculateMolecularWeight(mol));
        cell.DrawText(new OE2DPoint(0, offset), data, font);
    }

    public static void main(String[] args) {

        ArrayList<String> smiles = new ArrayList<String>();
        smiles.add("c1ccccc1 benzene");
        smiles.add("c1cccnc1 pyridine");
        smiles.add("c1cncnc1 pyrimidine");

        OEImage image = new OEImage(250, 250);
        image.Clear(oechem.getOELightGrey());

        int rows = 3;
        int cols = 2;
        OEImageGrid grid = new OEImageGrid(image, rows, cols);
        grid.SetMargins(5);
        grid.SetCellGap(5);

        OE2DMolDisplayOptions opts = new OE2DMolDisplayOptions(grid.GetCellWidth(),
                grid.GetCellHeight(), 
                OEScale.AutoScale);
        opts.SetTitleLocation(OETitleLocation.Hidden);

        for (int r = 1; r <= rows; ++r) {
            // depict molecule in first column
            OEImageBase cell = grid.GetCell(r, 1);
            OEGraphMol mol = new OEGraphMol();
            oechem.OESmilesToMol(mol, smiles.get(r-1));
            oedepict.OEPrepareDepiction(mol);

            OE2DMolDisplay disp = new OE2DMolDisplay(mol, opts);
            oedepict.OERenderMolecule(cell, disp);

            // depict data in second column
            cell = grid.GetCell(r, 2);
            DrawMoleculeData(cell, mol);
        }

        oedepict.OEWriteImage("ImageGridData.svg", image);
    }
}
../_images/ImageGridData.png

Example of depicting molecules and data

When an OE2DMolDisplay object is initialized, the dimensions of the depicted molecule is controlled by the width, height and scale parameters of the OE2DMolDisplayOptions object.

When only one molecule is depicted then auto scaling of this molecule is preferred (i.e. scaling the molecule in order to maximally fit it to the given dimensions). However, when more that one molecule, that are quite different in sizes, are depicted next to each other, auto scaling of each molecule can be visually misleading because it emphasizes molecules with greater scaling factors. See example in Figure: Example of using OEImageGrid that is generated by Listing 5.

Listing 5: Example of auto scaling of molecules

package openeye.docexamples.oedepict;

import java.util.ArrayList;
import openeye.oechem.*;
import openeye.oedepict.*;

public class ImageGridAutoScale {

    public static void main(String[] args) {
        ArrayList<String> smiles = new ArrayList<String>();
        smiles.add("c1ccccc1");
        smiles.add("c1cccc2c1ccnc2");
        smiles.add("c1ccc2c(c1)cc3ccccc3n2");

        OEImage image = new OEImage(400, 200);

        int rows = 1;
        int cols = 3;
        OEImageGrid grid = new OEImageGrid(image, rows, cols);

        OE2DMolDisplayOptions opts = new OE2DMolDisplayOptions(grid.GetCellWidth(),
                grid.GetCellHeight(),
                OEScale.AutoScale);

        int counter = 0;
        for (OEImageBase cell : grid.GetCells()) {
            OEGraphMol mol = new OEGraphMol();
            oechem.OESmilesToMol(mol, smiles.get(counter));
            oedepict.OEPrepareDepiction(mol);

            OE2DMolDisplay disp = new OE2DMolDisplay(mol, opts);
            oedepict.OERenderMolecule(cell, disp);
            counter += 1;
        }

        oedepict.OEWriteImage("ImageGridAutoScale.svg", image);
    }
}
../_images/ImageGridAutoScale.png

Example of auto scaling of molecules

The following example (Listing 6) shows how to ensure that all molecules are depicted using the same scaling factor. After initializing the molecules, the minimum scaling factor is determined by looping over the molecules being depicted and calling the OEGetMoleculeScale function. This function returns the scaling factor of the molecule considering the depiction options stored in the given OE2DMolDisplayOptions object. After determining the minimum scaling factor, the molecules are rendered to the cells of the grid by using this fixed scaling factor. The image created by Listing 6 is shown in Figure: Example of using OEImageGrid.

Listing 6: Example of identical scaling of molecules

package openeye.docexamples.oedepict;

import java.util.ArrayList;
import openeye.oechem.*;
import openeye.oedepict.*;

public class ImageGridFixedScale {
    public static void main(String[] args) {
        ArrayList<String> smiles = new ArrayList<String>();
        smiles.add("c1ccccc1");
        smiles.add("c1cccc2c1ccnc2");
        smiles.add("c1ccc2c(c1)cc3ccccc3n2");

        ArrayList<OEGraphMol> mollist = new ArrayList<OEGraphMol>();
        for (String smi : smiles) {
            OEGraphMol mol = new OEGraphMol();
            oechem.OESmilesToMol(mol, smi);
            oedepict.OEPrepareDepiction(mol);
            mollist.add(mol);
        }

        OEImage image = new OEImage(400, 200);

        int rows = 1;
        int cols = 3;
        OEImageGrid grid = new OEImageGrid(image, rows, cols);

        OE2DMolDisplayOptions opts = new OE2DMolDisplayOptions(grid.GetCellWidth(),
                grid.GetCellHeight(),
                OEScale.AutoScale);

        double minscale = Double.MAX_VALUE;
        for (OEGraphMol mol : mollist) {
            minscale = Math.min(minscale, oedepict.OEGetMoleculeScale(mol, opts));
        }
        opts.SetScale(minscale);

        OEImageBaseIter celliter = grid.GetCells();
        for (OEGraphMol mol : mollist) {
            OE2DMolDisplay disp = new OE2DMolDisplay(mol, opts);
            oedepict.OERenderMolecule(celliter.Target(), disp);
            celliter.Increment();
        }

        oedepict.OEWriteImage("ImageGridFixedScale.svg", image);
    }
}
../_images/ImageGridFixedScale.png

Example of identical scaling of molecules