我正在尝试对循环反应中的反应障碍进行图形可视化(参见柠檬酸循环)。
我有两条反应路径的障碍,通过不同的路径关闭相同的反应循环。对于这个用例,一个简单的 2D 绘图变得不直观,所以我给了 matplotlib 的 Axes3D 对象一个镜头:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from __future__ import (absolute_import, division,
print_function, unicode_literals)
from math import sin, cos
import numpy as np
from mpl_toolkits.mplot3d import axes3d
import matplotlib.pyplot as plt
from matplotlib import cm
def z_cycle(mesh, origin, cycle, r, angle_offset, ring_width=0.5):
disc_radius = r/(len(cycle)+1)
angles = np.linspace(0, 2*np.pi, len(cycle), endpoint=False)+angle_offset
mesh_x, mesh_y = mesh
xo, yo = origin
z = np.zeros_like(mesh_x)
for a, d in zip(angles, cycle):
xc, yc = xo + r/2*cos(a), yo + r/2*sin(a)
z += d*((mesh_x-xc)**2 + (mesh_y-yc)**2 < (0.2*r)**2)
z0_mask = np.where(z == 0)
ring = np.logical_and(
(mesh_x-xo)**2+(mesh_y-yo)**2 < (r/2+ring_width/2*disc_radius)**2,
(mesh_x-xo)**2+(mesh_y-yo)**2 > (r/2-ring_width/2*disc_radius)**2
)
z += min(cycle)/2*ring*(z == 0)
return z
def main(data='1,3,2,4,3,4,2;1,3,1.5,2', r=1.0):
"""
Plot energy barriers for reaction cycles in 3d
Cycles as separated by semicolon, and individual
barrier heights are separated by comma. Cycles need
to share the value of their respective first barrier height.
"""
max_barrier = None
cycles = []
max_ = lambda a, b: max(a, b) if b is not None else a
for cycle_string in data.split(';'):
cycle = []
for barrier in map(float, cycle_string.split(',')):
max_barrier = max_(barrier, max_barrier)
cycle.append(barrier)
cycles.append(cycle)
assert all(cycle[0] == cycles[0][0] for cycle in cycles[1:])
grid1d = np.linspace(-2*r, 2*r, 200)
mesh_x, mesh_y = mesh = np.meshgrid(grid1d, grid1d)
mesh_z = np.zeros_like(mesh_x)
angles = np.linspace(0, 2*np.pi, len(cycles), endpoint=False)
for angle, cycle in zip(angles, cycles):
# cycle is an iterable of numerical values corresponding to
# barrier heights
disc_radius = r/(len(cycle)+1)
centre = ((r/2+disc_radius)*cos(angle), (r/2+disc_radius)*sin(angle))
mesh_z += z_cycle(mesh, centre, cycle, r, np.pi+angle)
# Plot
fig = plt.figure()
ax = fig.gca(projection='3d')
ax.plot_surface(mesh_x, mesh_y, mesh_z, rstride=1, cstride=1,
cmap=cm.coolwarm, linewidths=0)
plt.savefig('barriers3d.png')
plt.show()
if __name__ == '__main__':
main()
这给了我:
这种方法的问题包括:
- 由于需要非常密集的网格而导致性能不佳(旋转变得缓慢)
- 图形人工制品
有谁知道解决这些问题的好方法?
我尝试使用手动生成表面,mpl_toolkits.mplot3d.art3d.Poly3DCollection
但它的文档很少。