pythonmatplotlib

How to redraw figure on event in matplotlib?


I'm trying to pre-generate and store matplotlib figures in python, and then display them on a keyboard event (left-right cursor keys).
It partially seems working, but fails after the first keypress.
Any idea, what am I doing wrong?

import matplotlib.pyplot as plt
import numpy as np


def new_figure(title, data):
    fig,ax = plt.subplots() 
    plt.plot(data, label=title) 
    ax.set_xlabel('x-axis')
    ax.set_ylabel('value')
    plt.legend()
    plt.title(title)
    plt.close(fig)
    return fig


def show_figure(fig):
    dummy = plt.figure() 
    new_manager = dummy.canvas.manager 
    new_manager.canvas.figure = fig 
    fig.set_canvas(new_manager.canvas) 


def redraw(event, cnt):
    event.canvas.figure.clear()
    dummy = event.canvas.figure
    new_manager = dummy.canvas.manager
    new_manager.canvas.figure = figs[cnt]
    figs[cnt].set_canvas(new_manager.canvas)
    event.canvas.draw()


def keypress(event):
    global cnt
    if event.key == 'right':
        cnt += 1
        cnt %= mx
    elif event.key == 'left':
        cnt -= 1
        if cnt < 0:
            cnt = mx-1
    redraw(event, cnt)


d = range(0, 360)
data = []
data.append(np.sin(np.radians(d)))
data.append(np.cos(np.radians(d)))
data.append(np.tan(np.radians(d)))
titles = ['sin','cos','tan']
mx = len(data)

figs = []
for i in range(mx):
    fig = new_figure(titles[i], data[i])
    figs.append(fig)

cnt = 0

show_figure(figs[0])
figs[0].canvas.mpl_connect('key_press_event', keypress)
plt.show()

The error I get eventually is:

  File "C:\Program Files\Python39\lib\tkinter\__init__.py", line 1636, in _configure
    self.tk.call(_flatten((self._w, cmd)) + self._options(cnf))
_tkinter.TclError: invalid command name ".!navigationtoolbar2tk.!button2"

Solution

  • Not sure about the root cause of the error, but one way to avoid this is to fully replace the figure and reconnect the key_press_event:

    def redraw(event, cnt):
        event.canvas.figure = figs[cnt]
        event.canvas.mpl_connect('key_press_event', keypress)
        event.canvas.draw()