2

The accepted answer to this question provides a means of dynamically updating matplotlib plots in a Jupyter notebook when using the nbagg backend. However, this solution doesn't allow any interaction with the plots until after the loop has finished, which means you can only interact with the final version of the plot. Is it possible to interact with a dynamically updated figure after each update step?

What I'm trying to do is access matplotlib events (clicks in this case) on each of the images and then plot the next image after X number of clicks. The following code works with the qt backend, but I can't figure out how to convert it to work with nbagg instead. At the moment I can get either the event handling or the dynamic plotting to work, but not both simultaneously.

import numpy as np
import time
import matplotlib.pyplot as plt

n_img = 4
img = np.random.rand(20,20,n_img)
fig,ax = plt.subplots()
im = ax.imshow(img[:,:,0]) 

clicks = []
def onclick(event):
    clicks.append(('button=%d, x=%d, y=%d, xdata=%f, ydata=%f' %
          (event.button, event.x, event.y, event.xdata, event.ydata)))
cid = fig.canvas.mpl_connect('button_press_event', onclick)

i = 1
while i < n_img:
    plt.pause(0.01)
    time.sleep(0.1)
    if len(clicks) > 2:  # plot next image after 3 clicks
        clicks = []
        im.set_data(img[:,:,i])
        plt.draw()
        i += 1
Community
  • 1
  • 1
TPK
  • 31
  • 3

1 Answers1

2

You really should be not using loops while interacting with GUIs. That's what event handling is for. You do not need to be polling variables, just make the event handler perform the necessary actions.

This code works for me using TkAgg, GTK3Agg and nbagg backends:

n_img = 4
img = np.random.rand(20,20,n_img)
fig,ax = plt.subplots()
im = ax.imshow(img[:,:,0]) 

nclicks = 0
i = 0
plt.title('{} clicks - image #{}'.format(nclicks, i))

def onclick(event):
    global nclicks
    global i
    if nclicks < 2:
        nclicks += 1
    else:
        nclicks = 0
        i += 1
        im.set_data(img[:,:,i])
        if i == n_img - 1:
            fig.canvas.mpl_disconnect(cid)
    plt.title('{} clicks - image #{}'.format(nclicks, i))
    plt.draw()  # only necessary with some backends

cid = fig.canvas.mpl_connect('button_press_event', onclick)
Stop harming Monica
  • 12,141
  • 1
  • 36
  • 56