here is my first tkInter application. I'd like to draw a matplotlib figure in a tkinter canvas. I read the following links to build it :
- How to update the contents of a FigureCanvasTkAgg
- Embed a pyplot in a tkinter window and update it
- How to update a plot in matplotlib?
but the result is not really satisfying : the figure is not refreshed in the callback method, but only when I run the "reset" button of my app. Could someone tell me how to get the figure/canvas refreshed in the "PlotCallback" ?
Thanks in advance !
#!/usr/bin/env python
# -*- coding: utf8 -*-
import os
import numpy as np
import Tkinter
import matplotlib
matplotlib.use('TkAgg')
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2TkAgg
from matplotlib.figure import Figure
import tkFileDialog
import tkMessageBox
#=========================
# App Class
#=========================
class Visu(Tkinter.Frame):
"""Main Frame for data visualization
"""
#------------------------------------
def __init__(self, parent, **kwargs):
"""Initialisation des widgets
"""
### USED VARIABLES (for file and data processing)
self.dataToPlot = []
self.itmsToPlot = []
self.presentsItems = []
self.chBtnVarLst = [] # list of "CheckButton" states for items selection
self.chBtnLst = [] # list of "CheckButton" labels
self.fic = ""
self.parent = parent
### IHM ###
Tkinter.Frame.__init__( self, parent, **kwargs )
self.pack(fill=Tkinter.BOTH)
# Create Menu Bar
menuBar = Tkinter.Menu( self )
menuFic = Tkinter.Menu( menuBar )
menuFic.add_command(label="Open", command = self.OpenCallback)
menuFic.add_separator()
menuFic.add_command(label="Quit", command = self.quit)
menuHlp = Tkinter.Menu( menuBar )
menuHlp.add_command(label="Help", command = self.HelpCallback)
menuBar.add_cascade(label = "File", menu = menuFic)
menuBar.add_cascade(label = "Help", menu = menuHlp)
parent.config(menu = menuBar)
# Create the Canvas for the plot figure
self.fig = Figure()
self.ax = self.fig.add_subplot(111)
t = np.arange(0.0, 3.0, 0.01)
s = np.sin(2*np.pi*t)
self.ax.plot(t,s)
self.canvas = FigureCanvasTkAgg(self.fig, master = self)
self.canvas.show()
self.canvas.get_tk_widget().pack()
toolbar = NavigationToolbar2TkAgg(self.canvas, self)
toolbar.update()
self.canvas._tkcanvas.pack(side=Tkinter.TOP, expand=1)
# Create controls
self.dataFrame = Tkinter.LabelFrame( self, text = "Available data" )
self.defButton = Tkinter.Checkbutton( self.dataFrame,
text = "Empty",
justify = Tkinter.LEFT,
state = Tkinter.DISABLED).pack()
self.dataFrame.pack()
# Create Buttons
self.BtnPlot = Tkinter.Button(self, text = "Plot", command = self.PlotCallback, state = Tkinter.DISABLED)
self.BtnPlot.pack(fill = Tkinter.BOTH, expand=1)
self.BtnRaZ = Tkinter.Button(self, text = "Reset", command = self.ResetCallback, state = Tkinter.DISABLED)
self.BtnRaZ.pack(fill = Tkinter.BOTH, expand=1)
#----------------------
def OpenCallback(self):
"""Open data file and add selection check buttons
"""
# Open file
options = {}
options['defaultextension'] = '.txt'
options['initialdir'] = '..'
options['title'] = 'Choix du fichier'
options['filetypes'] = [('text files', '.txt'),('all files', '.*')]
filename = tkFileDialog.askopenfilename(**options)
self.fic = os.path.basename( filename )
# Reader file header
f = open(filename)
self.presentsItems = f.readline().split()
f.close()
# Read data
self.dataToPlot = np.loadtxt(filename, skiprows=1)
#--- Frame to select items to be drawn ---
cnt = 0
for c in self.presentsItems:
cbVar = Tkinter.StringVar()
w = Tkinter.Checkbutton(self.dataFrame,
text = c,
variable = cbVar,
justify = Tkinter.LEFT,
onvalue = c)
w.deselect()
self.chBtnVarLst.append(cbVar)
self.chBtnLst.append(w)
w.grid(row = cnt % 10, column = cnt / 10)
cnt += 1
# Buttons activation
self.BtnPlot['state'] = Tkinter.NORMAL
self.BtnRaZ['state'] = Tkinter.NORMAL
#----------------------
def HelpCallback(self):
"""Instructions on how to use the program
"""
tkMessageBox.showinfo("Usage", "Work in progress...")
#----------------------
def PlotCallback(self):
# Read chosen items
for cbVar in self.chBtnVarLst:
if cbVar.get() != "0":
self.itmsToPlot.append( cbVar.get() )
# Plot those items
self.ax.cla()
self.fig.suptitle( self.fic )
for itm in self.itmsToPlot:
k = self.presentsItems.index(itm)
self.ax.plot(self.dataToPlot[:,k],label=itm)
self.ax.set_xlabel("Frame number")
self.ax.legend()
self.canvas.get_tk_widget().update()
self.update()
self.fig.canvas.draw()
#-----------------------
def ResetCallback(self):
"""Forgets the items and data, destroy associated buttons
"""
for cb in self.chBtnLst:
cb.destroy()
self.dataToPlot = []
self.itmsToPlot = []
self.presentsItems = []
self.chBtnLst = []
self.chBtnVarLst = []
self.fic = ""
#========
# Main
#========
if __name__=='__main__':
root = Tkinter.Tk()
root.wm_title("Visu XDE")
maVisu = Visu( root )
maVisu.mainloop()
Tested on Ubuntu 12.04 (unfortunately I need a special simulation framework existing only in 12.04) with Python 2.7.3, matplotlib 1.1.1rc, Tkinter Revision: 81008.