Wednesday, February 2, 2011

cdk Rendering Image from SMILES

The code below takes SMILES string as input and renders the structure diagram of the molecule. The program works with cdk-1.3.4.jar and cdk-jchempaint-8.jar

/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
/*
* ImageRenderer.java
*
* Created on Feb 1, 2011, 11:02:52 PM
*/
/**
* @author Harish Sankar
* @version 1.0
*/
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.ImageIcon;
import org.openscience.cdk.DefaultChemObjectBuilder;
import org.openscience.cdk.Molecule;
import org.openscience.cdk.exception.InvalidSmilesException;
import org.openscience.cdk.interfaces.IMolecule;
import org.openscience.cdk.layout.StructureDiagramGenerator;
import org.openscience.cdk.renderer.AtomContainerRenderer;
import org.openscience.cdk.renderer.font.AWTFontManager;
import org.openscience.cdk.renderer.generators.BasicAtomGenerator;
import org.openscience.cdk.renderer.generators.BasicBondGenerator;
import org.openscience.cdk.renderer.generators.BasicSceneGenerator;
import org.openscience.cdk.renderer.visitor.AWTDrawVisitor;
import org.openscience.cdk.smiles.SmilesParser;
import org.openscience.cdk.templates.MoleculeFactory;
/**
*
* @author Hari
*/
public class ImageRenderer extends javax.swing.JFrame {
/** Creates new form ImageRenderer */
public ImageRenderer() {
initComponents();
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
Dimension dim = new Dimension(screenSize.width-8, screenSize.height-40);
this.setMinimumSize(dim);
this.validate();
}
/** This method is called from within the constructor to
* initialize the form.
* WARNING: Do NOT modify this code. The content of this method is
* always regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">
private void initComponents() {
jTextField1 = new javax.swing.JTextField();
jLabel1 = new javax.swing.JLabel();
jButton1 = new javax.swing.JButton();
jPanel1 = new javax.swing.JPanel();
jLabel2 = new javax.swing.JLabel();
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
jTextField1.setText("NC(CO)C(=O)O");
jLabel1.setText("Smiles String");
jButton1.setText("Generate");
jButton1.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jButton1ActionPerformed(evt);
}
});
jPanel1.setBackground(new java.awt.Color(255, 255, 255));
jPanel1.setBorder(javax.swing.BorderFactory.createEtchedBorder());
jPanel1.setForeground(new java.awt.Color(236, 233, 216));
javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
jPanel1.setLayout(jPanel1Layout);
jPanel1Layout.setHorizontalGroup(
jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jLabel2, javax.swing.GroupLayout.DEFAULT_SIZE, 376, Short.MAX_VALUE)
);
jPanel1Layout.setVerticalGroup(
jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jLabel2, javax.swing.GroupLayout.DEFAULT_SIZE, 246, Short.MAX_VALUE)
);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addContainerGap())
.addGroup(layout.createSequentialGroup()
.addGap(18, 18, 18)
.addComponent(jLabel1)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(jTextField1, javax.swing.GroupLayout.DEFAULT_SIZE, 209, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jButton1)
.addGap(20, 20, 20))
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(jLabel1)
.addComponent(jButton1)
.addComponent(jTextField1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addContainerGap())
);
pack();
}// </editor-fold>
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
try {
// TODO add your handling code here:
int WIDTH = 400;
int HEIGHT = 400;
// the draw area and the image should be the same size
Rectangle drawArea = new Rectangle(WIDTH, HEIGHT);
Image image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
IMolecule triazole = MoleculeFactory.makeCyclobutane();
Molecule molecule = (Molecule) new SmilesParser(DefaultChemObjectBuilder.getInstance()).parseSmiles(jTextField1.getText());
StructureDiagramGenerator sdg = new StructureDiagramGenerator();
sdg.setMolecule(molecule);
try {
sdg.generateCoordinates();
} catch (Exception ex) {
//Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}
triazole = sdg.getMolecule();
// generators make the image elements
List generators = new ArrayList();
generators.add(new BasicSceneGenerator());
generators.add(new BasicBondGenerator());
generators.add(new BasicAtomGenerator());
// the renderer needs to have a toolkit-specific font manager
AtomContainerRenderer renderer = new AtomContainerRenderer(generators, new AWTFontManager());
// the call to 'setup' only needs to be done on the first paint
renderer.setup(triazole, drawArea);
// paint the background
Graphics2D g2 = (Graphics2D) image.getGraphics();
g2.setColor(Color.WHITE);
g2.fillRect(0, 0, WIDTH, HEIGHT);
// the paint method also needs a toolkit-specific renderer
renderer.paint(triazole, new AWTDrawVisitor(g2));
jLabel2.setIcon(new ImageIcon(image));
this.validate();
} catch (InvalidSmilesException ex) {
Logger.getLogger(ImageRenderer.class.getName()).log(Level.SEVERE, null, ex);
}
}
/**
* @param args the command line arguments
*/
public static void main(String args[]) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new ImageRenderer().setVisible(true);
}
});
}
// Variables declaration - do not modify
private javax.swing.JButton jButton1;
private javax.swing.JLabel jLabel1;
private javax.swing.JLabel jLabel2;
private javax.swing.JPanel jPanel1;
private javax.swing.JTextField jTextField1;
// End of variables declaration
}


Screen shot of above program in action

3 comments:

  1. Cool! Now, we need to get those implicit hydrogens drawn here... and I was also wondering if you could try to use CDK 1.3.8 with CDK-JChemPaint 17?

    To all readers: this is a nice way to explore the rendering capabilities of the new platform! Try putting in some charged atoms in those SMILES :) Wondering if isotope info works too...

    ReplyDelete
  2. yea sure , you read my mind :)... please do get to know our community Open Source Drug Discovery(OSDD) an initiative of CSIR(council for Science and Industrial Research).

    ReplyDelete
  3. This is very useful awesome code. Thank you share with us. I try it with eclipse. I added cdk-1.3.4.jar and cdk-jchempaint-8.jar into project, but it show error about "cann't import Molecule and IMolecule libraries". What should do for fixing it.?

    ReplyDelete