user779446 user779446 - 1 month ago 46
Python Question

Plotting in a non-blocking way with Matplotlib

I have been playing with Numpy and matplotlib in the last few days. I am having problems trying to make matplotlib plot a function without blocking execution. I know there are already many threads here on SO asking similar questions, and I 've googled quite a lot but haven't managed to make this work.

I have tried using show(block=False) as some people suggest, but all I get is a frozen window. If I simply call show(), the result is plotted properly but execution is blocked until the window is closed. From other threads I 've read, I suspect that whether show(block=False) works or not depends on the backend. Is this correct? My back end is Qt4Agg. Could you have a look at my code and tell me if you see something wrong? Here is my code. Thanks for any help.

from math import *
from matplotlib import pyplot as plt
print plt.get_backend()



def main():
x = range(-50, 51, 1)
for pow in range(1,5): # plot x^1, x^2, ..., x^4

y = [Xi**pow for Xi in x]
print y

plt.plot(x, y)
plt.draw()
#plt.show() #this plots correctly, but blocks execution.
plt.show(block=False) #this creates an empty frozen window.
_ = raw_input("Press [enter] to continue.")


if __name__ == '__main__':
main()


PS. I forgot to say that I would like to update the existing window every time I plot something, instead of creating a new one.

Answer

I spent a long time looking for solutions, and found this answer.

It looks like, in order to get what you (and I) want, you need the combination of plt.ion(), plt.show() (not with blocking=False, that's deprecated) and, most importantly, plt.pause(.001) (or whatever time you want). I think this is because it tries to mimic optimizations in MATLAB that cause it to delay drawing any changes to the graph unless there is a set time (pause) that will mean that whatever is displayed will actually be viewed. It's possible that this is implemented by picking up time from a sleeping thread, so maybe IDEs mess with that—I don't know.

Here's an implementation that works for me on python 3.5:

import numpy as np
from matplotlib import pyplot as plt

def main():
    plt.axis([-50,50,0,10000])
    plt.ion()
    plt.show()

    x = np.arange(-50, 51)
    for pow in range(1,5):   # plot x^1, x^2, ..., x^4
        y = [Xi**pow for Xi in x]
        plt.plot(x, y)
        plt.draw()
        plt.pause(0.001)
        input("Press [enter] to continue.")

if __name__ == '__main__':
    main()