#!/usr/bin/env python # -*- coding: UTF-8 -*- """ Simple Function graph Plotter © Thomas Führinger, Sam Tygier 2005-2007 http://lybniz2.sourceforge.net/ Version 1.3.2 Requires PyGtk 2.6 Released under the terms of the revised BSD license Modified: 2007-12-14 """ from __future__ import division import gtk, pango import sys import math from math import * app_version = "1.3.2" try: import gnome props = {gnome.PARAM_APP_DATADIR : '/usr/local/share'} prog = gnome.program_init("lybniz", str(app_version), properties=props) except: print "Gnome not found" import gettext gettext.install('lybniz') # profiling enable_profiling = False if enable_profiling: from time import time app_win = None actions = gtk.ActionGroup("General") graph = None connect_points = True x_res = 1 x_max = "5.0" x_min = "-5.0" x_scale = "1.0" y_max = "3.0" y_min = "-3.0" y_scale = "1.0" y1 = "sin(x)" y2 = "" y3 = "" icon_file = "/usr/local/share/pixmaps/lybniz.png" # some extra maths functions def fac(x): if type(x) != int or x < 0: raise ValueError if x==0: return 1 for n in range(2,x): x = x*n return x def sinc(x): if x == 0: return 1 return sin(x)/x # create a safe namespace for the eval()s in the graph drawing code def sub_dict(somedict, somekeys, default=None): return dict([ (k, somedict.get(k, default)) for k in somekeys ]) # a list of the functions from math that we want. safe_list = ['math','acos', 'asin', 'atan', 'atan2', 'ceil', 'cos', 'cosh', 'degrees', 'e', 'exp', 'fabs', 'floor', 'fmod', 'frexp', 'hypot', 'ldexp', 'log', 'log10', 'modf', 'pi', 'pow', 'radians', 'sin', 'sinh', 'sqrt', 'tan', 'tanh','fac','sinc'] safe_dict = sub_dict(locals(), safe_list) #add any needed builtins back in. safe_dict['abs'] = abs def marks(min_val,max_val,minor=1): "yield positions of scale marks between min and max. For making minor marks, set minor to the number of minors you want between majors" try: min_val = float(min_val) max_val = float(max_val) except: print "needs 2 numbers" raise ValueError if(min_val >= max_val): print "min bigger or equal to max" raise ValueError a = 0.2 # tweakable control for when to switch scales # big a value results in more marks a = a + log10(minor) width = max_val - min_val log10_range = log10(width) interval = 10 ** int(floor(log10_range - a)) lower_mark = min_val - fmod(min_val,interval) if lower_mark < min_val: lower_mark += interval a_mark = lower_mark while a_mark <= max_val: if abs(a_mark) < interval / 2: a_mark = 0 yield a_mark a_mark += interval class GraphClass: def __init__(self): # Create backing pixmap of the appropriate size def configure_event(widget, event): x, y, w, h = widget.get_allocation() self.pix_map = gtk.gdk.Pixmap(widget.window, w, h) # make colors self.gc = dict() for name, color in (('black',(0,0,0)),('red',(32000,0,0)),('blue',(0,0,32000)),('green',(0,32000,0))): self.gc[name] =self.pix_map.new_gc() self.gc[name].set_rgb_fg_color(gtk.gdk.Color(red=color[0],green=color[1],blue=color[2])) self.layout = pango.Layout(widget.create_pango_context()) self.canvas_width = w self.canvas_height = h self.x_max = eval(x_max,{"__builtins__":{}},safe_dict) self.x_min = eval(x_min,{"__builtins__":{}},safe_dict) self.x_scale = eval(x_scale,{"__builtins__":{}},safe_dict) self.y_max = eval(y_max,{"__builtins__":{}},safe_dict) self.y_min = eval(y_min,{"__builtins__":{}},safe_dict) self.y_scale = eval(y_scale,{"__builtins__":{}},safe_dict) self.plot() return True # Redraw the screen from the backing pixmap def expose_event(widget, event): x, y, w, h = event.area widget.window.draw_drawable(widget.get_style().fg_gc[gtk.STATE_NORMAL], self.pix_map, x, y, x, y, w, h) return False # Start marking selection def button_press_event(widget, event): global x_sel, y_sel if event.button == 1: self.selection[0][0], self.selection[0][1] = int(event.x), int(event.y) self.selection[1][0], self.selection[1][1] = None, None # End of selection def button_release_event(widget, event): if event.button == 1 and event.x != self.selection[0][0] and event.y != self.selection[0][1]: xmi, ymi = min(self.graph_x(self.selection[0][0]), self.graph_x(event.x)), min(self.graph_y(self.selection[0][1]), self.graph_y(event.y)) xma, yma = max(self.graph_x(self.selection[0][0]), self.graph_x(event.x)), max(self.graph_y(self.selection[0][1]), self.graph_y(event.y)) self.x_min, self.y_min, self.x_max, self.y_max = xmi, ymi, xma, yma parameter_entries_repopulate() graph.plot() self.selection[1][0] = None self.selection[0][0] = None # Draw rectangle during mouse movement def motion_notify_event(widget, event): if event.is_hint: x, y, state = event.window.get_pointer() else: x = event.x y = event.y state = event.state if state & gtk.gdk.BUTTON1_MASK and self.selection[0][0] is not None: gc = self.drawing_area.get_style().black_gc gc.set_function(gtk.gdk.INVERT) if self.selection[1][0] is not None: x0 = min(self.selection[1][0], self.selection[0][0]) y0 = min(self.selection[1][1], self.selection[0][1]) w = abs(self.selection[1][0] - self.selection[0][0]) h = abs(self.selection[1][1] - self.selection[0][1]) self.pix_map.draw_rectangle(gc, False, x0, y0, w, h) x0 = min(self.selection[0][0], int(x)) y0 = min(self.selection[0][1], int(y)) w = abs(int(x) - self.selection[0][0]) h = abs(int(y) - self.selection[0][1]) self.pix_map.draw_rectangle(gc, False, x0, y0, w, h) self.selection[1][0], self.selection[1][1] = int(x), int(y) self.draw_drawable() self.prev_y = [None, None, None] # Marked area point[0, 1][x, y] self.selection = [[None, None], [None, None]] self.drawing_area = gtk.DrawingArea() self.drawing_area.connect("expose_event", expose_event) self.drawing_area.connect("configure_event", configure_event) self.drawing_area.connect("button_press_event", button_press_event) self.drawing_area.connect("button_release_event", button_release_event) self.drawing_area.connect("motion_notify_event", motion_notify_event) self.drawing_area.set_events(gtk.gdk.EXPOSURE_MASK | gtk.gdk.LEAVE_NOTIFY_MASK | gtk.gdk.BUTTON_PRESS_MASK | gtk.gdk.BUTTON_RELEASE_MASK | gtk.gdk.POINTER_MOTION_MASK |gtk.gdk.POINTER_MOTION_HINT_MASK) self.scale_style = "dec" def draw_drawable(self): x, y, w, h = self.drawing_area.get_allocation() self.drawing_area.window.draw_drawable(self.drawing_area.get_style().fg_gc[gtk.STATE_NORMAL], self.pix_map, 0, 0, 0, 0, w, h) def plot(self): self.pix_map.draw_rectangle(self.drawing_area.get_style().white_gc, True, 0, 0, self.canvas_width, self.canvas_height) if (self.scale_style == "cust"): #draw cross self.pix_map.draw_lines(self.gc['black'], [(int(round(self.canvas_x(0))),0),(int(round(self.canvas_x(0))),self.canvas_height)]) self.pix_map.draw_lines(self.gc['black'], [(0,int(round(self.canvas_y(0)))),(self.canvas_width,int(round(self.canvas_y(0))))]) # old style axis marks iv = self.x_scale * self.canvas_width / (self.x_max - self.x_min) # pixel interval between marks os = self.canvas_x(0) % iv # pixel offset of first mark # loop over each mark. for i in xrange(int(self.canvas_width / iv + 1)): #multiples of iv, cause adding of any error in iv, so keep iv as float # use round(), to get to closest pixel, int() to prevent warning self.pix_map.draw_lines(self.gc['black'], [(int(round(os + i * iv)), int(round(self.canvas_y(0) - 5))), (int(round(os + i * iv)), int(round(self.canvas_y(0) + 5)))]) # and the y-axis iv = self.y_scale * self.canvas_height / (self.y_max - self.y_min) os = self.canvas_y(0) % iv for i in xrange(int(self.canvas_height / iv + 1)): self.pix_map.draw_lines(self.gc['black'], [(int(round(self.canvas_x(0) - 5)), int(round(i * iv + os))), (int(round(self.canvas_x(0) + 5)), int(round(i * iv + os)))]) else: #new style factor = 1 if (self.scale_style == "rad"): factor = pi # where to put the numbers numbers_x_pos = -10 numbers_y_pos = 10 # where to center the axis center_x_pix = int(round(self.canvas_x(0))) center_y_pix = int(round(self.canvas_y(0))) if (center_x_pix < 5): center_x_pix = 5 if (center_x_pix < 20):numbers_x_pos = 10 if (center_y_pix < 5): center_y_pix = 5 if (center_x_pix > self.canvas_width - 5): center_x_pix = self.canvas_width - 5 if (center_y_pix > self.canvas_height -5): center_y_pix = self.canvas_height - 5; if (center_y_pix > self.canvas_height -20): numbers_y_pos = - 10 # draw cross self.pix_map.draw_lines(self.gc['black'], [(center_x_pix,0),(center_x_pix,self.canvas_height)]) self.pix_map.draw_lines(self.gc['black'], [(0,center_y_pix),(self.canvas_width,center_y_pix)]) for i in marks(self.x_min / factor, self.x_max / factor): label = '%g' % i if (self.scale_style == "rad"): label += '\xCF\x80' i = i * factor self.pix_map.draw_lines(self.gc['black'], [(int(round(self.canvas_x(i))), center_y_pix - 5), (int(round(self.canvas_x(i))), center_y_pix + 5)]) self.layout.set_text(label) extents = self.layout.get_pixel_extents()[1] if (numbers_y_pos < 0): adjust = extents[3] else: adjust = 0 self.pix_map.draw_layout(self.gc['black'],int(round(self.canvas_x(i))), center_y_pix + numbers_y_pos - adjust,self.layout) for i in marks(self.y_min,self.y_max): label = '%g' % i self.pix_map.draw_lines(self.gc['black'], [(center_x_pix - 5, int(round(self.canvas_y(i)))), (center_x_pix + 5, int(round(self.canvas_y(i))))]) self.layout.set_text(label) extents = self.layout.get_pixel_extents()[1] if (numbers_x_pos < 0): adjust = extents[2] else: adjust = 0 self.pix_map.draw_layout(self.gc['black'],center_x_pix +numbers_x_pos - adjust,int(round(self.canvas_y(i))),self.layout) # minor marks for i in marks(self.x_min / factor, self.x_max / factor, minor=10): i = i * factor self.pix_map.draw_lines(self.gc['black'], [(int(round(self.canvas_x(i))), center_y_pix - 2), (int(round(self.canvas_x(i))), center_y_pix +2)]) for i in marks(self.y_min, self.y_max, minor=10): label = '%g' % i self.pix_map.draw_lines(self.gc['black'], [(center_x_pix - 2, int(round(self.canvas_y(i)))), (center_x_pix +2, int(round(self.canvas_y(i))))]) plots = [] # precompile the functions try: compiled_y1 = compile(y1.replace("^","**"),"",'eval') plots.append((compiled_y1,0,self.gc['blue'])) except: compiled_y1 = None try: compiled_y2 = compile(y2.replace("^","**"),"",'eval') plots.append((compiled_y2,1,self.gc['red'])) except: compiled_y2 = None try: compiled_y3 = compile(y3.replace("^","**"),"",'eval') plots.append((compiled_y3,2,self.gc['green'])) except: compiled_y3 = None self.prev_y = [None, None, None] if enable_profiling: start_graph = time() if len(plots) != 0: for i in xrange(0,self.canvas_width,x_res): x = self.graph_x(i + 1) for e in plots: safe_dict['x']=x try: y = eval(e[0],{"__builtins__":{}},safe_dict) y_c = int(round(self.canvas_y(y))) if y_c < 0 or y_c > self.canvas_height: raise ValueError if connect_points and self.prev_y[e[1]] is not None: self.pix_map.draw_lines(e[2], [(i, self.prev_y[e[1]]), (i + x_res, y_c)]) else: self.pix_map.draw_points(e[2], [(i + x_res, y_c)]) self.prev_y[e[1]] = y_c except: #print "Error at %d: %s" % (x, sys.exc_value) self.prev_y[e[1]] = None if enable_profiling: print "time to draw graph:", (time() - start_graph) * 1000, "ms" self.draw_drawable() def canvas_x(self, x): "Calculate position on canvas to point on graph" return (x - self.x_min) * self.canvas_width / (self.x_max - self.x_min) def canvas_y(self, y): return (self.y_max - y) * self.canvas_height / (self.y_max - self.y_min) def canvas_point(self, x, y): return (self.canvas_x(x), self.canvas_y(y)) def graph_x(self, x): "Calculate position on graph from point on canvas" return x * (self.x_max - self.x_min) / self.canvas_width + self.x_min def graph_y(self, y): return self.y_max - (y * (self.y_max - self.y_min) / self.canvas_height) def menu_toolbar_create(): app_win.menu_main = gtk.MenuBar() menu_file = gtk.Menu() menu_item_file = gtk.MenuItem(_("_File")) menu_item_file.set_submenu(menu_file) actions.save = gtk.Action("Save", _("_Save"), _("Save graph as bitmap"), gtk.STOCK_SAVE) actions.save.connect ("activate", save) actions.add_action(actions.save) menu_item_save = actions.save.create_menu_item() menu_item_save.add_accelerator("activate", app_win.accel_group, ord("S"), gtk.gdk.CONTROL_MASK, gtk.ACCEL_VISIBLE) menu_file.append(menu_item_save) actions.quit = gtk.Action("Quit", _("_Quit"), _("Quit Application"), gtk.STOCK_QUIT) actions.quit.connect ("activate", quit_dlg) actions.add_action(actions.quit) menuItem_quit = actions.quit.create_menu_item() menuItem_quit.add_accelerator("activate", app_win.accel_group, ord("Q"), gtk.gdk.CONTROL_MASK, gtk.ACCEL_VISIBLE) menu_file.append(menuItem_quit) menu_graph = gtk.Menu() menu_item_graph = gtk.MenuItem(_("_Graph")) menu_item_graph.set_submenu(menu_graph) actions.plot = gtk.Action("Plot", _("P_lot"), _("Plot Functions"), gtk.STOCK_REFRESH) actions.plot.connect ("activate", plot) actions.add_action(actions.plot) menu_item_plot = actions.plot.create_menu_item() menu_item_plot.add_accelerator("activate", app_win.accel_group, ord("l"), gtk.gdk.CONTROL_MASK, gtk.ACCEL_VISIBLE) menu_graph.append(menu_item_plot) actions.evaluate = gtk.Action("Evaluate", _("_Evaluate"), _("Evaluate Functions"), gtk.STOCK_EXECUTE) actions.evaluate.connect ("activate", evaluate) actions.add_action(actions.evaluate) menu_item_evaluate = actions.evaluate.create_menu_item() menu_item_evaluate.add_accelerator("activate", app_win.accel_group, ord("e"), gtk.gdk.CONTROL_MASK, gtk.ACCEL_VISIBLE) menu_graph.append(menu_item_evaluate) actions.zoom_in = gtk.Action("zoom_in", _("Zoom _In"), _("Zoom In"), gtk.STOCK_ZOOM_IN) actions.zoom_in.connect ("activate", zoom_in) actions.add_action(actions.zoom_in) menu_item_zoomin = actions.zoom_in.create_menu_item() menu_item_zoomin.add_accelerator("activate", app_win.accel_group, ord("+"), gtk.gdk.CONTROL_MASK, gtk.ACCEL_VISIBLE) menu_graph.append(menu_item_zoomin) actions.zoom_out = gtk.Action("zoom_out", _("Zoom _Out"), _("Zoom Out"), gtk.STOCK_ZOOM_OUT) actions.zoom_out.connect ("activate", zoom_out) actions.add_action(actions.zoom_out) menu_item_zoomout = actions.zoom_out.create_menu_item() menu_item_zoomout.add_accelerator("activate", app_win.accel_group, ord("-"), gtk.gdk.CONTROL_MASK, gtk.ACCEL_VISIBLE) menu_graph.append(menu_item_zoomout) actions.zoom_reset = gtk.Action("zoom_reset", _("Zoom _Reset"), _("Zoom Reset"), gtk.STOCK_ZOOM_100) actions.zoom_reset.connect ("activate", zoom_reset) actions.add_action(actions.zoom_reset) menu_item_zoomreset = actions.zoom_reset.create_menu_item() menu_item_zoomreset.add_accelerator("activate", app_win.accel_group, ord("r"), gtk.gdk.CONTROL_MASK, gtk.ACCEL_VISIBLE) menu_graph.append(menu_item_zoomreset) menu_item_toggle_connect = gtk.CheckMenuItem(_("_Connect Points")) menu_item_toggle_connect.set_active(True) menu_item_toggle_connect.connect ("toggled", toggle_connect) menu_graph.append(menu_item_toggle_connect) menu_scale_style = gtk.Menu() menu_item_scale_style = gtk.MenuItem(_("Scale Style")) menu_item_scale_style.set_submenu(menu_scale_style) menu_graph.append(menu_item_scale_style) actions.dec = gtk.Action("Dec", _("Decimal"), _("Set style to decimal"),None) actions.dec.connect ("activate", scale_dec) actions.add_action(actions.dec) menu_item_dec = actions.dec.create_menu_item() menu_scale_style.append(menu_item_dec) actions.rad = gtk.Action("Rad", _("Radians"), _("Set style to radians"),None) actions.rad.connect ("activate", scale_rad) actions.add_action(actions.rad) menu_item_rad = actions.rad.create_menu_item() menu_scale_style.append(menu_item_rad) actions.cust = gtk.Action("Cust", _("Custom"), _("Set style to custom"),None) actions.cust.connect ("activate", scale_cust) actions.add_action(actions.cust) menu_item_cust = actions.cust.create_menu_item() menu_scale_style.append(menu_item_cust) menu_help = gtk.Menu() menu_item_help = gtk.MenuItem(_("_Help")) menu_item_help.set_submenu(menu_help) actions.Help = gtk.Action("Help", _("_Contents"), _("Help Contents"), gtk.STOCK_HELP) actions.Help.connect ("activate", show_yelp) actions.add_action(actions.Help) menu_item_contents = actions.Help.create_menu_item() menu_item_contents.add_accelerator("activate", app_win.accel_group, gtk.gdk.keyval_from_name("F1"), 0, gtk.ACCEL_VISIBLE) menu_help.append(menu_item_contents) actions.about = gtk.Action("About", _("_About"), _("About Box"), gtk.STOCK_ABOUT) actions.about.connect ("activate", show_about_dialog) actions.add_action(actions.about) menu_item_about = actions.about.create_menu_item() menu_help.append(menu_item_about) app_win.menu_main.append(menu_item_file) app_win.menu_main.append(menu_item_graph) app_win.menu_main.append(menu_item_help) app_win.tool_bar = gtk.Toolbar() app_win.tool_bar.insert(actions.plot.create_tool_item(), -1) app_win.tool_bar.insert(actions.evaluate.create_tool_item(), -1) app_win.tool_bar.insert(gtk.SeparatorToolItem(), -1) app_win.tool_bar.insert(actions.zoom_in.create_tool_item(), -1) app_win.tool_bar.insert(actions.zoom_out.create_tool_item(), -1) app_win.tool_bar.insert(actions.zoom_reset.create_tool_item(), -1) app_win.tool_bar.insert(gtk.SeparatorToolItem(), -1) app_win.tool_bar.insert(actions.quit.create_tool_item(), -1) def plot(widget, event=None): global x_max, x_min, x_scale, y_max, y_min, y_scale, y1, y2, y3 x_max = app_win.x_max_entry.get_text() x_min = app_win.x_min_entry.get_text() x_scale = app_win.x_scale_entry.get_text() y_max = app_win.y_max_entry.get_text() y_min = app_win.y_min_entry.get_text() y_scale = app_win.y_scale_entry.get_text() graph.x_max = eval(x_max,{"__builtins__":{}},safe_dict) graph.x_min = eval(x_min,{"__builtins__":{}},safe_dict) graph.x_scale = eval(x_scale,{"__builtins__":{}},safe_dict) graph.y_max = eval(y_max,{"__builtins__":{}},safe_dict) graph.y_min = eval(y_min,{"__builtins__":{}},safe_dict) graph.y_scale = eval(y_scale,{"__builtins__":{}},safe_dict) y1 = app_win.y1_entry.get_text() y2 = app_win.y2_entry.get_text() y3 = app_win.y3_entry.get_text() graph.plot() def evaluate(widget, event=None): "Evaluate a given x for the three functions" def entry_changed(self): for e in ((y1, dlg_win.y1_entry), (y2, dlg_win.y2_entry), (y3, dlg_win.y3_entry)): try: x = float(dlg_win.x_entry.get_text()) safe_dict['x']=x e[1].set_text(str(eval(e[0].replace("^","**"),{"__builtins__":{}},safe_dict))) except: if len(e[0]) > 0: e[1].set_text("Error: %s" % sys.exc_value) else: e[1].set_text("") def close(self): dlg_win.destroy() dlg_win = gtk.Window(gtk.WINDOW_TOPLEVEL) dlg_win.set_title(_("Evaluate")) dlg_win.connect("destroy", close) dlg_win.x_entry = gtk.Entry() dlg_win.x_entry.set_size_request(200, 24) dlg_win.x_entry.connect("changed", entry_changed) dlg_win.y1_entry = gtk.Entry() dlg_win.y1_entry.set_size_request(200, 24) dlg_win.y1_entry.set_sensitive(False) dlg_win.y2_entry = gtk.Entry() dlg_win.y2_entry.set_size_request(200, 24) dlg_win.y2_entry.set_sensitive(False) dlg_win.y3_entry = gtk.Entry() dlg_win.y3_entry.set_size_request(200, 24) dlg_win.y3_entry.set_sensitive(False) table = gtk.Table(2, 5) label = gtk.Label("x = ") label.set_alignment(0, .5) table.attach(label, 0, 1, 0, 1, xpadding=5, ypadding=5, xoptions=gtk.FILL) table.attach(dlg_win.x_entry, 1, 2, 0, 1) label = gtk.Label("y1 = ") label.set_alignment(0, .5) label.modify_fg(gtk.STATE_NORMAL, gtk.gdk.color_parse("blue")) table.attach(label, 0, 1, 1, 2, xpadding=5, ypadding=5, xoptions=gtk.FILL) table.attach(dlg_win.y1_entry, 1, 2, 1, 2) label = gtk.Label("y2 = ") label.set_alignment(0, .5) label.modify_fg(gtk.STATE_NORMAL, gtk.gdk.color_parse("red")) table.attach(label, 0, 1, 2, 3, xpadding=5, ypadding=5, xoptions=gtk.FILL) table.attach(dlg_win.y2_entry, 1, 2, 2, 3) label = gtk.Label("y3 = ") label.set_alignment(0, .5) label.modify_fg(gtk.STATE_NORMAL, gtk.gdk.color_parse("DarkGreen")) table.attach(label, 0, 1, 3, 4, xpadding=5, ypadding=5, xoptions=gtk.FILL) table.attach(dlg_win.y3_entry, 1, 2, 3, 4) table.set_border_width(24) dlg_win.add(table) dlg_win.show_all() def zoom_in(widget, event=None): "Narrow the plotted section by half" center_x = (graph.x_min + graph.x_max) / 2 center_y = (graph.y_min + graph.y_max) / 2 range_x = (graph.x_max - graph.x_min) range_y = (graph.y_max - graph.y_min) graph.x_min = center_x - (range_x / 4) graph.x_max = center_x + (range_x / 4) graph.y_min = center_y - (range_y / 4) graph.y_max = center_y +(range_y / 4) parameter_entries_repopulate() graph.plot() def zoom_out(widget, event=None): "Double the plotted section" center_x = (graph.x_min + graph.x_max) / 2 center_y = (graph.y_min + graph.y_max) / 2 range_x = (graph.x_max - graph.x_min) range_y = (graph.y_max - graph.y_min) graph.x_min = center_x - (range_x) graph.x_max = center_x + (range_x) graph.y_min = center_y - (range_y) graph.y_max = center_y +(range_y) parameter_entries_repopulate() graph.plot() def zoom_reset(widget, event=None): "Set the range back to the user's input" graph.x_min = eval(x_min,{"__builtins__":{}},safe_dict) graph.y_min = eval(y_min,{"__builtins__":{}},safe_dict) graph.x_max = eval(x_max,{"__builtins__":{}},safe_dict) graph.y_max = eval(y_max,{"__builtins__":{}},safe_dict) parameter_entries_populate() graph.plot() def scale_dec(widget, event=None): graph.scale_style = "dec" app_win.scale_box.hide() plot(None) def scale_rad(widget, event=None): graph.scale_style = "rad" app_win.scale_box.hide() plot(None) def scale_cust(widget, event=None): graph.scale_style = "cust" app_win.scale_box.show() plot(None) def toggle_connect(widget, event=None): "Toggle between a graph that connects points with lines and one that does not" global connect_points connect_points = not connect_points graph.plot() def save(widget, event=None): "Save graph as .png" file_dialog = gtk.FileChooserDialog(_("Save as..."), app_win, gtk.FILE_CHOOSER_ACTION_SAVE, (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_SAVE, gtk.RESPONSE_OK)) file_dialog.set_default_response(gtk.RESPONSE_OK) filter = gtk.FileFilter() filter.add_mime_type("image/png") filter.add_pattern("*.png") file_dialog.add_filter(filter) file_dialog.set_filename("FunctionGraph.png") response = file_dialog.run() if response == gtk.RESPONSE_OK: x, y, w, h = graph.drawing_area.get_allocation() pix_buffer = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, False, 8, w, h) pix_buffer.get_from_drawable(graph.pix_map, graph.pix_map.get_colormap(), 0, 0, 0, 0, w, h) pix_buffer.save(file_dialog.get_filename(), "png") file_dialog.destroy() def quit_dlg(widget, event=None): gtk.main_quit() def show_yelp(widget): #import os #os.system("yelp /usr/local/share/gnome/help/lybniz/C/lybniz-manual.xml") try: gnome.help_display("lybniz") except: print _("Can't Show help") def show_about_dialog(widget): about_dialog = gtk.AboutDialog() about_dialog.set_name("Lybniz") about_dialog.set_version(str(app_version)) #about_dialog.set_copyright(u"© 2005 by Thomas Führinger") about_dialog.set_authors([u"Thomas Führinger","Sam Tygier"]) about_dialog.set_comments(_("Function graph Plotter")) about_dialog.set_license("Revised BSD") about_dialog.set_website("http://lybniz2.sourceforge.net/") try: lybniz_icon = gtk.gdk.pixbuf_new_from_file(icon_file) about_dialog.set_logo(lybniz_icon) except: print "icon not found at", icon_file about_dialog.connect ("response", lambda d, r: d.destroy()) about_dialog.run() def parameter_entries_create(): # create text entries for parameters table = gtk.Table(6, 3) app_win.y1_entry = gtk.Entry() app_win.y1_entry.set_size_request(300, 24) app_win.y2_entry = gtk.Entry() app_win.y3_entry = gtk.Entry() app_win.x_min_entry = gtk.Entry() app_win.x_min_entry.set_size_request(90, 24) app_win.x_min_entry.set_alignment(1) app_win.x_max_entry = gtk.Entry() app_win.x_max_entry.set_size_request(90, 24) app_win.x_max_entry.set_alignment(1) app_win.x_scale_entry = gtk.Entry() app_win.x_scale_entry.set_size_request(90, 24) app_win.x_scale_entry.set_alignment(1) app_win.y_min_entry = gtk.Entry() app_win.y_min_entry.set_size_request(90, 24) app_win.y_min_entry.set_alignment(1) app_win.y_max_entry = gtk.Entry() app_win.y_max_entry.set_size_request(90, 24) app_win.y_max_entry.set_alignment(1) app_win.y_scale_entry = gtk.Entry() app_win.y_scale_entry.set_size_request(90, 24) app_win.y_scale_entry.set_alignment(1) parameter_entries_populate() app_win.y1_entry.connect("key-press-event", key_press_plot) app_win.y2_entry.connect("key-press-event", key_press_plot) app_win.y3_entry.connect("key-press-event", key_press_plot) app_win.x_min_entry.connect("key-press-event", key_press_plot) app_win.y_min_entry.connect("key-press-event", key_press_plot) app_win.x_max_entry.connect("key-press-event", key_press_plot) app_win.y_max_entry.connect("key-press-event", key_press_plot) app_win.x_scale_entry.connect("key-press-event", key_press_plot) app_win.y_scale_entry.connect("key-press-event", key_press_plot) app_win.scale_box = gtk.HBox() label = gtk.Label("y1 = ") label.set_alignment(0, .5) label.modify_fg(gtk.STATE_NORMAL, gtk.gdk.color_parse("blue")) table.attach(label, 0, 1, 0, 1, xpadding=5, ypadding=5, xoptions=gtk.FILL) table.attach(app_win.y1_entry, 1, 2, 0, 1) label = gtk.Label(_("X min")) label.set_alignment(1, .5) table.attach(label, 2, 3, 0, 1, xpadding=5, ypadding=7, xoptions=gtk.FILL) table.attach(app_win.x_min_entry, 3, 4, 0, 1, xoptions=gtk.FILL) label = gtk.Label(_("Y min")) label.set_alignment(1, .5) table.attach(label, 4, 5, 0, 1, xpadding=5, ypadding=5, xoptions=gtk.FILL) table.attach(app_win.y_min_entry, 5, 6, 0, 1, xpadding=5, xoptions=gtk.FILL) label = gtk.Label("y2 = ") label.set_alignment(0, .5) label.modify_fg(gtk.STATE_NORMAL, gtk.gdk.color_parse("red")) table.attach(label, 0, 1, 1, 2, xpadding=5, ypadding=5, xoptions=gtk.FILL) table.attach(app_win.y2_entry, 1, 2, 1, 2) label = gtk.Label(_("X max")) label.set_alignment(1, .5) table.attach(label, 2, 3, 1, 2, xpadding=5, ypadding=7, xoptions=gtk.FILL) table.attach(app_win.x_max_entry, 3, 4, 1, 2, xoptions=gtk.FILL) label = gtk.Label(_("Y max")) label.set_alignment(1, .5) table.attach(label, 4, 5, 1, 2, xpadding=5, ypadding=5, xoptions=gtk.FILL) table.attach(app_win.y_max_entry, 5, 6, 1, 2, xpadding=5, xoptions=gtk.FILL) label = gtk.Label("y3 = ") label.set_alignment(0, .5) label.modify_fg(gtk.STATE_NORMAL, gtk.gdk.color_parse("DarkGreen")) table.attach(label, 0, 1, 2, 3, xpadding=5, ypadding=5, xoptions=gtk.FILL) table.attach(app_win.y3_entry, 1, 2, 2, 3) label = gtk.Label(_("X scale")) label.set_alignment(0, .5) app_win.scale_box.add(label) #table.attach(label, 2, 3, 2, 3, xpadding=5, ypadding=7, xoptions=gtk.FILL) #table.attach(app_win.x_scale_entry, 3, 4, 2, 3, xoptions=gtk.FILL) app_win.scale_box.add(app_win.x_scale_entry) label = gtk.Label(_("Y scale")) label.set_alignment(0, .5) app_win.scale_box.add(label) #table.attach(label, 4, 5, 2, 3, xpadding=5, ypadding=5, xoptions=gtk.FILL) #table.attach(app_win.y_scale_entry, 5, 6, 2, 3, xpadding=5, xoptions=gtk.FILL) app_win.scale_box.add(app_win.y_scale_entry) table.attach(app_win.scale_box, 2, 6, 2, 3, xpadding=5, xoptions=gtk.FILL) return table def parameter_entries_populate(): # set text in entries for parameters with user's input app_win.y1_entry.set_text(y1) app_win.y2_entry.set_text(y2) app_win.y3_entry.set_text(y3) app_win.x_min_entry.set_text(x_min) app_win.x_max_entry.set_text(x_max) app_win.x_scale_entry.set_text(x_scale) app_win.y_min_entry.set_text(y_min) app_win.y_max_entry.set_text(y_max) app_win.y_scale_entry.set_text(y_scale) def parameter_entries_repopulate(): # set text in entries for parameters app_win.y1_entry.set_text(y1) app_win.y2_entry.set_text(y2) app_win.y3_entry.set_text(y3) app_win.x_min_entry.set_text(str(graph.x_min)) app_win.x_max_entry.set_text(str(graph.x_max)) app_win.x_scale_entry.set_text(str(graph.x_scale)) app_win.y_min_entry.set_text(str(graph.y_min)) app_win.y_max_entry.set_text(str(graph.y_max)) app_win.y_scale_entry.set_text(str(graph.y_scale)) def key_press_plot(widget, event): if event.keyval == 65293: plot(None) return True else: return False def main(): global app_win, graph app_win = gtk.Window(gtk.WINDOW_TOPLEVEL) app_win.set_title("Lybniz") app_win.set_default_size(800, 600) app_win.connect("delete-event", quit_dlg) try: app_win.set_icon_from_file(icon_file) except: print "icon not found at", icon_file app_win.accel_group = gtk.AccelGroup() app_win.add_accel_group(app_win.accel_group) app_win.v_box = gtk.VBox(False, 1) app_win.v_box.set_border_width(1) app_win.add(app_win.v_box) app_win.status_bar = gtk.Statusbar() app_win.status_bar.ContextId = app_win.status_bar.get_context_id("Dummy") menu_toolbar_create() app_win.v_box.pack_start(app_win.menu_main, False, True, 0) handle_box = gtk.HandleBox() handle_box.add(app_win.tool_bar) app_win.v_box.pack_start(handle_box, False, True, 0) app_win.v_box.pack_start(parameter_entries_create(), False, True, 4) graph = GraphClass() app_win.v_box.pack_start(graph.drawing_area, True, True, 0) app_win.v_box.pack_start(app_win.status_bar, False, True, 0) app_win.show_all() app_win.scale_box.hide() gtk.main() # Start it all if __name__ == '__main__': main()