3

I want a user input and then stop the loop with a specific keyboard press.

from __future__ import print_function
import sys
import numpy as np
import matplotlib.pyplot as plt


def press(event):
    print('press', event.key)
    sys.stdout.flush()
    if event.key == 'x':
       visible = xl.get_visible()
       xl.set_visible(not visible)
       fig.canvas.draw()
    if event.key == 'enter':
       cnt.append(1)

cnt=[]
List=[]
fig, ax = plt.subplots()

fig.canvas.mpl_connect('key_press_event', press)

ax.plot(np.random.rand(12), np.random.rand(12), 'go')
xl = ax.set_xlabel('easy come, easy go')
ax.set_title('Press a key')
plt.show()
plt.waitforbuttonpress() #non specific key press!!!

result=cnt[0]+cnt[1]

I want to stop the loop, wait for the user to press enter and then continue the code using the cnt after. But if I do not put plt.waitforbuttonpress(), the code runs and finishes, but if I put plt.waitforbuttonpress() any keyboard or mouse press will run and end the entire code.

user5960525
  • 59
  • 1
  • 1
  • 6
  • Which loop do you want to stop? You mean the event loop which runs to allow user input or an outer loop not shown above? Your example runs for me, turning axis on and off with x. Nothing happens for enter as it should be `enter` in lower case (`interval` is also not defined). – Ed Smith Feb 26 '18 at 09:44
  • I want to use the user input and do some code after the input: result=cnt[0]+cnt[1] – user5960525 Feb 26 '18 at 11:33
  • The code is working as expected for me, you create a figure which should block at the `plt.show` command. I do not need the `plt.waitforbuttonpress()` as the `mpl_connect('key_press_event'` has started an event handle. It may be an issue with your matplotlib or backend. Does using `plt.show(block=True)` help? Also add `plt.ioff()` (turn off interactive mode). – Ed Smith Feb 26 '18 at 12:16

1 Answers1

3

The code is working as expected for me (matplotlib version 2.0.0 and TkAgg backend) You create a figure which should block at the plt.show command.

If not, try matplotlib.use("TkAgg") to change backend (see order here)

You then have a few options,

1) Include the code you want to run in the event handling loop, either after the event you have or maybe under a special key.

import numpy as np
import matplotlib.pyplot as plt

def press(event):
    print('press', event.key)
    if event.key == 'enter':
        cnt.append(1)
    if event.key == 'a':
        result = sum(cnt)
        print(result, cnt)

cnt=[]
fig, ax = plt.subplots()
fig.canvas.mpl_connect('key_press_event', press)
ax.plot(np.random.rand(12), np.random.rand(12), 'go')
plt.show()

when you press a you get assuming enter has been pressed 8 times when you press a. (8, [1, 1, 1, 1, 1, 1, 1])

2) Add an escape command to exit the figure (you may need to work out the best way to exit gracefully)

import numpy as np
import matplotlib.pyplot as plt

def press(event):
    print('press', event.key)
    if event.key == 'enter':
        cnt.append(1)
    if event.key == "escape":
        plt.close()

cnt=[]
fig, ax = plt.subplots()
fig.canvas.mpl_connect('key_press_event', press)
ax.plot(np.random.rand(12), np.random.rand(12), 'go')
plt.show()
result = sum(cnt)
print(result, cnt)

the command after plt.show() should then be run.

3) Set a timeout for the event loop and your code will be run after this time.

import numpy as np
import matplotlib.pyplot as plt

def press(event):
    print('press', event.key)
    if event.key == 'enter':
        cnt.append(1)

cnt=[]
fig, ax = plt.subplots()
fig.canvas.mpl_connect('key_press_event', press)
ax.plot(np.random.rand(12), np.random.rand(12), 'go')
plt.show(block=False)
plt.waitforbuttonpress()
plt.pause(5.)
result = sum(cnt)
print(result, cnt)

It looks like plt.waitforbuttonpress(time=5.) should do something similar but I could not get this to work.

Ed Smith
  • 12,716
  • 2
  • 43
  • 55
  • For some reason the `key_press_event` doesn't seem to allow me to perform `ax.imshow` if I have `ax` available inside the handler. Nothing changes in the figure. – CMCDragonkai Feb 07 '19 at 04:04
  • Hi @CMCDragonkai, may be worth a new question with version of matplotlib, etc – Ed Smith Feb 07 '19 at 08:41
  • Thanks for this @Ed Smith. Your code works fine for me, but when I change cnt from a list to an int it fails. (I changes cnt=[] to cnt=0 and cnt.append(1) to cnt+=1). Do you have any idea why this is? When I hit enter I get "UnboundLocalError: local variable 'cnt' referenced before assignment" – Blitzer May 25 '22 at 06:52
  • I think you need to make sure cnt is defined before you register the event 'fig.canvas.mpl_connect' which might use it, but without seeing the code difficult to know – Ed Smith May 26 '22 at 09:11