I'm trying to continuously plot data received via network using matplotlib.
On the y-axis, I want to plot a particular entity, while the x-axis is the current time.
The x-axis should cover a fixed period of time, ending with the current time.
Here's my current test code, which simulates the data received via network with random numbers.
import threading
import random
import time
import signal
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.dates as md
class NPData():
def __init__(self, size):
self.data = np.zeros((size,2)) # size rows, 2 cols
self.size = size
self.head = 0
def __len__(self):
return self.data.__len__()
def __str__(self):
return str(self.data)
def append(self, data):
self.data[self.head] = data
self.head = (self.head + 1) % self.size
def get_x_range(self):
return (self.data.min(axis=0)[0], self.data.max(axis=0)[0])
class Producer(threading.Thread):
def __init__(self):
super().__init__()
random.seed()
self.running = True
self.data = NPData(100)
def get_data(self):
return self.data.data
def stop(self):
self.running = False
def run(self):
while self.running:
now_ms = md.date2num(int(time.time() * 1000)) # ms
sample = np.array([now_ms, np.random.randint(0,999)])
self.data.append(sample)
time.sleep(0.1)
prog_do_run = True
def signal_handler(sig, frame):
global prog_do_run
prog_do_run = False
def main():
signal.signal(signal.SIGINT, signal_handler)
p = Producer()
p.start()
fig, ax = plt.subplots()
xfmt = md.DateFormatter('%H:%M:%S.%f')
ax.xaxis.set_major_formatter(xfmt)
#ax.plot(p.get_data())
#ax.set_ylim(0,999)
plt.show(block=False)
while prog_do_run:
x_range = p.data.get_x_range()
ax.set_xlim(x_range)
#ax.set_ylim(0,999)
print(p.get_data())
#ax.plot(p.get_data())
plt.draw()
plt.pause(0.05)
p.stop()
Notes:
The Producer class is supposed to emulate data received via network.
I've encountered two main issues:
I'm struggling to find out what actually needs to be called inside an endless loop in order for matplotlib to continuously update a plot (efficiently). Is it
draw(),plot(),pause()or a combination of those?I've been generating milliseconds timestamps and matplotlib seems to not like them at all. The official docs say to use
date2num(), which does not work. If I just useint(time.time() * 1000)orround(time.time() * 1000), I getOverflowError: int too big to convertfrom the formatter.
time.time() * 1e3-- i.e. make it a float1e3would explicitly make it a float. But I think thenp.array()constructor makes it a float anyway.np.arraywon't make it a float if everything you put in there is explicitly an int, it will preserve the datatype; your overflow error even tells you the items are still ints when they make it to the formatter.