molmugshot.mp4
Created using manim
![]() |
![]() |
![]() |
![]() |
| NPA031278 | NPA013270 | NPA006827 | NPA031401 |
![]() |
![]() |
![]() |
![]() |
| Cubane | Adamantane | Fullerene (C60) | [12]-helicene |
Four bridged natural products from NPAtlas and other visually appealing 3D molecules, rendered straight from SMILES.
Traditional 2D drawings of complex skeletons have two downsides:
- harder to imagine what the molecule looks like in 3D
- sometimes even hard to read, with deformed bonds
molmugshot flips the pipeline, by embedding the molecule in 3D using force fields, and then sweeping though up to thousands of candidate angles, it finds the best views for your molecule. The chosen view is then drawn in ACS-1996 style with depth-cued bond widths for a semi-realistic perspective.
Useful when you want to draw:
- bridged compounds, or molecules in general for which the 3D view is imporant
- anything where the canonical RDKit drawing makes you squint.
Clone the repository and pip install it:
git clone https://github.com/schwallergroup/MolMugshot.git molmugshot
cd molmugshot
pip install -e .pip will pull in rdkit, numpy, Pillow, cairosvg, and matplotlib for you.
After install, the molmugshot command is on your PATH. Run it on a SMILES.
molmugshot "CC(=O)[C@@H]1CCC[C@@H]2CC[C@H]1N2" --n-best 4Without -o/--output, an interactive viewer opens showing the top-N views and their mirrors:
- ← / → : switch between views (1..N)
- ↑ / ↓ : flip original ↔ mirror
- q : quit
Save to disk instead with -o:
molmugshot "<SMILES>" -o molecule.png --n-best 4
# writes molecule.png (best view) + molecule_grid_4.png (2 x 4 grid of views/mirrors)Or also emit an animation of the candidate-view sweep:
molmugshot "<SMILES>" -o molecule.png --animation sweep.mp4Useful flags:
| Flag | Purpose |
|---|---|
-n, --n-best |
Number of top views to keep (default 1). |
--min-separation-deg |
Min angular gap between kept views' r3 axes. |
--method |
fibonacci (default) or spiral sampling. |
--n-angle-samples |
Candidate views to score (default 1000). |
--seed |
RNG seed for embedding + noise. |
--animation |
Path to save an mp4/gif of the sweep. |
-o, --output |
Output path; omit for the interactive viewer. |
The CLI exposes only some of the many knobs at your disposal. For more granular control, the library itself is a few small functions in src/molmugshot/. The end-to-end example at notebooks/example.py shows the full pipeline you can copy-paste into your own script:
from rdkit import Chem
from molmugshot.draw_acs_rdkit import build_grid, mirrored_view, render_view
from molmugshot.principal_view import (
embed_3d, heavy_atom_coords, heavy_atom_is_hetero,
principal_axes, top_n_views,
)
mol_3d = embed_3d(Chem.MolFromSmiles("<SMILES>"))
heavy = heavy_atom_coords(mol_3d)
axes, _ = principal_axes(heavy)
views = top_n_views(
heavy, axes,
n=4,
is_hetero=heavy_atom_is_hetero(mol_3d),
mol=mol_3d,
method="fibonacci",
min_separation_deg=15.0,
)
svg, png = render_view(mol_3d, views[0])
open("molecule.svg", "w").write(svg)
open("molecule.png", "wb").write(png)Each of those calls is documented in its docstring. The interesting pieces:
principal_axes— inertia axes orderedI1 < I2 < I3(soe3is the long-inertia / "face-on" direction for planar molecules).top_n_views— searches Fibonacci-lattice (or spiral) tilts ofe3, scores each by minimum pairwise 2D heavy-atom distance (with halos for hetero labels and "linear-looking" carbons), then non-max-suppresses near-duplicate and near-antipodal views.render_view— projects to 2D, renders in ACS-1996 style, then post-processes the SVG to give every bond a depth-cued trapezoid width.mirrored_view+build_grid— render the enantiomeric "view from the other side" through RDKit (so labels stay upright) and tile views + mirrors into a single PNG.







![[12]-helicene](/schwallergroup/MolMugshot/raw/main/data/misc/12-helicene.png)