简体   繁体   English

当子图查看不同的轴区域时,如何在交互式 plot 中更新 matplotlib 子图轴?

[英]How can I update matplotlib subplot axes in an interactive plot when the subplots are viewing different axis regions?

I want to use the interactive subplots in matplotlib and have the changes I make (scrolling, cropping) apply to every subplot.我想使用 matplotlib 中的交互式子图,并将我所做的更改(滚动、裁剪)应用于每个子图。 Usually, I would use通常,我会使用

ax1 = plt.subplot(112)   
ax2 = plt.subplot(212, sharex=ax1)   

but I do not want the axes to be identical.但我不希望轴相同。 I want them to be dependent, but able to display different x values.我希望它们相互依赖,但能够显示不同的 x 值。 For example, I would want my initial plot to look like this例如,我希望我的初始 plot 看起来像这样

3 subplots showing a sine curve with slightly offset x-axes in each 3 个子图显示正弦曲线,每个子图中的 x 轴略有偏移

And then I would be able to use the interactive plot tools to scroll across, such that each moves an equal amount in the x-direction.然后我将能够使用交互式 plot 工具滚动,这样每个工具在 x 方向上移动相等的量。

I have tried我努力了

a,b = ax1.get_xlim()
ax2 = plt.subplot(212,xlim=(a-1,b-1))

but the get_xlim() does not get live, interactive updates to a and b , it only gets them once when the plot is first made.但是get_xlim()不会实时更新ab ,它只会在第一次制作 plot 时获得一次。

I can come up with two approaches, each with their drawbacks.我可以提出两种方法,每种方法都有其缺点。

Approach 1: hook into xlim_changed and ylim_changed axis callbacks方法 1:挂钩xlim_changedylim_changed轴回调

This approach works for panning, zooming, scroll events, and the home/forward/backward buttons.这种方法适用于平移、缩放、滚动事件和主页/前进/后退按钮。

However, only one axis can control the other axis or axes, as connecting all axes to each other results in infinite recursion on triggering the callback.但是,只有一个轴可以控制另一个轴或多个轴,因为将所有轴相互连接会导致触发回调时无限递归。

import numpy as np
import matplotlib.pyplot as plt

class XAxisUpdater(object):

    def __init__(self, master, slave):
        self.master = master
        self.slave = slave
        self.old_limits = self.get_limits(self.master)

    def __call__(self, dummy):
        new_limits = self.get_limits(self.master)
        deltas = new_limits - self.old_limits
        self.set_limits(self.slave, self.get_limits(self.slave) + deltas)
        self.old_limits = new_limits

    def get_limits(self, ax):
        return np.array(ax.get_xlim())

    def set_limits(self, ax, limits):
        ax.set_xlim(limits)


class YAxisUpdater(XAxisUpdater):

    def get_limits(self, ax):
        return np.array(ax.get_ylim())

    def set_limits(self, ax, limits):
        ax.set_ylim(limits)


if __name__ == '__main__':

    fig, (ax1, ax2) = plt.subplots(1, 2)
    ax1.set_xlim(0, 10)
    ax2.set_xlim(5, 15)
    ax1.callbacks.connect('xlim_changed', XAxisUpdater(ax1, ax2))
    ax1.callbacks.connect('ylim_changed', YAxisUpdater(ax1, ax2))
    plt.show()

Approach 2: detect panning (and zooming) events方法 2:检测平移(和缩放)事件

This doesn't result in recursion.这不会导致递归。 However, this approach breaks if the home, the forward, or the backward buttons is used.但是,如果使用主页、前进或后退按钮,则此方法会中断。

Additionally, my implementation below doesn't trigger on zoom for reasons I can't discern (even though it should, IMO).此外,由于我无法辨别的原因,我在下面的实现不会触发缩放(即使它应该,IMO)。 Maybe someone else can spot and correct the issue.也许其他人可以发现并纠正问题。

import numpy as np
import matplotlib.pyplot as plt


class PanEvent(object):
    def __init__(self, ax, func, button=1):
        self.ax = ax
        self.func = func
        self.button = button
        self.press = False
        self.move = False
        self.ax.figure.canvas.mpl_connect('button_press_event', self.on_press)
        self.ax.figure.canvas.mpl_connect('button_release_event', self.on_release)
        self.ax.figure.canvas.mpl_connect('motion_notify_event', self.on_move)

    def on_press(self, event):
        if (event.inaxes == self.ax) & (event.button == self.button):
            self.press = True

    def on_move(self, event):
        if (event.inaxes == self.ax) & self.press:
            self.func()

    def on_release(self, event):
        if event.inaxes == self.ax:
            self.press = False


class AxisUpdater(object):

    def __init__(self, axes):
        self.axes = axes
        self.limits = np.array([ax.axis() for ax in self.axes])

    def __call__(self):
        for ax, old_limits in zip(self.axes, self.limits):
            deltas = np.array(ax.axis()) - old_limits
            if not np.all(np.isclose(deltas, 0)):
                break

        for ii, (ax, old_limits) in enumerate(zip(self.axes, self.limits)):
            self.limits[ii] = old_limits + deltas
            ax.axis(self.limits[ii])


if __name__ == '__main__':

    fig, axes = plt.subplots(1, 2)
    axes[0].set_xlim(0, 10)
    axes[1].set_xlim(5, 15)
    instance1 = PanEvent(axes[0], AxisUpdater(axes)) # NB: you have to keep a reference to the class, otherwise it will be GCed.
    instance2 = PanEvent(axes[1], AxisUpdater(axes))
    plt.show()
 

暂无
暂无

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

相关问题 如何在matplotlib中将图形绘制到不同的子图轴 - How to plot figures to different subplot axes in matplotlib 为什么我不能将缩放轴范围应用于双轴,就像我可以平移轴范围一样,用于交互式 matplotlib plot? - Why cannot I apply zoom axes range to dual axis, like I can pan axes range, for interactive matplotlib plot? MatPlotLib - 子图的子图或单个图上的多个断轴图 - MatPlotLib - Subplots of subplot or multiple broken axis charts on single plot 如何在matplotlib中获得不同长度但比例相同的子图轴? - How can I get axis of different length but same scale for subplots in matplotlib? 如何使用matplotlib将斧头像情节一样没有子情节? - How can I put ax like a plot and no subplot with matplotlib? 当刻度标签的长度不同时,如何使用 pyqtgraph 控制多个子图中 y 轴的对齐方式? - How can I control the alignment of y axes in multiple subplots with pyqtgraph when the tick labels have different lengths? 如何使用 matplotlib 并排绘制子图和动态图形? - How can I plot a subplot and a dynamic figure with matplotlib side by side? 如何在不同的子图中绘制pcolor colorbar - matplotlib - How to plot pcolor colorbar in a different subplot - matplotlib 如何在其他子图中绘制Contourf Colorbar-Matplotlib - How to plot contourf colorbar in different subplot - matplotlib 如何在matplotlib的不同子图中重复绘图? - How to repeat a plot in different subplots in matplotlib?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM