Hey I have made this GUI, that shows matplotlib plots in a tkinter interface with a scrolled canvas. But when the plots are added to the canvas the scroll event for the mouse doesn’t work anymore. Im totaly new to tkinter so consider this when you check out the code if there can be improvements also. So here it is:
from Tkinter import *
import matplotlib
#matplotlib.use('TkAgg')
from numpy import arange, sin, pi
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2TkAgg
from matplotlib.figure import Figure
import matplotlib.pyplot as plt
import numpy as np
import os
import matplotlib.mlab as mlab
class App:
def __init__(self, master, figureList=[]):
frame = Frame(master, bg='#00BFFF', borderwidth=1, relief=RAISED)
frame.pack(expand=YES, fill=BOTH)
master.title("Listed Plots")
#Fullscreen for windows
if os.name == 'nt':
master.wm_state('zoomed')
#Create a Canvas
canvas=Canvas(frame,bg='#00BFFF', relief=SUNKEN)
canvas.config(highlightthickness=0)
#Create a Scrollbar Horisontal
hbar=Scrollbar(frame,orient=HORIZONTAL)
hbar.pack(side=BOTTOM,fill=X)
hbar.config(command=canvas.xview)
#Create a Scrollbar Vertical
vbar=Scrollbar(frame,orient=VERTICAL)
vbar.pack(side=RIGHT,fill=Y)
vbar.config(command=canvas.yview)
canvas.config(xscrollcommand=hbar.set, yscrollcommand=vbar.set)
canvas.pack(side=TOP,expand=True,fill=BOTH)
#Create a Frame in the canvas
canvFrame = Frame(canvas, bg='#00BFFF')
canvFrame.pack()
Label(canvFrame, text="Matplots of data", bg='#B4EEB4').pack(side=TOP,fill=X)
plotNbr = 1
windowHeight = 10
for fig in figureList:
Label(canvFrame, text="#Plotnumber: " + str(plotNbr), bg='#FF7F24').pack(side=TOP,fill=X)
frm = Frame(canvFrame, bg='#9FB6CD')
frm.pack(side=TOP, fill=X)
self.canvasMPL2, self.canvasMPLToolBar2 = getCanvas(frm, fig)
self.canvasMPL2.pack(side=TOP)
self.canvasMPLToolBar2.pack(side=TOP)
#Create space for the plot and tool bar.
windowHeight = windowHeight + 680
plotNbr = plotNbr + 1
canvas.config(width=1200,height= windowHeight)
canvas.config(scrollregion=(0,0,1200, windowHeight))
canvas.create_window(0,0, anchor = NW, window = canvFrame, width = 1200, height = windowHeight)
canvas.focus_set() #Doesnt work with FigureCanvasTkAgg, this steals the focus
#canvas.focus_force()
#canvas.grab_set_global()
#scrollwheel settings
canvas.configure(yscrollincrement='25')
def rollWheel(event):
#print "Mousescroll"
direction = 0
if event.num == 5 or event.delta == -120:
direction = 1
if event.num == 4 or event.delta == 120:
direction = -1
event.widget.yview_scroll(direction, UNITS)
canvas.bind('<MouseWheel>', lambda event: rollWheel(event))
canvas.bind('<Button-4>', lambda event: rollWheel(event))
canvas.bind('<Button-5>', lambda event: rollWheel(event))
plottedFigures = [] #To store matplotlib figures
def addPlottedFig(figure):
'''
Matplotlib figures to be shown in the GUI
'''
plottedFigures.append(figure)
def getCanvas(masterWidget, figure=None):
'''
Returns canvas of plot and canvas of tool bar
'''
if(figure==None):
f = getHistoGramPlot() #For testing
canvas = FigureCanvasTkAgg(f, master=masterWidget)
else:
canvas = FigureCanvasTkAgg(figure, master=masterWidget)
canvas.show()
toolbar = NavigationToolbar2TkAgg( canvas, masterWidget )
toolbar.update()
#return the plot and the toolbar
return canvas.get_tk_widget(), canvas._tkcanvas
def initiate(FigureList=None):
'''
Start the GUI Application
'''
root = Tk()
app = App(root, FigureList)
root.mainloop()
def main():
'''
Shows 2 histograms plots in a tkinter GUI
'''
fig1 = getHistoGramPlot()
fig2 = getHistoGramPlot()
figList = [fig1, fig2]
initiate(figList)
def getHistoGramPlot():
'''
Return a figure of a histogram
'''
mu, sigma = 100, 15
x = mu + sigma * np.random.randn(10000)
fig = plt.figure(figsize=(12, 6), dpi=100)
ax = fig.add_subplot(111)
n, bins, patches = ax.hist(x, 50, normed=1, facecolor='green', alpha=0.6)
bincenters = 0.5*(bins[1:]+bins[:-1])
mu = np.median(x)
sigma = np.std(x)
y = mlab.normpdf( bincenters, mu, sigma)
l = ax.plot(bincenters, y, 'r--', linewidth=1)
ax.set_xlabel('Values')
ax.set_ylabel('Probability')
xlimTop = max(x)
xlimBottom = min(x)
ax.set_xlim(xlimBottom, xlimTop)
ax.grid(True)
return fig
if __name__ == '__main__':
main()
For a quick & dirty solution:
capture mousewheel events for all widgets inside the window.