Reputation: 543
I wanna update a matplotlib plot in a tkinter GUI. I tried to do so in the following code example.
import matplotlib
matplotlib.use('TkAgg')
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2TkAgg
from matplotlib.figure import Figure
import tkinter as tk
import tkinter.ttk as ttk
import sys
class Application(tk.Frame):
def __init__(self, master=None):
tk.Frame.__init__(self,master)
self.createWidgets()
def createWidgets(self):
fig=plt.figure(figsize=(8,8))
ax=fig.add_axes([0.1,0.1,0.8,0.8],polar=True)
canvas=FigureCanvasTkAgg(fig,master=root)
canvas.get_tk_widget().grid(row=0,column=1)
canvas.show()
self.plotbutton=tk.Button(master=root, text="plot", command=self.plot)
self.plotbutton.grid(row=0,column=0)
def plot(self):
for line in sys.stdout: #infinite loop, reads data of a subprocess
theta=line[1]
r=line[2]
ax.plot(theta,r,linestyle="None",maker='o')
plt.show(block=False)
plt.pause(0.001)
plt.cla()
#here set axes
root=tk.Tk()
app=Application(master=root)
app.mainloop()
At the moment the problem is, that the ax object is not known in the plot function. If I try plot(self,canvas,ax) the GUI does not open. Only a figure that plots the data.
I wanna plot the data in the figure that is seen in the GUI. At least with a refresh rate round about 3-5Hz. Cause I am an absolute beginner this code solution is probably not the best way to do so. So I would be happy, if someone could show me a smarter solution.
Thanks!
Upvotes: 14
Views: 36003
Reputation: 11
With 3 extra code lines can animate the plot updates. To highlight the essence, I simplified the code by removing some pieces (like 'master=') related to multi-instance cases.
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import tkinter as tk
import numpy as np
class Application(tk.Tk):
def __init__(self):
super().__init__()
self.create_widgets()
def create_widgets(self):
fig = plt.figure(figsize=(8, 8))
ax = plt.axes((0.1, 0.1, 0.8, 0.8), polar=True)
canvas = FigureCanvasTkAgg(fig, self)
canvas.get_tk_widget().grid(row=0, column=1)
plotbutton = tk.Button(self, text="plot", command=lambda: self.auto_plot(ax))
plotbutton.grid(row=0, column=0)
def auto_plot(self, ax):
c = ['r', 'b', 'g']
for j in range(5):
ax.clear()
for i in range(3):
theta = np.random.uniform(0, 360, 10)
r = np.random.uniform(0, 1, 10)
plt.polar(theta, r, linestyle="None", marker='o', color=c[i])
plt.draw()
self.after(500) # display plot keeping button responsive
self.update() # redraw plot
Application().mainloop()
Upvotes: 0
Reputation: 600
I don't know if it will be useful to anybody, but I updated the code to run with matplotlib 3.1.x+ and python 3.
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import tkinter as tk
import numpy as np
class Application(tk.Frame):
def __init__(self, master=None):
tk.Frame.__init__(self,master)
self.createWidgets()
def createWidgets(self):
fig=plt.figure(figsize=(8,8))
ax=fig.add_axes([0.1,0.1,0.8,0.8],polar=True)
canvas=FigureCanvasTkAgg(fig,master=root)
canvas.get_tk_widget().grid(row=0,column=1)
canvas.draw()
self.plotbutton=tk.Button(master=root, text="plot", command=lambda: self.plot(canvas,ax))
self.plotbutton.grid(row=0,column=0)
def plot(self,canvas,ax):
c = ['r','b','g'] # plot marker colors
ax.clear() # clear axes from previous plot
for i in range(3):
theta = np.random.uniform(0,360,10)
r = np.random.uniform(0,1,10)
ax.plot(theta,r,linestyle="None",marker='o', color=c[i])
canvas.draw()
root=tk.Tk()
app=Application(master=root)
app.mainloop()
Upvotes: 7
Reputation: 4961
Thanks Abishek for taking the time to post the answer to your own problem.
I've just modified your answer a bit so that it runs as a standalone module without needing input from sys.stdout. Also changed the tkinter imports for python 2.7
import matplotlib
matplotlib.use('TkAgg')
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2TkAgg
from matplotlib.figure import Figure
import Tkinter as tk # python 2.7
import ttk # python 2.7
import sys
class Application(tk.Frame):
def __init__(self, master=None):
tk.Frame.__init__(self,master)
self.createWidgets()
def createWidgets(self):
fig=plt.figure(figsize=(8,8))
ax=fig.add_axes([0.1,0.1,0.8,0.8],polar=True)
canvas=FigureCanvasTkAgg(fig,master=root)
canvas.get_tk_widget().grid(row=0,column=1)
canvas.show()
self.plotbutton=tk.Button(master=root, text="plot", command=lambda: self.plot(canvas,ax))
self.plotbutton.grid(row=0,column=0)
def plot(self,canvas,ax):
c = ['r','b','g'] # plot marker colors
ax.clear() # clear axes from previous plot
for i in range(3):
theta = np.random.uniform(0,360,10)
r = np.random.uniform(0,1,10)
ax.plot(theta,r,linestyle="None",marker='o', color=c[i])
canvas.draw()
root=tk.Tk()
app=Application(master=root)
app.mainloop()
Upvotes: 7
Reputation: 543
Ok I could solve it myself. Here the solution:
import matplotlib
matplotlib.use('TkAgg')
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2TkAgg
from matplotlib.figure import Figure
import tkinter as tk
import tkinter.ttk as ttk
import sys
class Application(tk.Frame):
def __init__(self, master=None):
tk.Frame.__init__(self,master)
self.createWidgets()
def createWidgets(self):
fig=plt.figure(figsize=(8,8))
ax=fig.add_axes([0.1,0.1,0.8,0.8],polar=True)
canvas=FigureCanvasTkAgg(fig,master=root)
canvas.get_tk_widget().grid(row=0,column=1)
canvas.show()
self.plotbutton=tk.Button(master=root, text="plot", command=lambda: self.plot(canvas,ax))
self.plotbutton.grid(row=0,column=0)
def plot(self,canvas,ax):
for line in sys.stdout: #infinite loop, reads data of a subprocess
theta=line[1]
r=line[2]
ax.plot(theta,r,linestyle="None",maker='o')
canvas.draw()
ax.clear()
#here set axes
root=tk.Tk()
app=Application(master=root)
app.mainloop()
Upvotes: 7