- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我正在尝试将 2D 数据绘制到 3D 轴上。我有使用 ax.plot_surface
的 3D 形状,但我无法使用 ax.plot
使 2D 数据与轴壁齐平。
这是一个精简的示例代码,显示了我在使用 2D 数据时遇到的问题:
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
# Generate Example Data
x = [0.04,0,-0.04]
y = [0.04,0,-0.04]
z = [0.04,0,-0.04]
# Start plotting environment
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
# Plot 3 lines positioned against the axes "walls"
ax.plot(x,y,-0.08,zdir='z',c='r')
ax.plot(x,z, 0.08,zdir='y',c='g')
ax.plot(y,z,-0.08,zdir='x',c='b')
# Label each axis
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_zlabel('z')
# Set each axis limits
ax.set_xlim([-0.08,0.08])
ax.set_ylim([-0.08,0.08])
ax.set_zlim([-0.08,0.08])
# Equally stretch all axes
ax.set_aspect("equal")
# Set plot size for saving to disk
plt.gcf().set_size_inches(11.7,8.3)
# Save figure in .eps and .png format
plt.savefig('test.eps', format='eps')
plt.savefig('test.png', format='png', dpi=300)
# Display figure
plt.show()
这给出了以下结果,从中您可能会看到数据线的末端不在轴线上(即不与 0.04 和 -0.04 对齐):
通过交互式探索绘图,我确定将 ax.plot
调用中的 0.08 更改为 0.083 的幅度(同时保留相关符号)可以使绘图更加平坦墙。
我对此的解释是,该图并没有强制执行我的轴限制,这通过查看轴相交处的间距在图上显得很明显,但使用 ax.get_xlim()
等,显示我设置的值,所以我遗漏了一些东西。
关于如何让这些地 block 与墙壁齐平,我有什么想法吗?
非常感谢,
蒂姆
编辑:
我还尝试使用
设置轴限制ax.set_xlim3d(-0.08,0.08)
ax.set_ylim3d(-0.08,0.08)
ax.set_zlim3d(-0.08,0.08)
和
ax.set_xlim3d([-0.08,0.08])
ax.set_ylim3d([-0.08,0.08])
ax.set_zlim3d([-0.08,0.08])
没有任何运气。
我绝对倾向于将此归因于坐标轴相交处的填充问题,但我找不到与此相关的任何文档。IE。我将绘图位置设置为 -0.08,将轴限制设置为 -0.08,但绘图在末尾添加了一点填充以使限制介于 -0.082 和 -0.083 之间。
我想删除填充或获取填充值,以便我可以将其输入到 ax.plot
命令中。
编辑2:
遇到此问题但尚未解决问题的其他人 Changing the position of the grid walls in an mplot3d figure
最佳答案
你是对的,mplot3d
模块包含一个函数,可以在渲染轴之前向轴的最小值和最大值添加填充。
不幸的是,填充量是硬编码的,目前在最新可用版本的 matplotlib (v2.0) 中用户无法更改。
方案一:修改源码
我发现可以通过注释掉 axis3d.py 源代码文件中的两行源代码来禁用额外填充。 (在 matplotlib 源目录中,它位于 mpl_toolkits > mplot3d > axis3d.py 下)
在函数 _get_coord_info()
中,该函数首先使用 getter 函数 get_w_lims()
来检索您设置的 x、y 和 z 限制。它不会直接修改它们,因此为什么当您检查 ax.get_xlim()
时,它仍然返回 0.08 和 -0.08 的值。
def _get_coord_info(self, renderer):
minx, maxx, miny, maxy, minz, maxz = self.axes.get_w_lims()
if minx > maxx:
minx, maxx = maxx, minx
if miny > maxy:
miny, maxy = maxy, miny
if minz > maxz:
minz, maxz = maxz, minz
mins = np.array((minx, miny, minz))
maxs = np.array((maxx, maxy, maxz))
centers = (maxs + mins) / 2.
deltas = (maxs - mins) / 12.
mins = mins - deltas / 4.
maxs = maxs + deltas / 4.
vals = mins[0], maxs[0], mins[1], maxs[1], mins[2], maxs[2]
tc = self.axes.tunit_cube(vals, renderer.M)
avgz = [tc[p1][2] + tc[p2][2] + tc[p3][2] + tc[p4][2] for \
p1, p2, p3, p4 in self._PLANES]
highs = np.array([avgz[2*i] < avgz[2*i+1] for i in range(3)])
return mins, maxs, centers, deltas, tc, highs
请注意,它以一种有些随意的方式计算填充。因此填充不是固定数字,而是取决于您设置的轴限制。
deltas = (maxs - mins) / 12.
mins = mins - deltas / 4.
maxs = maxs + deltas / 4.
当调用draw()
函数渲染坐标轴时,它使用这些修改过的mins
和maxs
来构建实际的线你看,这就是为什么你总是在轴的每一端都得到填充。
我的 hacky 解决方案是像这样注释掉这两行:
#mins = mins - deltas / 4.
#maxs = maxs + deltas / 4.
为您提供线条与 3D 轴壁齐平的图形。
但请注意底角的轴标签如何相互重叠,并且 y 标签似乎未对齐...我怀疑这就是硬编码填充是一项功能的原因。 It may possible to tweak the y-axis tick labels with the rotation property 在 set_yticklabels(...)
方法中,直到它看起来适合您的需要。
解决方案 2:使用交互式绘图窗口中的缩放
另一种(某种)不需要修改源代码的解决方案是在交互式窗口中绘制图形,然后稍微放大直到线条与墙壁齐平。它需要一些反复试验,因为它是一种“目测”方法。请注意,这通常会删除最高的刻度线标签,但它避免了上述解决方案中的重叠问题。:
解决方案 3:结合以上所有内容
既然我们知道 mplot3d
如何计算填充量,我们是否可以使用它来将轴限制设置为恰到好处的量以避免填充问题,而不必使用交互模式或修改源代码?
是的,有一点额外的功能:
def get_fixed_mins_maxs(mins, maxs):
deltas = (maxs - mins) / 12.
mins = mins + deltas / 4.
maxs = maxs - deltas / 4.
return [mins, maxs]
minmax = get_fixed_mins_maxs(-0.08, 0.08)
# gives us: [-0.07666666666666667, 0.07666666666666667]
# Set each axis limits with the minmax value from our function
ax.set_xlim(minmax)
ax.set_ylim(minmax)
ax.set_zlim(minmax)
它给出了与解决方案 2 相同的图形,而无需打开交互式绘图窗口并用肉眼判断。
关于python - python mplot3D 中的 2D 图与 3D 轴壁不齐平,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36911238/
我是一名优秀的程序员,十分优秀!