【问题标题】:How to to enable sharing for the secondary axis (twiny) in python如何在 python 中为辅助轴(双轴)启用共享
【发布时间】:2016-09-27 19:18:56
【问题描述】:

我正在尝试为主轴和次轴启用共享。下面的代码说明了示例图。该图包含两个水平轴,主轴网格以绿色显示,而另一个轴具有红色网格。

#!/usr/bin/python

# -*- coding: utf-8 -*-

import numpy as np
import matplotlib.pyplot as plt

FIRST = 0.0
LAST  = 2.0
STEP  = 0.01

t = np.arange(FIRST, LAST, STEP)

s1 = np.sin(2*np.pi*t)
s2 = np.exp(-t)
s3 = s1*s2

###############################################################################

plt.rc('axes', grid=True)
plt.rc('grid', color='0.75', linestyle='-', linewidth=0.5)

fig3 = plt.figure()
ax1primary = plt.subplot2grid((4,3), (0,0), colspan=3, rowspan=2)
ax2primary = plt.subplot2grid((4,3), (2,0), colspan=3, sharex=ax1primary)
ax3primary = plt.subplot2grid((4,3), (3,0), colspan=3, sharex=ax1primary)

ax1primary.plot(t,s1)
ax1primary.set_yticks(np.arange(-0.9, 1.0, 0.3))
ax1primary.xaxis.grid(color='green')

ax2primary.plot(t[:150],s2[:150])
ax2primary.set_yticks(np.arange(0.3, 1, 0.2))
ax2primary.xaxis.grid(color='green')

ax3primary.plot(t[30:],s3[30:])
ax3primary.plot([0,2],[0.2,0.2],'m')
ax3primary.set_yticks(np.arange(-0.4, 0.7, 0.2))
ax3primary.xaxis.grid(color='green')

INDEX = t[np.where(abs(s3-0.2) < 0.005)[0]]
INDEX = np.append(INDEX, LAST)
INDEX = np.insert(INDEX, 0, FIRST)

ax1secondary = ax1primary.twiny()
ax1secondary.set_xticks(INDEX)
ax1secondary.xaxis.grid(color='red')

ax2secondary = ax2primary.twiny()
ax2secondary.set_xticks(INDEX)
ax2secondary.xaxis.grid(color='red')

ax3secondary = ax3primary.twiny()
ax3secondary.set_xticks(INDEX)
ax3secondary.xaxis.grid(color='red')

plt.tight_layout()
plt.subplots_adjust(hspace=0)

for ax in [ax1primary, ax2primary, ax2secondary, ax3secondary]:
    plt.setp(ax.get_xticklabels(), visible=False)

###############################################################################

plt.show()

在静态图上没有问题。当问题变得明显时 您开始平移(或缩放)其中一个子图。主要(绿色)轴完全同步并在所有子图中移动,但次轴(红色)未对齐并仅在活动子图中移动。

有没有办法解决这个问题?


我想要实现的行为如下:

我需要一个公共的“主要”x 轴(对于所有三个子图),刻度在图的底部,另一个公共的“次要”x 轴(对于所有三个子图),刻度在顶部图。主轴是标准的规则间隔轴,而辅助轴显示自定义刻度(例如零交叉)这在上面的示例中都得到了满足。现在我需要在平移和缩放子图时也满足它。

【问题讨论】:

  • 我不清楚你在寻找什么样的行为。 twiny 创建一个带有共享 y 轴的独立 x 轴,因此如果您在 ay1cay2cay3c 子图中平移,x 轴应该与其父轴“不同步”移动.另一方面,您的ax1cax2cax3c 子图是使用共享的 x 轴但独立的 y 轴创建的。您是否希望所有绘图都共享 x 轴和 y 轴?
  • 我可以理解这令人困惑。我没有很好地选择轴名称。 ay1cay2cay3c 与 y 轴无关(我将更改上面示例代码中的轴名称以消除混淆。感谢您的洞察力。)。尽管如此,我想要实现的行为是我有一个公共 x 轴(对于所有三个子图),刻度在图底部,另一个公共 x 轴(对于所有三个子图),刻度在顶部图。
  • 那么听起来好像您想使用twinx 而不是twiny 来创建ay1c 等。twiny 为您提供了一个共同的y 轴和一个独立的x 轴,而你想要一个共同的 x 轴和独立的 y 轴。
  • 我已经尝试了你的建议。结果是twinx 在图的右侧创建了刻度。您能否举例说明如何使用twinx 使刻度位于图形顶部?
  • 你所要求的对我来说真的没有意义。如果您希望新图与现有子图共享 x 轴,则新刻度应对应于新的独立 y 轴,因此应位于右侧而不是顶部。你能更详细地解释你想要达到的目标吗?

