from Tkinter import * import math from Cantera.num import * def plotLimits(ypts, f=0.0, ndiv=5, logscale=0): """Return plot limits that""" if logscale: threshold = 1.0e-19 else: threshold = -1.0e20 ymax = -1.e20 ymin = 1.e20 for y in ypts: if y > ymax: ymax = y if y < ymin and y > threshold: ymin = y dy = abs(ymax - ymin) if logscale: ymin = math.floor(math.log10(ymin)) ymax = math.floor(math.log10(ymax))+1 fctr = 1.0 ## if dy < 0.2*ymin: ## ymin = ymin*.9 ## ymax = ymax*1.1 ## dy = abs(ymax - ymin) ## else: else: ymin = ymin - f*dy ymax = ymax + f*dy dy = abs(ymax - ymin) try: p10 = math.floor(math.log10(0.1*dy)) fctr = math.pow(10.0, p10) except: return (ymin -1.0, ymax + 1.0, 1.0) mm = [2.0, 2.5, 2.0] i = 0 while dy/fctr > ndiv: fctr = mm[i % 3]*fctr i = i + 1 ymin = fctr*math.floor(ymin/fctr) ymax = fctr*(math.floor(ymax/fctr+0.999)) return (ymin, ymax, fctr) class DataGraph(Frame): def __init__(self,master, data, ix=0, iy=0, title='', label = ('x-axis','y-axis'), logscale = (0,0), pixelX=500, pixelY=500): self.logscale = logscale self.data = data self.ix = ix self.iy = iy self.minX, self.maxX, self.dx = plotLimits(data[ix,:], logscale=self.logscale[0]) self.minY, self.maxY, self.dy = plotLimits(data[iy,:], logscale=self.logscale[1]) Frame.__init__(self,master, relief=RIDGE, bd=2) self.title = Label(self,text=' ') self.title.grid(row=0,column=1,sticky=W+E) self.graph_w, self.graph_h = pixelX - 120, pixelY - 70 self.origin = (100, 20) self.canvas = Canvas(self, width=pixelX, height=pixelY, relief=SUNKEN,bd=1) id = self.canvas.create_rectangle(self.origin[0],self.origin[1], pixelX-20,pixelY-50) self.canvas.grid(row=1,column=1,rowspan=2,sticky=N+S+E+W) self.last_points=[] self.ticks(self.minX, self.maxX, self.dx, self.minY, self.maxY, self.dy, 10) self.screendata() self.draw() self.canvas.create_text(self.origin[0] + self.graph_w/2, self.origin[1] + self.graph_h + 30, text=label[0],anchor=N) self.canvas.create_text(self.origin[0] - 50, self.origin[1] + self.graph_h/2, text=label[1],anchor=E) def writeValue(self, y): yval = '%15.4f' % (y) self.title.config(text = yval) def delete(self, ids): for id in ids: self.canvas.delete(id) def screendata(self): self.xdata = array(self.data[self.ix,:]) self.ydata = array(self.data[self.iy,:]) npts = len(self.ydata) if self.logscale[0] > 0: self.xdata = log10(self.xdata) if self.logscale[1] > 0: self.ydata = log10(self.ydata) f = float(self.graph_w)/(self.maxX-self.minX) self.xdata = (self.xdata - self.minX)*f + self.origin[0] f = float(self.graph_h)/(self.maxY-self.minY) self.ydata = (self.maxY - self.ydata)*f + self.origin[1] def toscreen(self,x,y): if self.logscale[0] > 0: x = log10(x) if self.logscale[1] > 0: y = log10(y) f = float(self.graph_w)/(self.maxX-self.minX) xx = (x - self.minX)*f + self.origin[0] f = float(self.graph_h)/(self.maxY-self.minY) yy = (self.maxY - y)*f + self.origin[1] return (xx, yy) def move(self, id, newpos, oldpos): dxpt = (newpos[0] - oldpos[0])/(self.maxX-self.minX)*self.graph_w dypt = -(newpos[1] - oldpos[1])/(self.maxY-self.minY)*self.graph_h self.canvas.move(id, dxpt, dypt) self.writeValue(newpos[1]) def plot(self,n,color='black'): xpt, ypt = self.toscreen(self.data[self.ix,n], self.data[self.iy,n]) #xpt = (x-self.minX)/(self.maxX-self.minX)*float(self.graph_w) + self.origin[0] #ypt = (self.maxY-y)/(self.maxY-self.minY)*float(self.graph_h) + self.origin[1] id_ycross = self.canvas.create_line(xpt,self.graph_h+self.origin[1],xpt,self.origin[1],fill = 'gray') id_xcross = self.canvas.create_line(self.origin[0],ypt,self.graph_w+self.origin[0],ypt,fill = 'gray') id = self.canvas.create_oval(xpt-2,ypt-2,xpt+2,ypt+2,fill=color) #self.writeValue(y) s = '(%g, %g)' % (self.data[self.ix,n],self.data[self.iy,n]) if n > 0 and self.data[self.iy,n] > self.data[self.iy,n-1]: idt = self.canvas.create_text(xpt+5,ypt+5,text=s,anchor=NW) else: idt = self.canvas.create_text(xpt+5,ypt-5,text=s,anchor=SW) return [id,id_xcross,id_ycross, idt] def draw(self,color='red'): npts = len(self.xdata) for n in range(1,npts): self.canvas.create_line(self.xdata[n-1],self.ydata[n-1], self.xdata[n],self.ydata[n],fill=color) def addLabel(self, y, orient=0): if orient==0: xpt, ypt = self.toscreen(y, 1.0) ypt = self.origin[1] + self.graph_h + 5 self.canvas.create_text(xpt,ypt,text=y,anchor=N) else: xpt, ypt = self.toscreen(self.minX, y) xpt = self.origin[0] - 5 self.canvas.create_text(xpt,ypt,text=y,anchor=E) def addLegend(self,text,color=None): m=Message(self,text=text,width=self.graph_w-10) m.pack(side=BOTTOM) if color: m.config(fg=color) def pauseWhenFinished(self): self.wait_window() def minorTicks(self, x0, x1, y, n, size, orient=0): xtick = x0 dx = (x1 - x0)/float(n) if orient == 0: while xtick <= x1: xx, yy = self.toscreen(xtick, y) self.canvas.create_line(xx,yy, xx,yy-size) xtick += dx else: while xtick <= x1: xx, yy = self.toscreen(y, xtick) self.canvas.create_line(xx,yy, xx+size,yy) xtick += dx def ticks(self, xmin, xmax, dx, ymin, ymax, dy, size): if self.logscale[0]: xmin = math.pow(10.0,xmin) xmax = math.pow(10.0,xmax) if self.logscale[1]: ymin = math.pow(10.0,ymin) ymax = math.pow(10.0,ymax) n = 5 ytick = ymin while ytick <= ymax: xx, yy = self.toscreen(xmin, ytick) self.canvas.create_line(xx, yy, xx + size,yy) self.addLabel(ytick,1) xx, yy = self.toscreen(xmax, ytick) self.canvas.create_line(xx, yy, xx - size,yy) ytick0 = ytick if self.logscale[1]: ytick *= 10.0 n = 10 else: ytick = ytick + dy if ytick <= ymax: self.minorTicks(ytick0, ytick, xmin, n, 5, 1) self.minorTicks(ytick0, ytick, xmax, n, -5, 1) n = 5 xtick = xmin while xtick <= xmax: xx, yy = self.toscreen(xtick, ymin) self.canvas.create_line(xx, yy, xx, yy - size) self.addLabel(xtick,0) xx, yy = self.toscreen(xtick, ymax) self.canvas.create_line(xx, yy, xx, yy + size) if self.logscale[0]: xtick *= 10.0 n = 10 else: xtick = xtick + dx if xtick <= xmax: self.minorTicks(xtick - dx, xtick, ymin, n, 5, 0) self.minorTicks(xtick - dx, xtick, ymax, n, -5, 0)