#!/usr/bin/env python # -*- coding: utf-8 -*- # Version 1.2 12/15/2010 # *************************************************************************** # * Copyright (C) 2010, Paul Lutus * # * * # * This program is free software; you can redistribute it and/or modify * # * it under the terms of the GNU General Public License as published by * # * the Free Software Foundation; either version 2 of the License, or * # * (at your option) any later version. * # * * # * This program is distributed in the hope that it will be useful, * # * but WITHOUT ANY WARRANTY; without even the implied warranty of * # * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * # * GNU General Public License for more details. * # * * # * You should have received a copy of the GNU General Public License * # * along with this program; if not, write to the * # * Free Software Foundation, Inc., * # * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * # *************************************************************************** import re, scipy, pango import matplotlib, matplotlib.pyplot from matplotlib.backends.backend_gtkagg import FigureCanvasGTKAgg as Canvas import gtk class Icon: icon = [ "32 32 17 1", " c None", ". c #000000", "+ c #070707", "@ c #0C0C0C", "# c #141414", "$ c #1D1D1D", "% c #222222", "& c #262626", "* c #2C2C2C", "= c #343434", "- c #3C3C3C", "; c #444444", "> c #4B4B4B", ", c #595959", "' c #646464", ") c #6D6D6D", "! c #808080", " ", " ", " =%@...................# ", " ->>>>>>;;;----====***&$. ", " *>;;----=====****&&&%%$.. ", " #;-----=====****&&&&%%#... ", " .*#+.....%.......#%........ ", " +. +$ .#$. ", " .. ## .$#. ", " . .$@ .@+. ", " .%+ .#+. ", " .*. +#@. ", " .$. @$@. ", " +$. @&@. ", " @$. #*@ ", " #$. %*@ ", " %$. .*=# ", " .*$ .=-# ", " .=# .--# ", " +-@ .;-# ", " #-+ .;-$ ", " .=-. .;-&. , ", " %*=. .--=. ; ", " $*&=. -==# .+ ", " $&$%*. *=*==' @#. ", " $%#$&% %*&%-)!,&&. ", " +*+@#=@ +-%$###+$+ ", " @%+@#=. *%##@+#$. ", " =++*#. +=$@@%$. ", " +**#. +%*&@. ", " ... ... ", " " ] class PolyRegress: def __getitem__(self, key): return self.builder.get_object(key) def __init__(self): self.copyright = "Copyright © 2010 P.Lutus, http://arachnoid.com" self.n = 0 self.page = 1 self.poly = 3 self.data_error = False self.builder = gtk.Builder() self.builder.add_from_file('polyregress_gui.glade') self.mainwindow = self['matplotlib_window'] self.mainwindow.set_icon(gtk.gdk.pixbuf_new_from_xpm_data(Icon.icon)) self.mainwindow.connect('destroy', lambda w: gtk.main_quit()) self.graphic_box = self['graphic_box'] self['quit_button'].connect('clicked', lambda w: gtk.main_quit()) self['button_left'].connect('clicked', lambda w: self.adjust_poly(-1)) self['button_right'].connect('clicked', lambda w: self.adjust_poly(1)) self.tabbed_pane = self['tabbed_pane'] self.tabbed_pane.set_current_page(self.page) self.poly_disp = self['poly_disp'] self.data_text = self['data_text'] self.data_textb = self.data_text.get_buffer() self.data_textb.connect('modified-changed', self.decode_text_data) self.mainwindow.connect('key-press-event', self.keyboard_event) self.keymap = { 'Tab' : self.increment_page, 'Right' : lambda: self.adjust_poly(1), 'Left' : lambda: self.adjust_poly(-1), } self.function_text = self['function_text'] self.function_textb = self.function_text.get_buffer() fontms = pango.FontDescription("Monospace 10") self.function_text.modify_font(fontms) self.data_text.modify_font(fontms) self.plt = matplotlib.pyplot self.figure = self.plt.figure() self.canvas = Canvas(self.figure) self.graphic_box.pack_start(self.canvas, True, True) self.canvas.mpl_connect('motion_notify_event', self.track_mouse_position) self.load_sample_data() self.decode_text_data() def track_mouse_position(self,evt): tt = "Red = data points\nBlue = polynomial fit" s = "" try: # automatically reject out-of-bounds condition xv = float(evt.xdata) yv = float(evt.ydata) s = "X=%.2f, Y=%.2f" % (xv,yv) tt = s + "\n" + tt except: pass self.graphic_box.set_tooltip_text(tt) self['pos_label'].set_text(s) def increment_page(self): self.page = ((self.page + 1) % self.tabbed_pane.get_n_pages()) self.tabbed_pane.set_current_page(self.page) def keyboard_event(self,widget,evt): ks = gtk.gdk.keyval_name(evt.keyval) if(ks in self.keymap): self.keymap[ks]() return True def load_sample_data(self): sample_data = [(-1,-1),(0,3),(1,2.5),(2,5),(3,4),(5,2),(7,5),(9,4)] a = [] float_spec = "%+2.1f " for item in sample_data: for v in item: a.append(float_spec % v) a.append("\n") self.data_textb.set_text("".join(a)) def decode_text_data(self,*args): x = [] y = [] n = 0 self.maxx = self.maxy = -1e9 self.minx = self.miny = 1e9 start, end = self.data_textb.get_bounds() data = self.data_textb.get_text(start,end) for n,item in enumerate(re.finditer(r"([\d\.e\+-]+)",data)): s = item.group(0) try: v = float(s) except: print("Data conversion error: %s" % s) if(n % 2): y.append(v) else: x.append(v) self.data_error = (n % 2 == 0) if not (self.data_error): self.xdata = scipy.array(x) self.ydata = scipy.array(y) self.minx,self.maxx = min(x),max(x) self.miny,self.maxy = min(y),max(y) self.datasize = len(self.xdata) self.adjust_poly(0) def adjust_poly(self,n): maxdeg = self.datasize-1 q = self.poly + n if(q < 0): q = 0 if(q > maxdeg): q = maxdeg self.poly = q self.poly_disp.set_text("Degree %d" % self.poly) self.polyfit_plot() def polyfit_plot(self): self.plt.clf() if(self.data_error): self.plt.title('Data Incomplete (no data or not in pairs)',size=16,color='red') else: self.plt.ylabel('Y data') self.plt.xlabel('X data') self.plt.title('Polynomial Regression') self.plt.grid(True) self.plt.plot(self.xdata, self.ydata, 'ro',markersize=4) self.polycoeffs = scipy.polyfit(self.xdata, self.ydata,self.poly) yfit = lambda x: scipy.polyval(self.polycoeffs, x) ya = [yfit(z) for z in self.xdata] yb = sum(self.ydata)/self.datasize sr = sum([ (yi - yb)**2 for yi in ya]) st = sum([ (yi - yb)**2 for yi in self.ydata]) self.corr_coeff = sr / st self.stderr = 0 if(self.datasize > 2): a = 0 for i,x in enumerate(self.xdata): a += (yfit(x) - self.ydata[i])**2 self.stderr = scipy.sqrt(a / (self.datasize-2)) delta = 0.1 x = scipy.arange(self.minx,self.maxx+delta,delta) self.plt.plot(x,yfit(x), 'b-') self.plt.axis([self.minx-1,self.maxx+1,self.miny-2,self.maxy+2]) self.figure.canvas.draw() self.canvas.show() self.gen_function() self.data_textb.set_modified(False) def gen_function(self): out = "Degree %d, %d x,y pairs" % (self.poly,len(self.xdata)) out += "\nCorr. coeff. (r^2) = %+.16e" % self.corr_coeff out += "\nStandard Error = %+.16e" % self.stderr out += "\n\nf(x) = " a = [] for n,v in enumerate(self.polycoeffs[::-1]): s = "%+.16e" % v a.append("%s * x^%02d" % (s,n)) self.function_textb.set_text(out + "\n ".join(a) + "\n\n" + self.copyright) # end of class PolyRegress app=PolyRegress() gtk.main()