在Matplotlib中,在SecondaryAxis上绘制网格线

5

问题

我正在尝试从我的SecondaryAxis的刻度绘制网格线。

ax2.grid(color=color,linestyle='--')

图表上没有显示任何内容,我认为我的情况和格式化Matplotlib SecondaryAxis刻度标签的情况相同,是吗?

然而,有人是否有解决问题的方法而不需要颠倒比例尺?我的意思是将百分比比例尺放在主轴上,将普通比例尺放在次级轴上。

完整代码

import matplotlib.pyplot as plt
import numpy as np

#generate dummy load duration curve
dur=2500
load = np.random.normal(60,30,dur+1)
load[::-1].sort()

x=range(0,dur+1)

perticks = np.linspace(0,1,11)
xticks = perticks*dur

# get yticks from xticks
yticks = np.interp(xticks, range(0,dur+1), load)
print(yticks)

# create figure object with axe object
fig, ax1 = plt.subplots(figsize=(16, 8))
ax1.plot(x, load)

#create second axis
ax2 = ax1.secondary_yaxis('right')

# label and color of the secondaryaxis 
perlabels = ['0%', '10%', '20%', '30%', '40%', '50%', '60%', '70%', '80%', '90%', '100%']
color ='tab:blue'

ax2.set_yticks(yticks)
ax2.set_yticklabels(labels=perlabels)
ax2.tick_params(axis='y', color=color, labelcolor=color)

# draw grid lines on the secondaryaxis
ax2.grid(color=color,linestyle='--')

# do the same for x axis
ax3 = ax1.secondary_xaxis('top')

ax3.set_xticks(xticks)
ax3.set_xticklabels(labels=perlabels)
ax3.tick_params(axis='x', color=color, labelcolor=color)

ax3.grid(color=color,linestyle='--')

输出结果

无网格线的图表

2个回答

5

我对这个话题进行了一些调查,并在GitHub上打开了问题。以下是我发现的:

  • SecondaryAxis 是在 matplotlib 3.1.0 中新增的“相当新的东西”(2019年5月)。即使 v.3.3.3 文档 中也说 secondary_xaxis() 方法是实验性的。
  • SecondaryAxis 继承自 _AxesBase,这是一个“实现细节”。它不应该(截至 v.3.3.3)像 Axes 对象一样工作,并且 SecondaryAxis.grid() 不应该绘制任何内容(就像 _AxesBase.grid() 一样)。虽然如此,我认为有一个不起作用的方法是具有误导性的。
  • 因此,在撰写本文时,.grid() 只被认为可用于主轴。

使蓝色轴成为主轴

  • 由于.grid()仅适用于非次要轴,因此您需要将主轴设置为蓝色,并将其移动到顶部和右侧。

代码

# Take the x and y-ticks for transfering them to secondary axis
xticks_orig = ax1.get_xticks()
yticks_orig = ax1.get_yticks()

# Make the primary axis blue since we want to draw grid on it
ax1.xaxis.tick_top()
ax1.yaxis.tick_right()
ax1.set_xticks(xticks)
ax1.set_yticks(yticks)
ax1.set_yticklabels(labels=perlabels)
ax1.set_xticklabels(labels=perlabels)
ax1.tick_params(axis="both", color=color, labelcolor=color)
ax1.grid(color=color, linestyle="--")

# Draw the black secondary axis
ax2 = ax1.secondary_yaxis("left")
ax3 = ax1.secondary_xaxis("bottom")
ax2.set_yticks(yticks_orig)
ax3.set_xticks(xticks_orig)

example

手动添加网格线

您也可以手动添加网格线,像这样:

xlim = ax1.get_xlim()
for y in ax2.get_yticks():
    ax1.plot(xlim, (y, y), ls="--", color=color, lw=0.5)
ax1.set_xlim(xlim)

ylim = ax1.get_ylim()
for x in ax3.get_xticks():
    ax1.plot((x, x), ylim, ls="--", color=color, lw=0.5)
ax1.set_ylim(ylim)

输出如下:

enter image description here

这里的区别在于,现在我们在图形上画出了类似于网格线的线条。

1
非常好用,非常感谢。不过我会保持问题开放,看看是否有人知道为什么grid()在SecondaryAxis上不起作用。 - Xavier
增加了为什么SecondaryAxis.grid()无法工作的解释,以及另一种替代方法的说明。 - Niko Pasanen

1
补充np8的回答,你也可以使用axvline来画线。这样做的优点是你不需要手动跟踪y轴限制:
for x in ax2.get_xticks():
    ax1.axvline(x, color=color, zorder=-1, linestyle="--", linewidth=0.5)

请注意,您需要适当地转换x坐标以匹配从ax1到ax2所做的变换。
此外,在我的情况下,我必须先呈现画布才能生成刻度标签:
fig1.canvas.draw()

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接