确定 3D 轴的精确位置和长度并通过 2D 图形复制它是相当困难的(尽管并非不可能 - 我会投票支持任何完全做到这一点的解决方案)。但如果你做不到——那就假装吧。在这里,我们使用两个 3D 图并将其中一个转换为看起来像 2D 图:
from matplotlib import pyplot as plt
from mpl_toolkits.mplot3d.axes3d import Axes3D
def plot_3d_pseudo2d(arr):
#one figure, two 3D subplots
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(20, 10), subplot_kw={'projection': "3d"})
#ax1 - normal isometric 3D projection
ax1.view_init(elev=10, azim=-45)
ax1.set_xlabel("X")
ax1.set_ylabel("Y")
ax1.set_zlabel("Z")
ax1.plot(arr[:, 0], arr[:, 1], arr[:, 2], marker="o")
#pseudo-2D projection
ax2.view_init(elev=0, azim=-90.1)
#shrink y-axis projection length
ax2.get_proj = lambda: np.dot(Axes3D.get_proj(ax2), np.diag([1, 0.01, 1, 1]))
ax2.set_xlabel("X")
ax2.set_zlabel("Z")
#plot x-z pairs for y=0
ax2.plot(arr[:, 0], np.zeros(arr[:, 1].size), arr[:, 2], marker="o")
#remove y-ticks
ax2.set_yticks([])
#increase label distance
ax2.xaxis.labelpad = 10
ax2.zaxis.labelpad = 10
plt.subplots_adjust(wspace=0.1)
plt.show()
import numpy as np
plot_3d_pseudo2d(np.asarray([[1, 4, 5],
[12, 23, 89],
[123, 234, 789]]).T)
输出示例:
它并不完美 - 3D 投影在其周围创建了大量空白(以便有旋转空间),并且透视变形隐藏了 x 轴刻度并使 z 轴标签稍微偏离。
免责声明:在这个答案的帮助下,y轴投影被缩小了。
抱歉拖了一个旧线程,但我试图解决同样的问题,最终使用 gridspec 让它工作(并且无法通过 T 先生的方法得到我喜欢的东西)并想分享。它不会自动执行解决方案,并且需要手动进行一些调整,但如果您的格式一致,则只需执行一次。我已将其设置为使用我发现对我有用的默认设置,里程可能会有所不同,因为它们使用我的默认格式设置。
from matplotlib import pyplot as plt
import numpy as np
def plot_3d_and_2d_in_same_figure(scale_to_match_3dz_with_2dy=True,
twod_bottom_bound=None, twod_top_bound=None, x_offset=7):
'''
scale_to_match_3dz_with_2dy: bool. If True, scales the 2D subplot height to match the z-axis of the 3D
subplot with the y-axis of the 2D subplot. If False, scales the 2D subplot height to align the titles of both
subplots and the lowest visible parts of the subplots.
twod_bottom_bound: int/None. Integer between 0 and 99, should be less than the twod_top_bound value.
twod_top_bound: int/None. Integer between 0 and 99, should be greater than the twod_bottom_bound value.
x_offset: int, default 7. Integer between 0 and 49, how far to move the 2D subplot to the right to avoid axes overlapping.
'''
fig = plt.figure(figsize=(14,6))
gs = fig.add_gridspec(100,100)
if scale_to_match_3dz_with_2dy and twod_bottom_bound is None:
twod_bottom_bound = 30
elif twod_bottom_bound is None:
twod_bottom_bound = 18
if scale_to_match_3dz_with_2dy and twod_top_bound is None:
twod_top_bound = 76
elif twod_top_bound is None:
twod_top_bound = 87
x_offset = 7
ax1 = fig.add_subplot(gs[:,:50], projection='3d')
n_points = 50
rand = np.random.default_rng(45)
x = rand.normal(loc=0, scale=1, size=n_points)
y = rand.exponential(scale=4, size=n_points)
z = np.linspace(0,5,n_points)
ax1.plot(x,y,z, alpha=0.5)
ax1.set_title('3d subplot',y=0.95)
ax1.set_xlabel('x label 1',labelpad=15)
ax1.set_ylabel('y label 1',labelpad=15)
ax1.set_zlabel('z label 1',labelpad=15)
ax1.view_init(elev=13, azim=-142, )
ax2 = fig.add_subplot(gs[100-twod_top_bound:100-twod_bottom_bound, 50+x_offset:])
# ^ use 100-value so setting the values of twod_top_bound and twod_bottom_bound are more intuitive
ax2.scatter(x,y)
ax2.set(
title='2d subplot',
xlabel='x label 2',
ylabel='y label 2'
)
我有一个布尔值可以在两个格式选项之间进行更改,因为对于我的问题,我希望子图元素的整体高度匹配:
plot_3d_and_2d_in_same_figure(scale_to_match_3dz_with_2dy=True)
https://i.imgur.com/Foij7Vx.png
plot_3d_and_2d_in_same_figure(scale_to_match_3dz_with_2dy=False)
https://i.imgur.com/qcL4cYG.png
抱歉,我还没有发布图片的声誉。