I'm trying to plot can-data using the python-can and matplotlib library. I have a basic example on how to plot live data with matplotlib:
import numpy as np
import matplotlib.pyplot as plt
plt.axis([0, 10, 0, 1])
for i in range(10):
y = np.random.random()
plt.scatter(i, y)
# plt.pause(0.05)
plt.draw()
plt.show()
And I used a basic python-can example and added the matplotlib:
import sys
import argparse
import socket
from datetime import datetime
import can
from can import Bus, BusState, Logger
import numpy as np
import matplotlib.pyplot as plt
def main():
plt.axis([0, 10, 0, 1])
bus = Bus(bustype ='pcan')
i = 0
print(f"Connected to {bus.__class__.__name__}: {bus.channel_info}")
print(f"Can Logger (Started on {datetime.now()})")
plt.show()
try:
while True:
msg = bus.recv(1)
if msg is not None:
y = np.random.random()
plt.scatter(i, y)
plt.draw()
i += 1
print('Message id {id}'.format(id=msg.arbitration_id))
except KeyboardInterrupt:
pass
finally:
plt.show()
bus.shutdown()
if __name__ == "__main__":
main()
However as soon as I add the plt commands the script stops working, it just doesn't output the print statement anymore. When I Debug into it and step manually it works. Anything I'm doing wrong? Is there a better way to solve this? I'm not set on matplotlib, just the fastest way to plot something :)
I found a working solution using the blit function, its not perfect yet but its a good starting point:
from datetime import datetime
import can
from can import Bus, BusState, Logger
import numpy as np
import matplotlib.pyplot as plt
import struct
def main():
bus = Bus(bustype ='pcan')
i = 0
print(f"Connected to {bus.__class__.__name__}: {bus.channel_info}")
print(f"Can Logger (Started on {datetime.now()})")
x = np.linspace(0, 1000, num=1000)
y = np.zeros(1000)
fig = plt.figure()
ax1 = fig.add_subplot(1, 1, 1)
line, = ax1.plot([], lw=3)
text = ax1.text(0.8, 0.5, "")
ax1.set_xlim(x.min(), x.max())
ax1.set_ylim([-10, 10])
fig.canvas.draw() # note that the first draw comes before setting data
ax2background = fig.canvas.copy_from_bbox(ax1.bbox)
plt.show(block=False)
k = 0
try:
while True:
msg = bus.recv(1)
if msg is not None:
y = np.roll(y, 1)
value = struct.unpack('f', msg.data)
y[0] = np.int8(value)
line.set_data(x, y)
fig.canvas.restore_region(ax2background)
ax1.draw_artist(line)
ax1.draw_artist(text)
fig.canvas.blit(ax1.bbox)
fig.canvas.flush_events()
# print('Message data {data}, value {value}, counter {counter}'.format(data=msg.data, value=value, counter=k))
k += 1
if k > 100:
k = 0
except KeyboardInterrupt:
pass
finally:
plt.show()
bus.shutdown()
if __name__ == "__main__":
main()
The script assumes that the can message carries one single float over the first four uint8 and just plots it.