Molecular Style Sheets: Combining SVG and CSS
Cascading Style Sheets (CSS) are used by Web developers to modify the appearance of an HTML document without requiring changes to the document itself. This approach has become so popular because of the power it offers: developers can achieve a consistent and re-usable look by simply editing and/or copying a single document.
2-D molecular structures are like text documents in that context determines the best presentation style. For example, the way that a 2-D structure appears on a Web page, complete with atom color coding and anti-aliasing, may not be the best way for it to appear on a handheld device. Consider these use cases:
- An online publisher may want to achieve a consistent "look" for their 2-D molecular graphics, regardless of who generated them. For portability, they want to avoid hard-coding the styling information into the software they use.
- You want to be able to re-use the 2-D structures you've downloaded from a blog in your presentation. The appearance of these structures needs to match those you already have.
- An online substructure query may return results to a user that have been highlighted to indicate the atoms and bonds where the query hit. The user may want to set his or her own highlight color, or disable the feature altogether.
Users of ChemDraw and software like it are probably familiar with its concept of styles. This is the right idea, although limited in practice. The main limitation is that these products are aimed at single users on desktop machines that are willing to do a great deal of manual work to achieve consistency. Something far more general and automated is going to be needed, and to my knowledge it does not yet exist.
Could the style sheet concept be applied to 2-D structure diagrams? It turns out that SVG may offer a solution. Just as the appearance of an HTML document can be styled with CSS, so too can the appearance of an SVG document.
A Demonstration: Highlighting Bonds
As a demonstration, we'll see how a style sheet can be used to highlight one of naphthalene's rings, possibly as a result of it being hit by a substructure search.
Consider the above 2-D structure of naphthalene, which was generated by Structure-CDK, the latest version of which can be downloaded here. The SVG that generated this image is shown below. I have edited the commented lines.
<?xml version="1.0" encoding="UTF-8"?>
<!-- Edit: a stylesheet -->
<?xml-stylesheet href="style_normal.css" type="text/css"?>
<!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.0//EN' 'http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd'>
<svg fill-opacity="1" xmlns:xlink="http://www.w3.org/1999/xlink" color-rendering="auto" color-interpolation="auto" text-rendering="auto" stroke="black" stroke-linecap="square" stroke-miterlimit="10" shape-rendering="auto" stroke-opacity="1" fill="black" stroke-dasharray="none" font-weight="normal" stroke-width="1" xmlns="http://www.w3.org/2000/svg" font-family="'Dialog'" font-style="normal" stroke-linejoin="miter" font-size="12" stroke-dashoffset="0" image-rendering="auto">
<defs id="genericDefs" />
<g>
<g text-rendering="optimizeLegibility" stroke-width="0.098" transform="scale(47.2947,47.2947) translate(0.049,3.1127)" stroke-linecap="round" stroke-linejoin="round">
<line y2="-0.7" fill="none" x1="4.8497" x2="4.8497" y1="-2.1" />
<path fill="none" d="M4.8497 -2.1 L3.6373 -2.8 M4.5581 -1.945 L3.6488 -2.47" />
<path fill="none" d="M0 -2.1 L0 -0.7 M0.28 -1.925 L0.28 -0.875" class="hit" /> <!-- Edit: hit -->
<line y2="-2.8" fill="none" x1="0" x2="1.2124" y1="-2.1" class="hit" /> <!-- Edit: hit -->
<path fill="none" d="M4.8497 -0.7 L3.6373 0 M4.5581 -0.855 L3.6488 -0.33" />
<line y2="0" fill="none" x1="0" x2="1.2124" y1="-0.7" class="hit" /> <!-- Edit: hit -->
<line y2="-2.1" fill="none" x1="3.6373" x2="2.4249" y1="-2.8" />
<path fill="none" d="M1.2124 -2.8 L2.4249 -2.1 M1.224 -2.47 L2.1333 -1.945" class="hit" /> <!-- Edit: hit -->
<line y2="-0.7" fill="none" x1="3.6373" x2="2.4249" y1="0" />
<path fill="none" d="M1.2124 0 L2.4249 -0.7 M1.224 -0.33 L2.1333 -0.855" class="hit" /> <!-- Edit: hit -->
<line y2="-0.7" fill="none" x1="2.4249" x2="2.4249" y1="-2.1" class="hit" /> <!-- Edit: hit -->
</g>
</g>
</svg>
In the image of naphthalene rendered above, the stylesheet I used was blank. However, by applying the following one-line style sheet, I can significantly change the appearance of this image:
*.hit { stroke: red }
This line is known as a "class selector." A CSS-aware SVG renderer (such as Firefox), after loading this style sheet, will apply the red stroke styling to all elements containing the hit
class attribute. The output, shown below, highlights one of the rings of naphthalene in red.
Interestingly, the SVG document itself says nothing about what color the hit class should be - that's left for the style sheet to determine. So by changing one line in the style sheet, I can change the appearance of the hit highlighting to purple, green, or aquamarine. And this applies not only to colors, but to line thickness, line shape, anti-aliasing, and a variety of other properties.
Another Demonstration: Global Line Thickness
It's also possible to globally affect the appearance of naphthalene with a simple style sheet. For example, the following style sheet changes the line thickness and all line colors of naphthalene:
* { stroke-width: 0.25; stroke: green; }
When the naphthalene SVG is rendered with this style sheet, the image shown below is produced. The "*" selector is a wildcard, applying to all elements in the SVG document. This version of the style sheet ignores our "hit" styling from the example above. The hit styling could easily be added back in by adding the appropriate class selector line to the CSS.
You may notice in the image above that the leftmost vertical line appears clipped on its left side. This is because the SVG output from Structure-CDK exactly aligns the left line border with the leftmost side of the image area. By thickening the lines with a style sheet, we've overrun the image area. This could be fixed by moving the SVG viewport to the left. But that's a subject for another time.
A Limitation
It will probably never be possible to modify the distance between parallel lines, as for example in multiple bonds, with the CSS approach. These distances are set in the coordinate attributes of the line and path elements, and are independent of styling.
Conclusions
Of course, we're just scratching the surface of what's possible with CSS and 2-D molecular structures. For example, the same principles outlined here could be used for atom coloring schemes and a variety of line and drawing properties. Various forms of interactive animation are even possible. Despite its limitations, SVG and CSS make a powerful combination for developing next-generation molecular rendering platforms.