简体   繁体   English

如何在Tkinter中基于其他限制自动更新matplotlib子图限制?

[英]How do you automatically update matplotlib subplot limits based on another's limits within Tkinter?

I have two matplotlib subplots in a Tkinter canvas plotting the same data, with Matplotlib NavigationToolbar2TkAgg buttons for the user to navigate the subplots, etc. I would like to have the top panel display one region of the data (with xlimits x1 to x2), while the bottom panel automatically shows what the data looks like offset from that region (xlimits: x1+offset to x2+offset) based on how the user zooms/pans in either panel. 我在Tkinter画布中有两个matplotlib子图,它们绘制了相同的数据,并带有Matplotlib NavigationToolbar2TkAgg按钮供用户浏览子图,等等。我想让顶部面板显示数据的一个区域(x限制为x1到x2),而底部面板会根据用户在任一面板中缩放/平移的方式自动显示该区域的数据偏移量(xlimits:x1 + offset到x2 + offset)。 I'm essentially looking for sharex/sharey behaviour in Tkinter, but with the limit values manipulated by some simple function. 我本质上是在寻找Tkinter中的sharex / sharey行为,但是使用一些简单的函数来控制极限值。 Is there a way to catch a NavigationToolbar event happening to trigger a simple function; 有没有一种方法可以捕获正在触发一个简单功能的NavigationToolbar事件; or am I going about this the wrong way? 还是我走错路了?

You can set new axis limits for one plot depending on the axis limits of another plot. 您可以根据另一个图的轴限制为一个图设置新的轴限制。 Use xlim_changed events on both axes to call a function that adjusts the limits of the other plot depending on the current limits. 在两个轴上都使用xlim_changed事件来调用一个函数,该函数根据当前限制来调整另一个图的限制。
One needs to make sure to disconnect the event prior to changing the limits, in order not to end up in an infinite loop. 为了避免陷入无限循环,需要确保在更改限制之前断开事件。

The following would be an implementation where the bottom plot is shifted by 100 units compared to the top one. 以下是一种实现方式,其中底图与顶图相比偏移了100个单位。

import numpy as np; np.random.seed(1)
import matplotlib.pyplot as plt

x = np.linspace(0,500,1001)
y = np.convolve(np.ones(20), np.cumsum(np.random.randn(len(x))), mode="same")

fig, (ax, ax2) = plt.subplots(nrows=2)

ax.set_title("original axes")
ax.plot(x,y)
ax2.set_title("offset axes")
ax2.plot(x,y)

offset         = lambda x: x + 100
inverse_offset = lambda x: x - 100

class OffsetAxes():
    def __init__(self, ax, ax2, func, invfunc):
        self.ax = ax
        self.ax2 = ax2
        self.func = func
        self.invfunc = invfunc
        self.cid = ax.callbacks.connect('xlim_changed', self.on_lims)
        self.cid2 = ax2.callbacks.connect('xlim_changed', self.on_lims)
        self.offsetaxes(ax, ax2, func)  

    def offsetaxes(self,axes_to_keep, axes_to_change, func):
        self.ax.callbacks.disconnect(self.cid)
        self.ax2.callbacks.disconnect(self.cid2)
        xlim = np.array(axes_to_keep.get_xlim())
        axes_to_change.set_xlim(func(xlim))
        self.cid = ax.callbacks.connect('xlim_changed', self.on_lims)
        self.cid2 = ax2.callbacks.connect('xlim_changed', self.on_lims)

    def on_lims(self,axes):
        print "xlim"
        if axes == self.ax:
            self.offsetaxes(self.ax, self.ax2, self.func)
        if axes == self.ax2:
            self.offsetaxes(self.ax2, self.ax, self.invfunc)

o = OffsetAxes(ax, ax2, offset, inverse_offset)


plt.show()

在此处输入图片说明

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

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