最近在读《程序员数学:用Python学透线性代数和微积分》,其中“第三章 上升到三维世界”的主要内容是,把二维向量拓展到三维空间,并用matplotlib来作图示意。大多数的画图功能都能展示,只是在画“三维箭头”图形的时候,系统报错“AttributeError: ‘Arrow3D’ object has no attribute ‘do_3d_projection’”。有人建议,安装matplotlib3.4的版本来规避此问题,据说是3.5版本以后都会出现此问题。但是,最新的版本已经是3.7了,担心版本降低以后会影响其他的图形显示。因此,在参考了其他人的观点以后,对书中的源程序进行了部分调整,解决了这个问题,达到了和书中图形相同的效果。
将源代码中“Chapter 03”下的“draw3d.py”中的FancyArrow3D类,改成如下内容:
class FancyArrow3D(FancyArrowPatch):
# def __init__(self, xs, ys, zs, *args, **kwargs):
# FancyArrowPatch.__init__(self, (0, 0), (0, 0), *args, **kwargs)
# self._verts3d = xs, ys, zs
def __init__(self, xs, ys, zs, *args, **kwargs):
super().__init__((0, 0), (0, 0), *args, **kwargs)
self._verts3d = xs, ys, zs
def do_3d_projection(self, renderer=None):
xs3d, ys3d, zs3d = self._verts3d
xs, ys, zs = proj3d.proj_transform(xs3d, ys3d, zs3d, self.axes.M)
self.set_positions((xs[0], ys[0]), (xs[1], ys[1]))
return np.min(zs)
其中的被注释的部分,是原来的代码,后面的那个方法(method)是新增加上去的。
然后,再去修改“draw3d”函数的部分如下:
elif type(object) == Arrow3D:
xs, ys, zs = zip(object.tail, object.tip)
# a = FancyArrow3D(xs, ys, zs, mutation_scale=20, arrowstyle='-|>', color=object.color)
# ax.add_artist(a)
arrow_prop_dict = dict(mutation_scale=20, arrowstyle='-|>', color='k', shrinkA=0, shrinkB=0)
a = FancyArrow3D(xs, ys, zs, **arrow_prop_dict)
ax.add_artist(a)
说明:那个“elif”语句是原来就有的,注释的部分是原来的代码,修改成下面的部分即可。
修改完毕以后,所有的调用都是不用修改的。
用书中的一个练习来展示结果。
练习 3.5(小项目):下面的代码创建了一个包含 24个 Python向量的列表。把这 24个向量绘制成首尾相接的 Arrow3D 对象。
from math import sin, cos, pi
vs = [(sin(pi*t/6), cos(pi*t/6), 1.0/3) for t in range(0,24)]
running_sum = (0,0,0)
arrows = []
for v in vs:
next_sum = add(running_sum, v)
arrows.append(Arrow3D(next_sum, running_sum))
running_sum = next_sum
print(running_sum)
draw3d(*arrows)
执行结果是:
(-4.440892098500626e-16, -7.771561172376096e-16, 7.9999999999999964)
图像显示结果和书中的效果一致。至此,这个错误修改完成。