Update Canvas in Tkinter

I’m drawing a fig in a canvas inside a frame in Tkinter. The user can update the fig by selecting a new set of data from a drop-down and then click a button. Clicking the button triggers _make_graph() (see code below) which is also used to draw the initial fig.

Currently I destroy the widgets in the frame and recreate them meaning that the content of the whole frame has to be reloaded. It doesn’t look very nice in the gui when the whole fig disappears for a second and then comes back with the new data.

Is there some way I can just update the canvas with a new fig without having to destroy the content of the frame?

def _make_graph(self, ticker_data=None):

    self._get_ticker_data()
    
    try:
        for widgets in self.graph_frame.winfo_children():
            widgets.destroy()

    except AttributeError:
        pass

    self.fig, self.axlist = mpf.plot(self.ticker_df, type='candle', 
        title = f'{self.ticker_var.get()}',
        volume=True, style='binance', returnfig=True)
    
    self.canvas = FigureCanvasTkAgg(self.fig, self.graph_frame)

    self.toolbar = NavigationToolbar2Tk(self.canvas, self.graph_frame)

    self.toolbar.update()

    self.canvas.draw()

    self.canvas.get_tk_widget().pack()

Not tested, but I think something like:

# disconnect the old
old_fig = self.canvas.figure
old_fig.canvas = None
# connect the new
self.canvas.figure = new_fig
new_fig.canvas = self.canvas

is the right approach. For relatively new mpl the callbacks live on the Figure so you might need to sort out how to re-connect the toolbar without re-connecting it (the logic is in backend_bases.py).

I would also lobby @DanielGoldfarb for the ability to pass a figure into mpf.plot which would both solve this problem and would let mpf take advantage of the new SubFigure feature to do more complex layouts.