Reputation: 438
I have a matplotlib graph embedded in a tkinter interface with FigureCanvasTkAgg and the entire thing is within a class.
I want to get a data coordinate of a mouse click (the purpose would be to place a point on that mouse click) and so far nothing works. I've tried two options: using .bind directly on widget of canvas, and using figure.canvas.mpl_connect.
If I go with the first option, using .bind on widget of canvas, I can access event.x and event.y, but not event.xdata and event.ydata - which is understandable. Then I need to transform event.x and event.y with ax.transData.inverted().transform(()) - the problem here is that Y coordinate is inverted because in widget, y coordinate increases downwards, while in figure the y coordinate increases upwards. Eg. 0.6 where 0.4 should be. Also, behaves funky when I click outside of axes.
If I go with second option, using figure.canvas.mpl_connect, which should get me straight data coordinate with event.xdata and event.ydata, nothing happens.
Code is below:
Imports
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import tkinter as tk
from matplotlib.figure import Figure
import matplotlib
Function that creates a figure, and returns it:
def figure_create():
fig=Figure(figsize=(10,10))
ax=fig.add_subplot(111)
return(fig)
My class
class GToplevel()
def __init__(self,data=None):
self.master=tk.Toplevel()
figure=figure_create() #creates a figure
canvas=FigureCanvasTkAgg(figure,master=self.master) #creates a canvas
self.figure=figure
self.canvas=canvas
widget=canvas.get_tk_widget()
widget.pack()
canvas.draw() #draws canvas
#FIRST OPTION
#widget.bind("<Button-1>",self.click_coordinate) #binds the click to a function
#Y coordinate is inverted
#SECOND OPTION
#figure.canvas.mpl_connect('button_press_event', self.click_coordinate)
#nothing seems to happen
def click_coordinate(self,event):
x=event.x #x coordinate of event, not Data
y=event.y #y coordinate of event, not Data
print(x,y) #checking that the coordinates are right
canvas=self.canvas
figure=self.figure
ax=figure.get_axes()[0] #the only subplot of a figure
inv = ax.transData.inverted()
x,y=inv.transform((x,y)) #turns x,y into Data coordinates
canvas.draw()
Upvotes: 3
Views: 971
Reputation: 438
The answer was outside of class. Rewriting code:
class GToplevel():
def __init__(self,data=None):
self.master=tk.Toplevel()
figure=figure_create() #creates a figure
canvas=FigureCanvasTkAgg(figure,master=self.master) #creates a canvas
self.figure=figure
self.canvas=canvas
widget=canvas.get_tk_widget()
widget.pack()
canvas.draw() #draws canvas
figure.canvas.callbacks.connect('button_press_event', self.callback)
def callback(self,event):
x=event.xdata
y=event.ydata
print(x,y)
I can access data coordinates directly by using event.xdata and event.ydata, but figure.canvas.callbacks.connect must be called. This didn't work, because my main code was :
root=tk.Tk()
GToplevel()
root.mainloop()
But when I modified second line like this:
g=GToplevel()
Everything worked.
I have no idea why is that so, but this fixes my question.
Upvotes: 1