I have built a simple matplotlib plotting GUI in python using tkinter. Now I would like to to ginput to obtain coordinates from the plot. Unfortunately I keep receiving the following errors:
AttributeError: 'FigureCanvasTkAgg' object has no attribute 'manager'
Figure.show works only for figures managed by pyplot, normally created by pyplot.figure().
It seems that ginput doesn't work well with tkinter, I can get this code to work just fine if I don't use tkinter and simply produce a plot window from the command line.
I know there is an alternative way to do this sort of thing with event picking functions from matplotlib but I can't seem to translate the examples I've seen towards this functionality. Can anyone walk me through this?
import numpy as np
from matplotlib.pyplot import *
from Tkinter import *
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2TkAgg
class App:
def __init__(self, master):
global frame
frame = Frame(master)
frame.pack(side=TOP)
self.quitbutton = Button(frame, text="QUIT", fg="red", command=frame.quit)
self.quitbutton.grid(row=4,column=0,sticky=W)
self.hi_there = Button(frame, text="LOAD",command=self.loadfile)
self.hi_there.grid(row=0,column=0,sticky=W)
self.cutbutton = Button(frame, text="CUT", fg="purple",command=self.cut)
self.cutbutton.grid(row=1,column=0,sticky=W)
global canvas, ax, f
f = Figure(figsize=(20,4))
ax = f.add_subplot(111)
ax.set_xlabel('Time(s)',fontsize=20)
ax.set_ylabel('Current(nA)',fontsize=20)
canvas = FigureCanvasTkAgg(f, master=root)
canvas.show()
canvas.get_tk_widget().pack(side=BOTTOM, fill=BOTH, expand=1)
toolbar1 = NavigationToolbar2TkAgg( canvas, root )
toolbar1.update()
f.tight_layout()
def loadfile(self):
ax.clear()
self.data=rand(1000)
self.t=np.arange(0,len(self.data))
##############################################plot data
self.baseline=np.median(self.data)
self.var=2*std(self.data)
ax.plot(self.t,self.data,'b')
ax.set_xlabel('Time(s)',fontsize=20)
ax.set_ylabel('Current(nA)',fontsize=20)
ax.axhline(linewidth=2, y=self.baseline, color='g')
ax.set_xlabel('Time(s)',fontsize=20)
ax.set_ylabel('Current(nA)',fontsize=20)
canvas.draw()
def cut(self):
pts=np.array(f.ginput(2))
pts=pts[:,0]
print pts
self.data=np.delete(self.data,pts)
ax.clear()
self.baseline=np.median(self.data)
self.t=np.arange(0,len(self.data))
ax.plot(self.t,self.data,'b')
ax.axhline(linewidth=2, y=self.baseline, color='g')
canvas.draw()
root = Tk()
app = App(root)
root.mainloop()
root.destroy()
EDIT: it seems that the problem is in the distinction between Figure and figure
ginput seems to work with figure() but not Figure(). And tkinter only works with Figure...
is there a workaround for this?
Once you are inside python/Tkinter
.mainloop()
, base your Tkinter
GUI input on mouse-click Event, rather than on MATLAB/pyplot
.ginput()
No serious control-system ( and the Tkinter .mainloop()
is a pretty serious one ) likes to handover it's control-reins to any other, competing ( == blocking ) sub-system.
Tested to work with:
class App( Frame ): # The user interface:
def __init__( self, master = None ):
Frame.__init__( self, master )
self.fig = Figure( ( 6, 6 ), dpi = 100 )
canvas = FigureCanvasTkAgg( self.fig, master = self )
# ---------------------------------------------------# cover Tk.root
self.bind( "<Button-1>", # Tk Event type
self.showXY_handler # handler 2 call
)
# ----------------------------------------------------------------------
canvas.get_tk_widget().grid( row = 0, # this adds a plot
column = 0, # on Tk.root .grid()
columnspan = 4 # geometry manager
)
# ---------------------------------------------------cover graph area
canvas.get_tk_widget().bind( "<Button-1>",
self.showXY_handler
)
# -----------------------------------------------------------
#FINALLY THE INTERFACE TO A DEMO-HANDLER METHOD:
def showXY_handler( self, aHandledEVENT ):
print aHandledEVENT.x, aHandledEVENT.y
You may also rather use Class instance variables rather than global
-s
# global canvas, ax, f # rather to be avoided use of global-s
self.canvas = # instance variables, Class-wide visible
self.ax =
self.f =