Python Tkinter打开额外的matplotlib图

Python Tkinter打开额外的matplotlib图,python,matplotlib,tkinter,Python,Matplotlib,Tkinter,我正在使用Tkinter构建一个GUI,它将在窗口中显示一个动画图形(以及一些其他小部件)。这很好,但是第二个matplotlib窗口也会与Tkinter主窗口一起打开。我怎样才能防止这种情况发生 import matplotlib matplotlib.use('TkAgg') import matplotlib.pyplot as plt from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationTo

我正在使用Tkinter构建一个GUI,它将在窗口中显示一个动画图形(以及一些其他小部件)。这很好,但是第二个matplotlib窗口也会与Tkinter主窗口一起打开。我怎样才能防止这种情况发生

import matplotlib
matplotlib.use('TkAgg')
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2TkAgg
from matplotlib.figure import Figure
import Tkinter as tk 
import ttk  

class Application(tk.Frame):
    def __init__(self, master=None):
        tk.Frame.__init__(self, master)
        #self.a = Arduino() #the data is coming in from an arduino
        self.createWidgets()
    def createWidgets(self):
        fig = plt.figure(figsize=(6,6))
        ax = fig.add_axes([0,0,1,1])
        canvas = FigureCanvasTkAgg(fig, master=root)
        canvas.get_tk_widget().place(x=0, y=0)

        self.plotbutton=tk.Button(master = root, text="plot", command=lambda: self.plot(canvas,ax))
        self.plotbutton.place(x=500, y=0)

        self.quitButton = tk.Button(master=root, text="quit", command=self.quit)
        self.quitButton.place(x=600, y=0)

    def plot(self,canvas,ax):
        while(1):
            print "plotting"
            plt.pause(0.1) 
            ax.clear()         # clear axes from previous plot
            #values = self.getData(arduino) #in the full program, I get new theta and r data from an arduino
            theta = [0, 1, 2, 3, 4, 5] #arbitrary axis values for testing purposes
            r = [0, 1, 2, 3, 4, 5] 
            ax.plot(r, theta)
            plt.xlim([0, 6]) #arbitrary axes limits
            plt.ylim([0, 6])
            canvas.draw()

    def quit(self):
        self.master.destroy()

root=tk.Tk()
root.geometry("950x500+300+300")
app=Application(master = root)
app.mainloop()
谢谢


编辑:将程序制作成工作示例

谢谢您的示例。调用新窗口的是
plt.pause()
函数(我也不知道)。使用时间。睡眠。然而,您有一个更大的问题:在GUI中有任何
while(1)
循环将锁定GUI。使用matplotlib动画功能正确执行此操作。这是我为另一个SO答案所做的一个例子;我添加了一个随机数据生成器,因此您可以看到它在没有数据连接的情况下运行:

try:
    import Tkinter as tk
except ImportError:
    import tkinter as tk
#~ import serial
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure
from matplotlib import pyplot as plt
import matplotlib.animation as animation
from collections import deque
import random
import time

HISTORY_LEN = 200

class App(tk.Frame):
    def __init__(self, master=None, **kwargs):
        tk.Frame.__init__(self, master, **kwargs)

        self.running = False
        self.ani = None

        btns = tk.Frame(self)
        btns.pack()

        lbl = tk.Label(btns, text="update interval (ms)")
        lbl.pack(side=tk.LEFT)

        self.interval = tk.Entry(btns, width=5)
        self.interval.insert(0, '30')
        self.interval.pack(side=tk.LEFT)

        self.btn = tk.Button(btns, text='Start', command=self.on_click)
        self.btn.pack(side=tk.LEFT)

        self.fig = plt.Figure()
        self.ax1 = self.fig.add_subplot(111)
        self.line, = self.ax1.plot([], [], lw=2)
        self.canvas = FigureCanvasTkAgg(self.fig,master=self)
        self.canvas.show()
        self.canvas.get_tk_widget().pack()

        self.ax1.set_ylim(0,100)
        self.ax1.set_xlim(0,500)

    def on_click(self):
        '''the button is a start, pause and unpause button all in one
        this method sorts out which of those actions to take'''
        if self.ani is None:
            # animation is not running; start it
            return self.start()

        if self.running:
            # animation is running; pause it
            self.ani.event_source.stop()
            self.btn.config(text='Un-Pause')
        else:
            # animation is paused; unpause it
            self.ani.event_source.start()
            self.btn.config(text='Pause')
        self.running = not self.running

    def start(self):
        self.xdata = deque([], maxlen=HISTORY_LEN)
        self.ydata = deque([], maxlen=HISTORY_LEN)
        #~ self.arduinoData = serial.Serial('com5', 115200)
        #~ self.arduinoData.flushInput()
        self.ani = animation.FuncAnimation(
            self.fig,
            self.update_graph,
            interval=int(self.interval.get()),
            repeat=True)
        self.running = True
        self.btn.config(text='Pause')
        self.ani._start()
        self.start_time = time.time()
        print('started animation')

    def update_graph(self, i):
        self.xdata.append(i)
        #~ self.ydata.append(int(self.arduinoData.readline()))
        self.ydata.append(random.randrange(100)) # DEBUG
        self.line.set_data(self.xdata, self.ydata)
        self.ax1.set_ylim(min(self.ydata), max(self.ydata))
        self.ax1.set_xlim(min(self.xdata), max(self.xdata))
        return self.line,

def main():
    root = tk.Tk()
    app = App(root)
    app.pack()
    root.mainloop()

if __name__ == '__main__':
    main()

如果没有密码,我只能猜测:我会猜测,因为您在代码的某个地方使用了
plt.show()
,这将打开一个新窗口。如果你的情节嵌入到tkinter中,你就不需要它了。另外,使用matplotlib的动画函数,您的图形将更加平滑。@Novel我的代码中没有任何plt.show():(我按照您的建议修复了这个示例,也许在()在这种情况下不应该更有趣吗?@PRMoureu你可以在之后使用
,但你会重新发明一个内置在matplotlib中的轮子,所以我看没有理由这么做。@Novel非常感谢!它工作得很好。我还没有想太多,开始担心while(1)--哎呀!这对理解如何正确地做这件事真的很有帮助。