【问题标题】:How to save "IPython.core.display.SVG" as PNG file?如何将“IPython.core.display.SVG”保存为 PNG 文件?
【发布时间】:2023-12-24 04:08:01
【问题描述】:

我正在尝试在 Jupyter Notebook 环境中将数据类型为“IPython.core.display.SVG”的变量保存为 PNG 文件。

首先我尝试过:

with open('./file.png','wb+') as outfile:
    outfile.write(my_svg.data)

我得到了错误:

TypeError: a bytes-like object is required, not 'str'

接下来,我尝试了:

with open('./file.png','wb+') as outfile:
    outfile.write(my_svg.data.encode('utf-8'))

但是,我无法打开“file.png”。操作系统报错:

The file “file.png” could not be opened. It may be damaged or use a file format that Preview doesn’t recognize.

我可以使用“svg”扩展名保存“my_svg”,如下所示:

with open('./file.svg','wb+') as outfile:
    outfile.write(my_svg.data.encode('utf-8'))

但是,当我想通过以下方式将“file.svg”转换为“file.png”时:

import cairosvg
cairosvg.svg2png(url="./file.svg", write_to="./file.png")

我得到错误:

ValueError: unknown locale: UTF-8

这就是我在 Jupyter Notebook 中获得“IPython.core.display.SVG”数据类型的方式:

from rdkit import Chem
from rdkit.Chem.Draw import rdMolDraw2D
from IPython.display import SVG


smile_1 = 'C(C(N)=O)c(c)c'
smile_2 = 'o(cn)c(c)c'

m1 = Chem.MolFromSmiles(smile_1,sanitize=False)
Chem.SanitizeMol(m1, sanitizeOps=(Chem.SanitizeFlags.SANITIZE_ALL^Chem.SanitizeFlags.SANITIZE_KEKULIZE^Chem.SanitizeFlags.SANITIZE_SETAROMATICITY))
m2 = Chem.MolFromSmiles(smile_2,sanitize=False)
Chem.SanitizeMol(m2, sanitizeOps=(Chem.SanitizeFlags.SANITIZE_ALL^Chem.SanitizeFlags.SANITIZE_KEKULIZE^Chem.SanitizeFlags.SANITIZE_SETAROMATICITY))

mols = [m1, m2]
legends = ["smile_1", "smile_2"]

molsPerRow=2
subImgSize=(200, 200)
nRows = len(mols) // molsPerRow
if len(mols) % molsPerRow:
  nRows += 1
  
fullSize = (molsPerRow * subImgSize[0], nRows * subImgSize[1])
d2d = rdMolDraw2D.MolDraw2DSVG(fullSize[0], fullSize[1], subImgSize[0], subImgSize[1])
d2d.drawOptions().prepareMolsBeforeDrawing=False
d2d.DrawMolecules(list(mols), legends=legends)
d2d.FinishDrawing()
SVG(d2d.GetDrawingText())

环境:

  • macOS 11.2.3
  • python 3.6
  • RDKit 版本 2020.09.1

非常感谢任何帮助。

【问题讨论】:

    标签: svg jupyter-notebook ipython png rdkit


    【解决方案1】:

    与其使用 rdkit 创建 SVG 并尝试将其转换为 PNG,不如直接创建一个 PNG?

    from rdkit.Chem import Draw
    from rdkit import Chem
    
    # create rdkit mol
    smile = 'CCCC'
    mol = Chem.MolFromSmiles(smile)
    
    # create png
    d2d = Draw.MolDraw2DCairo(200, 200)
    d2d.DrawMolecule(mol)
    d2d.FinishDrawing()
    png_data = d2d.GetDrawingText()
    
    # save png to file
    with open('mol_image.png', 'wb') as png_file:
        png_file.write(png_data)
    

    我不确定为什么 MolDraw2DCairo 不适合你,但使用你提到的包 (cairosvg) 你可以很容易地扩展你的代码示例:

    # extra imports
    import cairosvg
    import tempfile
    
    # replace molecule drawing part
    d2d = rdMolDraw2D.MolDraw2DSVG(fullSize[0], fullSize[1], subImgSize[0], subImgSize[1])
    d2d.drawOptions().prepareMolsBeforeDrawing=False
    d2d.DrawMolecules(list(mols), legends=legends)
    d2d.FinishDrawing()
    svg_text = d2d.GetDrawingText()
    
    # save to png file
    with tempfile.NamedTemporaryFile(delete=True) as tmp:
        tmp.write(svg_text.encode())
        tmp.flush()
        cairosvg.svg2png(url=tmp.name, write_to="./mol_img.png")
    

    【讨论】:

    • 谢谢。我需要设置“d2d.drawOptions().prepareMolsBeforeDrawing=False”以避免在解析包括芳香原子如“C(C(N)=O)c(c)c”的 SMILES 时出错。 drawOption 不适用于“Draw.MolDraw2DCairo”。
    • 在问题中,我将代码更改为更简单的代码以避免混淆。我用我正在处理的主要代码修改了这个问题。
    • 我不知道为什么MolDraw2DCairo 不适合你。如果我在您的代码中切换它并删除 SVG 部分,将其替换为 PNG,它可以正常工作。我在 rdkit 版本 2020.09.3 可能与它有关?
    • 当我使用“MolDraw2DCairo”时,我得到错误:“AtomKekulizeException:非环原子 4 标记为芳香”。但是,您使用“tempfile”的代码可以正常工作。谢谢。