我注意到,当我在 RDKit 中从分子创建图像时,
size
参数会导致键宽和元素标签的缩放不一致。尺寸越大,线条越细,元素标签越小。
我通过使用
MolToImage
以逐渐变大的尺寸为同一分子生成图像来进行测试。我将这些图像重新缩放为 size=(600,600)
,然后将它们连接成 GIF。这就是结果。
这是我的代码
from glob import glob
from rdkit import Chem
from rdkit.Chem import Draw
from PIL import Image,ImageDraw,ImageFont
def make_frames_from_smi(smi):
for i in range(10):
s = (i+3)*100
mol = Chem.MolFromSmiles(smi)
img = Draw.MolToImage(mol,size=(s,s))
img = img.resize((600,600))
draw = ImageDraw.Draw(img)
text = '%d: Initial Size: (%d,%d)'%(i+1,s,s)
font_size = 40
font = ImageFont.truetype("arial.ttf", font_size) # Use your desired font
# Calculate text position
image_width, image_height = img.size
text_x = (image_width - (bbox[2] - bbox[0])) // 2
text_y = 20 # Adjust the vertical position as needed
draw.text((text_x, text_y), text, font=font, fill='black')
img.save('%03dtest.png'%i)
def make_gif_from_frames(paths):
frames_paths = glob(paths)
frames = [Image.open(imgp) for imgp in frames_paths]
frames[0].save("mols.gif", format="GIF", append_images=frames, save_all=True, duration=500, loop=False)
# make RDKit mol obj.
smi = 'CN(C)CC1CCCCC1(C2=CC(=CC=C2)OC)O'
make_frames_from_smi(smi)
make_gif_from_frames('*.png')
这是预期的行为吗?对于一定的像素绝对值,键合宽度是否保持恒定?无论像素的宽度/高度如何,如何生成比例一致的这些图像?
好的找到了,我希望有两个解决方案???
第一个,使用
Draw.rdMolDraw2D.MolDraw2DCairo
:
from glob import glob
from rdkit import Chem
from rdkit.Chem import Draw
from PIL import Image
from io import BytesIO
def make_frames_from_smi(smi):
mol = Chem.MolFromSmiles(smi)
for i in range(10):
s = (i+3)*100
mol = Chem.MolFromSmiles(smi)
d = Draw.rdMolDraw2D.MolDraw2DCairo(s,s)
dopts = d.drawOptions()
# dopts.maxFontSize=40
# dopts.minFontSize=40
dopts.maxFontSize=int(0.13*s)
dopts.minFontSize=int(0.13*s)
d.DrawMolecule(mol)
d.FinishDrawing()
img = d.GetDrawingText()
img_b = BytesIO()
img_b.write(img)
pil_img = Image.open(img_b).resize((600,600))
pil_img.save('%03dtest.png'%i)
def make_gif_from_frames(paths):
frames_paths = glob(paths)
frames = [Image.open(imgp) for imgp in frames_paths]
frames[0].save("mols.gif", format="GIF", append_images=frames, save_all=True, duration=500, loop=False)
smi = 'CN(C)CC1CCCCC1(C2=CC(=CC=C2)OC)O'
make_frames_from_smi(smi)
make_gif_from_frames('*.png')
结果:
或者使用 SVG,
Draw.rdMolDraw2D.MolDraw2DSVG
,我更喜欢它作为图片格式:
import rdkit
print('\n-------------------------------')
print('\n rdkit Version : ', rdkit.__version__)
print('\n-------------------------------')
from glob import glob
from rdkit import Chem
from rdkit.Chem import Draw
from PIL import Image,ImageDraw,ImageFont
from io import BytesIO
from cairosvg import svg2png
from moviepy.editor import ImageClip, concatenate_videoclips
def make_frames_from_smi(smi):
mol = Chem.MolFromSmiles(smi)
drawer= Draw.rdMolDraw2D.MolDraw2DSVG(600,600)
dopts = drawer.drawOptions()
for i in dir(dopts) :
print(i)
dopts.minFontSize = -1
dopts.maxFontSize = -1
# dopts.minFontSize = 80
# dopts.maxFontSize = 80
print('drawer.FontSize : ', drawer.FontSize())
# dopts.annotationFontScale = 0.5
dopts.addAtomIndices = True
drawer.DrawMolecule(mol)
drawer.FinishDrawing()
svg_data = drawer.GetDrawingText()
with open('dtest.svg' , 'w') as handler:
handler.write(svg_data)
for i in range(10):
s = (i+3)*100
png = svg2png(bytestring=svg_data)
img = Image.open(BytesIO(png)).convert('RGBA').resize((s,s))
img.save('%03dtest.png'%i)
def make_gif_from_frames(paths):
input_png_list = glob(paths)
input_png_list.sort()
clips = [ImageClip(i).set_duration(1)
for i in input_png_list]
concat_clip = concatenate_videoclips(clips, method="compose")
concat_clip.write_gif("test.gif", fps=2)
smi = 'CN(C)CC1CCCCC1(C2=CC(=CC=C2)OC)O'
make_frames_from_smi(smi)
make_gif_from_frames('*.png')
结果: