Added point-click status notification to gui.panel.plot.
authorW. Trevor King <wking@drexel.edu>
Sat, 7 Aug 2010 14:21:34 +0000 (10:21 -0400)
committerW. Trevor King <wking@drexel.edu>
Sat, 7 Aug 2010 14:21:34 +0000 (10:21 -0400)
Now clicking on points displays their x/y value as well as the index
of the nearest x point for the various displayed data blocks.

This allowed me to adjust the bounds of the testing WLC fit in
hooke.ui.gui to more appropriate values, but these commands will
eventually be removed once I get through the rough development phase.

hooke/ui/gui/__init__.py
hooke/ui/gui/dialog/selection.py
hooke/ui/gui/panel/plot.py
hooke/ui/gui/statusbar.py

index 3bc29d531b2e2e5ec13d01a447c1a1c0ce57b930..fecc90d312c8680546d438af29c9e57a2d15851b 100644 (file)
@@ -125,7 +125,7 @@ class HookeFrame (wx.Frame):
                 )
         self.execute_command(
                 command=self._command_by_name('polymer fit'),
-                args={'block':1, 'bounds':[400, 1000]},
+                args={'block':1, 'bounds':[918, 1103]},
                 )
         return # TODO: cleanup
         self.playlists = self._c['playlist'].Playlists
