How to dynamically update a plot in a loop in IPython notebook (within one cell)

97,291

Solution 1

Use the IPython.display module:

%matplotlib inline
import time
import pylab as pl
from IPython import display
for i in range(10):
    pl.plot(pl.randn(100))
    display.clear_output(wait=True)
    display.display(pl.gcf())
    time.sleep(1.0)

Solution 2

A couple of improvement's on HYRY's answer:

  • call display before clear_output so that you end up with one plot, rather than two, when the cell is interrupted.
  • catch the KeyboardInterrupt, so that the cell output isn't littered with the traceback.
import matplotlib.pylab as plt
import pandas as pd
import numpy as np
import time
from IPython import display
%matplotlib inline

i = pd.date_range('2013-1-1',periods=100,freq='s')

while True:
    try:
        plt.plot(pd.Series(data=np.random.randn(100), index=i))
        display.display(plt.gcf())
        display.clear_output(wait=True)
        time.sleep(1)
    except KeyboardInterrupt:
        break

Solution 3

You can further improve this by adding wait=True to clear_output:

display.clear_output(wait=True)
display.display(pl.gcf())

Solution 4

I tried many methods, but I found this as the simplest and the easiest way -> to add clear_output(wait=True), for example,

from IPython.display import clear_output

for i in range(n_iterations):
     clear_output(wait=True)
     x = some value
     y = some value
     plt.plot(x, y, '-r')
     plt.show()

This overwrites on the same plot, and gives an illusion of plot animation

Solution 5

Adding a label to the other solutions posted here will keep adding new labels in every loop. To deal with that, clear the plot using clf.

For example:

for t in range(100):
   if t % refresh_rate == 0:

     plt.clf()
     plt.plot(history['val_loss'], 'r-', lw=2, label='val')
     plt.plot(history['training_loss'], 'b-', lw=1, label='training')
     plt.legend()
     display.clear_output(wait=True)
     display.display(plt.gcf())
Share:
97,291

Related videos on Youtube

user3236895
Author by

user3236895

Updated on October 29, 2021

Comments

  • user3236895
    user3236895 over 2 years

    Environment: Python 2.7, Matplotlib 1.3, IPython notebook 1.1, Linux, and Chrome. The code is in one single input cell, using --pylab=inline.

    I want to use IPython notebook and Pandas to consume a stream and dynamically update a plot every five seconds.

    When I just use a print statement to print the data in text format, it works perfectly fine: the output cell just keeps printing data and adding new rows. But when I try to plot the data (and then update it in a loop), the plot never shows up in the output cell. But if I remove the loop, and just plot it once, it works fine.

    Then I did some simple test:

    i = pd.date_range('2013-1-1',periods=100,freq='s')
    while True:
        plot(pd.Series(data=np.random.randn(100), index=i))
        #pd.Series(data=np.random.randn(100), index=i).plot() also tried this one
        time.sleep(5)
    

    The output will not show anything until I manually interrupt the process (Ctrl + M + I). And after I interrupt it, the plot shows correctly as multiple overlapped lines. But what I really want is a plot that shows up and gets updated every five seconds (or whenever the plot() function gets called, just like what print statement outputs I mentioned above, which works well). Only showing the final chart after the cell is completely done is not what I want.

    I even tried to explicitly add the draw() function after each plot(), etc. None of them works. How can I dynamically update a plot by a for/while loop within one cell in IPython notebook?

  • user3236895
    user3236895 over 10 years
    thanks. gcf().show() also works. Need to add the clear_output() suggested by HYRY to show stuff on the same fig
  • denfromufa
    denfromufa over 9 years
    this is not smooth option, the plot is recreated from scratch with cell going up and down in between
  • ahwillia
    ahwillia over 9 years
    +1. This is very important. I think HYRY's answer should be updated with this info.
  • ahwillia
    ahwillia over 9 years
    Adding clear_output(wait=True) solves this problem. See wabu's answer below.
  • Peter
    Peter about 9 years
    This is good, but has the annoying side effect of clearing the print output as well.
  • herrlich10
    herrlich10 almost 9 years
    Indeed, display.display(gcf()) should go BEFORE display.clear_output(wait=True)
  • tacaswell
    tacaswell over 8 years
    You can do better these days with %matplotlib nbagg which gives you a live figure to play with.
  • Tom Phillips
    Tom Phillips over 8 years
    Thanks, @csta. Added it.
  • N. Virgo
    N. Virgo over 8 years
    @tcaswell I've added a new question asking how one uses nbagg to achieve this. (Pinging you in case you're interested in answering it.) stackoverflow.com/questions/34486642/…
  • Jakub Arnold
    Jakub Arnold about 6 years
    @herrlich10 Why should display be called before clear_output? Shouldn't you first clear the output and then display the new data, instead of doing it the other way around?
  • KIC
    KIC over 5 years
    this works but also destroys anything else in the cell like the printed measures. Is there a way really just updating the plot and keeping everything else in place?
  • MasayoMusic
    MasayoMusic over 4 years
    I am still getting a screen flicker with the graph updates, however it's not all the time. Is there a workaround to this?
  • MasayoMusic
    MasayoMusic over 4 years
    Is this in addition to "display.display(pl.gcf())"?
  • MasayoMusic
    MasayoMusic over 4 years
    Thanks plt.clf() works. However is there anyway to get rid of the flicker from the updates?
  • Neil Traft
    Neil Traft about 3 years
    If you are also trying to print text at the beginning of the loop, I find that this causes the graph to disappear, so that it is only visible for a split second. I do not have this problem when the display() call is placed after clear_output().
  • gammapoint
    gammapoint about 3 years
    Rather than sleeping for 1 second between graph updates, is there a way to make the figure only update after a button press?
  • muammar
    muammar over 2 years
    Why is this not working correctly if I use subplots?