Matplotlib漏洞:使用twinx()时数据显示在轴线上方

3
我正在尝试绘制两个数据集,它们之间的差异有几个数量级。经过一些研究(实际上只需要进行一次谷歌搜索),我发现了 twinx() 函数。
然而,在使用它时遇到了一些问题。我使用这个工具生成出版级别的图形,但有些东西令我困扰。
系统信息:matplotlib v1.3.1,python v2.7.4,Ubuntu 操作系统。
请考虑以下代码:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.ticker import MaxNLocator
from matplotlib.ticker import AutoMinorLocator


time = np.arange(0, 365, 1)
y1 = np.random.rand(len(time)) * np.exp(-0.03 * time)
y2 = 0.001 * np.random.rand(len(time)) * np.exp(-0.02 * time)

for i in range(30):
    y2[-i] = 0

fig = plt.figure(figsize=(8,6), dpi=300)
fig.subplots_adjust(hspace=0.0, right=0.9, top=0.94, left=0.12, bottom=0.07)
ax1 = fig.add_subplot(111)
ax2 = ax1.twinx()

for tl in ax1.get_yticklabels():
    tl.set_color('r')
for tl in ax2.get_yticklabels():
    tl.set_color('b')

for ax in [ax1, ax2]:
    ax.yaxis.set_major_locator(MaxNLocator(
        nbins=5,
        steps=[1,2,3,4,5,10],
        integer=False,
        symmetric=False,
        prune=None))
    ax.yaxis.set_minor_locator(AutoMinorLocator(4))

ax2.plot(time, y1, 'b-')
ax1.plot(time, y2, 'r-')
ax1.set_ylabel(r"y value", labelpad=15)
ax1.set_xlabel(r"x value")
ax1.set_xlim(0,365)
ax1.set_xticks(range(0,370,30))
ax1.xaxis.set_minor_locator(AutoMinorLocator(3))

fig.savefig("Errorplot.png", dpi=60)

现在,当查看这个低分辨率的输出时,我没有发现任何奇怪的东西: Error plot

然而,当放大到高分辨率(比如说,dpi=300)版本时,我看到了以下内容: Zoomed section of the error plot

很明显,第二个坐标轴中的线条绘制在第一个坐标轴的脊柱上。
我应该如何解决这个问题?是否有一种方法可以重新绘制一个轴实例的脊柱?
我尝试过:
  • 更改plot()调用的顺序
  • zorder kwarg设置为-1、-10。即使ax2的zorder比ax1小,我也会出现这种行为。
  • 与上述结合使用:ax2.spines['bottom'].set_zorder(10)

我无法复现你的错误。当我运行你的代码并查看.png文件时(我已将dpi提高到1200,所以像素非常细致),我发现所有的轴线都在数据点之上。 - Ffisegydd
我仍然在使用v 1.2.1版本。也许更新会解决这个问题。 - tschoppi
啊, 我现在使用的是1.3.1版本。请尝试更新看看是否能解决问题,如果不能,请告诉我们。 - Ffisegydd
好的,我刚刚更新到了1.3.1版本(甚至检查了matplotlib.__version__变量),但是仍然存在同样的问题... - tschoppi
1
很抱歉,我之前误解了你的问题。现在我已经找到了解决方法,并会发布答案 :) - Ffisegydd
2个回答

4

似乎这篇文章没有得到很多浏览,但我发现它很有用,并想添加另一种改变zorder的方法,以防其他人需要。这个帖子更接近我想做的事情,但重要的是改变zorder,@Ffisegydd已经概述了这一点。另一种方法是使用以下代码:

fig, ax1 = plt.subplots()
ax2 = ax1.twinx()
ax1.set_zorder(ax2.get_zorder()+1) # put ax1 in front of ax2 
ax1.patch.set_visible(False) # hide the 'canvas' 

ax1.plot(data1[:,0], data1[:,0])  # plot whatever data you want
ax2.plot(data2[:,0], data2[:,0])  # plot commands can precede the set_zorder command

我知道这并没有直接解决提出的问题,但希望它可以帮助像我一样在搜索相关问题的解决方案时找到这篇文章的人。


2
您可以在Matplotlib中使用zorder kwarg来更改对象绘制的顺序,这里有一个示例代码here
下面我添加了两个示例(为了节省空间,我剪切了大部分代码)。在一个示例中,我将zorder设置为较大的值,这意味着它将最后绘制(因此在顶部)。在另一个示例中,我将zorder设置为-1,这意味着它将首先绘制(因此在下方)。
ax2.plot(time, y1, 'b-', zorder=5)
ax1.plot(time, y2, 'r-', zorder=5)

Example plot

ax2.plot(time, y1, 'b-', zorder=-1)
ax1.plot(time, y2, 'r-', zorder=-1)

Example plot 2


即使按照您建议的将 zorder kwarg 设置为 -1,我仍然会发现蓝线覆盖了一半的脊柱线... - tschoppi
你能否上传一个在imgur上展示你的意思的例子,并在评论中发布吗?因为对我来说,使用zorder=-1看起来完全正常。 - Ffisegydd
如果我将zorder设置为-1(对于两个图表都是如此),那么我得到了上面显示的内容,这清楚地显示了脊柱在两个图表之上。 - Ffisegydd
即使我在ax2中将zorder设置为比ax1低的值,它仍然会在另一条线上方绘制。这里出了点问题... - tschoppi
另外,我注意到在您的第二张图片中,蓝色数据是在刻度线上面绘制的,而红色数据是在下面绘制的。如果两者都有“zorder = -1”,那么怎么会发生这种情况呢? - tschoppi

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