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.

3
  • 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). Commented Feb 26, 2018 at 9:44
  • I want to use the user input and do some code after the input: result=cnt[0]+cnt[1] Commented Feb 26, 2018 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). Commented Feb 26, 2018 at 12:16

1 Answer 1

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.

Sign up to request clarification or add additional context in comments.

4 Comments

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.
Hi @CMCDragonkai, may be worth a new question with version of matplotlib, etc
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"
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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.