How to Plot in Real-Time in a While Loop Using Matplotlib

Real time matplotlib plot is not working while still in a loop

Here is the solution add this plt.pause(0.0001) in your loop as below:

import matplotlib.pyplot as plt
import time
import random
from collections import deque
import numpy as np

# simulates input from serial port
def random_gen():
while True:
val = random.randint(1,10)
yield val
time.sleep(0.1)


a1 = deque([0]*100)
ax = plt.axes(xlim=(0, 20), ylim=(0, 10))
d = random_gen()

line, = plt.plot(a1)
plt.ion()
plt.ylim([0,10])
plt.show()

for i in range(0,20):
a1.appendleft(next(d))
datatoplot = a1.pop()
line.set_ydata(a1)
plt.draw()
print a1[0]
i += 1
time.sleep(0.1)
plt.pause(0.0001) #add this it will be OK.

update plot in while loop

I would recommend using a single Axes object for all of your plots. Something like this:

fig, ax = plt.subplots()

while cap.isOpened():

# generate data here

ax.scatter(df['x'], df['y'])

Python realtime plotting

The lightest solution you may have is to replace the X and Y values of an existing plot. (Or the Y value only, if your X data does not change. A simple example:

import matplotlib.pyplot as plt
import numpy as np
import time

fig = plt.figure()
ax = fig.add_subplot(111)

# some X and Y data
x = np.arange(10000)
y = np.random.randn(10000)

li, = ax.plot(x, y)

# draw and show it
ax.relim()
ax.autoscale_view(True,True,True)
fig.canvas.draw()
plt.show(block=False)

# loop to update the data
while True:
try:
y[:-10] = y[10:]
y[-10:] = np.random.randn(10)

# set the new data
li.set_ydata(y)

fig.canvas.draw()

time.sleep(0.01)
except KeyboardInterrupt:
break

This solution is quite fast, as well. The maximum speed of the above code is 100 redraws per second (limited by the time.sleep), I get around 70-80, which means that one redraw takes around 4 ms. But YMMV depending on the backend, etc.

How to plot data real time data from a txt file in a matplotlib line graph

First of all, make sure that the code that ultrasonic uses to write data to file is not buffering writes and writes to file instantly by forcing it to flush after every write output.flush(), I edited your code to do that and also changed it to append to file instead of removing all old data with each write also I made it to save time with each write to use it in the graph.

start_time = time.time()

while True:
output = open("front sensor distance.txt", "a")
output.write(str(round(time.time()-start_time))+","+str(round(get_distance()))+"\n")
time.sleep(2)
output.flush()

then you can use this code sample which reads data from the file every 1 second and updates the graph in real-time.

I tried to write it as close to your description as possible where the data file contains time,distance in each line separated by a comma.

import matplotlib.pyplot as plt
import matplotlib.animation as animation

fig = plt.figure()
ax = fig.add_subplot(1,1,1)

def animate(i):
file_data = open("front sensor distance.txt","r").read()
dataArray = file_data.split('\n')
time = []
distance = []
for eachLine in dataArray:
if len(eachLine)>1:
x,y = eachLine.split(',')
time.append(float(x))
distance.append(float(y))
ax.clear()
ax.plot(time,distance)

def Main():
ani = animation.FuncAnimation(fig, animate, interval=1000)
plt.show()
print("done")

Main()

I don't have the hardware you have to test with so I made distance function return random numbers on my machine to simulate your experience.
and running both files will result in the following real-time graph

Sample Image

Real time data plotting from a high throughput source

You could try to have two separate processes:

  • one for acquiring and storing the data
  • one for plotting the data

Below there are two basic scripts to get the idea.
You first run gen.py which starts to generate numbers and save them in a file.
Then, in the same directory, you can run plot.py which will read the last part of the file and will update the a Matplotlib plot.

Here is the gen.py script to generate data:

#!/usr/bin/env python3

import time
import random

LIMIT_TIME = 100 # s
DATA_FILENAME = "data.txt"


def gen_data(filename, limit_time):
start_time = time.time()
elapsed_time = time.time() - start_time
with open(filename, "w") as f:
while elapsed_time < limit_time:
f.write(f"{time.time():30.12f} {random.random():30.12f}\n") # produces 64 bytes
f.flush()
elapsed = time.time() - start_time


gen_data(DATA_FILENAME, LIMIT_TIME)

and here is the plot.py script to plot the data (reworked from this one):

#!/usr/bin/env python3


import io
import time
import matplotlib.pyplot as plt
import matplotlib as mpl
import matplotlib.animation


BUFFER_LEN = 64
DATA_FILENAME = "data.txt"
PLOT_LIMIT = 20
ANIM_FILENAME = "video.gif"


fig, ax = plt.subplots(1, 1, figsize=(10,8))
ax.set_title("Plot of random numbers from `gen.py`")
ax.set_xlabel("time / s")
ax.set_ylabel("random number / #")
ax.set_ylim([0, 1])


def get_data(filename, buffer_len, delay=0.0):
with open(filename, "r") as f:
f.seek(0, io.SEEK_END)
data = f.read(buffer_len)
if delay:
time.sleep(delay)
return data


def animate(i, xs, ys, limit=PLOT_LIMIT, verbose=False):
# grab the data
try:
data = get_data(DATA_FILENAME, BUFFER_LEN)
if verbose:
print(data)
x, y = map(float, data.split())
if x > xs[-1]:
# Add x and y to lists
xs.append(x)
ys.append(y)
# Limit x and y lists to 10 items
xs = xs[-limit:]
ys = ys[-limit:]
else:
print(f"W: {time.time()} :: STALE!")
except ValueError:
print(f"W: {time.time()} :: EXCEPTION!")
else:
# Draw x and y lists
ax.clear()
ax.set_ylim([0, 1])
ax.plot(xs, ys)


# save video (only to attach here)
#anim = mpl.animation.FuncAnimation(fig, animate, fargs=([time.time()], [None]), interval=1, frames=3 * PLOT_LIMIT, repeat=False)
#anim.save(ANIM_FILENAME, writer='imagemagick', fps=10)
#print(f"I: Saved to `{ANIM_FILENAME}`")

# show interactively
anim = mpl.animation.FuncAnimation(fig, animate, fargs=([time.time()], [None]), interval=1)
plt.show()
plt.close()

Anim

Note that I have also included and commented out the portion of code that I used to generate the animated GIF above.

I believe this should be enough to get you going.



Related Topics



Leave a reply



Submit