标签: python matplotlib


【解决方案1】:

感谢您澄清您的问题。 twiny 的预期用途是创建第二个完全独立的 x 轴,其具有自己的比例和偏移量,然后您将在其中绘制。但是,在您的情况下,您仅使用由 twiny 创建的辅助 x 轴作为显示第二组自定义 x 刻度的一种方式,并且您希望该轴始终具有与父 x 完全相同的比例和偏移量-轴。

一种方法是创建一个callback,当主轴平移时更新辅助轴的限制:

from matplotlib.backend_bases import NavigationToolbar2

parents = [ax1primary, ax2primary, ax3primary]
children = [ax1secondary, ax2secondary, ax3secondary]

def callback(event=None):
    # return immediately if the figure toolbar is not in "navigation mode"
    if not isinstance(parents[0].figure.canvas.manager.toolbar,
                      NavigationToolbar2):
        return
    for parent, child in zip(parents, children):
        child.set_xlim(*parent.get_xlim())
        child.set_ylim(*parent.get_ylim())

# connect the callback to the figure canvas
fig3.canvas.mpl_connect('motion_notify_event', callback)

【讨论】:

  • 这看起来是一个很有前途的解决方案,我会试一试...实际上,我希望得到一些简单的东西,例如 ax2secondary = ax2primary.twiny(sharex=ax1secondary)
【解决方案2】:

很遗憾,建议的回调解决方案不够稳健。大多数时候平移都可以正常工作,但缩放是一场灾难。尽管如此,网格还是经常错位。

在找到改进回调解决方案的方法之前,我决定编写一个自定义网格并注释图中的值。

#!/usr/bin/python

# -*- coding: utf-8 -*-

import numpy as np
import matplotlib.pyplot as plt

FIRST = 0.0
LAST  = 2.0
STEP  = 0.01

t = np.arange(FIRST, LAST, STEP)

s1 = np.sin(2*np.pi*t)
s2 = np.exp(-t)
s3 = s1*s2

###############################################################################

plt.rc('axes', grid=True)
plt.rc('grid', color='0.75', linestyle='-', linewidth=0.5)

fig3 = plt.figure()
ax1primary = plt.subplot2grid((4,3), (0,0), colspan=3, rowspan=2)
ax2primary = plt.subplot2grid((4,3), (2,0), colspan=3, sharex=ax1primary)
ax3primary = plt.subplot2grid((4,3), (3,0), colspan=3, sharex=ax1primary)

ax1primary.plot(t,s1)
ax1primary.set_yticks(np.arange(-0.9, 1.0, 0.3))
ax1primary.xaxis.grid(color='green')
ax1primary.set_ylim(-1, 1)

ax2primary.plot(t[:150],s2[:150])
ax2primary.set_yticks(np.arange(0.3, 1, 0.2))
ax2primary.xaxis.grid(color='green')
ax2primary.set_ylim(0.2, 1)

ax3primary.plot(t[30:],s3[30:])
ax3primary.plot([0,2],[0.2,0.2],'m')
ax3primary.set_yticks(np.arange(-0.4, 0.7, 0.2))
ax3primary.xaxis.grid(color='green')
ax3primary.set_ylim(-0.6, 0.8)

INDEX = np.where(abs(s3-0.2) < 0.005)[0]

for i in range(0, len(INDEX)):
    ax1primary.annotate(t[INDEX[i]], xy=(t[INDEX[i]], 0))

ax1primary.plot([t[INDEX], t[INDEX]], [-1e9 * np.ones(len(INDEX)), 1e9 * np.ones(len(INDEX))], 'r')
ax2primary.plot([t[INDEX], t[INDEX]], [-1e9 * np.ones(len(INDEX)), 1e9 * np.ones(len(INDEX))], 'r')
ax3primary.plot([t[INDEX], t[INDEX]], [-1e9 * np.ones(len(INDEX)), 1e9 * np.ones(len(INDEX))], 'r')

plt.tight_layout()
plt.subplots_adjust(hspace=0)

for ax in [ax1primary, ax2primary]:
    plt.setp(ax.get_xticklabels(), visible=False)

###############################################################################

plt.show()

【讨论】:

    猜你喜欢
    • 2020-03-28
    • 2012-10-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多