如何将PNG对象添加至Pandas DataFrame并正常显示?
解决RDKit生成的PIL图像在Pandas DataFrame中无法显示的问题
你遇到的问题是因为Pandas默认不会渲染PIL图像对象,只会输出它的字符串描述(比如<PIL.PngImagePlugin.PngImageFile...>)。要让图像在DataFrame中正常显示,有两种可行方案:
方案一:将图像转为Base64编码嵌入HTML显示
这种方法通过把PIL图像转换成Base64字符串,嵌入HTML标签中,让Jupyter Notebook能够渲染图像。
修改代码如下:
import pandas as pd import numpy as np from rdkit import Chem from rdkit.Chem import AllChem from rdkit import DataStructs from rdkit.Chem import PandasTools from rdkit.Chem import Draw from rdkit.Chem.Draw import IPythonConsole from IPython.display import HTML, display import base64 from io import BytesIO # 定义PIL图像转HTML的函数 def pil_to_html(img): buffer = BytesIO() img.save(buffer, format='PNG') img_base64 = base64.b64encode(buffer.getvalue()).decode() return f'<img src="data:image/png;base64,{img_base64}" style="max-width:400px;" />' smiles_list = ['N[C@H](C(=O)O)C'] mol_list = [] for smiles in smiles_list: mol = Chem.MolFromSmiles(smiles) mol_list.append(mol) glycine = mol_list[0] figure_list = [] bi = {} fp = AllChem.GetMorganFingerprintAsBitVect(glycine, 2, nBits=1024, bitInfo=bi) prints = [(glycine, x, bi) for x in fp.GetOnBits()] figure = Draw.DrawMorganBits(prints, molsPerRow=4, legends=[str(x) for x in fp.GetOnBits()]) figure_list.append(figure) df = pd.DataFrame({'smiles': smiles_list[0]}, index=[0]) PandasTools.AddMoleculeColumnToFrame(df,'smiles','Molecule') # 将图像列转为HTML格式 df['Fragments'] = df['Fragments'].apply(pil_to_html) # 显示渲染后的DataFrame display(HTML(df.to_html(escape=False)))
方案二:自定义Pandas对象格式化器
通过注册自定义的格式化函数,让Pandas在显示PIL图像对象时自动调用IPython的图像渲染功能。
修改代码如下:
import pandas as pd import numpy as np from rdkit import Chem from rdkit.Chem import AllChem from rdkit import DataStructs from rdkit.Chem import PandasTools from rdkit.Chem import Draw from rdkit.Chem.Draw import IPythonConsole from IPython.display import display_png # 定义PIL图像的显示函数 def display_pil_img(val): if isinstance(val, Draw.PIL.PngImagePlugin.PngImageFile): display_png(val) # 设置Pandas显示选项 pd.set_option('display.max_colwidth', None) # 注册对象格式化器 pd.io.formats.formatters.set_formatter('object', display_pil_img) smiles_list = ['N[C@H](C(=O)O)C'] mol_list = [] for smiles in smiles_list: mol = Chem.MolFromSmiles(smiles) mol_list.append(mol) glycine = mol_list[0] figure_list = [] bi = {} fp = AllChem.GetMorganFingerprintAsBitVect(glycine, 2, nBits=1024, bitInfo=bi) prints = [(glycine, x, bi) for x in fp.GetOnBits()] figure = Draw.DrawMorganBits(prints, molsPerRow=4, legends=[str(x) for x in fp.GetOnBits()]) figure_list.append(figure) df = pd.DataFrame({'smiles': smiles_list[0]}, index=[0]) PandasTools.AddMoleculeColumnToFrame(df,'smiles','Molecule') df['Fragments'] = figure_list # 直接显示DataFrame,图像会被自动渲染 df
注意事项
- 两种方案都需要在Jupyter Notebook/JupyterLab环境下运行,因为依赖IPython的渲染能力。
- 方案一中的
style="max-width:400px;"可以根据需要调整图像显示大小。
内容的提问来源于stack exchange,提问作者Andre Pimentel
相关产品推荐
相关产品推荐