@@ -201,6 +201,7 @@ class HookeFrame (wx.Frame):
 #                    style=wx.NO_BORDER|wx.TE_MULTILINE), 'right'),
             (panel.PANELS['plot'](
                     callbacks={
+                        '_set_status_text': self._on_plot_status_text,
                         },
                     parent=self,
                     style=wx.WANTS_CHARS|wx.NO_BORDER,
@@ -771,6 +772,14 @@ class HookeFrame (wx.Frame):
 
 
 
+    # Plot panel interface
+
+    def _on_plot_status_text(self, _class, method, text):
+        if 'status bar' in self._c:
+            self._c['status bar'].set_plot_text(text)
+
+
+
     # Navbar interface
 
     def _next_curve(self, *args):
@@ -912,6 +921,8 @@ class HookeFrame (wx.Frame):
             style=wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER)
         dialog.CenterOnScreen()
         dialog.ShowModal()
+        if dialog.canceled == True:
+            return
         names = [options[i] for i in dialog.selected]
         dialog.Destroy()
         self._delete_perspectives(
index ff7fbb70b059558c26668b6bd4445efe339a0e42..1ef0c76f16d05028b8a9c139d7b0abc856d08fb6 100644 (file)
@@ -49,6 +49,7 @@ class Selection (wx.Dialog):
             callbacks = {}
         self._callbacks = callbacks
         self._selection_style = selection_style
+        self.canceled = False
 
         self._c = {
             'text': wx.StaticText(
@@ -97,6 +98,7 @@ class Selection (wx.Dialog):
     def cancel(self, event):
         """Close the dialog.
         """
+        self.canceled = True
         self.EndModal(wx.ID_CANCEL)
 
     def button(self, event):
index 030fce72fad724be1fddcaab094ba15ec504bb54..66cc64da4d1c2653b546b15512bddec153ef673d 100644 (file)
@@ -36,6 +36,7 @@ from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas
 from matplotlib.backends.backend_wx import NavigationToolbar2Wx as NavToolbar
 from matplotlib.figure import Figure
 from matplotlib.ticker import Formatter, ScalarFormatter
+import numpy
 import wx
 
 from ....util.callback import callback, in_callback
@@ -104,8 +105,11 @@ class PlotPanel (Panel, wx.Panel):
         self.display_coordinates = False
         self.style = 'line'
         self._curve = None
+        self._config = {}
         self._x_column = None
         self._y_columns = []  # TODO: select right/left scales?
+        self._x_unit = ''
+        self._y_unit = ''
         super(PlotPanel, self).__init__(
             name='plot', callbacks=callbacks, **kwargs)
         self._c = {}
@@ -173,17 +177,32 @@ class PlotPanel (Panel, wx.Panel):
         self._c['figure'].set_edgecolor(col)
         self._c['canvas'].SetBackgroundColour(wx.Colour(*rgbtuple))
 
-    #def SetStatusText(self, text, field=1):
-    #    self.Parent.Parent.statusbar.SetStatusText(text, field)
+    def _set_status_text(self, text):
+        in_callback(self, text)
 
     def _on_size(self, event):
         event.Skip()
         wx.CallAfter(self._resize_canvas)
 
     def _on_click(self, event):
-        #self.SetStatusText(str(event.xdata))
-        #print 'button=%d, x=%d, y=%d, xdata=%f, ydata=%f'%(event.button, event.x, event.y, event.xdata, event.ydata)
-        pass
+        if self._curve == None:
+            return
+        d = self._config.get('plot decimals', 2)
+        x,y = (event.xdata, event.ydata)
+        xt = ppSI(value=x, unit=self._x_unit, decimals=d)
+        yt = ppSI(value=y, unit=self._y_unit, decimals=d)
+        point_indexes = []
+        for data in self._curve.data:
+            try:
+                x_col = data.info['columns'].index(self._x_column)
+            except ValueError:
+                continue  # data is missing a required column
+            index = numpy.absolute(data[:,x_col]-x).argmin()
+            point_indexes.append((data.info['name'], index))
+        self._set_status_text(
+            '(%s, %s) %s'
+            % (xt, yt,
+               ', '.join(['%s: %d' % (n,i) for n,i in point_indexes])))
 
     def _on_enter_axes(self, event):
         self.display_coordinates = True
@@ -222,6 +241,8 @@ class PlotPanel (Panel, wx.Panel):
             style=wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER)
         s.CenterOnScreen()
         s.ShowModal()
+        if s.canceled == True:
+            return
         self._y_columns = [self._columns[i] for i in s.selected]
         s.Destroy()
         if len(self._y_columns) == 0:
@@ -276,22 +297,24 @@ class PlotPanel (Panel, wx.Panel):
 
         if config['plot SI format'] == True:
             d = config['plot decimals']
-            x_n, x_unit = split_data_label(self._x_column)
-            y_n, y_unit = split_data_label(self._y_columns[0])
+            x_n, self._x_unit = split_data_label(self._x_column)
+            y_n, self._y_unit = split_data_label(self._y_columns[0])
             for y_column in self._y_columns[1:]:
-                y_n2, y_unit2 = split_data_label(y_column)
-                if y_unit2 != y_unit:
+                y_n, y_unit = split_data_label(y_column)
+                if y_unit != self._y_unit:
                     log = logging.getLogger('hooke')
                     log.warn('y-axes unit mismatch: %s != %s, using %s.'
-                             % (y_unit, y_unit2, y_unit))
-            fx = HookeFormatter(decimals=d, unit=x_unit)
+                             % (self._y_unit, y_unit, self._y_unit))
+            fx = HookeFormatter(decimals=d, unit=self._x_unit)
             axes.xaxis.set_major_formatter(fx)
-            fy = HookeFormatter(decimals=d, unit=y_unit)
+            fy = HookeFormatter(decimals=d, unit=self._y_unit)
             axes.yaxis.set_major_formatter(fy)
             axes.set_xlabel(x_n)
             if len(self._y_columns) == 1:
                 axes.set_ylabel(y_n)
         else:
+            self._x_unit = ''
+            self._y_unit = ''
             axes.set_xlabel(self._x_column)
             if len(self._y_columns) == 1:
                 axes.set_ylabel(self._y_columns[0])
index dcd1ac37fadf7bf3ddeefd3ae9f91f095b3f362c..7eb33eb00e5d71524f58df41a17d1d27790bf510 100644 (file)
@@ -27,6 +27,7 @@ from ... import version
 class StatusBar (wx.StatusBar):
     def __init__(self, *args, **kwargs):
         super(StatusBar, self).__init__(*args, **kwargs)
+        self.SetFieldsCount(2)
         self.SetStatusWidths([-2, -3])
         self.SetStatusText('Ready', 0)
         self.SetStatusText(u'Welcome to Hooke (version %s)' % version(), 1)
@@ -37,6 +38,9 @@ class StatusBar (wx.StatusBar):
     def set_curve(self, curve):
         pass
 
+    def set_plot_text(self, text):
+        self.SetStatusText(text, 1)
+
     def _playlist_status(self, playlist):
         fields = [
             playlist.name,