简体   繁体   English

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

[英]Why cannot I apply zoom axes range to dual axis, like I can pan axes range, for interactive matplotlib plot?

The below code example is modified from the basis on Matplotlib: Finding out xlim and ylim after zoom下面的代码示例是在Matplotlib 的基础上修改的:Finding out xlim and ylim after zoom

Basically, in that example, I want to have a dual x axis;基本上,在那个例子中,我想要一个双 x 轴; and I want the second (doubled) x axis to behave as the original one.我希望第二个(加倍的)x 轴表现得像原来的那样。 So, the link uses a callback to do that.因此,该链接使用回调来执行此操作。 However:然而:

  • While I only pan the plot, everything is fine - the dual copy is synchronized to the original X axis虽然我只平移 plot,但一切都很好 - 双副本与原始 X 轴同步
  • Once I zoom - something goes wrong, and apparently, the wrong range is applied to the dual axis - EVEN IF when printing the ranges in the callback, gives the expected range for the drawing after the zoom一旦我缩放 - 出现问题,显然,错误的范围应用于双轴 - 即使在回调中打印范围时,也会在缩放后给出预期的绘图范围
  • Once I start dragging after zoom, the two axes are dragged correspondingly - however, since the initial condition from the previous step is wrong, so is this part一旦我在缩放后开始拖动,两个轴就会相应地拖动 - 但是,由于上一步的初始条件是错误的,所以这部分也是
  • Now, I've added an extra call to the callback, on button release - so once I release the button from the drag move motion, THEN the two axes get synchronized again??!!现在,我在按钮释放时添加了一个额外的回调调用 - 所以一旦我从拖动移动动作中释放按钮,那么两个轴再次同步??!!

Here is an animated gif (Matplotlib 3.1.1, Python 3.7.4 on MSYS2/MINGW64 on Windows 10):这是一个动画 gif (Matplotlib 3.1.1, Python 3.7.4 on MSYS2/MINGW64 on Windows 10):

在此处输入图像描述

I truly, truly don't understand this.我真的,真的不明白这一点。 How come, when I just pan/drag the plot, ax.get_xlim() gives the right numbers, and ax22.set_xlim() applies them - but when I zoom the plot, ax.get_xlim() gives the right numbers, but ax22.set_xlim() does NOT apply them (or rather, applies them, but late - that is, applies the data from previous request in the current request)?????!!为什么,当我只是平移/拖动 plot 时, ax.get_xlim()给出了正确的数字,而ax22.set_xlim()应用了它们 - 但是当我缩放plot 时, ax22.set_xlim() ax.get_xlim()给出了正确的数字,但是ax22.set_xlim()不应用它们(或者更确切地说,应用它们,但迟到 - 即在当前请求中应用来自先前请求的数据)?????!! What is this sorcery?!这是什么法术?!

And how can I get the dual ax22 to be synchronized with the original ax axis, regardless if I drag or zoom in interactive mode?以及如何让双ax22与原始ax轴同步,无论我是否在交互模式下拖动或放大?

The code:编码:

#!/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()

Thanks to @ImportanceOfBeingErnest - I think I have an example now, that behaves the way I want - also for differing axes' ranges:感谢@ImportanceOfBeingErnest - 我想我现在有一个例子,它的行为符合我想要的方式 - 也适用于不同的轴范围:

图1

Basically, without a callback, and with setting labels manually, all works as @ImportanceOfBeingErnest mentioned - except, when zooming, the old set of labels will remain (and so, when you zoom in, you might see 10 ticks on the original axis, but only 1 tick on the dual);基本上,没有回调,并且手动设置标签,所有工作都像@ImportanceOfBeingErnest 提到的那样工作 - 除了缩放时,旧的标签集将保留(因此,当您放大时,您可能会在原始轴上看到 10 个刻度,但对偶只有 1 个刻度); so here, the callback is just used to "follow" the original axis labels:所以在这里,回调仅用于“跟随”原始轴标签:

#!/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()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM