comparison logplot.py @ 12:87d9d862ecc4

Avoid using pylab helper functions to reduce the magic level.
author darius
date Tue, 23 Oct 2007 01:01:48 +0000
parents cb03cea09bda
children 9264a9cacfde
comparison
equal deleted inserted replaced
11:17449d52d5e5 12:87d9d862ecc4
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 2
3 import re, datetime, time, pylab, matplotlib 3 import re, datetime, time, sys, cPickle, numpy
4 import matplotlib
5 import matplotlib.figure
6 import matplotlib.backends.backend_agg
7 import matplotlib.dates
8
4 daterestr = '([0-9]{4}/[0-9]{2}/[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}): ' 9 daterestr = '([0-9]{4}/[0-9]{2}/[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}): '
5 targtre = re.compile(daterestr + 'target temperature - (-?[0-9]+\.[0-9]+)') 10 targtre = re.compile(daterestr + 'target temperature - (-?[0-9]+\.[0-9]+)')
6 linere = re.compile(daterestr + '(-?[0-9]+\.[0-9]+)\s+(-?[0-9]+\.[0-9]+)\s+(-?[0-9]+\.[0-9]+)\s+([a-z-]+)\s+([a-z-]+)') 11 templre = re.compile(daterestr + '(-?[0-9]+\.[0-9]+)\s+(-?[0-9]+\.[0-9]+)\s+(-?[0-9]+\.[0-9]+)\s+([a-z-]+)\s+([a-z-]+)')
7 datefmt = '%Y/%m/%d %H:%M:%S' 12 datefmt = '%Y/%m/%d %H:%M:%S'
8 tz = matplotlib.pytz.timezone('Australia/Adelaide') 13 tz = matplotlib.pytz.timezone('Australia/Adelaide')
9 14
10 targetTemp = 18.0 15 #start = time.mktime(time.strptime("2007/09/22 14:00:00", datefmt))
11 logfile = '/tmp/beermon.log' 16 start = None
12 start = time.mktime(time.strptime("2007/09/24 00:00:00", datefmt)) 17 #end = time.mktime(time.strptime("2007/09/30 14:00:00", datefmt))
13 #end = time.mktime(time.strptime("2007/09/28 00:00:00", datefmt))
14 end = None 18 end = None
15 19
16 f = open(logfile) 20 def parselog(f, start, end, times, fermTemps, fridgeTemps, ambTemps, targetTemps, states):
21 targetTemp = 18.0 # Have to guess this..
17 22
18 times = [] 23 for line in f:
19 fermTemps = [] 24 # Log line?
20 fridgeTemps = [] 25 m = templre.match(line)
21 ambTemps = [] 26 if (m == None):
22 states = [] 27 # No, might be a target temp line
23 targetTemps = [] 28 m = targtre.match(line)
29 if (m != None):
30 # Parse date portion
31 t = datetime.datetime(*time.strptime(m.group(1), datefmt)[0:6])
32 if ((start != None and t < start) or (end != None and t > end)):
33 continue
24 34
25 for line in f: 35 targetTemp = float(m.group(2))
26 m = linere.match(line) 36 continue
27 if (m == None): 37 else:
28 m = targtre.match(line) 38 # Isn't anything, next!
29 if (m != None):
30 t = time.mktime(time.strptime(m.group(1), datefmt))
31 if (t < start or t > end):
32 continue 39 continue
33 40
34 targetTemp = float(m.group(2)) 41 # Parse date portion
42 t = datetime.datetime(*time.strptime(m.group(1), datefmt)[0:6])
43 if ((start != None and t < start) or (end != None and t > end)):
35 continue 44 continue
45
46 fermTemp = float(m.group(2))
47 fridgeTemp = float(m.group(3))
48 ambTemp = float(m.group(4))
49 state = m.group(5)
50
51 # Convert to Gregorian days (float) because that is what matplotlib uses
52 times.append(matplotlib.dates._to_ordinalf(t))
53 fermTemps.append(fermTemp)
54 fridgeTemps.append(fridgeTemp)
55 ambTemps.append(ambTemp)
56 targetTemps.append(targetTemp)
57 if (state == 'heat'):
58 states.append(10)
59 elif (state == 'idle'):
60 states.append(8)
36 else: 61 else:
37 continue 62 states.append(6)
38 63
39 t = time.mktime(time.strptime(m.group(1), datefmt)) 64 return(times, fermTemps, fridgeTemps, ambTemps, targetTemps, states)
40 if (start != None and t < start): 65
41 continue 66 def doplot(times, fermTemps, fridgeTemps, ambTemps, targetTemps, states, outfile):
67 assert(len(times) == len(fermTemps))
68 assert(len(times) == len(fridgeTemps))
69 assert(len(times) == len(ambTemps))
70 assert(len(times) == len(targetTemps))
71 assert(len(times) == len(states))
72 nrec = len(times)
73 print "nrec = %d" % (nrec)
74 newsz = [1000]
75 then = time.time()
76 times = rebin(numpy.array(times), newsz)
77 fermTemps = rebin(numpy.array(fermTemps), newsz)
78 fridgeTemps = rebin(numpy.array(fridgeTemps), newsz)
79 ambTemps = rebin(numpy.array(ambTemps), newsz)
80 targetTemps = rebin(numpy.array(targetTemps), newsz)
81 states = rebin(numpy.array(states, 'f'), newsz)
82 now = time.time()
83 print "Rebinning took %.2f msec" % ((now - then) * 1000)
84
85 title = "%s to %s (%d -> %d pts)" % (matplotlib.dates._from_ordinalf(times[0]).strftime(datefmt),
86 matplotlib.dates._from_ordinalf(times[-1]).strftime(datefmt),
87 nrec, len(times))
88 print title
89
90 then = time.time()
91 # A figure
92 fig = matplotlib.figure.Figure(figsize = (9.0, 5.0))
93
94 # Create a plot, get some axes
95 ax = fig.add_subplot(111)
96
97 # Plot the data onto the axes
98 p = ax.plot(times, fermTemps, times, fridgeTemps, times, ambTemps, times, targetTemps, times, states, '.')
99 ax.set_title(title, weight = 'bold')
100 ax.set_autoscale_on(True)
42 101
43 if (end != None and t > end): 102 # Add a formatter
44 continue 103 hoursFmt = matplotlib.dates.DateFormatter('%d %b\n%H:%M')
104 ax.xaxis.set_major_formatter(hoursFmt)
45 105
46 fermTemp = float(m.group(2)) 106 # Prettify it
47 fridgeTemp = float(m.group(3)) 107 ax.grid(True)
48 ambTemp = float(m.group(4)) 108 ax.set_xlabel('Date')
49 state = m.group(5) 109 ax.set_ylabel('Temperature(C)')
50 110
51 times.append(t / (24 * 60 * 60)) # Is in float days 111 # Set the legend
52 fermTemps.append(fermTemp) 112 legend = ax.legend((p[0], p[1], p[2], p[3], p[4]), ('Fermenter', 'Fridge', 'Ambient', 'Target', 'State'), 'best')
53 fridgeTemps.append(fridgeTemp) 113
54 ambTemps.append(ambTemp) 114 # Render the figure
55 states.append(state) 115 canvas = matplotlib.backends.backend_agg.FigureCanvasAgg(fig)
56 targetTemps.append(targetTemp) 116 canvas.print_figure(outfile, dpi = 96)
117 now = time.time()
118 print "Plotting took %.2f msec" % ((now - then) * 1000)
57 119
58 print "From %s to %s" % (time.asctime(time.localtime(times[0] * (24 * 60 * 60))), 120 def main():
59 time.asctime(time.localtime(times[-1] * (24 * 60 * 60)))) 121 logf = open(sys.argv[1], 'r')
60 fig = pylab.figure() 122 outfile = sys.argv[1][:-3] + 'png'
61 ax = fig.add_subplot(111) 123
62 p = ax.plot(times, fermTemps, times, fridgeTemps, times, ambTemps, times, targetTemps) 124 try:
63 ax.set_autoscale_on(True) 125 # Try reading the pickled data
64 hoursFmt = pylab.DateFormatter('%d %b %H:%M', tz = tz) 126 p = cPickle.Unpickler(open("data.pck", "r"))
65 ax.xaxis.set_major_formatter(hoursFmt) 127 then = time.time()
66 labels = ax.get_xticklabels() 128 times, fermTemps, fridgeTemps, ambTemps, targetTemps, states, offs = p.load()
67 pylab.setp(labels, 'rotation', 5.0) 129 now = time.time()
68 ax.grid(True) 130 print "Unpickle took %.2f msec" % ((now - then) * 1000)
69 ax.set_xlabel('time(UTC)') 131 # Seek up to the last place we parsed
70 ax.set_ylabel('Temperature(C)') 132 logf.seek(offs)
71 pylab.legend((p[0], p[1], p[2], p[3]), ('Fermenter', 'Fridge', 'Ambient', 'Target'), 'best') 133 del p
72 #pylab.legend((p[0], p[1], p[2]), ('Fermenter', 'Fridge', 'Ambient'), 'best') 134 print "Parsed pickle OK"
73 #pylab.axhline(y = targetTemp) 135
74 pylab.show() 136 except (IOError, cPickle.UnpicklingError, ValueError):
137 # Either the pickle doesn't exist, or it's invalid, start anew
138 print "Can't read pickle, starting from scratch"
139 times = []
140 fermTemps = []
141 fridgeTemps = []
142 ambTemps = []
143 states = []
144 targetTemps = []
145
146 then = time.time()
147 parselog(logf, start, end, times, fermTemps, fridgeTemps, ambTemps, targetTemps, states)
148 now = time.time()
149 print "Parselog took %.2f msec" % ((now - then) * 1000)
150
151 # Write the pickle back out
152 p = cPickle.Pickler(open("data.pck", "w"), protocol = -1)
153 then = time.time()
154 p.dump((times, fermTemps, fridgeTemps, ambTemps, targetTemps, states, logf.tell()))
155 now = time.time()
156 print "Pickle took %.2f msec" % ((now - then) * 1000)
157 del p
158
159 # Do the plot
160 doplot(times, fermTemps, fridgeTemps, ambTemps, targetTemps, states, outfile)
161
162 def rebin(a, newshape):
163 '''Rebin an array to a new shape.
164 '''
165 assert len(a.shape) == len(newshape)
166
167 slices = [slice(0, old, float(old)/new) for old,new in zip(a.shape,newshape) ]
168 coordinates = numpy.mgrid[slices]
169 indices = coordinates.astype('i') #choose the biggest smaller integer index
170 return a[tuple(indices)]
171
172 if __name__ == "__main__":
173 main()