我有以下绘制时间序列的代码。我可以在上面的子图中进行跨度选择,当按下“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()
我尝试改编工具管理器文档中给出的示例,但没有成功。
好的,我在下面的代码中找到了解决方案。
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”按钮不再起作用。
请问有关于如何使用工具管理器修复此问题的任何线索吗?