窗口大小调整时

时间:2016-01-26 05:05:48

标签: python python-3.x matplotlib tkinter resize

我正在开发一个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()

我怀疑初始化坐标是个问题,但我对如何解决这个问题感到茫然。有什么建议吗?

1 个答案:

答案 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()