如何将次要轴上的网格线放在主要图的后面?

时间:2019-04-10 14:57:10

标签: python matplotlib

以下脚本创建了一个Figure实例,该实例在辅助网格线的后面是蓝色直方图,而这些网格本身在橙色的累积直方图之后。

import matplotlib.pyplot as plt
import numpy as np

plt.style.use("seaborn-darkgrid")
np.random.seed(42)

foo = np.random.randn(1000)

fig, ax = plt.subplots()
ax.hist(foo, bins=50)
ax2 = ax.twinx()
ax2.hist(
    foo, bins=50, density=True, cumulative=True, histtype="step", color="tab:orange"
)

plt.show()

Output of the code snippet

我正在寻找一种将网格线放在蓝色直方图后面的方法,并在matplotlib/matplotlib#7984发现了一个相关问题。它说

  

您不能将一个轴上的艺术家的绘画顺序与另一个轴上的艺术家的绘画顺序交错

这解释了为什么ax2.set_axisbelow(True)对主要Axes没有影响。

我可以通过某种方式实现我的目标吗?欢迎使用变通方法(根据上面的引用,我想没有一个规范的解决方案)。

2 个答案:

答案 0 :(得分:1)

您想要的绘制顺序是(首先是背面)

  • 轴线的网格
  • 双轴网格
  • 在轴上绘制图
  • 双轴绘图

但是,如评论所见,这是不可能的

  

您不能将一个轴上的艺术家的绘画顺序与另一个轴上的艺术家的绘画顺序交错

这意味着您需要4个轴而不是2个轴。

  • 原始y尺度网格的轴
  • 次级y尺度网格的轴
  • 用于绘制原始y轴的轴
  • 用于绘制y轴的图的轴

这可能看起来像这样:

import matplotlib.pyplot as plt
import numpy as np

np.random.seed(42)

foo = np.random.randn(1000)

fig, ax1a = plt.subplots()  # ax1a for the histogram grid
ax2a = ax1a.twinx()         # ax2a for the cumulative step grid
ax1b = ax1a.twinx()         # ax1b for the histogram plot
ax2b = ax1a.twinx()         # ax2a for the cumulative step plot
# Link the respective y-axes for grid and plot
ax1a.get_shared_y_axes().join(ax1a, ax1b)
ax2a.get_shared_y_axes().join(ax2a, ax2b)
# Remove ticks and labels and set which side to label
ticksoff = dict(labelleft=False, labelright=False, left=False, right=False)
ax1a.tick_params(axis="y", **ticksoff)
ax2a.tick_params(axis="y", **ticksoff)
ax1b.tick_params(axis="y", labelleft=True, labelright=False, left=True, right=False)
ax2b.tick_params(axis="y", labelleft=False, labelright=True, left=False, right=True)
# Spines off
for ax in [ax1a, ax2a, ax1b]:
    for k,v in ax.spines.items():
        v.set_visible(False)

ax1b.hist(foo, bins=50)

ax2b.hist(
    foo, bins=50, density=True, cumulative=True, histtype="step", color="tab:orange"
)
ax1a.grid()
ax2a.grid()
plt.show()

enter image description here

答案 1 :(得分:0)

已经有一个公认的可行答案,但我认为还有另一种解决方法,同时也可以稍微改善美学效果:

  • 不要为ax2绘制网格
  • 使用ax.set_ylim()ax.set_yticks()手动指定范围和第一个y轴上的刻度,以便刻度与ax2上的刻度对齐。这样一来,就无需再使用第二组网格线,并且图形在视觉上也不再那么忙碌了。

在上面的示例中,您可以通过以下方式进行操作:

ax2.set_ylim(0.0, 1.05)
ax2.set_yticks(0.0, 0.2, 0.4, 0.6, 0.8, 1.0)

ax.set_ylim(0.0, 70*1.05)
ax.set_yticks(0, 14, 28, 42, 56, 70)
ax.grid(both)
ax.set_axisbelow(True)

当然,根据实际数字,这可能会更好或更坏,在示例中,我改用非整数。在15、30 ...处使用刻度线可能会起作用,或者将第二个y轴缩放到140,或者将第一个y缩放到100,但是没有理想的解决方案。自动执行此方法当然很困难-但是如果我需要为特定数据集制作漂亮的图形,那么我有时会使用它,而花时间对其进行调整是合理的。