Mercurial > ~darius > hgwebdir.cgi > beermon
changeset 12:87d9d862ecc4
Avoid using pylab helper functions to reduce the magic level.
author | darius |
---|---|
date | Tue, 23 Oct 2007 01:01:48 +0000 |
parents | 17449d52d5e5 |
children | 3dad7161af87 |
files | logplot.py |
diffstat | 1 files changed, 154 insertions(+), 55 deletions(-) [+] |
line wrap: on
line diff
--- a/logplot.py Tue Oct 23 01:00:19 2007 +0000 +++ b/logplot.py Tue Oct 23 01:01:48 2007 +0000 @@ -1,74 +1,173 @@ #!/usr/bin/env python -import re, datetime, time, pylab, matplotlib +import re, datetime, time, sys, cPickle, numpy +import matplotlib +import matplotlib.figure +import matplotlib.backends.backend_agg +import matplotlib.dates + daterestr = '([0-9]{4}/[0-9]{2}/[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}): ' targtre = re.compile(daterestr + 'target temperature - (-?[0-9]+\.[0-9]+)') -linere = re.compile(daterestr + '(-?[0-9]+\.[0-9]+)\s+(-?[0-9]+\.[0-9]+)\s+(-?[0-9]+\.[0-9]+)\s+([a-z-]+)\s+([a-z-]+)') +templre = re.compile(daterestr + '(-?[0-9]+\.[0-9]+)\s+(-?[0-9]+\.[0-9]+)\s+(-?[0-9]+\.[0-9]+)\s+([a-z-]+)\s+([a-z-]+)') datefmt = '%Y/%m/%d %H:%M:%S' tz = matplotlib.pytz.timezone('Australia/Adelaide') -targetTemp = 18.0 -logfile = '/tmp/beermon.log' -start = time.mktime(time.strptime("2007/09/24 00:00:00", datefmt)) -#end = time.mktime(time.strptime("2007/09/28 00:00:00", datefmt)) +#start = time.mktime(time.strptime("2007/09/22 14:00:00", datefmt)) +start = None +#end = time.mktime(time.strptime("2007/09/30 14:00:00", datefmt)) end = None -f = open(logfile) +def parselog(f, start, end, times, fermTemps, fridgeTemps, ambTemps, targetTemps, states): + targetTemp = 18.0 # Have to guess this.. -times = [] -fermTemps = [] -fridgeTemps = [] -ambTemps = [] -states = [] -targetTemps = [] + for line in f: + # Log line? + m = templre.match(line) + if (m == None): + # No, might be a target temp line + m = targtre.match(line) + if (m != None): + # Parse date portion + t = datetime.datetime(*time.strptime(m.group(1), datefmt)[0:6]) + if ((start != None and t < start) or (end != None and t > end)): + continue -for line in f: - m = linere.match(line) - if (m == None): - m = targtre.match(line) - if (m != None): - t = time.mktime(time.strptime(m.group(1), datefmt)) - if (t < start or t > end): + targetTemp = float(m.group(2)) + continue + else: + # Isn't anything, next! continue - targetTemp = float(m.group(2)) + # Parse date portion + t = datetime.datetime(*time.strptime(m.group(1), datefmt)[0:6]) + if ((start != None and t < start) or (end != None and t > end)): continue + + fermTemp = float(m.group(2)) + fridgeTemp = float(m.group(3)) + ambTemp = float(m.group(4)) + state = m.group(5) + + # Convert to Gregorian days (float) because that is what matplotlib uses + times.append(matplotlib.dates._to_ordinalf(t)) + fermTemps.append(fermTemp) + fridgeTemps.append(fridgeTemp) + ambTemps.append(ambTemp) + targetTemps.append(targetTemp) + if (state == 'heat'): + states.append(10) + elif (state == 'idle'): + states.append(8) else: - continue + states.append(6) + + return(times, fermTemps, fridgeTemps, ambTemps, targetTemps, states) - t = time.mktime(time.strptime(m.group(1), datefmt)) - if (start != None and t < start): - continue +def doplot(times, fermTemps, fridgeTemps, ambTemps, targetTemps, states, outfile): + assert(len(times) == len(fermTemps)) + assert(len(times) == len(fridgeTemps)) + assert(len(times) == len(ambTemps)) + assert(len(times) == len(targetTemps)) + assert(len(times) == len(states)) + nrec = len(times) + print "nrec = %d" % (nrec) + newsz = [1000] + then = time.time() + times = rebin(numpy.array(times), newsz) + fermTemps = rebin(numpy.array(fermTemps), newsz) + fridgeTemps = rebin(numpy.array(fridgeTemps), newsz) + ambTemps = rebin(numpy.array(ambTemps), newsz) + targetTemps = rebin(numpy.array(targetTemps), newsz) + states = rebin(numpy.array(states, 'f'), newsz) + now = time.time() + print "Rebinning took %.2f msec" % ((now - then) * 1000) + + title = "%s to %s (%d -> %d pts)" % (matplotlib.dates._from_ordinalf(times[0]).strftime(datefmt), + matplotlib.dates._from_ordinalf(times[-1]).strftime(datefmt), + nrec, len(times)) + print title + + then = time.time() + # A figure + fig = matplotlib.figure.Figure(figsize = (9.0, 5.0)) + + # Create a plot, get some axes + ax = fig.add_subplot(111) + + # Plot the data onto the axes + p = ax.plot(times, fermTemps, times, fridgeTemps, times, ambTemps, times, targetTemps, times, states, '.') + ax.set_title(title, weight = 'bold') + ax.set_autoscale_on(True) - if (end != None and t > end): - continue - - fermTemp = float(m.group(2)) - fridgeTemp = float(m.group(3)) - ambTemp = float(m.group(4)) - state = m.group(5) + # Add a formatter + hoursFmt = matplotlib.dates.DateFormatter('%d %b\n%H:%M') + ax.xaxis.set_major_formatter(hoursFmt) - times.append(t / (24 * 60 * 60)) # Is in float days - fermTemps.append(fermTemp) - fridgeTemps.append(fridgeTemp) - ambTemps.append(ambTemp) - states.append(state) - targetTemps.append(targetTemp) + # Prettify it + ax.grid(True) + ax.set_xlabel('Date') + ax.set_ylabel('Temperature(C)') + + # Set the legend + legend = ax.legend((p[0], p[1], p[2], p[3], p[4]), ('Fermenter', 'Fridge', 'Ambient', 'Target', 'State'), 'best') + + # Render the figure + canvas = matplotlib.backends.backend_agg.FigureCanvasAgg(fig) + canvas.print_figure(outfile, dpi = 96) + now = time.time() + print "Plotting took %.2f msec" % ((now - then) * 1000) + +def main(): + logf = open(sys.argv[1], 'r') + outfile = sys.argv[1][:-3] + 'png' -print "From %s to %s" % (time.asctime(time.localtime(times[0] * (24 * 60 * 60))), - time.asctime(time.localtime(times[-1] * (24 * 60 * 60)))) -fig = pylab.figure() -ax = fig.add_subplot(111) -p = ax.plot(times, fermTemps, times, fridgeTemps, times, ambTemps, times, targetTemps) -ax.set_autoscale_on(True) -hoursFmt = pylab.DateFormatter('%d %b %H:%M', tz = tz) -ax.xaxis.set_major_formatter(hoursFmt) -labels = ax.get_xticklabels() -pylab.setp(labels, 'rotation', 5.0) -ax.grid(True) -ax.set_xlabel('time(UTC)') -ax.set_ylabel('Temperature(C)') -pylab.legend((p[0], p[1], p[2], p[3]), ('Fermenter', 'Fridge', 'Ambient', 'Target'), 'best') -#pylab.legend((p[0], p[1], p[2]), ('Fermenter', 'Fridge', 'Ambient'), 'best') -#pylab.axhline(y = targetTemp) -pylab.show() + try: + # Try reading the pickled data + p = cPickle.Unpickler(open("data.pck", "r")) + then = time.time() + times, fermTemps, fridgeTemps, ambTemps, targetTemps, states, offs = p.load() + now = time.time() + print "Unpickle took %.2f msec" % ((now - then) * 1000) + # Seek up to the last place we parsed + logf.seek(offs) + del p + print "Parsed pickle OK" + + except (IOError, cPickle.UnpicklingError, ValueError): + # Either the pickle doesn't exist, or it's invalid, start anew + print "Can't read pickle, starting from scratch" + times = [] + fermTemps = [] + fridgeTemps = [] + ambTemps = [] + states = [] + targetTemps = [] + + then = time.time() + parselog(logf, start, end, times, fermTemps, fridgeTemps, ambTemps, targetTemps, states) + now = time.time() + print "Parselog took %.2f msec" % ((now - then) * 1000) + + # Write the pickle back out + p = cPickle.Pickler(open("data.pck", "w"), protocol = -1) + then = time.time() + p.dump((times, fermTemps, fridgeTemps, ambTemps, targetTemps, states, logf.tell())) + now = time.time() + print "Pickle took %.2f msec" % ((now - then) * 1000) + del p + + # Do the plot + doplot(times, fermTemps, fridgeTemps, ambTemps, targetTemps, states, outfile) + +def rebin(a, newshape): + '''Rebin an array to a new shape. + ''' + assert len(a.shape) == len(newshape) + + slices = [slice(0, old, float(old)/new) for old,new in zip(a.shape,newshape) ] + coordinates = numpy.mgrid[slices] + indices = coordinates.astype('i') #choose the biggest smaller integer index + return a[tuple(indices)] + +if __name__ == "__main__": + main()