Open Babel 2.2.0
Open Babel 2.2.0 has been released. This version introduces a variety of new features and improvements. It also includes the Ruby Open Babel interface that allows scripting through the popular Ruby language; Ruby Open Babel can be installed both quickly and easily. Further details are available from the release notes.
Future articles will highlight some of the new Open Babel features using Ruby.
From InChI to Image with Ruby Open Babel and Ruby CDK 2
Like SMILES, InChI is a line notation that can be used to encode and store chemical information relatively efficiently. Although there are a number of scenarios where this strategy is used, what many of them have in common is the need to eventually convert an InChI into a human-readable form. In most cases, this form will be a 2D chemical structure. This article will show how a small Ruby library can convert InChI strings into color PNG images with the help of Ruby Open Babel and Ruby CDK.
The Library
Our library accepts an InChI as input and produces a scaled PNG image as output. It re-uses part of a previously-discussed library for the interconversion of SMILES and InChI.
require 'rubygems'
require 'openbabel'
require_gem 'rcdk'
require 'rcdk/util'
module InChI
@@to_smiles = OpenBabel::OBConversion.new
@@to_smiles.set_in_and_out_formats 'inchi', 'smi'
def inchi_to_png inchi, path_to_png, width, height
smiles = inchi_to_smiles inchi
RCDK::Util::Image.smiles_to_png smiles, path_to_png, width, height
end
private
def inchi_to_smiles inchi
mol = OpenBabel::OBMol.new
@@to_smiles.read_string(mol, inchi) or raise "Can't parse InChI: #{inchi}."
@@to_smiles.write_string(mol).strip
end
endTesting
Our library can be tested by saving it to a file called inchi.rb and using interactive Ruby (the warning can safely be ignored for now):$ irb irb(main):001:0> require 'inchi' ./inchi.rb:3:Warning: require_gem is obsolete. Use gem instead. /usr/local/lib/ruby/gems/1.8/gems/rcdk-0.3.0/lib/rcdk/java.rb:26:Warning: require_gem is obsolete. Use gem instead. i=> true irb(main):002:0> include InChI => Object irb(main):003:0> inchi='InChI=1/C23H27FN4O2/c1-15-18(23(29)28-10-3-2-4-21(28)25-15)9-13-27-11-7-16(8-12-27)22-19-6-5-17(24)14-20(19)30-26-22/h5-6,14,16H,2-4,7-13H2,1H3' #risperidone => "InChI=1/C23H27FN4O2/c1-15-18(23(29)28-10-3-2-4-21(28)25-15)9-13-27-11-7-16(8-12-27)22-19-6-5-17(24)14-20(19)30-26-22/h5-6,14,16H,2-4,7-13H2,1H3" irb(main):004:0> inchi_to_png inchi, 'risperidone.png', 300, 300 => nil
This code produces the following image:

Our library can also be used on more complicated molecules, for example Brevetoxin:
$ irb irb(main):001:0> require 'inchi' ./inchi.rb:3:Warning: require_gem is obsolete. Use gem instead. /usr/local/lib/ruby/gems/1.8/gems/rcdk-0.3.0/lib/rcdk/java.rb:26:Warning: require_gem is obsolete. Use gem instead. => true irb(main):002:0> include InChI => Object irb(main):003:0> inchi='InChI=1/C49H70O13/c1-26-17-36-39(22-45(52)58-36)57-44-21-38-40(62-48(44,4)23-26)18-28(3)46-35(55-38)11-7-6-10-31-32(59-46)12-8-14-34-33(54-31)13-9-15-43-49(5,61-34)24-42-37(56-43)20-41-47(60-42)30(51)19-29(53-41)16-27(2)25-50/h6-8,14,25-26,28-44,46-47,51H,2,9-13,15-24H2,1,3-5H3/b7-6-,14-8-' #brevetoxin a => "InChI=1/C49H70O13/c1-26-17-36-39(22-45(52)58-36)57-44-21-38-40(62-48(44,4)23-26)18-28(3)46-35(55-38)11-7-6-10-31-32(59-46)12-8-14-34-33(54-31)13-9-15-43-49(5,61-34)24-42-37(56-43)20-41-47(60-42)30(51)19-29(53-41)16-27(2)25-50/h6-8,14,25-26,28-44,46-47,51H,2,9-13,15-24H2,1,3-5H3/b7-6-,14-8-" irb(main):004:0> inchi_to_png inchi, 'brevetoxin.png', 300, 200 => nil
This produces the following image:

