forked from sverl/live-plot
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathliveplot.py
More file actions
162 lines (138 loc) · 4.75 KB
/
liveplot.py
File metadata and controls
162 lines (138 loc) · 4.75 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
'''
This module provides the class LivePlot which can plot data from a serial device
live.
Tested on Ubuntu 15.10 with Arduino Uno.
@author: Sverre
'''
import serial
import matplotlib.pyplot as plt
import multiprocessing as mp
class LivePlot(mp.Process):
'''
This class handles extends multiprocessing.Process so that the
computation and plotting happens in a new thread.
To start the plotting, call the method L{start()}. The thread will close if
the main thread closes, so if no work is done, nothing will be plotted.
This can be avoided by calling L{raw_input()}.
The thread can be closed with the method L{join()}.
'''
def __init__(self, ser, comp, dec=None, prop=None, save=None, clean=None,
cb=None, verb=False):
'''
@param ser: The serial device to communicate with.
@type ser: Serial
@param comp: The function to be used on the input from the serial device
to convert it to something plotable.
@type comp: L{callable}
@keyword dec: String with decorations for the plot such as symbol for
data points.
@type dec: L{str}
@keyword prop: Properties of the plot such as alpha and color.
@type prop: L{tuple}
@keyword save: File to save the processed data to.
@type save: L{str}
@keyword cb: Not implemented.
@todo: Implement callback possibilities.
@keyword clean: Not implemented.
@todo: Implement the possibility to only read new serial data.
@keyword verb: Boolean indicating if the data is to be printed to the
terminal.
@type verb: L{bool}
'''
# Setup thread handling
mp.Process.__init__(self)
self.stopping = mp.Event()
# Initialize attributes
self.dec = dec
self.ser = ser
self.comp = comp
self.verb = verb
self.values = []
self.fig = None
self.prop = prop
self.save = save
if self.save is not None:
self.save_file = open(save, 'w+')
# Todo
if cb is not None:
raise NotImplementedError
if clean is not None:
raise NotImplementedError
def run(self):
'''
Read and process the data from the serial device, plot it and
potentially save it to a file. The thread runs continuously until
L{join()} is called or the script terminates.
'''
# Setup plot
plt.figure()
plt.ion()
plt.show()
plt.hold(False)
while not self.stopping.is_set():
# Process the data
raw = self.ser.readline()
data = self.comp(raw)
self.values.append(data)
# Display output
if self.verb:
print 'read: %splot: %s' % (raw, data)
if self.save is not None:
self.save_data(data)
self.plot()
def join(self):
'''
Stops the thread safely.
'''
self.stopping.set()
if self.save is not None:
self.save_file.close()
super(self.__class__, self).join()
def plot(self):
'''
Plots the data.
'''
if self.dec is not None:
self.fig = plt.plot(self.values, self.dec)
else:
self.fig = plt.plot(self.values)
if self.prop is not None:
plt.setp(self.fig, *self.prop)
plt.draw()
def save_data(self, data):
'''
Saves the data to a file.
@param data: The data to be saved.
'''
self.save_file.write(str(data) + '\n')
self.save_file.flush()
def example():
'''
Example use of LivePlot.
The serial device is an Arduino Uno connected on /dev/ttyACM0. The Arduino
is connected to a TMP36 sensor with +V_S connected to +5.0 VCC and V_OUT
connected to A0. The Arduino is connected on the port /dev/ttyACM0 and
loaded with the following sketch::
const int sensor = 0;
void setup(){
Serial.begin(9600);
}
void loop(){
delay(1000);
int signal = analogRead(sensor);
Serial.println(signal);
}
'''
a_ref = 5.0
def convert_to_temp(line):
signal = float(line)
voltage = (signal * a_ref) / 1024.
temperature = (voltage - .5) * 100
return temperature
device = serial.Serial(port='/dev/ttyACM0', baudrate=9600)
p = LivePlot(device, convert_to_temp, save='/home/user/temp.dat', verb=True)
p.start()
raw_input()
p.join()
if __name__ == '__main__':
example()