1

I have a function which plots a figure

import matplotlib.pyplot as plt


def myplot(x, y):
    plt.figure()
    plt.plot(x, y)
    plt.show()


myplot([1, 2, 3], [4, 5, 6])
myplot([1, 2, 3], [4, 5, 6])

However after I run the script only one figure shows up, and the second one shows when I close the first figure. I can move plt.show() into main function which calls myplot and this works fine, but I still want a better way, just like plot in Matlab. Thank you in advance.

7
  • the answer depends on how you are going to run python, are you running it in a terminal ? or what IDE you are using and how are you running your code from it ? i am guessing it is ran through an interactive session of an IDE like how IDLE runs but that's just speculation. Commented Oct 24, 2022 at 9:48
  • 3
    If you want to see both lines at the same time then "the better way" is to move plt.show() into main. Commented Oct 24, 2022 at 9:52
  • @AhmedAEK Thank you for response, the ultimate purpose is to import this .py as a module. This function has an argument isPlot, if isPlot==False, returns some values calculated from the input and if True plot a figure. I'm running python via VSCode just simply pressing F5. Commented Oct 24, 2022 at 11:02
  • @DSPnovice then in that case the first part of my answer will fit your requirements, as it detaches the plot, allowing it to be ran inside any code without restrictions, except on the ability to modify it. Commented Oct 24, 2022 at 11:04
  • @furas Thank you. As I commented above, I want to import this function in other script. So if I move the plt.show() outside my function, I need import matplotlib in the upper script, which is much more inconvenient. Commented Oct 24, 2022 at 11:04

1 Answer 1

1

this is not a simple thing, as Matlab is already running a GUI eventloop, while for python ... it depends on the IDE, for example Spyder will run it similar to Matlab as it is running an event loop, while Pycharm / VScode don't allow python to snatch their event loop, and jupyter notebook is running an asyncio server which sends the data to your browser so it can do it but it's not the same as Matlab .... so it depends on your IDE.

now assuming that you are running an interactive session inside your terminal ... or any IDE like IDLE, you can create another process that will be running that eventloop using loky, that has to run inside a thread ...

import matplotlib.pyplot as plt
import threading
from loky import ProcessPoolExecutor
import traceback

def myplot(*args,**kwargs):
    thread = threading.Thread(target=threaded_func,args=args,kwargs=kwargs,daemon=False)
    thread.start()

def threaded_func(*args,**kwargs):
    try:
        with ProcessPoolExecutor(max_workers=1) as executor:
            res = executor.submit(plotting_func,*args,**kwargs)
            res.result()
    except RuntimeError as e:
        pass

def plotting_func(*args,**kwargs):
    try:
        plt.figure()
        plt.plot(*args,**kwargs)
        plt.show()
    except Exception as e:
        traceback.print_exc()

myplot([1, 2, 3], [4, 5, 6])
myplot([1, 2, 3], [4, 5, 6])

this is obviously not perfect as you can only modify your plots inside your plotting_func, not inside your interactive code as Matlab does, and while there are ways to get some code working as expected, it really depends on the exact use-case, not a generic code like yours.

for example you can have matplotlib running a temporary eventloop in interactive mode.

import matplotlib.pyplot as plt
plt.ion()  # activate interactive mode

def myplot(x, y):
    plt.figure()
    plt.plot(x, y)
    plt.show()


myplot([1, 2, 3], [4, 5, 6])
myplot([1, 2, 3], [4, 5, 6])
plt.pause(5)  # run eventloop for 5 seconds

now everytime you want the plot to update you just call

plt.pause(5)

which will run the eventloop for 5 seconds for you to inspect the plot, and you can interactively modify it like matlab, but this is just a band-aid, and you have to think about writing python code that's not mirrored matlab code.

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

2 Comments

Thank you for your answer. I tried the first part of your answer but _register_atexit() in threading.py raises a runtime error "can't register atexit after shutdown".
@DSPnovice check again, i have fixed that issue, it was because you were not running it in interactive mode, i also modified plotting_func to act just like plt.plot so users can pass in some decorators, but it's up to you to change it

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.