在 Matplotlib 绘制一个3 d 立方体、一个球体和一个矢量

我用 Matplotlib 搜索如何用尽可能少的指令来绘制某些东西,但在文档中找不到任何帮助。

我想要描绘下面的事情:

  • 以0为中心,边长为2的线框立方体
  • 以0为中心,半径为1的“线框”球体
  • 坐标[0,0,0]上的一点
  • 从这一点开始到[1,1,1]的向量

怎么做?

150045 次浏览

It is a little complicated, but you can draw all the objects by the following code:

from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np
from itertools import product, combinations




fig = plt.figure()
ax = fig.gca(projection='3d')
ax.set_aspect("equal")


# draw cube
r = [-1, 1]
for s, e in combinations(np.array(list(product(r, r, r))), 2):
if np.sum(np.abs(s-e)) == r[1]-r[0]:
ax.plot3D(*zip(s, e), color="b")


# draw sphere
u, v = np.mgrid[0:2*np.pi:20j, 0:np.pi:10j]
x = np.cos(u)*np.sin(v)
y = np.sin(u)*np.sin(v)
z = np.cos(v)
ax.plot_wireframe(x, y, z, color="r")


# draw a point
ax.scatter([0], [0], [0], color="g", s=100)


# draw a vector
from matplotlib.patches import FancyArrowPatch
from mpl_toolkits.mplot3d import proj3d




class Arrow3D(FancyArrowPatch):


def __init__(self, xs, ys, zs, *args, **kwargs):
FancyArrowPatch.__init__(self, (0, 0), (0, 0), *args, **kwargs)
self._verts3d = xs, ys, zs


def draw(self, renderer):
xs3d, ys3d, zs3d = self._verts3d
xs, ys, zs = proj3d.proj_transform(xs3d, ys3d, zs3d, renderer.M)
self.set_positions((xs[0], ys[0]), (xs[1], ys[1]))
FancyArrowPatch.draw(self, renderer)


a = Arrow3D([0, 1], [0, 1], [0, 1], mutation_scale=20,
lw=1, arrowstyle="-|>", color="k")
ax.add_artist(a)
plt.show()

output_figure

For drawing just the arrow, there is an easier method:-

from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.gca(projection='3d')
ax.set_aspect("equal")


#draw the arrow
ax.quiver(0,0,0,1,1,1,length=1.0)


plt.show()

quiver can actually be used to plot multiple vectors at one go. The usage is as follows:- [ from http://matplotlib.org/mpl_toolkits/mplot3d/tutorial.html?highlight=quiver#mpl_toolkits.mplot3d.Axes3D.quiver]

quiver(X, Y, Z, U, V, W, **kwargs)

Arguments:

The x, y and z coordinates of the arrow locations

The x, y and z components of the arrow vectors

The arguments could be array-like or scalars.

Keyword arguments:

length: [1.0 | float] The length of each quiver, default to 1.0, the unit is the same with the axes

arrow_length_ratio: [0.3 | float] The ratio of the arrow head with respect to the quiver, default to 0.3

pivot: [ ‘tail’ | ‘middle’ | ‘tip’ ] The part of the arrow that is at the grid point; the arrow rotates about this point, hence the name pivot. Default is ‘tail’

normalize: [False | True] When True, all of the arrows will be the same length. This defaults to False, where the arrows will be different lengths depending on the values of u,v,w.

My answer is an amalgamation of the above two with extension to drawing sphere of user-defined opacity and some annotation. It finds application in b-vector visualization on a sphere for magnetic resonance image (MRI). Hope you find it useful:

from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np


fig = plt.figure()
ax = fig.gca(projection='3d')


# draw sphere
u, v = np.mgrid[0:2*np.pi:50j, 0:np.pi:50j]
x = np.cos(u)*np.sin(v)
y = np.sin(u)*np.sin(v)
z = np.cos(v)
# alpha controls opacity
ax.plot_surface(x, y, z, color="g", alpha=0.3)




# a random array of 3D coordinates in [-1,1]
bvecs= np.random.randn(20,3)


# tails of the arrows
tails= np.zeros(len(bvecs))


# heads of the arrows with adjusted arrow head length
ax.quiver(tails,tails,tails,bvecs[:,0], bvecs[:,1], bvecs[:,2],
length=1.0, normalize=True, color='r', arrow_length_ratio=0.15)


ax.set_xlabel('X-axis')
ax.set_ylabel('Y-axis')
ax.set_zlabel('Z-axis')


ax.set_title('b-vectors on unit sphere')


plt.show()