Molecules in Blender

CD-MOF ball and stick
tl;dr – A github repo containing all of this and much more can be found here. Follow the readme to use.

As a whole, science and technology have made incredible advancements in aesthetics. Programming presentations are succinct, biologists have made videos like this and this, and physicists can point to, like, every image of space ever taken.

However, most chemistry graphics look like they were thrown together by a toddler. I understand the sentiment behind this – “it’s the science that matters”, “I can’t waste time learning how to do this”, blah blah blah. While that’s kind of true, no one will even read your paper if it has these graphics. Seriously, anything short of a cure for cancer will be skimmed over if it isn’t visually appealing. You’ve spent months to years working toward a paper; you can afford yourself a week or two to make your graphics not look like crap.

As my inaugural scientific visualization post, let’s start with one of the most common visualization tasks for chemists. I will show you how to easily draw any molecule in blender.

 

What people are doing

The typical approach involves Powerpoint (or Photoshop/GIMP for the more artistically inclined) and a 3D molecule renderer like JMol. This approach is easy to learn and produces graphics that meet the industry standard. Let’s take an example molecule – caffeine – and work through the process.

First, we get the molecular structure from wikipedia or the nearest nerdy coffee mug (ie. why I chose this example). It looks like this:

Next, we download JMol and optimize / render the structure, giving us this:

God, that’s awful. From here, we make the black background transparent and copy and paste it around a coffee mug or something.

Pictured: Scientific art, 2012.

Now, you submit this graphic to Nature or Science with your manuscript. When you get your reviewer comments, there’s a good chance they will be harsh and almost nonsensical. Why? Because no one actually read your work. They saw no pretty pictures, which means they didn’t read any of it in depth, which then caused the aforementioned comments. It’s not fair by any means, but you can’t really blame them. It’s exactly what you would do if you were told to critique a pile of manuscripts.

 

A better approach

Enter Blender, an open-source 3D modeling program with the most active community of developers I have seen outside of Ubuntu. With training, it can be used to create movie-quality computer graphics. With almost no training, it can still produce scientific visualizations orders of magnitude better than what’s currently out there. The best part is its incredibly organized Python API, which makes it easy to automate repetitive tasks.

Blender works like most 3D graphical editors. We draw primitive objects (ie. spheres, cylinders, etc.), overlay them with materials and textures, and adjust our viewport and lighting. In order to draw molecules without adding shapes by hand, we need to use Python for some heavy automation.

 

Parsing molecules

First, let’s look into how we will want to specify chemical structures. The world of chemistry is littered with terrible file formats, and, due to the general resilience of legacy standards, we will need to consider them. Before we get to that, however, let’s decide upon a good extensible representation of molecular data. The common representation used in coding is called JavaScript Object Notation, or json, and it is very good at succinctly representing arbitrary data. If you’ve never heard of it before, I highly recommend reading up on it before continuing. Here’s the wiki.

As molecules are a subset of “arbitrary data”, json should suit our needs. Our drawer will need atom element types and 3D locations, and bond connections and orders. Therefore, let’s use something like shown below (the example is for ethane).

This is easy to parse in Python -  import json; data = json.loads(string) . In two lines, we now have a Python data structure! If we wanted to print, say, the y coordinate of the first atom, we could do so with  print(data["atoms"][0]["location"][1]) . This will come in handy later.

Now, back to the matter at hand. We want to offer support for the hundreds of file formats out there (molfiles, smiles, sdf, cif, pdb, etc.), but parsing them all is an absolute nightmare. In a previous version of this post, I recommended parsing a molfile directly. I now take that back. That was stupid. Let’s use Pybel, a Python wrapper on the openbabel library. Download it, and then we can unify all of these file formats in one line of code -  molecule = pybel.readstring(format, string) . If there is no positional data in the input file format, we can generate it by simply calling  molecule.make3D() .

Now, if we can convert this unified format to json, we will have a unified data format without needing to write any more parsing logic.

There is some additional messiness in the github repository to handle corner cases, but this function should generally work.

Converting from the molecule object to json will help us out in many ways. For example, we can test the quality of our file format converter without even needing to involve blender (it’s better to debug code in isolated chunks than it is to debug the whole thing). If your script is creating valid json, then it should load into this website without any problems. Cool, right?

Remembering that the task at hand was to create a caffeine molecule, let’s do so. I’m partial to the SMILES representation of small molecules, which can be found all over the internet. Caffeine’s SMILES is O=C1C2=C(N=CN2C)N(C(=O)N1C)C, which can be loaded directly into our pipeline.

