本文为使用py3Dmol库创建一系列分子坐标(多帧)组成的分子轨迹,进行动态可视化的教程。

3Dmol.js

3Dmol.js 是一个用于科学可视化的开源 JavaScript 库,特别是用于显示和操纵生物分子结构。支持多种文件格式,如 PDB(Protein Data Bank)文件、SDF(Structure-Data File)文件等,用于加载分子数据。利用 WebGL 技术,3Dmol.js 能够高效地渲染大型分子结构,提供流畅的用户体验。因此被广泛应用于生物信息学、药物设计和分子生物学等领域,用于研究和展示分子的三维结构和相互作用。

py3Dmol

简单来说,py3Dmol 可以被视为 3Dmol.js 的 Python API。py3Dmol 是一个 Python 库,它提供了与 3Dmol.js 交互的接口,使得用户可以在 Python 环境中使用 3Dmol.js 的功能。py3Dmol 为需要在 Python 环境中进行分子可视化的用户提供了便利,使得 3Dmol.js 的强大功能可以更方便地应用于科学研究和数据分析。

有人可能会问为什么不直接使用 GUI 界面的软件,或者 ase 库中的 view 等,本教程主要是针对 Linux 中没有 GUI 的情况下对分子的快捷可视化。

对于分子的可视化,py3Dmol 是非常实用的,但 py3Dmol 中实现的接口功能并不多,并且没有文档支持,以至于我花费很长时间读 py3Dmol 的源码才搞清楚如何使用其进行分子轨迹的可视化ToT,为了防止大家踩坑所以出一个教程。

py3Dmol安装

如果你还没有安装 py3Dmol(可能是废话,不然你也不会点进来),可以方便地直接通过 pip 安装。

1
pip install py3Dmol

以及安装可能用到的 pymatgen 库。

1
pip install pymatgen

可视化单个分子构象(示例)

很简单的例子,如果你还没有用过 py3Dmol ,可以在 jupyter 中试一下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import py3Dmol

def draw_mol_xyz(file_path):
# 读取一个 .xyz 文件进行可视化
with open(file_path, 'r') as fo:
xyz = fo.read()
view = py3Dmol.view(width=800, height=400)
view.addModel(xyz, 'xyz')
view.setStyle({'sphere': {'scale': 0.35}, 'stick': {'radius': 0.20}})
view.zoomTo()
view.show()

file_path = '.xyz' # 你的 .xyz 文件路径
draw_mol_xyz(file_path)

运行结果如下:

可视化分子轨迹

这里以生成苯环的多帧坐标轨迹为例。

首先读取分子的原子序数和坐标

1
2
3
4
5
6
import py3Dmol
from pymatgen.core.structure import Molecule

coords = [] # 输入你的多帧坐标,此处省略。
# 使用 pymatgen 创建 Molecule对象以便于 .xyz 格式转换,此处我有100帧坐标因此创建100个对象。
benzenes = [Molecule(["C"]*6 + ['H']*6, coords[i]) for i in range(100)]
  • coords: 轨迹坐标,维度为[frames, N, 3],frames为帧数。
  • benzenes: Molecule对象列表,[frames, ]

也可以直接读取 .xyz 文件,或者用以下示例创建 Molecule 对象,但要保证原子序数的一致和对齐。

1
mols = [Molecule(species=traj['atomic_numbers'], coords=traj['pos']) for traj in trajs]

格式转换以及可视化

1
2
3
4
5
6
7
8
9
10
11
12
molecules = [mol.to(fmt="xyz") for mol in benzenes[-50:]] + [benzenes[-1].to(fmt="xyz")] * 20 # 最后一帧停顿
models = ''

view = py3Dmol.view(width=800, height=400)

for i, mol in enumerate(molecules):
models += mol + '\n'
view.addModelsAsFrames(models) # 添加多帧 xyz 字符串
view.setStyle({'sphere': {'scale': 0.35}, 'stick': {'radius': 0.20}})
view.zoomTo()
view.animate({'loop': 'forward'}) # animate
view.show()

运行结果如下: