from Tkinter import * from array import * def quadratic(x,c): return(x*x + c) OutOfBounds = "Out of Bounds" class Graphalyzer: def __init__(self, width=400, height=300, x_min=0.0, x_max=1.1, c=.25, f=quadratic, orbit_size = 300): self.width, self.height = width, height self.x_min, self.x_max, self.f, self.c = x_min, x_max, f, c self.orbit_size = orbit_size self.x_value = array('f', range(self.width)) self.y_value = array('f', range(self.width)) self.orbit_value = [] self.window = Tk() self.window.title('Graphalyzer') self.canvas = Canvas(self.window, width=width, height=height,cursor='plus') self.canvas.bind("", self.motion) self.canvas.bind("", self.leave) self.canvas.bind("", self.mouse_up) self.canvas.pack() self.dot = None self.graph = None self.identity = None self.orbit_steps = [] self.orbit_dots = [] self.set(x_min, x_max, c, f) def motion(self, event): if self.dot : self.canvas.delete(self.dot) self.dot = None try: y = int( (self.y_max - self.x_value[event.x])/self.delta_y ) except IndexError: return self.dot = self.canvas.create_oval(event.x - 2, y - 2, event.x + 2, y + 2) return def leave(self, event): if self.dot : self.canvas.delete(self.dot) self.dot = None def mouse_up(self, event): self.erase_orbit() self.make_orbit(event.x) def set(self, x_min=None, x_max=None, c=None, f=None): self.erase_orbit() if x_min: self.x_min = float(x_min) if x_max: self.x_max = float(x_max) if c: self.c = float(c) if f: self.f = f self.delta_x = (self.x_max - self.x_min)/self.width for i in range(self.width): self.x_value[i] = self.x_min + i*self.delta_x if self.graph: self.canvas.delete(self.graph) self.graph = self.make_graph() if self.identity: self.canvas.delete(self.identity) self.identity = self.make_identity() def pixels(self,x,y): x_pixel = int( (x - self.x_min)/self.delta_x ) y_pixel = int( (self.y_max - y)/self.delta_y ) return (x_pixel, y_pixel) def make_identity(self): points = [] for i in range(self.width): points.append(i) points.append(int( (self.y_max - self.x_value[i])/self.delta_y )) points.append({'fill':'darkgreen'}) return self.canvas.create_line(*points) def make_graph(self): self.y_min = self.x_min self.y_max = self.x_max for i in range(self.width): y = self.f(self.x_value[i], self.c) if y > self.y_max: self.y_max = y if y < self.y_min: self.y_min = y self.y_value[i] = y self.delta_y = (self.y_max - self.y_min)/self.height points = [] for i in range(self.width): points.append(i) points.append( int( (self.y_max - self.y_value[i])/self.delta_y ) ) points.append({'fill':'blue'}) return self.canvas.create_line(*points) def make_dot(self, x): x0, y0 = self.pixels(x,x) return self.canvas.create_oval(x0-2, y0-2, x0+2, y0+2, fill='red') def make_orbit(self, x_index): x_val = self.x_value[x_index] self.orbit_value.append(x_val) self.orbit_dots.append( self.make_dot(x_val) ) try: for i in range (self.orbit_size): self.extend_orbit() except OutOfBounds: return def erase_orbit(self): for step in self.orbit_steps: self.canvas.delete(step) for dot in self.orbit_dots: self.canvas.delete(dot) self.orbit_steps = [] self.orbit_dots = [] self.orbit_value=[] def extend_orbit(self): x_val = self.orbit_value[-1] if x_val > self.x_max or x_val < self.x_min: raise OutOfBounds y_val = self.f(x_val, self.c) self.orbit_value.append(y_val) x0, y0 = self.pixels(x_val, x_val) x1, y1 = self.pixels(y_val, y_val) if abs(x1 - x0) > 10: self.orbit_steps.append( self.canvas.create_line(x0, y0, x0, y1, x1, y1, arrow=LAST, arrowshape=(8,10,2)) ) else: self.orbit_steps.append( self.canvas.create_line(x0, y0, x0, y1, x1, y1) ) self.orbit_dots.append( self.make_dot(y_val) )