source: sasview/sansguiframe/src/sans/guiframe/data_processor.py @ 2f81957

ESS_GUIESS_GUI_DocsESS_GUI_batch_fittingESS_GUI_bumps_abstractionESS_GUI_iss1116ESS_GUI_iss879ESS_GUI_iss959ESS_GUI_openclESS_GUI_orderingESS_GUI_sync_sascalccostrafo411magnetic_scattrelease-4.1.1release-4.1.2release-4.2.2release_4.0.1ticket-1009ticket-1094-headlessticket-1242-2d-resolutionticket-1243ticket-1249ticket885unittest-saveload
Last change on this file since 2f81957 was 10675c3, checked in by Gervaise Alina <gervyh@…>, 13 years ago

working on batch panel

  • Property mode set to 100644
File size: 21.9 KB
Line 
1"""
2Implement grid used to store data
3"""
4import wx
5import numpy
6import math
7import re
8import sys
9import copy
10from wx.lib.scrolledpanel import ScrolledPanel
11import  wx.grid as  Grid
12import wx.aui
13from wx.aui import AuiNotebook as nb
14from sans.guiframe.panel_base import PanelBase
15import wx.lib.sheet as sheet
16
17from sans.guiframe.events import NewPlotEvent
18from sans.guiframe.events import StatusEvent 
19from sans.guiframe.dataFitting import Data1D
20
21FUNC_DICT = {"sqrt": "math.sqrt",
22             "pow": "math.sqrt"}
23def parse_string(sentence, list):
24    """
25    Return a dictionary of column label and index or row selected
26    :param sentence: String to parse
27    :param list: list of columns label
28    """
29    toks = []
30    p2 = re.compile(r'\d+')
31    p = re.compile(r'[\+\-\*\%\/]')
32    labels = p.split(sentence)
33    col_dict = {}
34    for elt in labels:
35        rang = None
36        temp_arr = []
37        for label in  list:
38            label_pos =  elt.find(label)
39            if label_pos != -1:
40                if elt.count(',') > 0:
41                    new_temp = []
42                    temp = elt.split(label)
43                    for item in temp:
44                        range_pos = item.find(":")
45                        if range_pos != -1:
46                            rang = p2.findall(item)
47                            for i in xrange(int(rang[0]), int(rang[1])+1 ):
48                                new_temp.append(i)
49                    temp_arr += new_temp
50                else:
51                    temp = elt.split(label)
52                    for item in temp:
53                        range_pos = item.find(":")
54                        if range_pos != -1:
55                            rang = p2.findall(item)
56                            for i in xrange(int(rang[0]), int(rang[1])+1 ):
57                                temp_arr.append(i)
58                col_dict[elt] = (label, temp_arr)
59    return col_dict
60
61class GridPage(sheet.CSheet):
62    """
63    """
64    def __init__(self, parent, panel=None):
65        """
66        """
67        sheet.CSheet.__init__(self, parent)
68        self.SetLabelBackgroundColour('#DBD4D4')
69        self.AutoSize()
70        self.panel = panel
71        self.col_names = []
72        self._cols = 50
73        self._rows = 51
74        col_with = 30
75        row_height = 20
76        self.axis_value = []
77        self.axis_label = ""
78        self.selected_cells = []
79        self.selected_cols = []
80        self.SetColMinimalAcceptableWidth(col_with)
81        self.SetRowMinimalAcceptableHeight(row_height)
82        self.SetNumberRows(self._cols)
83        self.SetNumberCols(self._rows)
84        self.Bind(wx.grid.EVT_GRID_LABEL_LEFT_CLICK, self.on_left_click)
85        self.Bind(wx.grid.EVT_GRID_LABEL_RIGHT_CLICK, self.on_right_click)
86        self.Bind(wx.grid.EVT_GRID_CELL_LEFT_CLICK, self.on_selected_cell)
87       
88    def on_selected_cell(self, event):
89        """
90        Handler catching cell selection
91        """
92        flag = event.CmdDown() or event.ControlDown()
93        row, col = event.GetRow(), event.GetCol()
94        cell = (row, col)
95        if not flag:
96            self.selected_cells = []
97            self.axis_value = []
98            self.axis_label = ""
99        if cell in self.selected_cells:
100            self.selected_cells.remove(cell)
101        else:
102            self.selected_cells.append(cell)
103        if row > 1:
104            if (cell) in self.selected_cells:
105                self.axis_value.append(self.GetCellValue(row, col))
106        self.axis_label = self.GetCellValue(row, col)
107        event.Skip()
108     
109    def on_left_click(self, event):
110        """
111        Catch the left click on label mouse event
112        """
113        flag = event.CmdDown() or event.ControlDown()
114        col = event.GetCol()
115        if not flag:
116            self.selected_cols = []
117            self.axis_value = []
118            self.axis_label = ""
119        if col not in self.selected_cols:
120            self.selected_cols.append(col)
121        if not flag :
122            for row in range(2, self.GetNumberRows()+ 1):
123                self.axis_value.append(self.GetCellValue(row, col))
124            row = 1
125            self.axis_label = self.GetCellValue(row, col)
126        event.Skip()
127       
128    def on_right_click(self, event):
129        """
130        Catch the right click mouse
131        """
132        col = event.GetCol()
133        if col != -1 and len(self.col_names) > col:
134            label = self.col_names[int(col)]
135            self.axis_label = label
136            if label in self.data.keys():
137                col_val = self.data[label]
138                self.axis_value = col_val
139        # Slicer plot popup menu
140        slicerpop = wx.Menu()
141        id = wx.NewId()
142        slicerpop.Append(id, '&Set X axis', 'Set X axis')
143        wx.EVT_MENU(self, id, self.on_set_x_axis)
144       
145        id = wx.NewId()
146        slicerpop.Append(id, '&Set Y axis', 'Set Y axis')
147        wx.EVT_MENU(self, id, self.on_set_y_axis)
148        pos = event.GetPosition()
149        pos = self.ScreenToClient(pos)
150        self.PopupMenu(slicerpop, pos)
151       
152    def on_set_x_axis(self, event):
153        """
154        """
155        self.panel.set_xaxis(x=self.axis_value, label=self.axis_label)
156   
157    def on_set_y_axis(self, event):
158        """
159        """
160        self.panel.set_yaxis(y=self.axis_value, label=self.axis_label)     
161           
162    def set_data(self, data):
163        """
164        Add data to the grid
165        """
166        if data is None:
167            data = {}
168        if  len(data) > 0:
169            self._cols = self.GetNumberCols()
170            self._rows = self.GetNumberRows()
171            self.data = data
172            self.col_names = data.keys()
173            self.col_names.sort() 
174            nbr_user_cols = len(self.col_names)
175            #Add more columns to the grid if necessary
176            if nbr_user_cols > self._cols:
177                new_col_nbr = nbr_user_cols -  self._cols
178                self.AppendCols(new_col_nbr, True)
179            #Add more rows to the grid if necessary 
180            nbr_user_row = len(self.data.values())
181            if nbr_user_row > self._rows + 1:
182                new_row_nbr =  nbr_user_row - self._rows
183                self.AppendRows(new_row_nbr, True)
184            # add data to the grid   
185            row = 0
186            for index  in range(nbr_user_cols):
187                col = index
188                # use the first row of the grid to add user defined labels
189                self.SetCellValue(row, col, str(self.col_names[index]))
190            col = 0
191            for value_list in self.data.values():
192                row = 1
193                for index in range(len(value_list)):
194                    self.SetCellValue(row, col, str(value_list[index]))
195                    row += 1
196                col += 1
197            self.AutoSize()
198           
199
200class Notebook(nb, PanelBase):
201    """
202    ## Internal name for the AUI manager
203    window_name = "Fit panel"
204    ## Title to appear on top of the window
205    """
206    window_caption = "Notebook "
207   
208    def __init__(self, parent, manager=None, data=None, *args, **kwargs):
209        """
210        """
211        nb.__init__(self, parent, -1,
212                    style= wx.aui.AUI_BUTTON_DOWN|
213                    wx.aui.AUI_NB_WINDOWLIST_BUTTON|
214                    wx.aui.AUI_NB_DEFAULT_STYLE|
215                    wx.CLIP_CHILDREN)
216        PanelBase.__init__(self, parent)
217        self.enable_close_button()
218        self.parent = parent
219        self.manager = manager
220        self.data = data
221        self.Bind(wx.aui.EVT_AUINOTEBOOK_PAGE_CLOSE, self.on_close_page)
222   
223    def enable_close_button(self):
224        """
225        display the close button on tab for more than 1 tabs else remove the
226        close button
227        """
228        if self.GetPageCount() <= 1:
229            style = self.GetWindowStyleFlag() 
230            flag = wx.aui.AUI_NB_CLOSE_ON_ACTIVE_TAB
231            if style & wx.aui.AUI_NB_CLOSE_ON_ACTIVE_TAB == flag:
232                style = style & ~wx.aui.AUI_NB_CLOSE_ON_ACTIVE_TAB
233                self.SetWindowStyle(style)
234        else:
235            style = self.GetWindowStyleFlag()
236            flag = wx.aui.AUI_NB_CLOSE_ON_ACTIVE_TAB
237            if style & wx.aui.AUI_NB_CLOSE_ON_ACTIVE_TAB != flag:
238                style |= wx.aui.AUI_NB_CLOSE_ON_ACTIVE_TAB
239                self.SetWindowStyle(style)
240             
241    def on_edit_axis(self):
242        """
243        Return the select cell of a given selected column
244        """
245        pos = self.GetSelection()
246        grid = self.GetPage(pos)
247        if len(grid.selected_cols) > 1:
248            msg = "Edit axis doesn't understand this selection.\n"
249            msg += "Please select only one column"
250            raise ValueError, msg
251        list_of_cells = []
252        if len(grid.selected_cols) == 1:
253            col = grid.selected_cols[0]
254            if len(grid.selected_cells) > 0:
255                cell_row, cell_col = grid.selected_cells[0]
256                if cell_col  != col:
257                    msg = "Edit axis doesn't understand this selection.\n"
258                    msg += "Please select element of the same col"
259                    raise ValueError, msg
260            for row in range(grid.GetNumberRows()):
261                list_of_cells.append((row + 1 , col))
262            for item in grid.selected_cells:
263                if item in list_of_cells:
264                    list_of_cells.remove(item)
265        elif len(grid.selected_cols) == 0:
266            list_of_cells = [(row + 1, col) for row, col in grid.selected_cells]
267        return list_of_cells
268   
269    def get_column_labels(self):
270        """
271        return dictionary of columns labels of the current page
272        """
273        pos = self.GetSelection()
274        grid = self.GetPage(pos)
275        labels = {}
276        row = 0
277        for col in range(grid.GetNumberCols()):
278            label = grid.GetCellValue(row, col)
279            if label.strip() != "" :
280                labels[label.strip()] = col
281        return labels
282       
283    def create_axis_label(self, cell_list):
284        """
285        Receive a list of cells and  create a string presenting the selected
286        cells.
287        :param cell_list: list of tuple
288       
289        """
290        pos = self.GetSelection()
291        grid = self.GetPage(pos)
292        label = ""
293        col_name = ""
294        if len(cell_list) > 0:
295            temp_list = copy.deepcopy(cell_list)
296            temp_list.sort()
297            temp = []
298            for item in temp_list:
299                if item[0] <= 1:
300                    temp.append(item)
301            for element in temp:
302                temp_list.remove(element)
303            row_min, col  = temp_list[0]   
304            row_max = row_min
305            col_name = grid.GetCellValue(0, col)
306            label += str(col_name) + "[" + str(row_min) + ":"
307            for index in xrange(len(temp_list)):
308                prev = index - 1
309                row, _ = temp_list[index]
310                if row > row_max + 1 :
311                    if prev > 0:
312                        row_max, _ = temp_list[prev]
313                        label += str(row_max) + "]" + ","
314                        row_min = row
315                        label  += "[" + str(row_min) + ":"
316                row_max = row
317                if (index == len(temp_list)- 1):
318                    label +=  str(row_max) + "]"     
319        return label, col_name
320   
321    def on_close_page(self, event):
322        """
323        close the page
324        """
325        if self.GetPageCount() == 1:
326            event.Veto()
327        self.enable_close_button()
328       
329    def set_data(self, data):
330        if data is None:
331            return
332           
333        grid = GridPage(self, panel=self.parent)
334        grid.set_data(data) 
335        self.AddPage(grid, "")
336        pos = self.GetPageIndex(grid)
337        title = "Batch " + str(self.GetPageCount())
338        self.SetPageText(pos, title)
339       
340    def add_column(self):
341        """
342        Append a new column to the grid
343        """
344        pos = self.GetSelection()
345        grid = self.GetPage(pos)
346        grid.AppendCols(1, True)
347       
348    def on_remove_column(self):
349        """
350        Remove column to the current grid
351        """
352        pos = self.GetSelection()
353        grid = self.GetPage(pos)
354        cols_pos = grid.GetSelectedCols() 
355        for cpos in cols_pos:
356            grid.DeleteCols(cpos)
357         
358         
359class SPanel(ScrolledPanel):
360    def __init__(self, parent, *args, **kwds):
361        ScrolledPanel.__init__(self, parent , *args, **kwds)
362        self.SetupScrolling() 
363
364
365class GridPanel(SPanel):
366    def __init__(self, parent, data=None, *args, **kwds):
367        SPanel.__init__(self, parent , *args, **kwds)
368        self.vbox = wx.BoxSizer(wx.VERTICAL)
369       
370        self.plotting_sizer = wx.FlexGridSizer(3, 7, 10, 5)
371        self.grid_sizer = wx.BoxSizer(wx.HORIZONTAL)
372        self.vbox.AddMany([(self.grid_sizer, 1, wx.EXPAND, 0),
373                           (wx.StaticLine(self, -1), 0, wx.EXPAND, 0),
374                           (self.plotting_sizer)])
375        self.parent = parent
376        self._data = data
377        self.x = []
378        self.= []
379        self.x_axis_label = None
380        self.y_axis_label = None
381        self.x_axis_title = None
382        self.y_axis_title = None
383        self.x_axis_unit = None
384        self.y_axis_unit = None
385        self.plot_button = None
386        self.notebook = None
387        self.layout_grid()
388        self.layout_plotting_area()
389        self.SetSizer(self.vbox)
390       
391    def set_data(self, data):
392        """
393        """
394        if self.notebook is not None:
395            self.notebook.set_data(data)
396       
397    def set_xaxis(self, label="", x=None):
398        """
399        """
400        if x is None:
401            x = []
402        self.x = x
403        self.x_axis_label.SetValue("%s[:]" % str(label))
404        self.x_axis_title.SetValue(str(label))
405       
406    def set_yaxis(self, label="", y=None):
407        """
408        """
409        if y is None:
410            y = []
411        self.y = y
412        self.y_axis_label.SetValue("%s[:]" % str(label))
413        self.y_axis_title.SetValue(str(label))
414       
415    def get_plot_axis(self, col, list):
416        """
417       
418        """
419        axis = []
420        pos = self.notebook.GetSelection()
421        grid = self.notebook.GetPage(pos)
422        for row in list:
423            label = grid.GetCellValue(row - 1, col)
424            if label.strip() != "":
425                axis.append(float(label.strip()))
426        return axis
427   
428    def on_plot(self, event):
429        """
430        Evaluate the contains of textcrtl and plot result
431        """ 
432        pos = self.notebook.GetSelection()
433        grid = self.notebook.GetPage(pos)
434        column_names = {}
435        if grid is not None:
436            column_names = self.notebook.get_column_labels()
437        #evalue x
438        sentence = self.x_axis_label.GetValue()
439        if sentence.strip() == "":
440            msg = "select value for x axis"
441            raise ValueError, msg
442        dict = parse_string(sentence, column_names.keys())
443        for tok, (col_name, list) in dict.iteritems():
444            col = column_names[col_name]
445            xaxis = self.get_plot_axis(col, list)
446            sentence = sentence.replace(tok, 
447                                        "numpy.array(%s)" % str(xaxis))
448        for key, value in FUNC_DICT.iteritems():
449            sentence = sentence.replace(key.lower(), value)
450        x = eval(sentence)
451        #evaluate y
452        sentence = self.y_axis_label.GetValue()
453        if sentence.strip() == "":
454            msg = "select value for y axis"
455            raise ValueError, msg
456        dict = parse_string(sentence, column_names.keys())
457        for tok, (col_name, list) in dict.iteritems():
458            col = column_names[col_name]
459            yaxis = self.get_plot_axis(col, list)
460            sentence = sentence.replace(tok, 
461                                        "numpy.array(%s)" % str(yaxis))
462        for key, value in FUNC_DICT.iteritems():
463            sentence = sentence.replace(key, value)
464        y = eval(sentence)
465        #plotting
466        new_plot = Data1D(x=x, y=y)
467        new_plot.id =  wx.NewId()
468        new_plot.group_id = wx.NewId()
469        title = "%s vs %s" % (self.y_axis_title.GetValue(), 
470                              self.x_axis_title.GetValue())
471        new_plot.xaxis(self.x_axis_title.GetValue(), self.x_axis_unit.GetValue())
472        new_plot.yaxis(self.y_axis_title.GetValue(), self.y_axis_unit.GetValue())
473        try:
474            title = self.notebook.GetPageText(pos)
475            wx.PostEvent(self.parent.parent, 
476                             NewPlotEvent(plot=new_plot, 
477                        group_id=str(new_plot.group_id), title =title))   
478        except:
479            pass
480       
481    def layout_grid(self):
482        """
483        Draw the area related to the grid
484        """
485        self.notebook = Notebook(parent=self)
486        self.notebook.set_data(self._data)
487        self.grid_sizer.Add(self.notebook, 1, wx.EXPAND, 0)
488       
489    def layout_plotting_area(self):
490        """
491        Draw area containing options to plot
492        """
493        self.x_axis_title = wx.TextCtrl(self, -1)
494        self.y_axis_title = wx.TextCtrl(self, -1)
495        self.x_axis_label = wx.TextCtrl(self, -1, size=(200, -1))
496        self.y_axis_label = wx.TextCtrl(self, -1, size=(200, -1))
497        self.x_axis_add = wx.Button(self, -1, "Add")
498        self.x_axis_add.Bind(event=wx.EVT_BUTTON, handler=self.on_edit_axis, 
499                            id=self.x_axis_add.GetId())
500        self.y_axis_add = wx.Button(self, -1, "Add")
501        self.y_axis_add.Bind(event=wx.EVT_BUTTON, handler=self.on_edit_axis, 
502                            id=self.y_axis_add.GetId())
503        self.x_axis_unit = wx.TextCtrl(self, -1)
504        self.y_axis_unit = wx.TextCtrl(self, -1)
505        self.plot_button = wx.Button(self, -1, "Plot")
506        wx.EVT_BUTTON(self, self.plot_button.GetId(), self.on_plot)
507        self.plotting_sizer.AddMany([
508                    (wx.StaticText(self, -1, "x-axis label"), 1,
509                      wx.TOP|wx.BOTTOM|wx.LEFT, 10),
510                    (self.x_axis_label, 1, wx.TOP|wx.BOTTOM, 10),
511                    (self.x_axis_add, 1, wx.TOP|wx.BOTTOM|wx.RIGHT, 10),
512                    (wx.StaticText(self, -1, "x-axis title"), 1, 
513                     wx.TOP|wx.BOTTOM|wx.LEFT, 10),
514                    (self.x_axis_title, 1, wx.TOP|wx.BOTTOM, 10),
515                    (wx.StaticText(self, -1 , "unit"), 1, 
516                     wx.TOP|wx.BOTTOM, 10),
517                    (self.x_axis_unit, 1, wx.TOP|wx.BOTTOM, 10),
518                    (wx.StaticText(self, -1, "y-axis label"), 1, 
519                     wx.BOTTOM|wx.LEFT, 10),
520                    (self.y_axis_label, wx.BOTTOM, 10),
521                    (self.y_axis_add, 1, wx.BOTTOM|wx.RIGHT, 10),
522                    (wx.StaticText(self, -1, "y-axis title"), 1, 
523                     wx.BOTTOM|wx.LEFT, 10),
524                    (self.y_axis_title,  wx.BOTTOM, 10),
525                    (wx.StaticText(self, -1 , "unit"), 1, wx.BOTTOM, 10),
526                    (self.y_axis_unit, 1, wx.BOTTOM, 10),
527                      (-1, -1),
528                      (-1, -1),
529                      (-1, -1),
530                      (-1, -1),
531                      (-1, -1),
532                      (-1, -1),
533                      (self.plot_button, 1, wx.LEFT|wx.BOTTOM, 10)])
534   
535    def on_edit_axis(self, event):
536        """
537        Get the selected column on  the visible grid and set values for axis
538        """
539        cell_list = self.notebook.on_edit_axis()
540        label, title = self.create_axis_label(cell_list)
541        tcrtl = event.GetEventObject()
542        if tcrtl == self.x_axis_add:
543            self.edit_axis_helper(self.x_axis_label, self.x_axis_title,
544                                   label, title)
545        elif tcrtl == self.y_axis_add:
546            self.edit_axis_helper(self.y_axis_label, self.y_axis_title,
547                                   label, title)
548           
549    def create_axis_label(self, cell_list):
550        """
551        Receive a list of cells and  create a string presenting the selected
552        cells.
553        :param cell_list: list of tuple
554       
555        """
556        if self.notebook is not None:
557            return self.notebook.create_axis_label(cell_list)
558   
559    def edit_axis_helper(self, tcrtl_label, tcrtl_title, label, title):
560        """
561        get controls to modify
562        """
563        tcrtl_label.SetValue(str(label))
564        tcrtl_title.SetValue(str(title))
565       
566    def add_column(self):
567        """
568        """
569        if self.notebook is not None:
570            self.notebook.add_column()
571       
572    def on_remove_column(self):
573        """
574        """
575        if self.notebook is not None:
576            self.notebook.on_remove_column()
577       
578       
579class GridFrame(wx.Frame):
580    def __init__(self, parent=None, data=None, id=-1, 
581                 title="Batch Results", size=(700, 400)):
582        wx.Frame.__init__(self, parent=parent, id=id, title=title, size=size)
583        self.parent = parent
584        self.panel = GridPanel(self, data)
585        menubar = wx.MenuBar()
586        self.SetMenuBar(menubar)
587        edit = wx.Menu()
588        menubar.Append(edit, "&Edit")
589        self.Bind(wx.EVT_CLOSE, self.on_close)
590       
591        add_col_menu = edit.Append(wx.NewId(), 'Add Column', 'Add column')
592        wx.EVT_MENU(self, add_col_menu.GetId(), self.on_add_column)
593        remove_col_menu = edit.Append(wx.NewId(), 'Remove Column', 
594                                      'Remove Column')
595        wx.EVT_MENU(self, remove_col_menu.GetId(), self.on_remove_column)
596
597    def on_close(self, event):
598        """
599        """
600        self.Hide()
601       
602    def on_remove_column(self, event):
603        """
604        Remove the selected column to the grid
605        """
606        self.panel.on_remove_column()
607       
608    def on_add_column(self, event):
609        """
610        Append a new column to the grid
611        """
612        self.panel.add_column()
613       
614    def set_data(self, data):
615        """
616        """
617        self.panel.set_data(data)
618     
619     
620if __name__ == "__main__":
621    app = wx.App()
622   
623    try:
624        data = {}
625        j = 0
626        for i in range(4):
627            j += 1
628            data["index"+str(i)] = [i/j, i*j, i, i+j]
629           
630        frame = GridFrame(data=data)
631        frame.Show(True)
632    except:
633        print sys.exc_value
634       
635    app.MainLoop()
Note: See TracBrowser for help on using the repository browser.