Axes.autoscale_view() works when bound to tkinter '<KeyPress>' but not as ttk.Button command

Hello all,

very frustrating problem here that I’ve been trying to solve for about 12 hours, but I suspect the cause is more sophisticated than my skill level will allow me to diagnose.

I have a matplotlib + tkinter application that contains a routine in which an axes’ data limits are recomputed using Axes.relim() and then the view into the axes is scaled to match the new data limits using Axes.autoscale_view() before Canvas.draw_idle() is called.

The routine is bound to a tkinter '<KeyPress>' event on the root window, and is also passed as the argument to the command parameter of a ttk.Button widget.

Rather frustratingly, the routine exhibits the desired behaviour when the 'r' key is pressed, but does nothing when the ttk.Button is pressed, even though both invoke the exact same block of code.

I’ve confirmed the routine is being run when the button is pressed with a simple print() statement, so it seems that for some reason, one or both of Axes.relim() and Axes.autoscale_view() don’t work when invoked by a button.

My suspicion is that this has something to do with which widget has focus, as when I press the button (and nothing happens) if I then press 'r', nothing happens again! Despite the routine being run in both cases - as confirmed by the print statement.

If I click inside the figure canvas and then press 'r', the routine once again exhibits the desired behaviour.

I’ve included a minimal reproducible example below. If one zooms the view of the subplot and then presses 'r', the view is reset. If you zoom the view and press the 'reset' button, nothing happens, then press 'r', nothing happens again. Now click the canvas and press 'r' one more time and the view is reset.

I’ve tried setting/forcing the keyboard focus to the FigureCanvasTkAgg at the start of the routine with FigureCanvasTkAgg.get_tk_widget().focus_set() (and also .focus_force()) and then calling .update_idletasks() for good measure, but no dice :thinking:

Any help is much appreciated!

edit: sorry, forgot to add the MRE…

# imports
import tkinter as tk
from tkinter import ttk
from matplotlib import pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2Tk
from numpy import arange, pi, sin

# callback routine which relimits the axis values and autoscales the view
def resetView(*args):
    print(True)
    (axes, ) = fig.axes
    axes.relim()
    axes.autoscale_view()
    fig.canvas.draw_idle()

# figure/axes objects
fig, ax = plt.subplots()

# tk root window
root = tk.Tk()

# figure canvas + navigation toolbar
canvas = FigureCanvasTkAgg(fig, root); canvas.get_tk_widget().grid(row=0, column=0)
NavigationToolbar2Tk(canvas, root, pack_toolbar=False).grid(row=1, column=0)

# remaining tk widgets
ttk.Button(root, text='reset', command=resetView).grid(row=2, column=0)

# bind the callback routine to the 'r' key
root.bind('<KeyPress-r>', resetView)

# plot some data
x = arange(0, 2 * pi, 0.01)
ax.plot(x, sin(2 * pi * x) + 1)

# start the application mainloop
root.mainloop()
~