python - Matplotlib - 强制 3D 绘图使用可用的 figsize
问题描述
我想创建一个具有指定图形大小的图,其中 3D 轴尝试使用整个可用空间,同时在所有轴上保持相同的纵横比。
我当前的尝试显示了一个隐藏部分网格的剪切矩形。
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure(figsize=(5, 2.5))
ax = fig.add_subplot(projection='3d')
ax.get_proj = lambda: np.dot(Axes3D.get_proj(ax), np.diag([1, 1, 1, 0.5]))
u = v = np.linspace(0, 2 * np.pi, 50)
u, v = np.meshgrid(u, v)
X = np.cos(v) * (6 - (5/4 + np.sin(3 * u)) * np.sin(u - 3 * v))
Y = (6 - (5/4 + np.sin(3 * u)) * np.sin(u - 3 * v)) * np.sin(v)
Z = -np.cos(u - 3 * v) * (5/4 + np.sin(3 * u))
ax.plot_surface(X, Y, Z, rstride=1, cstride=1, color=[0.7] * 3, linewidth=0.25, edgecolor="k")
ax.set_box_aspect([ub - lb for lb, ub in (getattr(ax, f'get_{a}lim')() for a in 'xyz')])
plt.show()
我能做些什么?
解决方案
我复制了您提供的代码,并在最后添加了 4 行。
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np
plt.close()
fig = plt.figure(figsize=(5, 2.5))
ax = fig.add_subplot(projection='3d')
ax.get_proj = lambda: np.dot(Axes3D.get_proj(ax), np.diag([1, 1, 1, 0.5]))
u = v = np.linspace(0, 2 * np.pi, 50)
u, v = np.meshgrid(u, v)
X = np.cos(v) * (6 - (5/4 + np.sin(3 * u)) * np.sin(u - 3 * v))
Y = (6 - (5/4 + np.sin(3 * u)) * np.sin(u - 3 * v)) * np.sin(v)
Z = -np.cos(u - 3 * v) * (5/4 + np.sin(3 * u))
ax.plot_surface(X, Y, Z, rstride=1, cstride=1, color=[0.7] * 3, linewidth=0.25, edgecolor="k")
# ax.set_box_aspect([ub - lb for lb, ub in (getattr(ax, f'get_{a}lim')() for a in 'xyz')])
left, right = plt.xlim()
ax.set_zlim(left, right)
ax.set_ylim(left, right)
plt.tight_layout()
我注释掉该行ax.set_box_aspect
,因为它给了我一个错误。上面的输出是:
- - 编辑 - -
我有一个解决方法的想法,让它在 matplotlib v3.4.2 中工作:
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np
import os
plt.close()
# your code starts here, with a little modification
fig = plt.figure(figsize=(5,5))
ax = fig.add_subplot(projection='3d')
u = v = np.linspace(0, 2 * np.pi, 50)
u, v = np.meshgrid(u, v)
X = np.cos(v) * (6 - (5/4 + np.sin(3 * u)) * np.sin(u - 3 * v))
Y = (6 - (5/4 + np.sin(3 * u)) * np.sin(u - 3 * v)) * np.sin(v)
Z = -np.cos(u - 3 * v) * (5/4 + np.sin(3 * u))
ax.plot_surface(X, Y, Z, rstride=1, cstride=1, color=[0.7] * 3, linewidth=0.25, edgecolor="k")
# set the axes limits
left, right = plt.xlim()
ax.set_zlim(left, right)
ax.set_ylim(left, right)
# zoom in to the plot
ax.dist = 6
# make everything other than the plot itself transparent
fig.patch.set_alpha(0)
ax.patch.set_alpha(0)
ax.axis('off')
plt.tight_layout()
# save plot as image
plt.savefig('plotted.png')
# remove the axes where the image was plotted
ax.remove()
# resize figsize
fig = matplotlib.pyplot.gcf()
fig.set_size_inches(5, 2.5)
# add fake axes for gridlines as in 3d plot to make it look like a real plot
# skip this part if the gridlines are unnecessary
ax_bg = fig.add_subplot(111, projection='3d')
ax_bg.dist = 3
# add axes in cartesian coordinates (xy-plane) for the image
ax = fig.add_subplot(111)
fig.patch.set_alpha(1)
fig.subplots_adjust(left=0, bottom=0, right=1, top=1, wspace=0, hspace=0)
im = plt.imread('plotted.png')
h, w, dc = im.shape # (height=500, width=500, depth/color=4)
im_cropped = im[120:390, :, :] # this is manually adjusted
ax.axis('off')
ax.imshow(im_cropped)
# delete the saved image
os.remove('plotted.png')
输出是:
我不知道它是否适用于您的特定环境,但它仅用于解决您的问题。
如果有不清楚的地方,请告诉我。
推荐阅读
- r - RSQLite 无法读取带有“。”的列名。
- python - QAction 可在 QMenu 中使用嵌套菜单进行检查
- android - 在协程中并行运行两个 Kotlin 协程
- wcf - 错误:基础安全会话在可靠会话完全完成之前出现故障。可靠会话出现故障
- magento - 未加载送货方式
- c - 使用类型双关语将对象分解为单词
- reactjs - 强制以大写形式输入表单 - onChange 和 React Hooks
- gnu - Busybox 中是否缺少花括号支持?
- c++ - xcode 10 和 11,没有高级语法着色 (c++)
- jquery - jquery 查找最后一个 tr 的最后一个 td,以便在单击最后一个 td 时添加新 tr