Я немного упростил ваш код, удалив метод update_view
, который (на мой взгляд) не был строго необходим.Я добавил все соответствующее содержимое в метод sel_span
, который вызывается каждый раз, когда вы выбираете область на графике.
Я также создал другой метод remove_spans
для удаления выбранной области иочистите список ниже.Это я также привязал к кнопке Delete
, так что если кнопка нажата, выделение и текстовое поле очищаются.
Я также удалил привязку списка к событию ListboxSelect
, поскольку список будет обновляться при вызове метода insert
.
Последнее: я добавил ваши значения xmin
и xmax
в список вместо элементов span.get_label()
.Вот пример кода:
class App:
def __init__(self, master, l_val_pair):
# Create a container
frame = tk.Frame(master)
# Create fields
self.button_left = tk.Button(frame,text="Export")
self.button_left.pack(side="left")
self.button_right = tk.Button(frame,text="Delete", command = self.remove_spans)
self.button_right.pack(side="left")
self.listbox = tk.Listbox(master)
self.listbox.pack(side='bottom', fill=tk.X)
#define figure
self.fig = Figure()
self.ax = self.fig.add_subplot(111)
#sample data for a line
self.x = np.arange(0.0, 5.0, 0.01)
self.y = np.sin(2*np.pi*self.x) + 0.5*np.random.randn(len(self.x))
#plot line and list of spans
self.ax.plot(self.x,self.y)
self.l_spans = [self.ax.axes.axvspan(val_pair[0],val_pair[1], facecolor='red', alpha=0.3, label=val_pair)
for val_pair in l_val_pair]
#create a listbox
[self.listbox.insert(tk.END, item.get_label()) for item in self.l_spans]
#plot figure
self.canvas = FigureCanvasTkAgg(self.fig,master=master)
self.canvas.show()
self.canvas.get_tk_widget().pack(side='top', fill='both', expand=1)
frame.pack()
#use span selector
self.span = SpanSelector(self.ax, self.sel_span, 'horizontal', useblit=True,
rectprops=dict(alpha=0.5, facecolor='red'), span_stays=False)
#connect
self.canvas.mpl_connect('key_press_event', self.span)
def sel_span(self, xmin, xmax):
#clear visualisation
self.remove_spans()
indmin, indmax = np.searchsorted(self.x, (xmin, xmax))
indmax = min(len(self.x) - 1, indmax)
span = self.ax.axes.axvspan(xmin=self.x[indmin], xmax=self.x[indmax],
alpha = 0.5, facecolor='red')
#add actual span to list of spans
self.l_spans.append(span)
#for span in self.l_spans:
self.listbox.insert(tk.END, xmin)
self.listbox.insert(tk.END, xmax)
def remove_spans(self):
self.listbox.delete(0,tk.END)
for span in self.l_spans:
try:
span.remove()
except:
pass
self.canvas.draw_idle()
list_vals= [[1,2],[2.5,4]]
root = tk.Tk()
app = App(root, list_vals)
root.mainloop()
РЕДАКТИРОВАТЬ: комментарий немного прояснил сценарий использования, так что вот измененная версия кода.Я повторно ввел привязку к событию <<ListboxSelect>>
и написал метод highlight_span
, который:
- Проверяет, какой диапазон в списке был выбран
- выделяет его на рисункезеленым цветом (просто чтобы сделать его более заметным)
Я также изменил код, чтобы старые выборки не удалялись из списка:
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure
from matplotlib.widgets import SpanSelector
import tkinter as tk
import numpy as np
import ast
class App:
def __init__(self, master, l_val_pair):
# Create a container
frame = tk.Frame(master)
# Create fields
self.button_left = tk.Button(frame,text="Export")
self.button_left.pack(side="left")
self.button_right = tk.Button(frame,text="Delete", command = self.remove_spans)
self.button_right.pack(side="left")
self.listbox = tk.Listbox(master)
self.listbox.pack(side='bottom', fill=tk.X)
self.listbox.bind('<<ListboxSelect>>', self.highlight_span)
#define figure
self.fig = Figure()
self.ax = self.fig.add_subplot(111)
#sample data for a line
self.x = np.arange(0.0, 5.0, 0.01)
self.y = np.sin(2*np.pi*self.x) + 0.5*np.random.randn(len(self.x))
#plot line and list of spans
self.ax.plot(self.x,self.y)
self.l_spans = [self.ax.axes.axvspan(val_pair[0],val_pair[1], facecolor='red', alpha=0.3, label=val_pair)
for val_pair in l_val_pair]
#create a listbox
[self.listbox.insert(tk.END, item.get_label()) for item in self.l_spans]
#plot figure
self.canvas = FigureCanvasTkAgg(self.fig,master=master)
self.canvas.show()
self.canvas.get_tk_widget().pack(side='top', fill='both', expand=1)
frame.pack()
#use span selector
self.span = SpanSelector(self.ax, self.sel_span, 'horizontal', useblit=True,
rectprops=dict(alpha=0.5, facecolor='red'), span_stays=False)
#connect
self.canvas.mpl_connect('key_press_event', self.span)
def sel_span(self, xmin, xmax):
#clear visualisation
for span in self.l_spans:
try:
span.remove()
except:
pass
self.canvas.draw_idle()
indmin, indmax = np.searchsorted(self.x, (xmin, xmax))
indmax = min(len(self.x) - 1, indmax)
span = self.ax.axes.axvspan(xmin=self.x[indmin],
xmax=self.x[indmax],
alpha = 0.5,
facecolor='red',
label = [xmin, xmax])
#add actual span to list of spans
self.l_spans.append(span)
self.listbox.insert(tk.END, span.get_label())
def remove_spans(self):
self.listbox.delete(0,tk.END)
for span in self.l_spans:
try:
span.remove()
except:
pass
self.canvas.draw_idle()
def highlight_span(self, evt):
w = evt.widget
index = w.curselection()[0]
value = w.get(index)
value = list(map(float, ast.literal_eval(value)))
xmin = value[0]
xmax = value[1]
indmin, indmax = np.searchsorted(self.x, (xmin, xmax))
indmax = min(len(self.x) - 1, indmax)
span = self.ax.axes.axvspan(xmin=self.x[indmin],
xmax=self.x[indmax],
alpha = 0.5,
facecolor='green',
label = [xmin, xmax])
self.l_spans.append(span)
self.canvas.draw_idle()
list_vals= [[1,2],[2.5,4]]
root = tk.Tk()
app = App(root, list_vals)
root.mainloop()
Надеюсь, это поможет.