user169808
user169808

Reputation: 533

multiprocessing show matplotlib plot

I'm trying to open up multiple plots but I ran into a few problems. When I tried to create plots using threading, python would first open a number of windows, then close all but the first.

In another question it was recommended that I use multiprocessing which I have tried. The code runs without error, it just doesn't show any plot.
I'm trying to get something very simple to work before moving on to my main project.

# Import the necessary packages and modules
import matplotlib.pyplot as plt
import numpy as np


#from threading import Thread
import multiprocessing

def plot(datax, datay, name):
    # Prepare the data
    x = datax
    y = datay**2
    # Plot the data
    plt.scatter(x, y, label=name)

    # Add a legend
    plt.legend()

    # Show the plot
    plt.show()



#plot(3,3,)
'''
for i in range(10):
    t = Thread(target=plot, args=(i,i+1,i,))
    t.start()
    '''
for i in range(2):
    p = multiprocessing.Process(target=plot, args=(i, i, i))
    p.start()

update: for some reason, multiprocessing stopped working again. I tried creating a function multiP() only to open the processes but it didn't work when I added the input('value: '). scine I can't figure out how to send data to a specific thread I'm going to save data like this: dat = [[x,y0,y1,...yn],[x,y0,y1,...yn],...] and each plot process with check the if something was added to dat.

import matplotlib.pyplot as plt
import numpy as np

import multiprocessing
#multiprocessing.freeze_support() # <- may be required on windows

def plot(datax, datay, name):
    x = datax
    y = datay**2
    plt.scatter(x, y, label=name)
    plt.legend()
    plt.show()

def multiP():
    if __name__ == "__main__":   
        for i in range(2):
            p = multiprocessing.Process(target=plot, args=(i, i, i))
            p.start()
if True:
    #input('Vlaue: ') # while commented plots are shown
    multiP()

Upvotes: 5

Views: 15821

Answers (2)

hugo
hugo

Reputation: 31

Taking ImportanceOfBeingErnest answer, I leave below an implementation which only shows one window and waits for the window to close, which can be very handy. Every time it is called, it displays a new window with the corresponding image (a new pocess will be started for each image). I used a lot to view images when stopped at some breakpoint during debug.

# Library packages needed
import numpy as np
import datetime
import sys
import queue
import multiprocessing

# Plot related packages
import matplotlib.pyplot as plt


def showImage(img: np.ndarray, title: str = str(datetime.datetime.today())):
    """Show an image in a new process without blocking. Usefull for debugging.

    Args:
        img (np.ndarray): Image to be shown
        title (str, optional): Title to be shown. Defaults to
    str(datetime.datetime.today()).
    """

    def plot(q, title):
        fig = plt.figure()
        fig.suptitle(title)
        try:
            q.get(True, 2.0)  # Wait a couple of seconds
        except queue.Empty:
            print('Not image received to plot...quitting')
            sys.exit()

        plt.imshow(img)
        plt.show()
        sys.exit()

    # Create a queue to share data between process
    q = multiprocessing.Queue()

    # Create and start the process
    proc = multiprocessing.Process(None, plot, args=(q, title))
    proc.start()
    q.put(img)

To run it, just save this to a show_image.py file and call

from show_image.py import showImage
show_image(img, title)

Upvotes: 0

ImportanceOfBeingErnest
ImportanceOfBeingErnest

Reputation: 339755

The following code produces two figures as desired.

import matplotlib.pyplot as plt
import numpy as np

import multiprocessing
#multiprocessing.freeze_support() # <- may be required on windows

def plot(datax, datay, name):
    x = datax
    y = datay**2
    plt.scatter(x, y, label=name)
    plt.legend()
    plt.show()

def multiP():
    for i in range(2):
        p = multiprocessing.Process(target=plot, args=(i, i, i))
        p.start()

if __name__ == "__main__": 
    input('Value: ') 
    multiP()

Upvotes: 4

Related Questions