Python Matplotlib: Dynamically update plot - array length not known a priori


Question

I am aware of these questions: (A), (B) and (C) - all of which address parts of my problem.
I have also read the Animations Cookbook
My questions, however, seem not to be addressed in any of the above.
I wish to plot objective functions returned by an optimizer while the optimizer is running. I do not know in advance how many iterations the optimizer will run. Independent of how I get the array containing the objective functions, the problem can be isolated in this minimal example:

import numpy as np  
import matplotlib.pyplot as plt  

SIZE = 50  
R1 = 0.5
R2 = 0.75

plt.ion()

fig = plt.figure()
ax = fig.add_subplot(111)
fig.canvas.set_window_title('broken spiral')

for i in range(0, SIZE):
  A.append(R1 * i * np.sin(i))
  B.append(R2 * i * np.cos(i))
  line1, = ax.plot(A,'-k',label='black')
  line2, = ax.plot(B,'-r',label='red')
  legend = ax.legend(loc=0)
  plt.draw()

plt.savefig('test_broken_spiral.png')

Here the plot is only 'pseudo'-updated. What really happens is that for each iteration a new line for A and B is generated, overlying with the original one, but also generating a new legend entry. After 50 iterations, I have 100 lines and 100 legend entries.
I tried this next:

for i in range(0, SIZE):
  A.append(R1 * i * np.sin(i))
  B.append(R2 * i * np.cos(i))
  if i == 0: 
    line1, = ax.plot(A,'-k',label='black')
    line2, = ax.plot(B,'-r',label='red')
    legend = ax.legend(loc=0)
    plt.draw()
  else:
    line1.set_ydata(A)
    line2.set_ydata(B)
    plt.draw()

plt.savefig('test_broken_spiral.png')

Unfortunately, this plot has completely messed up axis.
I put the if i == 0 statement in, because I do not know the number of iterations in advance (yes, I do in this case, but not in the application this is targeted at) and somehow have to 'initialize' the plot and legend.
My questions can be summarized as follows:
1.) How do I update my plot? If I run the optimizer for 10,000 iterations, I don't want 10,000 overlying lines in my plot (filesize).
2.) Where do I place the legend command?

I'm running python 2.6.6 and matplotlib 0.99.1.1

Edit:
This seems to be a similar question, with the same unanswered issue.

1
2
5/23/2017 12:31:17 PM

Accepted Answer

Just make the line objects with empty data outside of your loop:

line1, = ax.plot([], [],'-k',label='black')
line2, = ax.plot([], [],'-r',label='red')
ax.legend()
for i in range(0, SIZE):
  A.append(R1 * i * np.sin(i))
  B.append(R2 * i * np.cos(i))
  line1.set_ydata(A)
  line1.set_xdata(range(len(A)))
  line2.set_ydata(B)
  line2.set_xdata(range(len(B)))
  ax.relim()
  ax.autoscale_view()
  plt.draw() 

You can probably be a bit more clever about updating your xdata.

For a more complete example see here and the full gallery of animation examples.

2
4/10/2013 4:04:15 PM

Licensed under: CC-BY-SA with attribution
Not affiliated with: Stack Overflow
Icon