#! python import sys sys.path.append("./py-svg") import time import math import svgscene # hardwired min resolution of 60s def logtimeago(fromtime, latesttime): logago = math.log(latesttime - fromtime) minresolution = math.log(300) # 5 minutes if logago < minresolution: return 0 else: return logago - minresolution class inverseLogGraph: def __init__(self, xmin, xmax, xorigin, ymin, ymax, width, height): self._xmin = xmin self._xmax = xmax self._xorigin = xorigin self._ymin = ymin self._ymax = ymax self._width = width self._height = height def xvaltopixel(self, value): if value < self._xmin: raise "value too low" valuelog = logtimeago(value, self._xorigin) xminlog = logtimeago(self._xmin, self._xorigin) xmaxlog = logtimeago(self._xmax, self._xorigin) return self._width * ( xminlog - valuelog ) / ( xminlog - xmaxlog ) def yvaltopixel(self, value): scaled = self._height * ( value - self._ymin ) / ( self._ymax - self._ymin ) return self._height - scaled class dataset: def __init__(self, origintime): self._buckets = [] self._latesttime = origintime def add(self, fromtime, value): bucket = self.getbucket(fromtime) bucket.addtime(fromtime) bucket.add(value) def getbucket(self, fromtime): timeago = logtimeago(fromtime, self._latesttime) bucketnum = int(timeago * 10) while len(self._buckets) <= bucketnum: self._buckets.append(bucket()) return self._buckets[bucketnum] def maxcount(self): maxc = self._buckets[0].max for b in self._buckets: if b.max > maxc: maxc = b.max return maxc def oldesttime(self): return self._buckets[len(self._buckets)-1].mintime def latesttime(self): for b in self._buckets: if b.nonempty(): return b.maxtime def graph(self, scene, graph, css): maxcount = self.maxcount() for b in self._buckets: b.drawmarker(scene, graph, css) def dump(self): for b in self._buckets: if b.nonempty(): b.dump() class bucket: def __init__(self): self.max = None self.min = None self.total = 0 self.points = 0 self.maxtime = None self.mintime = None def add(self, value): if self.max == None or value > self.max: self.max = value if self.min == None or value < self.min: self.min = value self.total = self.total + value self.points = self.points + 1 def addtime(self, time): if self.maxtime == None or time > self.maxtime: self.maxtime = time if self.mintime == None or time < self.mintime: self.mintime = time def dump(self): print self.min, "to", self.max, "avg", (self.total / self.points), "between", time.ctime(self.mintime), "and", time.ctime(self.maxtime) def nonempty(self): return self.max != None def drawmarker(self, scene, graph, css): if not self.nonempty(): return xhigh = graph.xvaltopixel(self.mintime) xlow = graph.xvaltopixel(self.maxtime) midpoint = xlow + ( xhigh - xlow ) / 2 ymax = graph.yvaltopixel(self.max) ymin = graph.yvaltopixel(self.min) yavg = graph.yvaltopixel(self.total / self.points) if xlow == xhigh: scene.line(xlow-1, yavg, xhigh+1, yavg, css) else: scene.line(midpoint, ymin, midpoint, ymax, css) scene.line(xlow, yavg, xhigh, yavg, css) def fileheader(filetitle): print """ """ + filetitle + """

""" + filetitle + """

""" def filefooter(): print """ """ def main(): file = open("inbox.csv") count = 0 lastfrom = 0 origintime = time.time() header = file.readline() datasets = [ dataset(origintime), dataset(origintime), dataset(origintime) ] for line in file: fields = line.split(',') fromtime = float(fields[1]) #if fromtime - lastfrom > 1000000: #print fromtime, logtimeago(fromtime, time.time()) #lastfrom = fromtime count = count + 1 fld = 0 for datapoint in fields[2:]: datasets[fld].add(fromtime, float(datapoint)) fld = fld + 1 #print count #print "read: ", #read.dump() #print "unread: ", #unread.dump() fileheader("email graph") mintime = min([dset.oldesttime() for dset in datasets]) maxtime = max([dset.latesttime() for dset in datasets]) maxcount = max([dset.maxcount() for dset in datasets]) scene = svgscene.scene("graph of email") graph = inverseLogGraph(mintime, maxtime, origintime, 0, maxcount, 800, 600) print "graph between", time.ctime(mintime), "and", time.ctime(maxtime), "max count is", maxcount #print "min time maps to", graph.xvaltopixel(mintime) #print "max time maps to", graph.xvaltopixel(maxtime) scene.line(0, 600, 800, 600, 'axes') scene.line(0, 0, 0, 600, 'axes') # draw a line at midnight "today" now_struct = time.localtime(time.time()) thishr_struct = (now_struct[0], now_struct[1], now_struct[2], now_struct[3], 0, 0, now_struct[6], now_struct[7], now_struct[8]) thishr = time.mktime(thishr_struct) thishr_pix = graph.xvaltopixel(thishr) scene.line(thishr_pix, 0, thishr_pix, 60, 'axes') scene.text(thishr_pix + 3, 60, time.strftime("%H:%M", time.localtime(thishr)), 'axes') midnight_struct = (now_struct[0], now_struct[1], now_struct[2], 0, 0, 0, now_struct[6], now_struct[7], now_struct[8]) midnight = time.mktime(midnight_struct) midnight_pix = graph.xvaltopixel(midnight) scene.line(midnight_pix, 0, midnight_pix, 60, 'axes') scene.text(midnight_pix + 3, 60, time.strftime("%a %d %b %H:%M", time.localtime(midnight)), 'axes') # "yesterday" midnight -= 24 * 60 * 60 midnight_pix = graph.xvaltopixel(midnight) scene.line(midnight_pix, 0, midnight_pix, 60, 'axes') scene.text(midnight_pix + 3, 60, time.strftime("%a", time.localtime(midnight)), 'axes') thismon_struct = (now_struct[0], now_struct[1], 1, 0, 0, 0, now_struct[6], now_struct[7], now_struct[8]) thismon = time.mktime(thismon_struct) thismon_pix = graph.xvaltopixel(thismon) scene.line(thismon_pix, 0, thismon_pix, 60, 'axes') scene.text(thismon_pix + 3, 60, time.strftime("%a %d %b", time.localtime(thismon)), 'axes') css = ['read', 'unread', 'pending'] for dset in datasets: dset.graph(scene, graph, css[0]) css = css[1:] scene.end() filefooter() main()