Search code examples
pythonmatplotlibwhile-loopraspberry-piexit

Exiting live plotting with a key press


I have made a program that plots data from a network analyzer live. The plotting of the graph is inside a while loop. The program does not stop plotting unless the program is closed. I want a program that closes the graphs (breaks the while loop) when I press a button on my keyboard. I do not want to use input because then the code would wait for the input. The code should run smoothly until the button is pressed. I am running the program in Thonny on a raspberry pi.

import matplotlib.pyplot as plt

plt.ion()

x_data= []
y_data= []

graph= plt.plot(x_data,y_data)

while True:

  do something


  graph.set_ydata(y_data)
  graph.set_xdata(x_data)
  plt.draw()
  plt.pause(0.01)

Note this is not the code, just a small example; the problem does not lie in the plotting but in trying to break the loop.


Solution

  • Considering that this code needs to run on a Raspberry...
    Using the keyboard module may not be a good idea, since on Linux, the execution of your program may suddenly demand root access in order to interact with the device drivers and listen for keyboard events.
    To make the command "sudo python my_script.py" works, further adjustment might be necessary.

    Therefore, here is my simple solution that exploits threading and the std input() function, to avoid using the keyboard library and closing the python program.

    As suggested by @jared, it is better to choose an arbitrary key to achieve the desired result, not whatever key.

    Snippet:

    import matplotlib.pyplot as plt
    import threading
    
    # Empty data for now
    x_data = []
    y_data = []
    
    ############## Plotting 
    # Enable the interactive mode for plotting
    plt.ion() 
    # The comma after "graph" is fundamental to unpack the first element of the returned tuple 
    # and assigning it to the variable graph.
    # (Without the comma, graph would be assigned to the entire tuple)
    graph, = plt.plot(x_data, y_data)
    
    def keyboard_input():
        """ It is not necessary to specify the 'q' key, 
        since input() waits for the user to enter a value and press enter,  
        but if the value entered is "q", the function return and then the subsequent code is executed.
        """
        input()
        plt.close()
    
    # Start the thread that execute the keyboard input method
    thread = threading.Thread(target=keyboard_input)
    thread.start()
    
    # Display the plot. It is constantly updated in real-time as new data can be, someway, added to x_data and y_data
    while True:
        graph.set_ydata(y_data)
        graph.set_xdata(x_data)
        plt.draw()
        plt.pause(0.01)
        # Check if the plot window (with the specified figure number 1, the default value) has been closed, 
        # Otherwise, waits for the thread object to complete the join() method and exit
        if not plt.fignum_exists(1):
            thread.join()
            break