This will create a file called “caffeine.json” that will reflect the json example shown above. (Note: in the sample code shown here, the json will be printed on one line without most of its whitespace. If you want to add whitespace back in, add indent=4 to the  json.dumps(...)  method in the converter.)

With a single data format and no more need of external libraries, we are ready to use Blender!

 

Python in Blender

Using Python in Blender requires a bit of explanation. While its API is through a Python package, this library only works in Blender’s own script editor (there are workarounds that I’m not getting in to… let’s use Blender the way the developers intended). Rather than thinking of Blender as a Python library, think of Python like a feature of Blender. Backwards, I know, but it makes sense when you start using it. Start up Blender, click and drag the top right tab to create multiple windows, and then select the text editor. Repeat to add in a Python console.

That’s it. You have your Python editor directly in Blender.

As you become comfortable with 1. your terminal (especially on mac/linux) and 2. Blender, you can now run Blender Python scripts directly in a terminal. Typing  blender -P my_script.py will open a new Blender window with the results of the script loaded. However, for the sake of learning, I recommend following the previous approach for at least a little while.

All example renders shown below were done with no lamps. I used ambient occlusion with environment lighting. This produces good results in this example with minimal work on our part. (To copy this setup, click the little globe in the right-hand panel. There will be checkboxes for both of these options.)

 

Drawing atoms

First, let’s load the caffeine.json file we made.

That’s it. Now that we have the necessary information in a Python data structure, let’s look into drawing. For simplicity, let’s start with an atom-only space-filling model. The atoms will all be spheres. Easy enough. We will iterate through the data we collected previously and, using Blender’s “bpy” Python library, draw the shapes we need.


For each atom, we draw a sphere at the specified location.

We’re already starting to see the shape of the molecule forming, and we can see Blender’s awesome rendering capabilities. With nothing more than a few spheres, the molecule is looking pretty good. For the next step, let’s reduce the size of the atoms and add in bonds.

 

Drawing Bonds

We have bond information that we currently aren’t using. We will need to figure out where to draw each bond, and then place cylinders in the corresponding locations. As Blender requires a magnitude and a direction for each bond, we will need to use some vector mathematics. Let’s add to the the above function.

Don’t get too scared by the mathematics… it’s all basic vector operations. We get the coordinates of each atom in the bond, and then convert to a magnitude and a direction. Size the cylinder by its magnitude, and then rotate to the desired direction. Reducing the atom radius to 0.4, we end up with:

It’s getting close. Before moving forward, let’s add in support for double and triple bonds. This will require the ability to translate cylinders orthogonal to their current direction. With our previous vector math, this should be easy. Let’s make translation rules for each type of bond, and then use those as needed.

We create a list of translation vectors based on the number of bonds that exist. For single and triple bonds, one cylinder remains unmoved. All other bonds are in the direction of the local object axis, with the constants of 1.4 and 2.0 chosen as separation values. Adding this results in, well, exactly what you’d expect.

 

Coloring structures

Materials are arguably the most important aspect of rendering in Blender. They have a lot of really cool options, and give meaning to the primitives underlying the render. The shapes we have been dealing with so far are rendered without materials, which is why they’re so boring looking.

For this example, let’s make materials for carbon, nitrogen, and oxygen and give them different colors. We will then assign these materials as we draw the shapes. In the drawing function, we will now start with:

The colors dictionary is in RGB format, so bonds -> gray, C -> lighter gray, N -> blue, and O -> red. For each atom, we make a material with this diffuse color, and we lower the specularity (“shininess”) to make it look less plastic-y. In the lines after each call to draw a sphere or cylinder, add:

Which will, as you can probably guess, add a material to the active (most recently added) object. In the case of bonds, replace element with “bond”. Doing this gives the following result:

That’s basically it! Let’s add in some final aesthetic touches and generalize sizing spheres so we can use atomic radii.

 

Sizing atoms 

One issue that we have yet to address is atom sizing. In our current code, hydrogen would be the same size as a heavy metal, which would make some weird-looking molecules. Luckily, this is an easy fix. Similar to our materials approach, let’s make a dictionary of sphere radii and functionalize them based off of the atom type.

I got the atom information from wikipedia, and chose a bond radius that didn’t look weird. The loop converts from larger numbers (easier to work with) to Blender sizes. It ensures that a carbon sphere is 0.4 Blender units, which is what we were using before. Now, all we have to do is generalize the sphere/cylinder drawing to something like:

And we’re done.

Doing this produces our final product. The sizing in this case is subtle, but it definitely helps in other examples.

 

In conclusion

I know that this might seem like a lot of work to just draw a molecule, but, once you understand the approach, you’ll be able to use it easily from here on out. With this script, I can draw a high-resolution molecule in a few seconds, additionally making it the fastest approach to visualize an array of molecules (being able to easily do this is an important aspect of my work).

Most powerfully, you now have access to this molecule in both Python and Blender. With Python, you can put this entire approach in a loop to draw different molecules in different locations. It’s almost as easy to draw ten thousand chemicals as it is to draw only one. With Blender, you can use the molecule as one aspect of a much larger 3D scene. This is great for cover images and TOCs.

Once again, the github repo can be found here. It runs much faster and handles a lot more corner cases. If any clarification is needed, feel free to leave a message in the comments!

 

10 Thoughts on “Molecules in Blender

  1. This is an amazing tutorial. Thank you for writing it!

  2. Morten G on 12 August 2012 at 9:20 am said:

    There’s a shitload of resonance in that structure. It’s pretty much all continuous pi-orbitals and you’ve failed to illustrate that in your pretty picture.
    The programming is all cool tho.

    • My goal here was completely aesthetic… I’m not trying to replace JMol as a molecule viewer. JMol’s advantage is that it can render in real time (you can rotate the structure, view orbitals, etc.), but it sacrifices looks to do that. Blender does not render in real time, but allows you to make high-quality visualizations.

  3. Kotter on 18 March 2013 at 12:30 pm said:

    First off, that’s an impressive piece of work here, I have been looking exactly for something like this. Now, I’m absolutely new to Blender and seem to be stuck at a certain point. Unfortunately, I can not do the translation of the multibonds at

    “bpy.ops.transform.translate(value=Vtrans[i])”

    I always get the message that there was an error, yet, there is none specified in the console (I launch the code itself from a text editor window open in Blender as well)

    I’ve tried printing out the Vtrans values to see, if there was something wrong with the file I’m using, yet, this gives me an ‘invalid syntax’ exception :?

    Any ideas on what I’m doing wrong here?

    Cheers & thanks,

    K

  4. Hi Kotter,

    I’m glad you’re following through with this! I’ve been meaning to update this blog post for a while now, as it doesn’t reflect changes I’ve made to the process over the last year or so. Have you looked at the github repository? It uses more generalized / faster code, has been updated to include changes to Blender over the last year, and, most importantly, should be easier to understand.

    Edit: I updated this tutorial. The github version still deviates in how it handles blender meshes (using bpy.ops.* is slowww), but its conceptually aligned with this tutorial.

  5. Kotter on 5 April 2013 at 4:43 am said:

    Hey Patrick,

    luckily, I managed to figure out the bug: There are mol2 files, which denote aromatic bonds with the number ’4′ as opposed to the ’2′ for the actual double-bonds. In this case, the above code unfortunately fails to produce the wanted output. After specifically setting them to conjugated double bonds rather than aromatic ones, everything worked fine for me :)

    Thanks again & cheers,

    K

  6. Erwann Jeanneau on 1 May 2013 at 10:58 am said:

    Very interesting. Specially the ability to use different file formats with openbabel.

    As a small molecule crystallographer I mainly work with the CIF file format and it would be fantastic if a Blender script could give the ability to act as a molecular builder with the atomic positions and symmetry elements given in the CIF file (I haven’t seen anything that could handle symmetry operations properly yet).

    Also the ability to draw polyhedron around selected atoms would be awsome…

    Anyway thanks for this tutorial which helped me understand quite a few things concerning python programming.

    • I also work on small molecule crystallography, and there are a lot of ways to use this script to do what you need.

      The easiest way is always to convert a cif file to p1 symmetry, removing the need to infer symmetry. Most crystallographic programs will do this for you. If you don’t want to do that, OpenBabel does support inferring unit cells (OBUnitCell.FillUnitCell() – http://openbabel.org/dev-api/classOpenBabel_1_1OBUnitCell.shtml#af5cee9c530db13a5ec558a3783893315). You can write your own cif parser, but I have found that literally interpreting symmetry_pos_as_xyz causes issues due to poor regulation of experimental cif file data.

      Good luck!

  7. Erwann Jeanneau on 3 May 2013 at 8:37 am said:

    Hi,

     

    I found an easy way of generating one molecule, a unit-cell or more. I open my CIF file with CCDC’s Mercury software (limited version is available for free on their website) and then save this file in PDB format which can then be open by Blender. The advantage is that Mercury generates as many atoms as seen on screen and not only symetry independent atoms.

    I will try to adapt the part of your script where you draw bonds for polyhedra representation.

     

    Cheers,

     

    Erwann

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Post Navigation