如何在带有子图的 matplotlib 中使用 SpanSelector?
How to use SpanSelector in matplotlib with subplots?
我正在绘制来自多个来源的数据,并使用 SpanSelector 来分析特定事件期间的数据。我可以 select 每个子图中的数据并提取数据。但是,当我在新的子图中创建新的 selection 时,我希望前一个子图中的 selection 消失。
有span.set_visible(True/False)
。但是为了让它起作用,我需要知道哪个子图正在 selected。我试图找到使用 lambda 函数的方法,但目前无法正常工作。
我先试了:
for signal in self.signals:
self.span[k] = SpanSelector(
self.ax[k],
onselect = lambda min, max : self.onselect_function(min, max, k),
# onselect = self.onselect_function,
direction = 'horizontal',
minspan = 1,
useblit = True,
interactive = True,
button = 1,
props = {'facecolor': 'red', 'alpha':0.5},
drag_from_anywhere = True
)
k += 1
def onselect_function(self, min_value, max_value, selected_graph)
...
但它一直在为 selected_graph 发送 selected_graph = 3
的值,无论我 select 是哪个子图。有 3 个子图 ( k = 0 - 2).
我认为这是因为 k 不在命名空间中,我试过:
onselect = lambda min, max, k : self.onselect_function(min, max, k)
但是现在,我收到以下错误:
File "C:\Users\Ashu\miniconda3\envs\my_env\lib\site-packages\matplotlib\cbook\__init__.py", line 287, in process
func(*args, **kwargs)
File "C:\Users\Ashu\miniconda3\envs\my_env\lib\site-packages\matplotlib\widgets.py", line 1958, in release
self._release(event) File "C:\Users\Ashu\miniconda3\envs\my_env\lib\site-packages\matplotlib\widgets.py", line 2359, in _release
self.onselect(vmin, vmax)
TypeError: <lambda>() missing 1 required positional argument: 'k'
理想情况下,我希望 selection 突出显示所有子图中的 x 轴范围(我仍然可以手动执行此操作,因为我有关于 selected 范围的信息,如图中虚线所示)。但是当新的 selection 开始时,我需要之前的 selection 消失。
当前显示方式的示例。最后一个 selection 是在顶部图表中制作的,因此每个图表都显示了该 selection (51-53) 的文本信息,但底部两个图表中的高亮显示在错误的部分。我也试过清除坐标轴,但还是不行。
编辑:添加最小的可重现示例
import matplotlib.pyplot as plt
from matplotlib.widgets import SpanSelector
from random import randrange
import math
plt.style.use('seaborn')
noOfDataToShow = 10
noOfSignals = 3
fig, ax = plt.subplots(nrows = noOfSignals, ncols = 1)
x_pos = []
signal_data_holder = []
for i in range(noOfDataToShow):
x_pos.append(i)
for i in range(noOfSignals):
temp = []
for j in range (noOfDataToShow):
temp.append(randrange(0,10))
signal_data_holder.append(temp)
def onselect_function(min_value, max_value, selected_graph = 0):
k = 0
for param in signal_data_holder:
ax[k].cla()
ax[k].set_ylim([0,10])
ax[k].plot(x_pos, param, label = str (math.trunc(param[noOfDataToShow - 1])))
ax[k].legend(loc = "upper left")
k += 1
#******Calculating Min_Max (Can be ignored) ******#
min_value = math.floor(min_value)
max_value = math.ceil(max_value)
min_value_data = [None] * noOfSignals
max_value_data = [None] * noOfSignals
if (min_value < 0):
min_value = 0
if (max_value >= noOfDataToShow):
max_value = noOfDataToShow
for k in range(noOfSignals):
min_value_data = signal_data_holder[k][min_value]
max_value_data = signal_data_holder[k][min_value]
for i in range(min_value, max_value):
if (signal_data_holder[k][i] < min_value_data):
min_value_data = signal_data_holder[k][i]
elif (signal_data_holder[k][i] > max_value_data):
max_value_data = signal_data_holder[k][i]
labelText = "Min_Value: " + str (min_value_data) + "\n"
labelText += "Max_Value: " + str (max_value_data) + "\n"
labelText += "Range: " + str (min_value) + "-" + str (max_value) + "\n"
ax[k].legend(labels = [labelText], loc = "upper left")
print(min_value_data, max_value_data)
ax[k].axvline(min_value, color = 'red', linestyle = 'dashed')
ax[k].axvline(max_value, color = 'red', linestyle = 'dashed')
fig.canvas.draw()
#******Calculating Min_Max (Can be ignored) ******#
return min_value, max_value
span = [None] * noOfSignals
for k in range(noOfSignals):
span[k] = SpanSelector(
ax[k],
# onselect = lambda min, max, k : onselect_function(min, max, k),
# onselect = lambda min, max : onselect_function(min, max, k),
onselect = onselect_function,
direction = 'horizontal',
minspan = 1,
useblit = True,
interactive = True,
button = 1,
props = {'facecolor': 'red', 'alpha':0.5},
drag_from_anywhere = True
)
k = 0
for param in signal_data_holder:
ax[k].cla()
ax[k].set_ylim([0,10])
ax[k].plot(x_pos, param, label = str (math.trunc(param[noOfDataToShow - 1])))
ax[k].legend(loc = "upper left")
k += 1
plt.show()
我认为您不能直接检索链接到跨度选择器的轴对象(或者至少,我不知道如何检索)。不过我们也可以收集最后一次鼠标点击的轴对象:
import matplotlib.pyplot as plt
from matplotlib.widgets import SpanSelector
import numpy as np
#sample data
fig, axis = plt.subplots(3)
for i, ax in enumerate(axis):
t=np.linspace(-i, i+1 , 100)
ax.plot(t, np.sin(2 * np.pi * t))
#list to store the axis last used with a mouseclick
curr_ax = []
#detect the currently modified axis
def on_click(event):
if event.inaxes:
curr_ax[:] = [event.inaxes]
#modify the current axis objects
def onselect(xmin, xmax):
#ignore if accidentally clicked into an axis object
if xmin==xmax:
return
#set all span selectors invisible accept the current
for ax, span in zip(axis, list_of_spans):
if ax != curr_ax[0]:
span.set_visible(False)
#do something with xmin, xmax
print(xmin, xmax)
fig.canvas.draw_idle()
#collect span selectors in a list in the same order as their axes objects
list_of_spans = [SpanSelector(
ax,
onselect,
"horizontal",
useblit=True,
props=dict(alpha=0.5, facecolor="tab:blue"),
interactive=True,
drag_from_anywhere=True
)
for ax in axis]
plt.connect('button_press_event', on_click)
plt.show()
我正在绘制来自多个来源的数据,并使用 SpanSelector 来分析特定事件期间的数据。我可以 select 每个子图中的数据并提取数据。但是,当我在新的子图中创建新的 selection 时,我希望前一个子图中的 selection 消失。
有span.set_visible(True/False)
。但是为了让它起作用,我需要知道哪个子图正在 selected。我试图找到使用 lambda 函数的方法,但目前无法正常工作。
我先试了:
for signal in self.signals:
self.span[k] = SpanSelector(
self.ax[k],
onselect = lambda min, max : self.onselect_function(min, max, k),
# onselect = self.onselect_function,
direction = 'horizontal',
minspan = 1,
useblit = True,
interactive = True,
button = 1,
props = {'facecolor': 'red', 'alpha':0.5},
drag_from_anywhere = True
)
k += 1
def onselect_function(self, min_value, max_value, selected_graph)
...
但它一直在为 selected_graph 发送 selected_graph = 3
的值,无论我 select 是哪个子图。有 3 个子图 ( k = 0 - 2).
我认为这是因为 k 不在命名空间中,我试过:
onselect = lambda min, max, k : self.onselect_function(min, max, k)
但是现在,我收到以下错误:
File "C:\Users\Ashu\miniconda3\envs\my_env\lib\site-packages\matplotlib\cbook\__init__.py", line 287, in process
func(*args, **kwargs)
File "C:\Users\Ashu\miniconda3\envs\my_env\lib\site-packages\matplotlib\widgets.py", line 1958, in release
self._release(event) File "C:\Users\Ashu\miniconda3\envs\my_env\lib\site-packages\matplotlib\widgets.py", line 2359, in _release
self.onselect(vmin, vmax)
TypeError: <lambda>() missing 1 required positional argument: 'k'
理想情况下,我希望 selection 突出显示所有子图中的 x 轴范围(我仍然可以手动执行此操作,因为我有关于 selected 范围的信息,如图中虚线所示)。但是当新的 selection 开始时,我需要之前的 selection 消失。
当前显示方式的示例。最后一个 selection 是在顶部图表中制作的,因此每个图表都显示了该 selection (51-53) 的文本信息,但底部两个图表中的高亮显示在错误的部分。我也试过清除坐标轴,但还是不行。
编辑:添加最小的可重现示例
import matplotlib.pyplot as plt
from matplotlib.widgets import SpanSelector
from random import randrange
import math
plt.style.use('seaborn')
noOfDataToShow = 10
noOfSignals = 3
fig, ax = plt.subplots(nrows = noOfSignals, ncols = 1)
x_pos = []
signal_data_holder = []
for i in range(noOfDataToShow):
x_pos.append(i)
for i in range(noOfSignals):
temp = []
for j in range (noOfDataToShow):
temp.append(randrange(0,10))
signal_data_holder.append(temp)
def onselect_function(min_value, max_value, selected_graph = 0):
k = 0
for param in signal_data_holder:
ax[k].cla()
ax[k].set_ylim([0,10])
ax[k].plot(x_pos, param, label = str (math.trunc(param[noOfDataToShow - 1])))
ax[k].legend(loc = "upper left")
k += 1
#******Calculating Min_Max (Can be ignored) ******#
min_value = math.floor(min_value)
max_value = math.ceil(max_value)
min_value_data = [None] * noOfSignals
max_value_data = [None] * noOfSignals
if (min_value < 0):
min_value = 0
if (max_value >= noOfDataToShow):
max_value = noOfDataToShow
for k in range(noOfSignals):
min_value_data = signal_data_holder[k][min_value]
max_value_data = signal_data_holder[k][min_value]
for i in range(min_value, max_value):
if (signal_data_holder[k][i] < min_value_data):
min_value_data = signal_data_holder[k][i]
elif (signal_data_holder[k][i] > max_value_data):
max_value_data = signal_data_holder[k][i]
labelText = "Min_Value: " + str (min_value_data) + "\n"
labelText += "Max_Value: " + str (max_value_data) + "\n"
labelText += "Range: " + str (min_value) + "-" + str (max_value) + "\n"
ax[k].legend(labels = [labelText], loc = "upper left")
print(min_value_data, max_value_data)
ax[k].axvline(min_value, color = 'red', linestyle = 'dashed')
ax[k].axvline(max_value, color = 'red', linestyle = 'dashed')
fig.canvas.draw()
#******Calculating Min_Max (Can be ignored) ******#
return min_value, max_value
span = [None] * noOfSignals
for k in range(noOfSignals):
span[k] = SpanSelector(
ax[k],
# onselect = lambda min, max, k : onselect_function(min, max, k),
# onselect = lambda min, max : onselect_function(min, max, k),
onselect = onselect_function,
direction = 'horizontal',
minspan = 1,
useblit = True,
interactive = True,
button = 1,
props = {'facecolor': 'red', 'alpha':0.5},
drag_from_anywhere = True
)
k = 0
for param in signal_data_holder:
ax[k].cla()
ax[k].set_ylim([0,10])
ax[k].plot(x_pos, param, label = str (math.trunc(param[noOfDataToShow - 1])))
ax[k].legend(loc = "upper left")
k += 1
plt.show()
我认为您不能直接检索链接到跨度选择器的轴对象(或者至少,我不知道如何检索)。不过我们也可以收集最后一次鼠标点击的轴对象:
import matplotlib.pyplot as plt
from matplotlib.widgets import SpanSelector
import numpy as np
#sample data
fig, axis = plt.subplots(3)
for i, ax in enumerate(axis):
t=np.linspace(-i, i+1 , 100)
ax.plot(t, np.sin(2 * np.pi * t))
#list to store the axis last used with a mouseclick
curr_ax = []
#detect the currently modified axis
def on_click(event):
if event.inaxes:
curr_ax[:] = [event.inaxes]
#modify the current axis objects
def onselect(xmin, xmax):
#ignore if accidentally clicked into an axis object
if xmin==xmax:
return
#set all span selectors invisible accept the current
for ax, span in zip(axis, list_of_spans):
if ax != curr_ax[0]:
span.set_visible(False)
#do something with xmin, xmax
print(xmin, xmax)
fig.canvas.draw_idle()
#collect span selectors in a list in the same order as their axes objects
list_of_spans = [SpanSelector(
ax,
onselect,
"horizontal",
useblit=True,
props=dict(alpha=0.5, facecolor="tab:blue"),
interactive=True,
drag_from_anywhere=True
)
for ax in axis]
plt.connect('button_press_event', on_click)
plt.show()