【问题标题】:Can't Get Axis to Align Right on MatPlotLib 3d无法让轴在 MatPlotLib 3d 上右对齐
【发布时间】:2019-05-18 16:51:35
【问题描述】:

我正在尝试制作 3d matplot 图。我无法使用对齐良好的标签来显示整个轴。我在下面概述了我尝试过的步骤。

1) 我可以使用以下方法设置 y 轴标签:

yTicks = list(range(0,90,5)
ax.set_yticks(range(len(yTicks)), True)

但是,如您所见,标签对齐非常糟糕。它也与我实际定义的不匹配,应该是按 5 而不是 10 计数的滴答声。

2) 如果我也尝试使用set_yticklabels,则对齐会修复,但它只会打印轴的一部分。这是代码和图像:

ax.set_yticklabels(yTicks, verticalalignment='baseline', horizontalalignment='left')

注意 y 轴如何从 80 变为 40。

3) 如果我去掉 set_yticks 中的 True,一切都会挤在一起:

4) 最后,如果我在标签函数中同时使用set_yticksset_yticklabels 调用get_yticks(),它几乎可以工作,但您可以看到轴线延伸到图形的“表面”之外:

ax.set_yticks(range(len(yTicks)), True)
ax.set_yticklabels(ax.get_yticks(), verticalalignment='baseline',
               horizontalalignment='left')

5)这是我的代码的更完整版本供参考:

plt.clf()

ax = plt.axes(projection='3d')

ax.bar3d(x,y,z, 
     1,1,[val*-1 if val != 0 else 0 for val in z])

xTicks = list(range(0,25,2))
yTicks = list(range(30,90,5))

ax.set_zlim(0, 1)

ax.set_xticks(range(len(xTicks)), True)
ax.set_yticks(range(len(yTicks)), True)

ax.set_xticklabels(ax.get_xticks(), 
                verticalalignment='baseline',
                horizontalalignment='left')

ax.set_yticklabels(ax.get_yticks(), 
                verticalalignment='baseline',
                horizontalalignment='left')

plt.savefig(file_path)

如何让它以 5 的间隔显示我的全轴 (0-90) 并使其对齐良好?

6) 更新:根据下面与@ImportanceOfBeingErnest 的对话,这是我在使用以下代码时仍然遇到的问题:

x=[15,28,20]; y=[30,50,80]; z=[1,1,1]

plt.clf()

ax = plt.axes(projection='3d')

ax.bar3d(x,y,z, 
         1,1,[val*-1 if val != 0 else 0 for val in z])

xTicks = list(range(0,25,2))
yTicks = list(range(30,90,5))
ax.set_xticks(xTicks)
ax.set_yticks(yTicks)

ax.set_yticklabels(ax.get_yticks(), 
                verticalalignment='baseline',
                horizontalalignment='left')

ax.set_zlim(0, 1)

plt.savefig(getSaveGraphPath(save_name))

【问题讨论】:

  • set_yticks 的第二个参数是一个布尔值,指定第一个参数是否是次要刻度。提供一个列表作为第二个参数似乎没有任何意义。然而,真正的问题在这里无法解决,因为我们根本不知道您的柱的实际数据单位。见minimal reproducible example
  • 示例中可以看到条形的实际数据单元,但这也无所谓。任何值都会产生相同的结果。问题不在于条形,而在于轴值,我确实在上面的描述中提供了该信息。 set_yticks 是对的(与 plt.yticks() 不同),但删除该参数会产生更糟糕的结果。它从字面上停止计算轴的一部分
  • 如果任何值都产生相同的结果,那将是问题的核心。但我无法重现这一点。我没有看到您声称没有对轴进行任何修改的任何图片,所以不,我无法“查看示例中条形的实际数据单元”。
  • 我已经在上面添加了我的代码,所以你可以看到。您可以为 x、y、z 选择任何值,只要它们在我定义的标签范围内即可。
  • 如果没有实际数据,唯一的答案是您可以通过ax.set_yticks(np.arange(0,90,5)) 设置刻度这一微不足道的事实。

