Построение 3D-изображений в matplotlib
немного сложно. Обычно вы рисуете целые поверхности сразу, а не одну линию за раз. Вы делаете это, передавая три двумерных массива, по одному для каждого измерения положения (x, y, z). Но вы не можете просто пропустить старые 2d-массивы; сами точки должны быть в точном порядке!
Иногда вы можете сделать что-то, что просто работает, но мне проще явно параметризовать графики, используя размеры u
и v
. Вот что я смог получить здесь:
# Abstract u and v parameters describing surface coordinates
u_plt = np.arange(x.shape[1])
v_plt = np.arange(x.shape[0])
# The outer products here produce 2d arrays. We multiply by
# ones in this case for an identity transformation, but in
# general, you could use any broadcasted operation on `u`
# and `v`.
x_plt = np.outer(np.ones(np.size(v_plt)), u_plt)
y_plt = np.outer(v_plt, np.ones(np.size(u_plt)))
# In this case, our `x` array gives the `z` values directly.
z_plt = x
fig = plt.figure(figsize=(16, 10))
ax = fig.add_subplot(111, projection='3d')
ax.set_zmargin(1) # Add a bit more space around the plot.
ax.plot_wireframe(x_plt, y_plt, z_plt,
rstride=1, cstride=1, # "Resolution" of the plot
color='blue', linewidth=1.0,
alpha=0.7, antialiased=True)
# Tilt the view to match the example.
ax.view_init(elev = 45, azim = -45)
plt.xlabel('i')
plt.ylabel('x')
plt.title('test')
plt.show()
А вот и полученное изображение. Мне пришлось уменьшить n
до 80, чтобы сделать это вообще понятным, и я понятия не имею, на что смотрю, поэтому я не уверен, что это правильно. Но я думаю, что это в целом похоже на пример, который вы привели.
![wireframe plot](https://i.stack.imgur.com/ObOTm.jpg)
Просто чтобы проиллюстрировать силу этого подхода, вот оболочка наутилуса. Он использует двухэтапную параметризацию, которая может быть сжата, но концептуально более понятна:
n_ticks = 100
# Abstract u and v parameters describing surface coordinates
u_plt = np.arange(n_ticks // 2) * 2
v_plt = np.arange(n_ticks)
# theta is the angle along the leading edge of the shell
# phi is the angle along the spiral of the shell
# r is the distance of the edge from the origin
theta_plt = np.pi * ((u_plt / n_ticks) * 0.99 + 0.005)
phi_plt = np.pi * v_plt / (n_ticks / 5)
r_plt = v_plt / (n_ticks / 5)
# These formulas are based on the formulas for rendering
# a sphere parameterized by theta and phi. The only difference
# is that r is variable here too.
x_plt = r_plt[:, None] * np.cos(phi_plt[:, None]) * np.sin(theta_plt[None, :])
y_plt = r_plt[:, None] * np.sin(phi_plt[:, None]) * np.sin(theta_plt[None, :])
z_plt = r_plt[:, None] * \
(np.ones(np.shape(phi_plt[:, None])) * np.cos(theta_plt[None, :]))
# This varies the color along phi
colors = cm.inferno(1 - (v_plt[:, None] / max(v_plt))) * \
np.ones(np.shape(u_plt[None, :, None]))
fig = plt.figure(figsize=(8, 8))
ax = fig.add_subplot(111, projection='3d')
ax.set_zmargin(1)
ax.plot_surface(x_plt, y_plt, z_plt,
rstride=1, cstride=1,
facecolors=colors, linewidth=1.0,
alpha=0.3, antialiased=True)
ax.view_init(elev = 45, azim = -45)
plt.show()
![plot of a nautilus shell](https://i.stack.imgur.com/a4oJN.png)