Mercurial > ~darius > hgwebdir.cgi > beermon
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() |