Search code examples
pythonmultiprocessing

Python - Is there a way to print data to the command window continuously and allow user to open a graph multiple times using multiprocessing?


In Python, I would like to have the main output windows printing output continuously but also launch a matplotlib graph that shows the same data in a parallel process. I want the user to be able to close the graph and re-open as they wish but always have the output window printing the new data without pausing. I want it to be a parallel process because I want the main output window to keep updating.

I am new to Python and multiprocessing so apologies if I am not explaining things precisely.

__

Whenever I run the example script below and close the graph, the main output window asks if I want to restart the graph, as expected, but when I type 'y', I get an error that I cannot restart the process:

assert self._popen is None, 'cannot start a process twice'
AssertionError: cannot start a process twice`

Example script.

import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
from multiprocessing import Process, Pipe
import multiprocessing
import time
import random


# Shows matplotlib graph that updates based on "generate_data" function
def show_graph(connection):
   
    fig, ax = plt.subplots()
    line, = plt.plot([], [], 'r-')

    def init():
        ax.set_xlim(0, 30)
        ax.set_ylim(0, 30)
        return line,

    def update(frame):
        [x,y] = connection.recv()
        line.set_data(x, y)
        return line,

    ani = FuncAnimation(fig, update, frames=None, init_func=init, blit=True)
    plt.show()
    
    
# Function that obtains data to plot 
def generate_data():
    x = random.sample(range(0, 30), 20)
    y = random.sample(range(0, 30), 20)
    return x, y



if __name__ == "__main__":

    parent_conn, child_conn = Pipe()
    plot_process = multiprocessing.Process(target=show_graph, args=(child_conn,))
    plot_process.start()
    
    while True:
        time.sleep(0.5)
        x, y = generate_data()

        # Display data in main output window
        print(x)
        print(y)
        
        if plot_process.is_alive():
            parent_conn.send([x,y])
        else:
            name = input("Graphing process is dead! Restart graph?") 
            if name == "y":
                plot_process.start()


Solution

  • As the error says, you cannot start the same process twice. You should terminate it so that you can start it again with plot_process.terminate() and wait for it to actually terminate with plot_process.join() before starting it again.

    if name == "y":
        plot_process.terminate()
        plot_process.join()
        plot_process = multiprocessing.Process(target=show_graph, args=(child_conn,))
        plot_process.start()