0

I'm making a multiplot in matplotlib that displays a molecule structure made with RDKit in one of the axes/subplots. I know you can display raster images with imshow, but what I want is just being able to load an SVG as an SVG into one of my subplots.

I have taken the code from this answer to obtain the raw plain text of the SVG of the molecule. I could save it and convert it with cairoSVG to a raster image that can be then loaded with imshow, but I feel like there must be a way to just display an image (or in this case, text string) that is already an SVG in a mpl subplot. Is that possible or am I forced to take a detour through PNG pixelisation?

Note: The cairo code doesn't even work for me bc I get the OSError that it isn't properly installed, but if I didn't have that problem my code should work just fine. For the time being I left it commented out and replaced it with a random numpy array for style points.

import numpy as np
import matplotlib.pyplot as plt
# from cairosvg import svg2png
from rdkit import Chem
from rdkit.Chem import rdDepictor
from rdkit.Chem.Draw import rdMolDraw2D


smiles = 'C1=CC(=C(C=C1C2=C(C(=O)C3=C(C=C(C=C3O2)O)O)O)O)O' 


def moltosvg(mol, molSize = (300,300), kekulize = True):
    mc = Chem.Mol(mol.ToBinary())
    if kekulize:
        try:
            Chem.Kekulize(mc)
        except:
            mc = Chem.Mol(mol.ToBinary())
    if not mc.GetNumConformers():
        rdDepictor.Compute2DCoords(mc)
    drawer = rdMolDraw2D.MolDraw2DSVG(molSize[0],molSize[1])
    drawer.DrawMolecule(mc)
    drawer.FinishDrawing()
    svg = drawer.GetDrawingText()
    return svg.replace('svg:','')

def plot(text,smiles):

    m = Chem.MolFromSmiles(smiles)
    svg_string = moltosvg(m)

    # svg2png(bytestring=svg_code,write_to='output.png')
    lorem_ipsum = [np.random.uniform(0,1,100) for i in range(100)]

    fig = plt.figure(frameon=False, figsize=(6,3))
    gs = fig.add_gridspec(ncols=2, hspace=0, wspace=0, width_ratios=[1,1])
    axes = gs.subplots()

    for ax in axes:
        for spine in ax.spines.values():
                spine.set_visible(False)
        ax.tick_params(bottom=False, labelbottom=False, left=False, labelleft=False)


    axes[0].text(1.,0.5,text,size=20,ha='right',va='center',transform=axes[0].transAxes)
    axes[1].imshow(lorem_ipsum)

    plt.show()

plot('TEST',smiles)
J.Doe
  • 224
  • 1
  • 4
  • 19
  • Have you seen https://stackoverflow.com/questions/12161559/plot-svg-within-matplotlib-figure-embedded-in-wxpython and https://stackoverflow.com/questions/31452451/importing-an-svg-file-into-a-matplotlib-figure ? – Thierry Lathuille May 12 '22 at 14:22
  • the second one always converts to PNG first as far as I can tell and this pylustrator thing I have never heard of before. – J.Doe May 12 '22 at 14:27
  • also, pylustrator only has the function `load()` , which immediately opens a mpl window. it returns a NoneType, which cannot be loaded into an axes of my plot. It just opens as it's own window and then quits. – J.Doe May 12 '22 at 15:02

0 Answers0