在工具栏中添加按钮以对数据执行一些处理(matplotlib)

问题描述 投票:0回答:1

我有以下绘制时间序列的代码。我可以在上面的子图中进行跨度选择,当按下“z”键时应用一些处理并在下面的子图中显示这个新数据。此外,单击工具栏中的“主页”按钮时可以返回到数据的初始上图。

我想在工具栏上添加一个名为“Process”的新按钮,该按钮将执行与用户单击时按“z”键相同的操作。如果可以简化实现,则可以删除按键功能。

代码:

import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.widgets import SpanSelector
import matplotlib.dates as mdates

if __name__ == '__main__':
    idx = pd.date_range("2018-01-01", "2018-01-03", freq="10s")
    df = pd.DataFrame(range(len(idx)), index=idx, columns=['val_phys'])

    date_min = df.index.values[0]
    date_max = df.index.values[len(df) - 1]

    # Display non-overlapping layout
    plt.rcParams['figure.constrained_layout.use'] = True
    # Use concise dates for labels
    plt.rcParams['date.converter'] = 'concise'
    # Display grid
    plt.rcParams['axes.grid'] = True
    fig, (ax1, ax2) = plt.subplots(2, 1, sharex=True)
    tb = fig.canvas.toolbar

    ax1.plot(df)
    # We scale the x-axis to the scale of the data (for Windows)
    ax1.set_xlim([mdates.date2num(date_min), mdates.date2num(date_max)])
    # For aesthetics we set the second plot axes
    ax2.set_xlim(ax1.get_xlim())

    # We push this scale onto the stack of the toolbar
    tb.push_current()

    def on_select(xmin, xmax):
        global date_min, date_max

        date_min = mdates.num2date(xmin).replace(tzinfo = None)
        date_max = mdates.num2date(xmax).replace(tzinfo = None)

        ax1.set_xlim([xmin, xmax])
        visible_y = df.loc[(df.index >= date_min) & (df.index <= date_max)].val_phys
        if len(visible_y):
            ax1.set_ylim(min(visible_y), max(visible_y))
        ax2.set_xlim(ax1.get_xlim())
        tb.push_current()
        plt.draw()

    def on_key(event):
        #print('you pressed', event.key, event.xdata, event.ydata)
        if event.key == 'z':
            # We filter dataframe to selected date range by mouse
            df_selected = df.loc[(df.index >= date_min) & (df.index <= date_max)]

            # We only keep one sample every 5 minutes (5*6=30 10-seconds samples)
            df_selected = df_selected.iloc[::30]

            ax2.clear()
            ax2.set_xlim(ax1.get_xlim())
            ax2.plot(df_selected)
            ax2.autoscale(enable=True, axis="y", tight=False)
            plt.draw()

    span_selector = SpanSelector(ax1, on_select, direction='horizontal', useblit=True)
    cid = fig.canvas.mpl_connect('key_press_event', on_key)

    plt.show()

我尝试改编工具管理器文档中给出的示例,但没有成功。

python matplotlib button toolbar
1个回答
0
投票

好的,我在下面的代码中找到了解决方案。

import pandas as pd
import matplotlib
import matplotlib.pyplot as plt
from matplotlib.widgets import SpanSelector
from matplotlib.backend_tools import ToolBase
import matplotlib.dates as mdates

matplotlib.rcParams["toolbar"] = "toolmanager"

if __name__ == '__main__':
    idx = pd.date_range("2018-01-01", "2018-01-03", freq="10s")
    df = pd.DataFrame(range(len(idx)), index=idx, columns=['val_phys'])

    class Process(ToolBase):
        def __init__(self, *args, **kwargs):
            super().__init__(*args, **kwargs)
            self.toggle_flag = False  # Initial state

        def trigger(self, sender, event, data=None):
            self.toggle_flag = True  # Toggle state
            if self.toggle_flag:
                # We filter dataframe to selected date range by mouse
                df_selected = df.loc[(df.index >= date_min) & (df.index <= date_max)]

                # We only keep one sample every 5 minutes (5*6=30 10-seconds samples)
                df_selected = df_selected.iloc[::30]

                ax2.clear()
                ax2.set_xlim(ax1.get_xlim())
                ax2.plot(df_selected.drop(columns=['cq']))
                ax2.set_ylabel(labels[meta['unite_phys']])
                ax2.autoscale(enable=True, axis="y", tight=False)
                plt.draw()

                self.toggle_flag = False

    date_min = df.index.values[0]
    date_max = df.index.values[len(df) - 1]

    # Display non-overlapping layout
    plt.rcParams['figure.constrained_layout.use'] = True
    # Use concise dates for labels
    plt.rcParams['date.converter'] = 'concise'
    # Display grid
    plt.rcParams['axes.grid'] = True
    fig, (ax1, ax2) = plt.subplots(2, 1, sharex=True)
    #tb = fig.canvas.toolbar
    tm = fig.canvas.manager.toolmanager
    tm.add_tool("Process", Process)
    fig.canvas.manager.toolbar.add_tool(tm.get_tool("Process"), "toolgroup")

    ax1.plot(df.drop(columns = ['cq']))
    # We scale the x-axis to the scale of the data (for Windows)
    ax1.set_xlim([mdates.date2num(date_min), mdates.date2num(date_max)])
    ax1.set_ylabel(labels[meta['unite_phys']])
    ax1.set_title(meta['ncon'])
    # For aesthetics we set the second plot axes
    ax2.set_xlim(ax1.get_xlim())

    # We push this scale onto the stack of the toolbar
    #tb.push_current()

    def on_select(xmin, xmax):
        global date_min, date_max

        date_min = mdates.num2date(xmin).replace(tzinfo = None)
        date_max = mdates.num2date(xmax).replace(tzinfo = None)
        vprint(f"Selected Span: xmin={date_min}, xmax={date_max}")

        ax1.set_xlim([xmin, xmax])
        visible_y = df.loc[(df.index >= date_min) & (df.index <= date_max)].val_phys
        if len(visible_y):
            ax1.set_ylim(min(visible_y), max(visible_y))
        ax2.set_xlim(ax1.get_xlim())
        #tb.push_current()
        plt.draw()

    def on_key(event):
        #print('you pressed', event.key, event.xdata, event.ydata)
        if event.key == 'z':
            # We filter dataframe to selected date range by mouse
            df_selected = df.loc[(df.index >= date_min) & (df.index <= date_max)]

            # We only keep one sample every 5 minutes (5*6=30 10-seconds samples)
            df_selected = df_selected.iloc[::30]

            ax2.clear()
            ax2.set_xlim(ax1.get_xlim())
            ax2.plot(df_selected.drop(columns=['cq']))
            ax2.set_ylabel(labels[meta['unite_phys']])
            ax2.autoscale(enable=True, axis="y", tight=False)
            plt.draw()

    span_selector = SpanSelector(ax1, on_select, direction='horizontal', useblit=True)
    cid = fig.canvas.mpl_connect('key_press_event', on_key)

    plt.show()

问题在于我必须注释对

tb.push_current()
方法的调用,因此“Home”、“Forward”和“Backward”按钮不再起作用。

请问有关于如何使用工具管理器修复此问题的任何线索吗?

© www.soinside.com 2019 - 2024. All rights reserved.