我正在开发一个Python 3.4应用程序,用于显示EEG信号的功率谱密度图。我想在图表上叠加色块以指示delta,theta,alpha,beta和gamma的标准频段。
下面的骨架程序显示了按下“显示”按钮时图形在弹出窗口中的显示方式。调整第一个弹出窗口时,一切都很好。调整第二个弹出窗口的大小时会出现问题(通过再次单击“显示”按钮)。然后,色块出现在不正确的位置,并且不对应于指示的频带。
import tkinter as tk
from tkinter import BOTH, TOP, Y
from tkinter import ttk
from tkinter import Frame
import matplotlib.pyplot as plt
import matplotlib.patches as patches
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2TkAgg
# The following is used for psd semi-log graphs only
XMIN = 0 # minimum frequency
XMAX = 55 # maximum frequency
YMIN = 0.1 # minimum PSD value
YMAX = 100 # maximum PSD value
lblY = YMAX - 30
band_patches = [
patches.Rectangle((XMIN, YMIN), 4, YMAX, facecolor="blue", alpha=0.2),
patches.Rectangle((4, YMIN), 4, YMAX, facecolor="cyan", alpha=0.2),
patches.Rectangle((8, YMIN), 4, YMAX, facecolor="green", alpha=0.2),
patches.Rectangle((12, YMIN), 18, YMAX, facecolor="orange", alpha=0.2),
patches.Rectangle((30, YMIN), XMAX-30, YMAX, facecolor="magenta", alpha=0.2),
]
class PV(ttk.Frame):
def __init__(self, name='demo'):
ttk.Frame.__init__(self, name=name)
self.pack(expand=Y, fill=BOTH)
self.master.title('Demo')
self._create_viewer_panel()
def _create_viewer_panel(self):
viewerPanel = Frame(self, name='pv')
viewerPanel.pack(side=TOP, fill=BOTH, expand=Y)
# create the notebook
nb = ttk.Notebook(viewerPanel, name='notebook')
nb.enable_traversal()
nb.pack(fill=BOTH, expand=Y, padx=2, pady=3)
self._create_UI_tab(nb) #NEW
def _create_UI_tab(self, nb):
# frame to hold contentx
self.frame = ttk.Frame(nb, height='10i', width='8i', name='main')
btn0 = ttk.Button(self.frame, text='Display', width='25', command=self.draw_psd)
btn0.grid(row=0, column=1)
# add to notebook (underline = index for short-cut character)
nb.add(self.frame, text='Main', underline=0, padding=2)
def draw_psd(self):
popup = tk.Tk()
popup.geometry('720x480') # Set dimensions of popup window to 800x500 pixels
popup.wm_title("Power Spectral Density")
p = plt.figure()
self.ax = plt.subplot(111)
box = self.ax.get_position()
self.ax.set_position([box.x0, box.y0, box.width, box.height*0.95])
self.ax.set_yscale('log')
self.ax.set_xscale('linear')
plt.xlabel('Frequency (Hz)')
plt.xlim(XMIN, XMAX)
plt.ylim(YMIN, YMAX)
for ptch in band_patches:
self.ax.add_patch(ptch)
self.ax.annotate('delta', xy=(2,lblY), fontsize=10, color=None, horizontalalignment='center')
self.ax.annotate('theta', xy=(6,lblY), fontsize=10, color=None, horizontalalignment='center')
self.ax.annotate('alpha', xy=(10,lblY), fontsize=10, color=None, horizontalalignment='center')
self.ax.annotate('beta', xy=(21,lblY), fontsize=10, color=None, horizontalalignment='center')
self.ax.annotate('gamma', xy=(42,lblY), fontsize=10, color=None, horizontalalignment='center')
plt.show()
canvas = FigureCanvasTkAgg(p, master=popup)
canvas.show()
canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=1)
toolbar = NavigationToolbar2TkAgg(canvas, popup)
toolbar.update()
canvas._tkcanvas.pack(side=tk.TOP, expand=1)
popup.mainloop()
return None
if __name__ == '__main__':
PV().mainloop()
我怀疑初始化坐标是个问题,但我对如何解决这个问题感到茫然。有什么建议吗?
答案 0 :(得分:0)
看起来您必须按顺序重新定义每个新绘图的补丁 让他们的“变形”正常运作。
每个应用程序应该只有一个Tk实例。用于辅助窗户 使用Toplevel。
此外,当您将matplotlib嵌入到tkinter应用程序中时,它就是 最好避免所谓的“pyplot接口” - plt.show()等。相反, 明确使用matplotlib API:plt.xlabel(...) - > ax.set_xlabel(...)
import tkinter as tk
from tkinter import BOTH, TOP, Y
from tkinter import ttk
from tkinter import Frame, Toplevel
##import matplotlib.pyplot as plt
import matplotlib.patches as patches
from matplotlib.figure import Figure
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2TkAgg
XMIN = 0 # minimum frequency
XMAX = 55 # maximum frequency
YMIN = 0.1 # minimum PSD value
YMAX = 100 # maximum PSD value
lblY = YMAX - 30
##band_patches = [
## patches.Rectangle((XMIN, YMIN), 4, YMAX, facecolor="blue", alpha=0.2),
## patches.Rectangle((4, YMIN), 4, YMAX, facecolor="cyan", alpha=0.2),
## patches.Rectangle((8, YMIN), 4, YMAX, facecolor="green", alpha=0.2),
## patches.Rectangle((12, YMIN), 18, YMAX, facecolor="orange", alpha=0.2),
## patches.Rectangle((30, YMIN), XMAX-30, YMAX, facecolor="magenta", alpha=0.2),
##]
class WinPsd(Toplevel):
def __init__(self, master, cnf={}, **kw):
Toplevel.__init__(self, master, **kw)
self._create_plot()
def _create_plot(self):
self.fig = Figure()
self.ax = self.fig.add_subplot(111)
ax = self.ax
box = ax.get_position()
ax.set_position([box.x0, box.y0, box.width, box.height*0.95])
ax.set_yscale('log')
ax.set_xscale('linear')
ax.set_xlabel('Frequency (Hz)')
ax.set_xlim(XMIN, XMAX)
ax.set_ylim(YMIN, YMAX)
band_patches = [
patches.Rectangle((XMIN, YMIN), 4, YMAX,
facecolor="blue", alpha=0.2
),
patches.Rectangle((4, YMIN), 4, YMAX,
facecolor="cyan", alpha=0.2
),
patches.Rectangle((8, YMIN), 4, YMAX,
facecolor="green", alpha=0.2
),
patches.Rectangle((12, YMIN), 18, YMAX,
facecolor="orange", alpha=0.2
),
patches.Rectangle((30, YMIN), XMAX-30, YMAX,
facecolor="magenta", alpha=0.2
),
]
for ptch in band_patches:
ax.add_patch(ptch)
ax.annotate('delta', xy=(2,lblY), fontsize=10, color=None, horizontalalignment='center')
ax.annotate('theta', xy=(6,lblY), fontsize=10, color=None, horizontalalignment='center')
ax.annotate('alpha', xy=(10,lblY), fontsize=10, color=None, horizontalalignment='center')
ax.annotate('beta', xy=(21,lblY), fontsize=10, color=None, horizontalalignment='center')
ax.annotate('gamma', xy=(42,lblY), fontsize=10, color=None, horizontalalignment='center')
xdata,ydata = [],[]
self.line, = ax.plot(xdata, ydata)
canvas = FigureCanvasTkAgg(self.fig, master=self)
toolbar = NavigationToolbar2TkAgg(canvas, self)
toolbar.update()
canvas._tkcanvas.pack(fill='both', expand=1)
canvas.show()
def draw(self, xdata, ydata):
self.line.set_xdata(xdata)
self.line.set_ydata(ydata)
self.fig.canvas.draw()
class WinMain(tk.Tk):
def __init__(self, name='demo', **kw):
tk.Tk.__init__(self, **kw)
self.title(name)
self._create_viewer_panel()
def _create_viewer_panel(self):
viewerPanel = ttk.Frame(self, name='pv')
viewerPanel.pack(side=TOP, fill=BOTH, expand=Y)
nb = ttk.Notebook(viewerPanel, name='notebook')
nb.enable_traversal()
nb.pack(fill=BOTH, expand=Y, padx=2, pady=3)
self._create_UI_tab(nb)
def _create_UI_tab(self, nb):
self.frame = ttk.Frame(nb, height='10i', width='8i', name='main')
btn0 = ttk.Button(self.frame, text='Display', width='25', command=self.show_psd)
btn0.grid(row=0, column=1)
nb.add(self.frame, text='Main', underline=0, padding=2)
def show_psd(self):
xdata,ydata = [range(50)],[range(50)] #get some data from somewhere
popup = WinPsd(self)
popup.wm_title("Power Spectral Density")
popup.draw(xdata, ydata)
if __name__ == '__main__':
WinMain().mainloop()