Python matplotlib 3d 绘图有两个轴?

SAF*_*FEX 7 python matplotlib

我正在尝试创建一个类似于下面摘自本文的图,本质上是一个具有两个不同 y 轴的 3d 图。按照本博客中的指导,我创建了一个最小的示例。

模块

from mpl_toolkits import mplot3d
import numpy as np
%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
Run Code Online (Sandbox Code Playgroud)

创建一些数据

def f(x, y):
    return np.sin(np.sqrt(x ** 2 + y ** 2))

x = np.linspace(-6, 6, 30)
y = np.linspace(-6, 6, 30)

X, Y = np.meshgrid(x, y)
Z = f(X, Y)
Z2 = Z*100+100
Run Code Online (Sandbox Code Playgroud)

绘图
这会创建一个漂亮的 3D 绘图,但显然只有一个 y 轴。我在网上找不到任何关于如何使用 python 的建议,尽管有一些关于 matlab 的建议。

fig = plt.figure()
ax = plt.axes(projection='3d')
ax.plot_surface(X, Y, Z2, rstride=1, cstride=1,
                cmap='viridis', edgecolor='none')
ax.set_title('surface');
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_zlabel('z');
Run Code Online (Sandbox Code Playgroud)

代码给出:

阴谋

参考图: 这个

joh*_*ins 1

这并不容易。一种可能的解决方法如下:

  • 根据您共享的参考图,我认为您的意思实际上是您正在寻求实现第二个 z 轴,而不是 y 轴。
  • 3d 图的对象axes仍然是单一和共享的(出于必要/明显的 matplotlib 3d 图限制),但数据被绘制为好像在相同的连续值尺度上,但轴刻度和标签被自定义覆盖以反映不同的尺度价值观

例如,

import numpy as np
import matplotlib.pyplot as plt


def f(x, y):
    return np.sin(np.sqrt(x ** 2 + y ** 2))


def g(x, y):
    return -np.cos(np.sqrt(x ** 2 + y ** 2))


x = np.linspace(-6, 6, 30)
y = np.linspace(-6, 6, 30)
X, Y = np.meshgrid(x, y)
Z = f(X, Y)
Z_new = g(X, Y)
offset = 5
Z_new_offset = Z_new + Z.max() + offset

fig = plt.figure(figsize=(16, 12))
ax = fig.add_subplot(111, projection="3d")

surf1 = ax.plot_surface(
    X, Y, Z, rstride=1, cstride=1, cmap="viridis", edgecolor="none", alpha=0.7
)

surf2 = ax.plot_surface(
    X,
    Y,
    Z_new_offset,
    rstride=1,
    cstride=1,
    cmap="plasma",
    edgecolor="none",
    alpha=0.7,
)

z_ticks_original = np.linspace(Z.min(), Z.max(), 5)

# Add custom tick labels and tick marks for the new plot on the left
z_ticks_new = np.linspace(Z_new_offset.min(), Z_new_offset.max(), 5)
for z_tick in z_ticks_new:
    ax.text(
        X.min() - 0.5,
        Y.min() - 2.5,
        z_tick + 0.25,
        f"{z_tick - (offset+1):.1f}",
        color="k",
        verticalalignment="center",
    )
    ax.plot(
        [X.min() - 0.5, X.min()],
        [Y.min() - 0.5, Y.min()],
        [z_tick, z_tick],
        color="k",
    )

ax.set_zticks(np.block([z_ticks_original, z_ticks_new]))

fig.canvas.draw()
labels = []
for lab, tick in zip(ax.get_zticklabels(), ax.get_zticks()):
    if float(tick) >= 1.0:
        lab.set_text("")
    labels += [lab]
ax.set_zticklabels(labels)

# Draw the left Z-axis line
ax.plot(
    [X.min() - 0.5] * 2,
    [Y.min() - 0.5] * 2,
    [z_ticks_new.min(), z_ticks_new.max()],
    color="k",
)

ax.set_xlabel("X")
ax.set_ylabel("Y")
ax.set_zlabel("Z")

cbar1 = fig.colorbar(
    surf1, ax=ax, pad=-0.075, orientation="vertical", shrink=0.5
)
cbar1.set_label("Z Values (primary z-axis)")
cbar2 = fig.colorbar(
    surf2,
    ax=ax,
    pad=0.12,
    orientation="vertical",
    shrink=0.5,
    ticks=z_ticks_original,
)
cbar2.set_label("Z Values (secondary z-axis)")


plt.show()

Run Code Online (Sandbox Code Playgroud)

产生: Matplotlib 3d 图显示定制设计的辅助共享 z 轴比例