为什么不能为交互式matplotlib图将缩放轴范围应用于双轴,就像可以平移轴范围一样?

时间:2019-10-16 11:12:15

标签: python matplotlib plot

下面的代码示例是根据Matplotlib: Finding out xlim and ylim after zoom

修改的

基本上,在该示例中,我想要一个双x轴;我希望第二个(加倍)x轴的行为与原始轴相同。因此,该链接使用回调来做到这一点。但是:

  • 虽然我只平移绘图,但一切都很好-双重副本已同步到原始X轴
  • 一旦我缩放-出了点问题,很明显,错误的范围被应用到了双轴-即使在回调中打印范围时,即使在缩放后,也会给出图形的预期范围
  • 缩放后,一旦我开始拖动,就会相应地拖动两个轴-但是,由于上一步的初始条件是错误的,因此这部分也是
  • 现在,在按钮释放时,我向回调添加了一个额外的调用-因此,一旦我从拖动移动动作中释放了按钮,则两个轴又重新同步了!

以下是动画gif(Matplotlib 3.1.1,Windows 10上的MSYS2 / MINGW64上的Python 3.7.4):

enter image description here

我真的,真的不明白这一点。怎么会这样,当我只是平移/拖曳绘图时,ax.get_xlim()给出了正确的数字,而ax22.set_xlim()应用了它们-但是当我 zoom 绘图时,ax.get_xlim()给出正确的数字,但是ax22.set_xlim()不应用它们(或者应用它们,但是延迟-也就是说,应用当前请求中先前请求的数据)?这是什么法术?!

无论如何在交互模式下拖动或缩放,如何使双ax22与原始ax轴同步?

代码:

#!/usr/bin/env python3

import matplotlib
print("matplotlib.__version__ {}".format(matplotlib.__version__))
import matplotlib.pyplot as plt

#
# Some toy data
x_seq = [x / 100.0 for x in range(1, 100)]
y_seq = [x**2 for x in x_seq]

#
# Scatter plot
fig, ax = plt.subplots(1, 1)
ax.plot(x_seq, y_seq)

# https://stackoverflow.com/questions/31803817/how-to-add-second-x-axis-at-the-bottom-of-the-first-one-in-matplotlib
ax22 = ax.twiny() # instantiate a second axes that shares the same y-axis
# Move twinned axis ticks and label from top to bottom
ax22.xaxis.set_ticks_position("bottom")
ax22.xaxis.set_label_position("bottom")
# Offset the twin axis below the host
ax22.spines["bottom"].set_position(("axes", -0.06))

ax22.set_xlim(*ax.get_xlim())

#
# Declare and register callbacks
def on_xlims_change(axes):
  print("updated xlims: ", ax.get_xlim())
  ax22.set_xlim(*ax.get_xlim())

ax.callbacks.connect('xlim_changed', on_xlims_change)
fig.canvas.mpl_connect('button_release_event', on_xlims_change)

#
# Show
plt.show()

1 个答案:

答案 0 :(得分:0)

感谢@ImportanceOfBeingErnest-我想我现在有一个示例,其行为符合我想要的方式-也适用于不同轴的范围:

Figure_1

基本上,没有回调,并且手动设置了标签,所有操作都与@ImportanceOfBeingErnest相同-除非缩放时,旧的标签集将保留(因此,放大时,您可能会看到10个刻度原始轴,但双轴上只有1个刻度);所以在这里,回调仅用于“跟随”原始轴标签:

#!/usr/bin/env python3

import matplotlib
print("matplotlib.__version__ {}".format(matplotlib.__version__))
import matplotlib.pyplot as plt

#
# Some toy data
x_seq = [x / 100.0 for x in range(1, 100)]
y_seq = [x**2 for x in x_seq]

#
# Scatter plot
fig, ax = plt.subplots(1, 1)
ax.plot(x_seq, y_seq)

# https://stackoverflow.com/questions/31803817/how-to-add-second-x-axis-at-the-bottom-of-the-first-one-in-matplotlib
ax22 = ax.twiny() # instantiate a second axes that shares the same y-axis
# Move twinned axis ticks and label from top to bottom
ax22.xaxis.set_ticks_position("bottom")
ax22.xaxis.set_label_position("bottom")
# Offset the twin axis below the host
ax22.spines["bottom"].set_position(("axes", -0.06))

factor = 655
old_xlims = ax.get_xlim()
new_xlims = (factor*old_xlims[0], factor*old_xlims[1])
old_tlocs = ax.get_xticks()
new_tlocs = [i*factor for i in old_tlocs]
print("old_xlims {} new_xlims {} old_tlocs {} new_tlocs {}".format(old_xlims, new_xlims, old_tlocs, new_tlocs))
ax22.set_xticks(new_tlocs)
ax22.set_xlim(*new_xlims)

def on_xlims_change(axes):
  old_tlocs = ax.get_xticks()
  new_tlocs = [i*factor for i in old_tlocs]
  ax22.set_xticks(new_tlocs)

ax.callbacks.connect('xlim_changed', on_xlims_change)

#
# Show
plt.show()