Conclusions
While our library could certainly be improved, it solves what otherwise would be a very difficult problem conveniently. Areas for further work include error handling and improving the appearance of the images (the latter is the aim of Firefly). Despite the fact that three programming languages are used (Ruby, C++, and Java), this complexity is neatly encapsulated behind a simple Ruby interface.
Interconvert (Almost) Any SMILES and InChI with Ruby Open Babel 8
SMILES and InChI are the two most widely-used line notations in cheminformatics. Not surprisingly, there are many situations in which it's useful to interconvert the two. This article shows a simple method for doing so using Ruby Open Babel.
Parsing InChIs
Version 1.01 of the IUPAC/NIST C InChI toolkit introduced the ability to parse InChIs. This capability has subsequently been incorporated into Open Babel, and by extension, Ruby Open Babel. It's this capability that we'll take advantage of.
A Simple Library
The following library provides everything we need to convert between SMILES and InChI via Ruby:
require 'openbabel'
module InChI
@@to_smiles = OpenBabel::OBConversion.new
@@to_inchi = OpenBabel::OBConversion.new
@@to_smiles.set_in_and_out_formats 'inchi', 'smi'
@@to_inchi.set_in_and_out_formats 'smi', 'inchi'
def inchi_to_smiles inchi
mol = OpenBabel::OBMol.new
@@to_smiles.read_string(mol, inchi) or raise "Can't parse InChI: #{inchi}."
@@to_smiles.write_string(mol).strip
end
def smiles_to_inchi smiles
mol = OpenBabel::OBMol.new
@@to_inchi.read_string(mol, smiles) or raise "Can't parse SMILES #{smiles}."
@@to_inchi.write_string(mol).strip
end
endTesting the Library
After saving the above code to a file named inchi.rb, we can interactively convert SMILES and InChIs:
$ irb irb(main):001:0> require 'inchi' => true irb(main):002:0> include InChI => Object irb(main):003:0> smiles = inchi_to_smiles "InChI=1/C14H12/c1-3-7-13(8-4-1)11-12-14-9-5-2-6-10-14/h1-12H/b12-11-" => "c1ccc(cc1)C(/[H])=C(/[H])c1ccccc1" irb(main):004:0> inchi = smiles_to_inchi smiles => "InChI=1/C14H12/c1-3-7-13(8-4-1)11-12-14-9-5-2-6-10-14/h1-12H/b12-11-"
In the above test, the InChI for cis-stilbene is converted into a SMILES string which is then converted back to InChI form with complete fidelity, including alkene geometry. Note that this would not have been possible using the approach that was previously discussed in which molfiles were used as intermediate datastructures.
What about chiral centers? Here the results are mixed. For example, when the round-trip conversion is applied to propranalol (PubChem, Video), the configuration of the stereocenter is inverted.
$ irb irb(main):001:0> require 'inchi' => true irb(main):002:0> include InChI => Object irb(main):003:0> smiles = inchi_to_smiles "InChI=1/C16H21NO2/c1-12(2)17-10-14(18)11-19-16-9-5-7-13-6-3-4-8-15(13)16/h3-9,12,14,17-18H,10-11H2,1-2H3/t14-/m1/s1" => "CC(C)NC[C@@H](COc1cccc2ccccc12)O" irb(main):004:0> inchi = smiles_to_inchi smiles => "InChI=1/C16H21NO2/c1-12(2)17-10-14(18)11-19-16-9-5-7-13-6-3-4-8-15(13)16/h3-9,12,14,17-18H,10-11H2,1-2H3/t14-/m0/s1"
However, the same round-trip conversion of phenethanol works without inversion of stereochemistry:
$ irb irb(main):001:0> require 'inchi' => true irb(main):002:0> include InChI => Object irb(main):003:0> smiles = inchi_to_smiles " InChI=1/C8H10O/c1-7(9)8-5-3-2-4-6-8/h2-7,9H,1H3/t7-/m0/s1" => "C[C@@H](c1ccccc1)O" irb(main):004:0> inchi = smiles_to_inchi smiles => "InChI=1/C8H10O/c1-7(9)8-5-3-2-4-6-8/h2-7,9H,1H3/t7-/m0/s1"
The most likely explanation is that under certain conditions, Open Babel incorrectly interprets and/or writes stereo parities.
One More Gotcha
On my system (Linux Mandriva 2007.1), attempting to perform the round-trip test on glucose resulted (reproducibly) in a segfault:
$ irb irb(main):001:0> require 'inchi' => true irb(main):002:0> include InChI => Object irb(main):003:0> smiles = inchi_to_smiles "InChI=1/C6H12O6/c7-1-2-3(8)4(9)5(10)6(11)12-2/h2-11H,1H2/t2-,3-,4+,5-,6?/m1/s1" => "C([C@H]1[C@H]([C@@H]([C@H](C(O)O1)O)O)O)O" irb(main):004:0> inchi = smiles_to_inchi smiles ./inchi.rb:20: [BUG] Segmentation fault ruby 1.8.6 (2007-03-13) [i686-linux] Aborted
The same segfault was obtained when using the babel command-line utility:
$ babel -ismi -oinchi C([C@H]1[C@H]([C@@H]([C@H](C(O)O1)O)O)O)O [Return] Segmentation fault
Conclusions
As you can see, Ruby Open Babel makes short work of interconverting SMILES and InChIs. Despite problems with stereochemical configuration and segfaults on reading certain SMILES strings, the approach outlined here offers a quick and economical way to interconvert a variety of SMILES and InChIs.
Interactive Ruby Open Babel
One of my favorite features of Ruby is the Interactive Ruby (irb) shell. For those who haven't used it, irb lets you interactively create Ruby programs. Are you not exactly sure how to use that new library? Do you want to be able to "play" with an object to see how it works? Then irb is the perfect tool.
One of the new features contained in Open Babel 2.1 is a Ruby interface. The power and convenience of irb makes it an excellent tool for exploring Open Babel. With some minor customizations, it can be even better.
Customizing irb
Your irb sessions can be customized by creating and editing the .irbrc file located in your home directory. This file, containing standard Ruby, is loaded prior to the start of your irb session.
Tab Completion
Code completion is one of those things that, once you've used it, you wonder how you ever got by without. Although it tends not to be activated by default, irb fully supports code completion with the "Tab" key.
To activate this feature, add the following line to your .irbrc file:
require 'irb/completion'$ irb irb(main):001:0> require 'openbabel' => true irb(main):002:0> mol=OpenBabel::OBMol.new => #<OpenBabel::OBMol:0xb7cd30a4>
What exactly can this OBMol do? Let's start with the "get" methods. Entering mol.get followed by the Tab key gives the following:
irb(main):003:0> mol.get mol.get_angle mol.get_gidvector mol.get_atom mol.get_givector mol.get_bond mol.get_gtdvector mol.get_conformer mol.get_internal_coord mol.get_conformers mol.get_mod mol.get_coordinates mol.get_mol_wt mol.get_data mol.get_residue mol.get_dimension mol.get_spaced_formula mol.get_energy mol.get_sssr mol.get_exact_mass mol.get_title mol.get_first_atom mol.get_torsion mol.get_flags mol.get_total_charge mol.get_formula mol.get_total_spin_multiplicity irb(main):003:0> mol.get_
If you were interested in molecular weight, you'd see the mol.get_mol_wt method, which you could fully enter by typing mol.get_mol followed by the Tab key.
Tab completion also works with module names. What are the complete contents of the OpenBabel module? Just type OpenBabel:: followed by the Tab key. There are over 400 possibilities, so you might want to narrow it down a bit. For example, OpenBabel::OBM followed by the Tab key gives:
irb(main):003:0> OpenBabel::OBM OpenBabel::OBMessageHandler OpenBabel::OBMolAtomDFSIter OpenBabel::OBMolRingIter OpenBabel::OBMol OpenBabel::OBMolAtomIter OpenBabel::OBMolTorsionIter OpenBabel::OBMolAngleIter OpenBabel::OBMolBondIter OpenBabel::OBMolAtomBFSIter OpenBabel::OBMolPairIter irb(main):003:0> OpenBabel::OBM
Persistent Command History
Just like other shell environments, irb supports a command line history through the up and down arrows. Like Tab completion, it's one of those things you can't work without.
As you use irb, you'll find yourself exiting and re-entering frequently. By default, irb doesn't support persistent command histories. This means your previous commands are lost every time you exit. What a pain.
Luckily, it's easy to create a persistent command history. Fire up your text editor and make the following changes to .irbrc:
require 'irb/completion'
require 'irb/ext/save-history'
ARGV.concat [ "--readline", "--prompt-mode", "simple" ]
IRB.conf[:SAVE_HISTORY] = 100
IRB.conf[:HISTORY_FILE] = "#{ENV['HOME']}/.irb-save-history"From now on, your last 100 irb commands will be just a single key away, regardless of how many sessions ago they were entered.
One caveat: if you compile Ruby from source, you may notice that the command history doesn't work. Instead, pressing the up-arrow displays "[[A". I found the fix in this list posting. In your Ruby source distribution directory, execute the following commands:$ cd ext/readline $ ruby extconf.rb $ make $ sudo make install
Why this extension doesn't compile by default is beyond me, but at least the solution is simple.
Other Customizations
You can customize irb in many other ways. For some ideas, see The Pickaxe Book and RubyGarden.
Painless Installation of Ruby Open Babel 3
Open Babel 2.1.0 has just been released. Among its new features is a Ruby interface containing most of the functionality of the C++ library. Installation is quick and easy, as shown in this article.
Prerequisites
In addition to a working build system, you'll need Ruby and the Ruby development libraries. Although any recent version should do, this tutorial was written with version 1.8.5.
Step 0: Compile and Install Open Babel
Given the right tools on your system, compiling and and installing Open Babel from source is trivial. This page gives instructions for doing so on Linux, Windows, and Mac OS X.
Step 1: Create the Wrapper's Makefile
After unpacking, compiling, and installing Open Babel, change into the scripts/ruby directory of your source distribution. Next, run the extconf.rb script:
$ ruby extconf.rb checking for main() in -lopenbabel... yes creating Makefile
As you've probably guessed, the purpose of this script is to generate a Makefile specific to your platform. This script uses the standard Ruby library mkmf.
Step 2: Compile the Wrapper
After creating a Makefile, we're ready to compile the C++ Ruby wrapper, contained in openbabel_ruby.cpp:
$ make g++ -I. -I. -I/usr/lib/ruby/1.8/x86_64-linux-gnu -I. -I../../include -fPIC -O2 -g -pipe -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -Wall -fPIC -c openbabel_ruby.cpp
This output will be followed by other lines as the compiler builds the wrapper library.
Step 3: Install the Wrapper
After compiling the wrapper, we're ready to install it. You can probably guess that the next command will be (as root):
# make install /usr/bin/install -c -m 0755 openbabel.so /usr/lib/ruby/site_ruby/1.8/x86_64-linux-gnu
Your install directory is chosen by Ruby to be appropriate for your platform and Ruby version.
Hello, Benzene!
Congratulations, you've installed Ruby Open Babel! You can verify that your new library works with interactive Ruby (irb):
$ irb irb(main):001:0> require 'openbabel' => true irb(main):002:0> c=OpenBabel::OBConversion.new => #<OpenBabel::OBConversion:0x2acedbadd020> irb(main):003:0> c.set_in_format 'smi' => true irb(main):004:0> benzene=OpenBabel::OBMol.new => #<OpenBabel::OBMol:0x2acedbacfa10> irb(main):005:0> c.read_string benzene, 'c1ccccc1' => true irb(main):006:0> benzene.num_atoms => 6
Older posts: 1 2

