3

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()

1 Answer 1

1

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.

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.