我尝试执行的步骤如下:
1.插入值对列表[xmin,xmax]
2.创建跨度对象的初始列表
3.绘制跨度并将标签写到列表框中
4.添加跨度到绘图(通过onlick事件)并更新列表框
5.删除并突出显示跨度
这是示例代码:
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
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 =
lambda: self.delete(self.l_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]
self.listbox.bind('<<ListboxSelect>>', self.highlight_span)
#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):
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)
#update view (spans and listbox) with central list of spans
self.update_view()
def update_view(self):
#clear visualisation
self.listbox.delete(0,tk.END)
[span.remove() for span in self.l_spans]
#fill with new data
[self.listbox.insert(tk.END, span.get_label()) for span in self.l_spans]
[span.draw(self.ax) for span in self.l_spans] #HERE IS THE PROBLEM!!!
#update view
#...
def highlight_span():
pass
def delete(self,item):
pass
list_vals= [[1,2],[2.5,4]]
root = tk.Tk()
app = App(root, list_vals)
root.mainloop()
函数update_view中的问题:
我需要在span.draw()中插入什么渲染器?
我不确定我的方法是否合适,因为我没有使用tkinter的经验。你觉得呢?
答案 0 :(得分:1)
我已经稍微简化了您的代码,删除了(我认为)非严格必要的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()
我希望这会有所帮助。