Skip to content

Instantly share code, notes, and snippets.

@djwbrown
Last active April 11, 2022 10:24
Show Gist options
  • Save djwbrown/3e24bf4e0c5e9ee156a5 to your computer and use it in GitHub Desktop.
Save djwbrown/3e24bf4e0c5e9ee156a5 to your computer and use it in GitHub Desktop.
matplotlib.pyplot blackmagic to make CTRL-C work again
import sys
import matplotlib.pyplot as plt
try:
# Put matplotlib.pyplot in interactive mode so that the plots are shown in a background thread.
plt.ion()
while(True):
plt.show()
except KeyboardInterrupt:
print ""
sys.exit(0)
@jcmonteiro
Copy link

I had to change it to

while(True):
    plt.show(block=True)
    break

to make it work. Enabling blocking was necessary to actually show the plots and break to exit the loop in case the user clicks the close button.

@towry
Copy link

towry commented Jun 5, 2019

doesn't work.

@moooeeeep
Copy link

This is what I do to be able to exit the loop:

import matplotlib.pyplot as plt

def handle_close(evt):
    handle_close.stop = True
handle_close.stop = False

plt.ion()
plt.show(block=False)
plt.gcf().canvas.mpl_connect('close_event', handle_close)

while(True):
    if handle_close.stop:
        break
    plt.plot([0,1], [0,1])
    plt.gcf().canvas.flush_events()

plt.show()
plt.ioff()

Still doesn't react to KeyboardInterrupt though.

@normanius
Copy link

normanius commented Jun 7, 2021

My use-case involved updating a figure in a for-loop and exit the app once the user requests the termination. In the below example, the user can exit the loop prematurely in three ways:

  • Hit "e" or "q" (requires the figure to be the active window)
  • Close the figure via the close button
  • Interrupt by hitting CTRL+C or CMD+C in the console

The nice thing is that figure/axes can be reused over multiple iterations.

The code below requires python3+. I tested with matplotlib 3.4.1 and python3.8.

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

def test():
    def handle_key(event):
        if event.key in "eEqQ":
            nonlocal show
            show = False
            print("Stop on key press")
            return False

    def handle_close(event):
        nonlocal show
        show = False
        print("Stop on close")

    show = True
    t = np.linspace(0, np.pi, 100)
    fig, ax = plt.subplots()
    fig.canvas.mpl_connect("key_release_event", handle_key)
    fig.canvas.mpl_connect("close_event", handle_close)
    for i in np.linspace(1,10,101):
        if show:
            try:
                ax.clear()
                ax.plot(t, np.sin(i*t))
                # Return values of waitforbuttonpress():
                #   - True if key was pressed
                #   - False if mouse button was pressed
                #   - (None if timeout was reached without event)
                fig.canvas.draw()
                while not fig.waitforbuttonpress() and show:
                    pass
                fig.canvas.flush_events()
            except KeyboardInterrupt:
                print("Stop on interrupt")
                show = False
    plt.close(fig)
    print("Exit normally")

test()

@fospald
Copy link

fospald commented Apr 11, 2022

More simple solution: Add at beginning of your program

import signal
signal.signal(signal.SIGINT, signal.SIG_DFL)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment