3

I read a lot of stack overflow questions regarding this topics but after a lot of experiment I can't figure out my problem.

I use PyCharm 2016.3.2 on Windows 7 (but I have the same issue on OSX), my interpreter is the last version of Anaconda with Python 3.6 and matplotlib 2.0.0.

Here is what I try to achieve (and maybe I am not using the right approach because I am trying to recreate the behavior I am use to in Octave/Matlab) :

  1. Plot one figure in a popup windows
  2. Pause my script (input("press a key to continue"))
  3. Observe the figure, then press a key to continue the script
  4. Compute something else
  5. Plot new data on the same figure
  6. Pause my script (input("press a key to continue"))
  7. Observe the figure, then press a key to continue the script

Here is my test code :

import matplotlib
matplotlib.use('TkAgg')
import matplotlib.pyplot as plt

print('Plotting Data...')

plt.ion()
plt.figure(1)
plt.plot([1, 5, 10, 20], [1, 5, 10, 20])
plt.xlabel('x label')
plt.ylabel('y label')
plt.show()
plt.pause(0.0001)

input('Plotting Data done..., Press a key to continue')

plt.figure(1)
plt.plot([1, 5, 10, 20], [2, 10, 20, 40])
plt.show()
plt.pause(0.0001)

input('Program paused. Press enter to end.\n')

This is the closest version of what I want, the plots are correct but not responsive when I mouse over them (plt.pause(0.0001) generates a warning but code works).

I played a lot with parameters (plt.ion() ; plt.pause() ; plt.show(block=False)). Most of the time, this led to empty plot windows or I needed to close the window to continue the execution.

Thanks for your help !

Capy
  • 55
  • 2
  • 9
  • You cannot work in two different event loops at once. Why can't you just plot everything the normal way and use the closure of the window as the trigger for continuation of the program? – ImportanceOfBeingErnest Feb 06 '17 at 20:19
  • 1
    The normal way ? If I use the closure of the windows as the trigger to continue, even when I recall figure(1), I can't find a way to plot a second element on top of the 1st one (without redo a plt.plot with the first dataset). But sometimes I just want to do multiple plots and let them all open until the end of the execution. Thanks! – Capy Feb 06 '17 at 20:35
  • @ImportanceOfBeingErnest This post is looking at the same issue [Similar question](http://stackoverflow.com/questions/28269157/plotting-in-a-non-blocking-way-with-matplotlib) and it basically uses the same workaround with a pause (figures are plotted correctly but unresponsive) – Capy Feb 07 '17 at 02:20
  • So does the accepted answer from the linked question work for you? In my case it does the same as here: the input blocks the window event loop, which thereby becomes unresponsive. – ImportanceOfBeingErnest Feb 07 '17 at 07:37
  • @ImportanceOfBeingErnest You are right, I have the behavior, plots are correct but in an unresponsive windows. I think trying to mimic what Matlab does is not the right approach. So I can either do it in non-interactive mode and wait for all the data before plotting everything in one figure (then close it) or save figures in files if I want to review all of them at the end of the execution. Thanks a lot for your help! – Capy Feb 07 '17 at 13:31
  • It really depends on the application. But in any case, if you have a calculation that does not take long time to run, you can simply plot all relavant figures at the end and if you have a calculation which does take a long time, you wouldn't want it to be interrupted anyways. – ImportanceOfBeingErnest Feb 07 '17 at 16:55

1 Answers1

0

Once plt.show() is called the main loop is taken over by the Window. Therefore, as soon as input get's called, the main loop becomes unresponsive.

You could try to stay in the GUI loop and handle the key press there.

import matplotlib
matplotlib.use('TkAgg')
import matplotlib.pyplot as plt

print('Plotting Data...')

fig, ax = plt.subplots()
ax.set_xlabel('x label')
ax.set_ylabel('y label')
i=[0]

def f1():
    ax.plot([1, 5, 10, 20], [1, 5, 10, 20])

def f2():
    ax.plot([1, 5, 10, 20], [2, 10, 20, 40])

def f3():
    ax.plot([1, 5, 10, 20], [5, 9, 17, 28])


def update(event=None):
    if i[0]==0: f1()
    if i[0]==1: f2()
    if i[0]==2: f3()
    fig.canvas.draw_idle()
    i[0]+=1
    print('Step {} done..., Press a key to continue'.format(i[0]))

fig.canvas.mpl_connect("key_press_event", update)    

update()
plt.show()
ImportanceOfBeingErnest
  • 321,279
  • 53
  • 665
  • 712
  • Thanks for this answer. I'm getting familiar with the pyplot OO synthax and will have to understand darw_idle a bit more.
    Another way of doing this would be to call again a closed plot (either to display it again as it was initially or add data to display new data in addition to initial one) but I don't understand yet how to do that
    – Capy Feb 06 '17 at 22:41