标签: python matplotlib 3d bar-chart axis


【解决方案1】:

正如评论,您可以通过ax.set_yticks 设置刻度。

import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

x=[15,28,20]; y=[30,50,80]; z=[1,1,1]

ax = plt.axes(projection='3d')

ax.bar3d(x,y,z, 
     1,1,[val*-1 if val != 0 else 0 for val in z])


yTicks = list(range(30,90,5))
ax.set_yticks(yTicks)

ax.set_yticklabels(ax.get_yticks(), 
                verticalalignment='baseline',
                horizontalalignment='left')

ax.set_zlim(0, 1)

plt.show()

这将在 y 轴上显示所需的 5 个单位步长。

【讨论】:

  • 确实如此,但引发我最初问题的问题是,如果这样做,标签往往会非常糟糕地对齐。例如,请注意 85 是如何在其刻度线之前相当多的(这在我包含的第一个图形图像上更容易看到,但也可以在你的图中看到)。没有办法使用 set_yticks 调整对齐方式,必须使用 set_ylabels。然而,这会产生上述问题。我正在努力寻找 1)设置 y 刻度和 2)设置刻度标签对齐而不会导致问题的指令排列。
  • 嗯,我的意思是如果你愿意,你仍然可以在答案中的代码中添加ax.set_yticklabels(ax.get_yticks(), verticalalignment='baseline', horizontalalignment='left')?!
  • 我做到了,这是问题所在。您可以看到它使图表看起来如何。
  • 我对您报告的哪个命令正在执行的操作有点困惑。我刚刚用那条线和结果图更新了我的答案。
  • 感谢您的耐心等待,我复制粘贴了您的代码(刚刚添加了ax.set_xticks(xTicks)),但它的解析方式不同。一方面,即使代码将范围设置为从 0 开始,您的图表也以 16(在 x 轴上)结束,而我的图表确实到了 0。但是,我的图表不会在全轴上着色,只是尽可能远因为有数据。请查看我的问题的更新以获取我所看到的图片。
【解决方案2】:

因此,经过多次反复试验,我可以让图形在各种限制情况下正确渲染轴的唯一方法如下。我对此并不完全满意(请注意最后一个 y 刻度标签没有出现),但它是唯一在刻度线旁边有数字的版本)。只有当数据没有超过它们的值时,我才必须让 x 和 y 限制有效,而 z 边界是一个硬限制。我并没有声称理解为什么这些排列都是必要的(这只是 3D 绘图的问题),但这是适合我的解决方案:

plt.clf()

ax = plt.axes(projection='3d')

# Need to force include fake NaN data at the axis limits to make sure labels
# render correctly
#
# xLims and yLims create boundaries only if data doesn't stretch beyond them

xstart, xend = xLims
ystart, yend = yLims
x = [xstart] + x + [xend]
y = [ystart] + y + [yend]
z = [numpy.nan] + z + [numpy.nan]

# Plot graph

ax.bar3d(x,y,z,1,1,[val*-1 if val != 0 else 0 for val in z])

# Set z boundary (after graph creation)

ax.set_zbound(zBounds)

# Need to adjust labels slightly to make sure they align properly

use_x_ticks = ax.get_xticks()

### ON SOME SYSTEMS, use_x_ticks = ax.get_xticks()[1:] is needed for correct alignment ###

ax.set_xticklabels([int(x)  if x==int(x) else x for x in use_x_ticks],
                    horizontalalignment='right',
                    verticalalignment='baseline')

ax.set_yticklabels([int(y) if y==int(y) else y for y in ax.get_yticks()],
                    verticalalignment='top')

# Save graph

plt.savefig(file_save_path)

正如您在下面看到的,一切都很好地对齐:

【讨论】:

    猜你喜欢
    • 2017-07-14
    • 1970-01-01
    • 2022-11-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多