MatPlotLib's ion() and draw() not working

23,855

Solution 1

Adapted for your case from : Python realtime plotting

import matplotlib.pyplot as plt
import numpy as np
import time

fig = plt.figure()
ax = fig.add_subplot(111)

# some X and Y data
x = [0]
y = [0]

li, = ax.plot(x, y,'o')

# draw and show it
fig.canvas.draw()
plt.show(block=False)

# loop to update the data
for i in range(100):
    try:
        x.append(i)
        y.append(i)

        # set the new data
        li.set_xdata(x)
        li.set_ydata(y)

        ax.relim() 
        ax.autoscale_view(True,True,True) 

        fig.canvas.draw()

        time.sleep(0.01)
    except KeyboardInterrupt:
        plt.close('all')
        break

Solution 2

This solution example has worked for me on multiple machines. Try adjusting plt.pause(...)

import matplotlib.pyplot as plt
import numpy as np

F = lambda x: np.sin(2*x)

plt.ion()    
x = np.linspace(0, 1, 200)
plt.plot(x, F(x))


for i in range(100):
    if 'ax' in globals(): ax.remove()
    newx = np.random.choice(x, size = 10)
    ax = plt.scatter(newx, F(newx))
    plt.pause(0.05)

plt.ioff()
plt.show()

Solution 3

Hey I was having the same problem, I checked other questions and my issue was solved when I plugged a pause into my solution. Here's some example code that worked for me.

import matplotlib.pyplot as plt
import numpy as np
plt.ion()
x = np.arange(0, 4*np.pi, 0.1)
y = [np.sin(i) for i in x]
plt.plot(x, y, 'g-', linewidth=1.5, markersize=4)
plt.pause(0.0001)         
plt.plot(x, [i**2 for i in y], 'g-', linewidth=1.5, markersize=4)
plt.pause(0.0001)
plt.plot(x, [i**2*i+0.25 for i in y], 'r-', linewidth=1.5, markersize=4) 
plt.pause(0.0001)

The solution was posted here: Matplotlib ion() and subprocesses

Solution 4

The problem - and the solution - is highly dependent on the plot.draw() function within the Python environment and back end, and may even vary in different product releases. It manifests itself in different ways depending on the environment. The problem shows up in many places on stackoverflow with some solutions working for some people and not for others.

The gold standard on my Windows laptop is running the Python from the command line - no IDE, just plain vanilla Python3. draw() as shown in the example always works fine there.

If I try it in Jupyter notebook on the same machine, no amount of draw(), plot.pause(), plot.show(), or any other suggestion works. I tried %matplotlib with notebook, widget and ipympl. Nothing gets drawn until complete end of cell code execution.

Some other sources on stackoverflow suggested using figure.canvas.flush_events(). I had some success with that and investigated further.

The best solution turned out to be to run the draw() at the figure.canvas level instead of the axes or plot level.

You can get the figure by creating your plot with command:

fig, graph, = plt.subplots()

or, if you've already created the plot, as in the code at the top of the ticket, put the following outside the loop:

fig = plt.gcf() #get current figure

Inside the loop, instead of plt.draw(), use

fig.canvas.draw()

It's proven reliable in my Jupyter Notebook environment even when running multiple axes/plots across multiple figures. I can drop in sleep() statements and everything appears when expected.

Your mileage may vary.

Share:
23,855
Alex
Author by

Alex

Updated on July 09, 2022

Comments

  • Alex
    Alex almost 2 years

    I am trying to plot figures in real time using a for loop. I have the following simple code:

    import matplotlib.pyplot as plt
    
    plt.ion()
    plt.figure()
    for i in range(100):
        plt.plot([i], [i], 'o')
        plt.draw()
        plt.pause(0.0001)
    

    This code does not show the figure until it has finished computing, which I don't want. I want it to draw the figure after every loop. If I replace plt.draw() with plt.show, multiple figures are output in real time, but I want them all to appear in the same figure. Any ideas?

    EDIT:
    I downloaded PyCharm with Anaconda and everything works fine. I guess it's a problem with Spyder since I tried a few different versions of it without success. If anyone has any clue what is causing this problem in Spyder, let me know!

  • Alex
    Alex over 8 years
    Thanks for the reply. I tried running your code, but I get an error saying show() got an unexpected argument. I read that the block argument was experimental, but I'm not sure why it doesn't work on my Spyder platform.
  • CoMartel
    CoMartel over 8 years
    Does it works without the blockkeyword? Apparently it is not working if you already are in an interactive mode.
  • Alex
    Alex over 8 years
    It does work without the block statement, but doing this outputs many different figures. Is there a way to put them all together?
  • CoMartel
    CoMartel over 8 years
    This looks like a spyder-specific issue, as it works perfectly fine on my computer. I'm not familiar enough with Spyder to help you
  • d.popov
    d.popov over 3 years
    plt.pause() instead of time.sleep() also worked for me
  • d.popov
    d.popov over 3 years
    time.sleep() does not work for me, but using plt.pause() fixes it
  • Matiss Zuravlevs
    Matiss Zuravlevs almost 3 years
    Thank you! This is example that finally got it working for me. Inital try was not a success, but I did not think lines ax.relim() & ax.autoscale_view(True,True,True) were important. After adding them, it worked.