4

I want to use MatPlotLib to plot a graph, where the plot changes over time. At every time step, an additional data point will be added to the plot. However, there should only be one graph displayed, whose appearance evolves over time.

In my test example, the plot is a simple linear plot (y = x). Here is what I have tried:

for i in range(100):
    x = range(i)
    y = range(i)
    plt.plot(x, y)
    plt.ion()
    plt.show()
    time.sleep(1)

However, what happens here is that multiple windows are created, so that by the end of the loop I have 100 windows. Also, I have noticed that for the most recent window, it is just a white window, and the plot only appears on the next step.

So, my two questions are:

1) How can I change my code so that only a single window is displayed, whose contents changes over time?

2) How can I change my code so that for the most recent timestep, the plot is actually displayed on the window, rather than it only displaying a white window?

Thanks!

Karnivaurus
  • 22,823
  • 57
  • 147
  • 247
  • Possible duplicate of [Dynamically updating plot in matplotlib](http://stackoverflow.com/questions/10944621/dynamically-updating-plot-in-matplotlib) – Diziet Asahi Feb 03 '17 at 13:42

3 Answers3

7

(1)

You can set plt.ion() at the beginning and plot all graphs to the same window. Within the loop use plt.draw() to show the graph and plt.pause(t) to make a pause. Note that t can be very small, but the command needs to be there for the animation to work on most backends.
You might want to clear the axes before plotting new content using plt.gca().cla().

import matplotlib.pyplot as plt

plt.ion()
for i in range(100):
    x = range(i)
    y = range(i)
    # plt.gca().cla() # optionally clear axes
    plt.plot(x, y)
    plt.title(str(i))
    plt.draw()
    plt.pause(0.1)

plt.show(block=True) # block=True lets the window stay open at the end of the animation.

Alternatively to this very simple approach, use any of the examples for animations provided in http://matplotlib.org/examples/animation/index.html

(2)

In order to get each plot in a new window, use plt.figure() and remove plt.ion(). Also only show the windows at the end:

import matplotlib.pyplot as plt

for i in range(100):
    x = range(i)
    y = range(i)
    plt.figure()
    plt.plot(x, y)
    plt.title(str(i))
    
plt.show()

Note that you might find that in both cases the first plot is empty simply because for i=0, range(i) == [] is an empty list without any points. Even for i=1 there is only one point being plotted, but of course no line can connect a single point with itself.

Community
  • 1
  • 1
ImportanceOfBeingErnest
  • 321,279
  • 53
  • 665
  • 712
  • Additionally if you call `plt.figure()` outside of the `for` loop then it will work in a similar way to the `plt.ion()` method shown above with the exception that you don't have to close the figure before the rest of the script is run (like I have to do with 2.7). –  Feb 03 '17 at 15:28
  • @FeeJF Sorry, I don't quite understand what you're saying. If you call `plt.figure()` outside the loop there is only one window and no animation at all. – ImportanceOfBeingErnest Feb 03 '17 at 15:47
1

I think the best way is to create one line plot and then update data in it. Then you will have single window and single graph that will continuously update.

import matplotlib.pyplot as plt

plt.ion()
fig = plt.figure(figsize=(16,8))
axes = fig.add_subplot(111)
data_plot=plt.plot(0,0)
line, = axes.plot([],[])
for i in range(100):
    x = range(i)
    y = range(i)
    line.set_ydata(y)
    line.set_xdata(x)
    if len(y)>0:
        axes.set_ylim(min(y),max(y)+1) # +1 to avoid singular transformation warning
        axes.set_xlim(min(x),max(x)+1)
    plt.title(str(i))
    plt.draw()
    plt.pause(0.1)

plt.show(block=True)
Kortium
  • 11
  • 2
1

Here is one way I find works really well.

You will need this package

from IPython.display import clear_output

%matplotlib inline
import matplotlib.pyplot as plt

clear_output clears the output of the notebook.

def plot_graph(list_of_points: list):
    clear_output(wait=True)
    plt.figure(figsize=(15, 10), linewidth=2, edgecolor='steelblue', facecolor='skyblue')
    plt.subplots_adjust(left=0.20, bottom=0.20)
    ax = plt.gca()
    ax.set_xlim([0, max_x])
    plt.plot(list_of_points, label="Points")
    plt.legend()
    plt.show()

This takes a list of points, and clears the output of the cell and draws a new graph.

You can place this inside a for loop which would look something like this:

points = []
for i in range(10):
    points.append(i + random.randint(0, 9))
    plot_graph(points, 10)

It should look like this.

Animated Graph

I am not saying this is the way, but its simple enough that I can understand and edit and gets the job done for me.

EDIT I added plt.legend() to show the names of the plots, it doesnt show in the gif because that was after I created the gif.

Bola Gadalla
  • 370
  • 3
  • 14