Add ability to select multiple y columns to gui.panel.plot
authorW. Trevor King <wking@drexel.edu>
Sat, 7 Aug 2010 12:59:05 +0000 (08:59 -0400)
committerW. Trevor King <wking@drexel.edu>
Sat, 7 Aug 2010 12:59:05 +0000 (08:59 -0400)
hooke/ui/gui/panel/plot.py

index 2eb9eab407b58102b1acbfe5e7c80c002bee578a..030fce72fad724be1fddcaab094ba15ec504bb54 100644 (file)
@@ -28,6 +28,8 @@ Originally based on `this example`_.
   http://matplotlib.sourceforge.net/examples/user_interfaces/embedding_in_wx2.html
 """
 
+import logging
+
 import matplotlib
 matplotlib.use('WXAgg')  # use wxpython with antigrain (agg) rendering
 from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas
@@ -38,6 +40,7 @@ import wx
 
 from ....util.callback import callback, in_callback
 from ....util.si import ppSI, split_data_label
+from ..dialog.selection import Selection
 from . import Panel
 
 
@@ -102,7 +105,7 @@ class PlotPanel (Panel, wx.Panel):
         self.style = 'line'
         self._curve = None
         self._x_column = None
-        self._y_column = None  # TODO: _y_columns (allow multiple, simultaneous y axes (rescaled?))
+        self._y_columns = []  # TODO: select right/left scales?
         super(PlotPanel, self).__init__(
             name='plot', callbacks=callbacks, **kwargs)
         self._c = {}
@@ -134,11 +137,11 @@ class PlotPanel (Panel, wx.Panel):
         self._c['x column'].SetToolTip(wx.ToolTip('x column'))
         self._c['toolbar'].AddControl(self._c['x column'])
         self._c['x column'].Bind(wx.EVT_CHOICE, self._on_x_column)
-        self._c['y column'] = wx.Choice(
-            parent=self._c['toolbar'], choices=[])
+        self._c['y column'] = wx.Button(
+            parent=self._c['toolbar'], label='y column(s)')
         self._c['y column'].SetToolTip(wx.ToolTip('y column'))
         self._c['toolbar'].AddControl(self._c['y column'])
-        self._c['y column'].Bind(wx.EVT_CHOICE, self._on_y_column)
+        self._c['y column'].Bind(wx.EVT_BUTTON, self._on_y_column)
 
         self._c['toolbar'].Realize()  # call after putting items in the toolbar
         if wx.Platform == '__WXMAC__':
@@ -206,7 +209,23 @@ class PlotPanel (Panel, wx.Panel):
         self.update()
 
     def _on_y_column(self, event):
-        self._y_column = self._c['y column'].GetStringSelection()
+        if not hasattr(self, '_columns') or len(self._columns) == 0:
+            self._y_columns = []
+            return
+        s = Selection(
+            options=self._columns,
+            message='Select visible y column(s).',
+            button_id=wx.ID_OK,
+            selection_style='multiple',
+            parent=self,
+            title='Select y column(s)',
+            style=wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER)
+        s.CenterOnScreen()
+        s.ShowModal()
+        self._y_columns = [self._columns[i] for i in s.selected]
+        s.Destroy()
+        if len(self._y_columns) == 0:
+            self._y_columns = self._columns[-1:]
         self.update()
 
     def _resize_canvas(self):
@@ -234,18 +253,14 @@ class PlotPanel (Panel, wx.Panel):
         self._columns = sorted(columns)
         if self._x_column not in self._columns:
             self._x_column = self._columns[0]
-        if self._y_column not in self._columns:
-            self._y_column = self._columns[-1]
+        self._y_columns = [y for y in self._y_columns if y in self._columns]
+        if len(self._y_columns) == 0:
+            self._y_columns = self._columns[-1:]
         if 'x column' in self._c:
             for i in range(self._c['x column'].GetCount()):
                 self._c['x column'].Delete(0)
             self._c['x column'].AppendItems(self._columns)
             self._c['x column'].SetStringSelection(self._x_column)
-        if 'y column' in self._c:
-            for i in range(self._c['y column'].GetCount()):
-                self._c['y column'].Delete(0)
-            self._c['y column'].AppendItems(self._columns)
-            self._c['y column'].SetStringSelection(self._y_column)
         self.update(config=config)
 
     def update(self, config=None):
@@ -262,27 +277,36 @@ 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_column)
+            y_n, 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:
+                    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)
             axes.xaxis.set_major_formatter(fx)
             fy = HookeFormatter(decimals=d, unit=y_unit)
             axes.yaxis.set_major_formatter(fy)
             axes.set_xlabel(x_n)
-            axes.set_ylabel(y_n)
+            if len(self._y_columns) == 1:
+                axes.set_ylabel(y_n)
         else:
             axes.set_xlabel(self._x_column)
-            axes.set_ylabel(self._y_column)
+            if len(self._y_columns) == 1:
+                axes.set_ylabel(self._y_columns[0])
 
         self._c['figure'].hold(True)
         for i,data in enumerate(self._curve.data):
-            try:
-                x_col = data.info['columns'].index(self._x_column)
-                y_col = data.info['columns'].index(self._y_column)
-            except ValueError:
-                continue  # data is missing a required column
-            axes.plot(data[:,x_col], data[:,y_col],
-                      '.',
-                      label=data.info['name'])
-        if config['plot legend'] == 'True':  # HACK: config should convert
+            for y_column in self._y_columns:
+                try:
+                    x_col = data.info['columns'].index(self._x_column)
+                    y_col = data.info['columns'].index(y_column)
+                except ValueError:
+                    continue  # data is missing a required column
+                axes.plot(data[:,x_col], data[:,y_col],
+                          '.',
+                          label=('%s, %s' % (data.info['name'], y_column)))
+        if config['plot legend'] == True:
             axes.legend(loc='best')
         self._c['canvas'].draw()