2

I want to plot data in matplotlib in real time. I want to open a figure once at the start of the programme, then update the figure when new data is acquired. Despite there being a few similar questions out there, none quite answer my specific question.

I want each set of data points new_data1 and new_data2 to be plotted on the same figure at the end of each while loop i.e. one line after the first while loop, two lines on the same figure after the second while loop etc. Currently they are all plotted together, but only right at the end of the programme, which is no use for real time data acquisition.

import matplotlib.pyplot as plt
import numpy


hl, = plt.plot([], [])

def update_line(hl, new_datax, new_datay):
    hl.set_xdata(numpy.append(hl.get_xdata(), new_datax))
    hl.set_ydata(numpy.append(hl.get_ydata(), new_datay))
    plt.xlim(0, 50)
    plt.ylim(0,200)
    plt.draw()

x = 1
while x < 5:
    new_data1 = []    
    new_data2 = []
    for i in range(500):
        new_data1.append(i * x)
        new_data2.append(i ** 2 * x)
    update_line(hl, new_data1, new_data2)
    x += 1

else:
    print("DONE")

This programme plots all 5 lines, but at the end of the programme. I want each line to be plotted after one another, after the while loop is completed. I have tried putting in plt.pause(0.001) in the function, but it has not worked.

This programme is different from the one that has been put forward - that programme only plots one graph and does not update with time.

L Rush
  • 23
  • 4
  • 1
    Possible duplicate of [Fast Live Plotting in Matplotlib / PyPlot](https://stackoverflow.com/questions/40126176/fast-live-plotting-in-matplotlib-pyplot) – SpghttCd Oct 01 '19 at 14:22
  • @SpghttCd would you mind explaining how I could incorporate multiple datasets into the example you've provided. I don't think it answers my question. Thanks for your help. – L Rush Oct 01 '19 at 15:17
  • Also @SpghttCd would you mind explaining why this programme doesn't do what I want it to do? Thanks. – L Rush Oct 01 '19 at 15:20
  • I think you are running into a race condition, where the figure has not been yet setup when you are forcing the draws. When I add a `plt.pause(0.1)` after `plt.draw()`, a window with a figure is actually opened and all lines are displayed in sequence. – Paul Brodersen Oct 01 '19 at 16:39
  • The duplicate I posted above is imo a perfect fit to your headline - perhaps you should consider editing it to sth with regards to "animation" or "control of successive plotting of several lines". "real time" and "data acquisition" remind me of something completely different. That said, vote to close for duplicate reasons retracted. – SpghttCd Oct 01 '19 at 21:35

2 Answers2

1

If I correctly understood your specifications, you can modify just a bit your MWE as follows:

import matplotlib.pyplot as plt
import numpy

fig = plt.figure(figsize=(11.69,8.27))
ax = fig.gca()
ax.set_xlim(0, 50)
ax.set_ylim(0,200)

hl, = plt.plot([], [])

def update_line(hl, new_datax, new_datay):
    # re initialize line object each time if your real xdata is not contiguous else comment next line
    hl, = plt.plot([], [])
    hl.set_xdata(numpy.append(hl.get_xdata(), new_datax))
    hl.set_ydata(numpy.append(hl.get_ydata(), new_datay))

    fig.canvas.draw_idle()
    fig.canvas.flush_events()

x = 1
while x < 10:
    new_data1 = []
    new_data2 = []
    for i in range(500):
        new_data1.append(i * x)
        new_data2.append(i ** 2 * x)
    update_line(hl, new_data1, new_data2)
    # adjust pause duration here
    plt.pause(0.5)
    x += 1

else:
    print("DONE")

which displays :

rendering

Yacola
  • 2,873
  • 1
  • 10
  • 27
0

Not sure, if I am reading the requirements right but below is a blueprint. Please change it to suit your requirements. You may want to change the function Redraw_Function and edit the frames (keyword parameter, which is np.arange(1,5,1) ) in the FuncAnimation call. Also interval=1000 means 1000 milliseconds of delay.

If you are using Jupyter then comment out the second last line (where it says plt.show()) and uncomment the last line. This will defeat your purpose of real time update but I am sorry I had trouble making it work real time in Jupyter. However if you are using python console or official IDLE please run the code as it is. It should work nicely.

import numpy as np
from matplotlib import pyplot as plt
from matplotlib.animation import FuncAnimation

fig, ax = plt.subplots()
plot, = plt.plot([],[])

def init_function():
    ax.set_xlim(0,50)
    ax.set_ylim(0,250)
    return plot,

def Redraw_Function(UpdatedVal):
    new_x = np.arange(500)*UpdatedVal
    new_y = np.arange(500)**2*UpdatedVal
    plot.set_data(new_x,new_y)
    return plot,

Animated_Figure = FuncAnimation(fig,Redraw_Function,init_func=init_function,frames=np.arange(1,5,1),interval=1000)
plt.show()
# Animated_Figure.save('MyAnimated.gif',writer='imagemagick')

When you run the code, you obtain the below result. I tried to keep very little code but I am sorry, if your requirement was totally different.

Best Wishes,

enter image description here

Amit
  • 2,018
  • 1
  • 8
  • 12
  • 1
    This is brilliant! I thoroughly appreciate your help. Just to warn people using Spyder, I had to change the preferences: Tools->Preferences->iPython Console->Graphics->Backend->Automatic (change from inline). Then shut down Spyder and restart and the animation will work! – L Rush Oct 02 '19 at 08:26