-1

I want to update a line plot with matplotlib and wonder, if there is a good modification of the code, such that the line plotted simply gets updated instead of getting redrawn every time. Here is a sample code:

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
matplotlib.style.use('ggplot')

plt.ion() 
fig=plt.figure()

i=0
df = pd.DataFrame({"time": [pd.datetime.now()], "value": 0}).set_index("time")
plt.plot(df);

while True:
    temp_y=np.random.random();
    df2 = pd.DataFrame({"time": [pd.datetime.now()], "value": temp_y}).set_index("time")
    df = df.append(df2)
    plt.plot(df)
    i+=1
    plt.show()
    plt.pause(0.000001) 

As you see, the plotting gets slower and slower after a while and I think the line chart is redrawn every iteration since it changes colours.

Pat
  • 1,299
  • 4
  • 17
  • 40

3 Answers3

2

Yes.

x = np.arange(10)
y = np.random.rand(10)

line, = plt.plot(x,y)
line.set_data(x,np.random.rand(10))
plt.draw()

However, your plotting gets slower because your are extending your data frame and each append operation presumably copies that frame in memory to a new location. As your data frame increases in size, that copy operation takes longer. I would loop over an index and plot that (for ii in range(len(data)): line.set_data(x[:ii], y[:ii]))

EDIT:

import numpy as np
import matplotlib.pyplot as plt; plt.ion()
import pandas as pd

n = 100
x = np.arange(n)
y = np.random.rand(n)
# I don't get the obsession with pandas...
df = pd.DataFrame(dict(time=x, value=y))

# initialise plot and line
line, = plt.plot(df['time'], df['value'])

# simulate line drawing
for ii in range(len(df)):
    line.set_data(df['time'][:ii], df['value'][:ii]) # couldn't be bothered to look up the proper way to index in pd
    plt.draw()
    plt.pause(0.001)
Paul Brodersen
  • 11,221
  • 21
  • 38
  • Could I ask you to provide an example based on the code I've posted, please. Many thanks, Pat. – Pat Oct 07 '16 at 12:55
  • Thanks, for the edit. Your example with the [:ii] only works if you knew the length of the data in advance (n=100), right? Using a while-loop and creating the new appended data within the while-loop (as in my example) I have to do it the other way. – Pat Oct 07 '16 at 13:57
  • No, please don't -- your plotting will eventually grind to a halt. Presumably, you at least know for how long you want the plot running, at least roughly. You then initialise an empty array that is large enough and populate that array with your data as it is coming in, and then you plot the data that you already have as I suggested above. Appending to an array is always a bad idea and in 99.9999% of the cases unnecessary with a bit of planning. – Paul Brodersen Oct 07 '16 at 14:11
  • Hmmm. I understand your point. But what is currently going on is, that I have a data feed from a financial information system. These new data points, which are in these examples the appended data are stored and pulled afterwards from a HDF store. My goal would be to have a countinously plotted rolling window of the last n elements from this HDFstore. So there is -in my opinion- no reason, why opening a while loop and plotting the rolling data would be a bad choice since the programm, theoretically could run forever. – Pat Oct 07 '16 at 14:25
  • Well, it won't at the moment run forever, because soon you will be lagging minutes if not hours behind the ticker (if indeed you are updating every microsecond as your code shows). Just initialise an array large enough for 1h or a day, and then initialise and append a new array of the same size when that one is full. Also, I really, really hope that you are not appending in the same way to your hdf5 files, because there you will have the exact same problem... Accept the answer, it does what you initially asked for and much more. – Paul Brodersen Oct 07 '16 at 14:53
  • I don't think your example is referring to what I need. In your case I know everyting I want to plot in advance and and go through it with a for loop. So it's backward-looking if you want. I am looking for an appropriate way to update a plot live with data which I don't have until I received it. So either way the for ii loop won't be applicable here unless you can show a better way to solve the problem. – Pat Oct 07 '16 at 15:05
  • Mate, I don't know how else to explain this: you can have a half full array and only plot the part of the array that is already filled. And then get another big array once your already large array is full. Think about it like this: it is a bad strategy to go to an all-you-can eat buffet with a small plate, and then each time you see something new that you would like to eat get a 1 micrometer larger plate (which is literally what you are doing now) once your initial plate is full. It is much, much better to start with a big plate, and when that one is full, get another large plate. – Paul Brodersen Oct 07 '16 at 15:18
0

You can use the below code for Live plot in matplotlib

import random 
from itertools import count
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation

plt.style.use('fivethirtyeight')

x_vals = []
y_vals = []

index = count()


def analyse(i):

    data = pd.read_csv(<your file which is updated or live data>)#u can use the pandas or any other data frame work
    x = data['index']
    y1 = data['readings']

    plt.cla()

    plt.plot(x, y1, label='Temperature') #in my case data is temperature
    
    plt.legend(loc='upper left')
    plt.tight_layout()

ani = FuncAnimation(plt.gcf(), analyse, interval=1000) #adjust intervals for call

plt.tight_layout()
plt.show()
Eric Aya
  • 69,473
  • 35
  • 181
  • 253
0

There is a simple way to do it, given a panda dataframe . You would usually do something like this to draw(df is dataframe) :

ax = df.plot.line()

Using

df.plot.line(reuse_plot=True,ax=ax)

one can reuse the same figure to redraw it elegantly and probably fast enough. This is probably the case when updating plot occasionally. If one needs more than this, there is a chapter on animations, and some optimizations can be done. https://matplotlib.org/stable/api/animation_api.html

user2679290
  • 144
  • 9