Reputation: 65
Here this simple code:
#import serial
from tkinter import *
from matplotlib import pyplot as plt
import matplotlib.animation as animation
from matplotlib import style
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import serial
fig = plt.gcf()
fig.show()
fig.canvas.draw()
ser = serial.Serial('COM35', 115200, timeout=.1)
while True:
data = ser.readline()
print(data)
plt.plot(data)
fig.canvas.draw()
now when i run this i'm getting something like this..in pic
and the data values are like this
but i need output something like this (which is continuous graph)..
but after adding the list key word on to the list(ser.readline())
I get this error..
Upvotes: 1
Views: 434
Reputation: 51683
You could also change to use the animation module of matplotlib - this answer is heavily inspired by tacaswell answer to How to update values from serial port in matplotlib animations?
Same data generator:
from itertools import cycle
data = [0,0,0,0,0,0,0,0,0,2,25,64,92,119,132,139,124,123,103,71,38,3]
cyc = cycle(data)
def serial():
from random import randint
def create_data():
for k in range(randint(2,3)):
yield next(cyc)
return list(create_data())
from matplotlib import pyplot as plt from matplotlib import animation import numpy as np fig = plt.figure() ax = plt.axes(xlim=(0, 150), ylim=(-200, 200))
max_points = 150
# fill initial artist with nans (so nothing draws) line, = ax.plot(np.arange(max_points), np.ones(max_points, dtype=np.float)*np.nan, lw=2) def init(): return line, def animate(i):
y = serial() # arduino.readline()
old_y = line.get_ydata() # adjusted here for this question data, coming
new_y = np.r_[old_y[len(y):], y] # in as chunks rather then single values
line.set_ydata(new_y) return line, anim = animation.FuncAnimation(fig, animate, init_func=init, frames=200, interval=20, blit=False) plt.show()
The adaptations made to @tacaswell's code are due to the fact that this questions data needed other limits for the output graph and that the data coming in for this question provides multiple, chunked datapoints, not single values. The "data-refresh" in def animate(i)
had to be adapted to work for this.
Upvotes: 0
Reputation: 51683
This answer is not as elegant as using the animation-api - but it works.
You have to adapt quite a lot - for sake of giving a Minimal, Complete, and Verifiable example I had to implement my own "serial" dataprovider:
from itertools import cycle
data = [0,0,0,0,0,0,0,0,0,2,25,64,92,119,132,139,124,123,103,71,38,3]
cyc = cycle(data)
def serial():
from random import randint
def create_data():
for k in range(randint(2,3)):
yield next(cyc)
return list(create_data())
One way to solve it:
You need to get the the axes of your plot as well to adjust the "area" that is shown, then you need to supply correct x-values as "time" and the y-values as reading from serial (you can increment a "how many data received" variable on each draw for the time):
from tkinter import *
from matplotlib import pyplot as plt
fig, ax = plt.subplots()
ax.set_ylim(-200, 200)
ax.set_xlim(0,110)
fig.show()
fig.canvas.draw()
time = 0
last = 0
while True:
# "animate" x-axis
if time > 100:
ax.set_xlim(time-100,time+10)
data = serial()
print(data)
# add the last datapoint again so you get a continuous curve
plt.plot([time-1]+[time+x for x in range(len(data))], [last]+data)
# increment time
time += len(data)
# remember last data-value
last = data[-1]
fig.canvas.draw()
To get (text output omitted - it just repeats the data from above differently chunked):
You can see by the colored line-segments which data was added together.
Upvotes: 1