2017-08-01 8 views
0

私はTkinterを使ってGUI内にアニメーショングラフを表示します(他のウィジェットと一緒に)。これはうまくいきますが、2番目のmatplotlibウィンドウもTkinterメインウィンドウとともに開きます。これを防ぐ方法を教えてください。Tkinterがextra matplotlib figureを開く

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

ありがとうございます!

編集:作業例にプログラムを作成

+0

なし[MCVE]私は推測することができます:あなたはどこかに自分のコードで 'plt.showを()'を使用するので、私は推測します新しいウィンドウが開きます。プロットがtkinterに埋め込まれている場合は、その必要はありません。また、matplotlibのアニメーション関数を使用すると、グラフがよりスムーズになります。 – Novel

+0

@Novel私はコードにplt.show()を持っていません:( あなたが示唆したように私はこの例を修正しました。おそらくそれはもっと役に立つでしょう – janizer

答えて

1

ありがとうございます。新しいウィンドウを呼び出すのはplt.pause()関数です(私はそれも知らなかった)。代わりにtime.sleepを使用してください。しかし、あなたはもっと大きな問題を抱えています: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() 
+0

'after()'はこの場合面白いはずはありません? – PRMoureu

+0

@PRMoureuあなたは 'after'を使うことができましたが、matplotlibに組み込まれているホイールを再改造しているので、私はそれを行う理由はありません – Novel

+0

申し訳ありません、私はコード全体をチェックしませんでした。 .sleep'はまったく... – PRMoureu

関連する問題