source: sasview/sansguiframe/src/sans/guiframe/data_processor.py @ 904830e

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 904830e was 904830e, checked in by Gervaise Alina <gervyh@…>, 13 years ago

working on batch gui

  • 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            label_row = 0
186            for index  in range(nbr_user_cols):
187                # use the first row of the grid to add user defined labels
188                self.SetCellValue(label_row, index, str(self.col_names[index]))
189            col = 0
190            for value_list in self.data.values():
191                for row in range(1, len(value_list)):
192                    self.SetCellValue(row, col, str(value_list[row]))
193                col += 1
194            self.AutoSize()
195           
196
197class Notebook(nb, PanelBase):
198    """
199    ## Internal name for the AUI manager
200    window_name = "Fit panel"
201    ## Title to appear on top of the window
202    """
203    window_caption = "Notebook "
204   
205    def __init__(self, parent, manager=None, data=None, *args, **kwargs):
206        """
207        """
208        nb.__init__(self, parent, -1,
209                    style= wx.aui.AUI_BUTTON_DOWN|
210                    wx.aui.AUI_NB_WINDOWLIST_BUTTON|
211                    wx.aui.AUI_NB_DEFAULT_STYLE|
212                    wx.CLIP_CHILDREN)
213        PanelBase.__init__(self, parent)
214        self.enable_close_button()
215        self.parent = parent
216        self.manager = manager
217        self.data = data
218        self.Bind(wx.aui.EVT_AUINOTEBOOK_PAGE_CLOSE, self.on_close_page)
219   
220    def enable_close_button(self):
221        """
222        display the close button on tab for more than 1 tabs else remove the
223        close button
224        """
225        if self.GetPageCount() <= 1:
226            style = self.GetWindowStyleFlag() 
227            flag = wx.aui.AUI_NB_CLOSE_ON_ACTIVE_TAB
228            if style & wx.aui.AUI_NB_CLOSE_ON_ACTIVE_TAB == flag:
229                style = style & ~wx.aui.AUI_NB_CLOSE_ON_ACTIVE_TAB
230                self.SetWindowStyle(style)
231        else:
232            style = self.GetWindowStyleFlag()
233            flag = wx.aui.AUI_NB_CLOSE_ON_ACTIVE_TAB
234            if style & wx.aui.AUI_NB_CLOSE_ON_ACTIVE_TAB != flag:
235                style |= wx.aui.AUI_NB_CLOSE_ON_ACTIVE_TAB
236                self.SetWindowStyle(style)
237             
238    def on_edit_axis(self):
239        """
240        Return the select cell of a given selected column
241        """
242        pos = self.GetSelection()
243        grid = self.GetPage(pos)
244        if len(grid.selected_cols) > 1:
245            msg = "Edit axis doesn't understand this selection.\n"
246            msg += "Please select only one column"
247            raise ValueError, msg
248        list_of_cells = []
249        if len(grid.selected_cols) == 1:
250            col = grid.selected_cols[0]
251            if len(grid.selected_cells) > 0:
252                cell_row, cell_col = grid.selected_cells[0]
253                if cell_col  != col:
254                    msg = "Edit axis doesn't understand this selection.\n"
255                    msg += "Please select element of the same col"
256                    raise ValueError, msg
257            for row in range(grid.GetNumberRows()):
258                list_of_cells.append((row + 1 , col))
259            for item in grid.selected_cells:
260                if item in list_of_cells:
261                    list_of_cells.remove(item)
262        elif len(grid.selected_cols) == 0:
263            list_of_cells = [(row + 1, col) for row, col in grid.selected_cells]
264        return list_of_cells
265   
266    def get_column_labels(self):
267        """
268        return dictionary of columns labels of the current page
269        """
270        pos = self.GetSelection()
271        grid = self.GetPage(pos)
272        labels = {}
273        row = 0
274        for col in range(grid.GetNumberCols()):
275            label = grid.GetCellValue(row, col)
276            if label.strip() != "" :
277                labels[label.strip()] = col
278        return labels
279       
280    def create_axis_label(self, cell_list):
281        """
282        Receive a list of cells and  create a string presenting the selected
283        cells.
284        :param cell_list: list of tuple
285       
286        """
287        pos = self.GetSelection()
288        grid = self.GetPage(pos)
289        label = ""
290        col_name = ""
291        if len(cell_list) > 0:
292            temp_list = copy.deepcopy(cell_list)
293            temp_list.sort()
294            temp = []
295            for item in temp_list:
296                if item[0] <= 1:
297                    temp.append(item)
298            for element in temp:
299                temp_list.remove(element)
300            row_min, col  = temp_list[0]   
301            row_max = row_min
302            col_name = grid.GetCellValue(0, col)
303            label += str(col_name) + "[" + str(row_min) + ":"
304            for index in xrange(len(temp_list)):
305                prev = index - 1
306                row, _ = temp_list[index]
307                if row > row_max + 1 :
308                    if prev > 0:
309                        row_max, _ = temp_list[prev]
310                        label += str(row_max) + "]" + ","
311                        row_min = row
312                        label  += "[" + str(row_min) + ":"
313                row_max = row
314                if (index == len(temp_list)- 1):
315                    label +=  str(row_max) + "]"     
316        return label, col_name
317   
318    def on_close_page(self, event):
319        """
320        close the page
321        """
322        if self.GetPageCount() == 1:
323            event.Veto()
324        self.enable_close_button()
325       
326    def set_data(self, data):
327        if data is None:
328            return
329           
330        grid = GridPage(self, panel=self.parent)
331        grid.set_data(data) 
332        self.AddPage(grid, "")
333        pos = self.GetPageIndex(grid)
334        title = "Batch " + str(self.GetPageCount())
335        self.SetPageText(pos, title)
336       
337    def add_column(self):
338        """
339        Append a new column to the grid
340        """
341        pos = self.GetSelection()
342        grid = self.GetPage(pos)
343        grid.AppendCols(1, True)
344       
345    def on_remove_column(self):
346        """
347        Remove column to the current grid
348        """
349        pos = self.GetSelection()
350        grid = self.GetPage(pos)
351        cols_pos = grid.GetSelectedCols() 
352        for cpos in cols_pos:
353            grid.DeleteCols(cpos)
354         
355         
356class SPanel(ScrolledPanel):
357    def __init__(self, parent, *args, **kwds):
358        ScrolledPanel.__init__(self, parent , *args, **kwds)
359        self.SetupScrolling() 
360
361
362class GridPanel(SPanel):
363    def __init__(self, parent, data=None, *args, **kwds):
364        SPanel.__init__(self, parent , *args, **kwds)
365        self.vbox = wx.BoxSizer(wx.VERTICAL)
366       
367        self.plotting_sizer = wx.FlexGridSizer(3, 7, 10, 5)
368        self.grid_sizer = wx.BoxSizer(wx.HORIZONTAL)
369        self.vbox.AddMany([(self.grid_sizer, 1, wx.EXPAND, 0),
370                           (wx.StaticLine(self, -1), 0, wx.EXPAND, 0),
371                           (self.plotting_sizer)])
372        self.parent = parent
373        self._data = data
374        self.x = []
375        self.= []
376        self.x_axis_label = None
377        self.y_axis_label = None
378        self.x_axis_title = None
379        self.y_axis_title = None
380        self.x_axis_unit = None
381        self.y_axis_unit = None
382        self.plot_button = None
383        self.notebook = None
384        self.layout_grid()
385        self.layout_plotting_area()
386        self.SetSizer(self.vbox)
387       
388    def set_data(self, data):
389        """
390        """
391        if self.notebook is not None:
392            self.notebook.set_data(data)
393       
394    def set_xaxis(self, label="", x=None):
395        """
396        """
397        if x is None:
398            x = []
399        self.x = x
400        self.x_axis_label.SetValue("%s[:]" % str(label))
401        self.x_axis_title.SetValue(str(label))
402       
403    def set_yaxis(self, label="", y=None):
404        """
405        """
406        if y is None:
407            y = []
408        self.y = y
409        self.y_axis_label.SetValue("%s[:]" % str(label))
410        self.y_axis_title.SetValue(str(label))
411       
412    def get_plot_axis(self, col, list):
413        """
414       
415        """
416        axis = []
417        pos = self.notebook.GetSelection()
418        grid = self.notebook.GetPage(pos)
419        for row in list:
420            label = grid.GetCellValue(row - 1, col)
421            if label.strip() != "":
422                axis.append(float(label.strip()))
423        return axis
424   
425    def on_plot(self, event):
426        """
427        Evaluate the contains of textcrtl and plot result
428        """ 
429        pos = self.notebook.GetSelection()
430        grid = self.notebook.GetPage(pos)
431        column_names = {}
432        if grid is not None:
433            column_names = self.notebook.get_column_labels()
434        #evalue x
435        sentence = self.x_axis_label.GetValue()
436        if sentence.strip() == "":
437            msg = "select value for x axis"
438            raise ValueError, msg
439        dict = parse_string(sentence, column_names.keys())
440        for tok, (col_name, list) in dict.iteritems():
441            col = column_names[col_name]
442            xaxis = self.get_plot_axis(col, list)
443            sentence = sentence.replace(tok, 
444                                        "numpy.array(%s)" % str(xaxis))
445        for key, value in FUNC_DICT.iteritems():
446            sentence = sentence.replace(key.lower(), value)
447        x = eval(sentence)
448        #evaluate y
449        sentence = self.y_axis_label.GetValue()
450        if sentence.strip() == "":
451            msg = "select value for y axis"
452            raise ValueError, msg
453        dict = parse_string(sentence, column_names.keys())
454        for tok, (col_name, list) in dict.iteritems():
455            col = column_names[col_name]
456            yaxis = self.get_plot_axis(col, list)
457            sentence = sentence.replace(tok, 
458                                        "numpy.array(%s)" % str(yaxis))
459        for key, value in FUNC_DICT.iteritems():
460            sentence = sentence.replace(key, value)
461        y = eval(sentence)
462        #plotting
463        new_plot = Data1D(x=x, y=y)
464        new_plot.id =  wx.NewId()
465        new_plot.group_id = wx.NewId()
466        title = "%s vs %s" % (self.y_axis_title.GetValue(), 
467                              self.x_axis_title.GetValue())
468        new_plot.xaxis(self.x_axis_title.GetValue(), self.x_axis_unit.GetValue())
469        new_plot.yaxis(self.y_axis_title.GetValue(), self.y_axis_unit.GetValue())
470        try:
471            title = self.notebook.GetPageText(pos)
472            wx.PostEvent(self.parent.parent, 
473                             NewPlotEvent(plot=new_plot, 
474                        group_id=str(new_plot.group_id), title =title))   
475        except:
476            pass
477       
478    def layout_grid(self):
479        """
480        Draw the area related to the grid
481        """
482        self.notebook = Notebook(parent=self)
483        self.notebook.set_data(self._data)
484        self.grid_sizer.Add(self.notebook, 1, wx.EXPAND, 0)
485       
486    def layout_plotting_area(self):
487        """
488        Draw area containing options to plot
489        """
490        self.x_axis_title = wx.TextCtrl(self, -1)
491        self.y_axis_title = wx.TextCtrl(self, -1)
492        self.x_axis_label = wx.TextCtrl(self, -1, size=(200, -1))
493        self.y_axis_label = wx.TextCtrl(self, -1, size=(200, -1))
494        self.x_axis_add = wx.Button(self, -1, "Add")
495        self.x_axis_add.Bind(event=wx.EVT_BUTTON, handler=self.on_edit_axis, 
496                            id=self.x_axis_add.GetId())
497        self.y_axis_add = wx.Button(self, -1, "Add")
498        self.y_axis_add.Bind(event=wx.EVT_BUTTON, handler=self.on_edit_axis, 
499                            id=self.y_axis_add.GetId())
500        self.x_axis_unit = wx.TextCtrl(self, -1)
501        self.y_axis_unit = wx.TextCtrl(self, -1)
502        self.plot_button = wx.Button(self, -1, "Plot")
503        wx.EVT_BUTTON(self, self.plot_button.GetId(), self.on_plot)
504        self.plotting_sizer.AddMany([
505                    (wx.StaticText(self, -1, "x-axis label"), 1,
506                      wx.TOP|wx.BOTTOM|wx.LEFT, 10),
507                    (self.x_axis_label, 1, wx.TOP|wx.BOTTOM, 10),
508                    (self.x_axis_add, 1, wx.TOP|wx.BOTTOM|wx.RIGHT, 10),
509                    (wx.StaticText(self, -1, "x-axis title"), 1, 
510                     wx.TOP|wx.BOTTOM|wx.LEFT, 10),
511                    (self.x_axis_title, 1, wx.TOP|wx.BOTTOM, 10),
512                    (wx.StaticText(self, -1 , "unit"), 1, 
513                     wx.TOP|wx.BOTTOM, 10),
514                    (self.x_axis_unit, 1, wx.TOP|wx.BOTTOM, 10),
515                    (wx.StaticText(self, -1, "y-axis label"), 1, 
516                     wx.BOTTOM|wx.LEFT, 10),
517                    (self.y_axis_label, wx.BOTTOM, 10),
518                    (self.y_axis_add, 1, wx.BOTTOM|wx.RIGHT, 10),
519                    (wx.StaticText(self, -1, "y-axis title"), 1, 
520                     wx.BOTTOM|wx.LEFT, 10),
521                    (self.y_axis_title,  wx.BOTTOM, 10),
522                    (wx.StaticText(self, -1 , "unit"), 1, wx.BOTTOM, 10),
523                    (self.y_axis_unit, 1, wx.BOTTOM, 10),
524                      (-1, -1),
525                      (-1, -1),
526                      (-1, -1),
527                      (-1, -1),
528                      (-1, -1),
529                      (-1, -1),
530                      (self.plot_button, 1, wx.LEFT|wx.BOTTOM, 10)])
531   
532    def on_edit_axis(self, event):
533        """
534        Get the selected column on  the visible grid and set values for axis
535        """
536        cell_list = self.notebook.on_edit_axis()
537        label, title = self.create_axis_label(cell_list)
538        tcrtl = event.GetEventObject()
539        if tcrtl == self.x_axis_add:
540            self.edit_axis_helper(self.x_axis_label, self.x_axis_title,
541                                   label, title)
542        elif tcrtl == self.y_axis_add:
543            self.edit_axis_helper(self.y_axis_label, self.y_axis_title,
544                                   label, title)
545           
546    def create_axis_label(self, cell_list):
547        """
548        Receive a list of cells and  create a string presenting the selected
549        cells.
550        :param cell_list: list of tuple
551       
552        """
553        if self.notebook is not None:
554            return self.notebook.create_axis_label(cell_list)
555   
556    def edit_axis_helper(self, tcrtl_label, tcrtl_title, label, title):
557        """
558        get controls to modify
559        """
560        tcrtl_label.SetValue(str(label))
561        tcrtl_title.SetValue(str(title))
562       
563    def add_column(self):
564        """
565        """
566        if self.notebook is not None:
567            self.notebook.add_column()
568       
569    def on_remove_column(self):
570        """
571        """
572        if self.notebook is not None:
573            self.notebook.on_remove_column()
574       
575       
576class GridFrame(wx.Frame):
577    def __init__(self, parent=None, data=None, id=-1, 
578                 title="Batch Results", size=(700, 400)):
579        wx.Frame.__init__(self, parent=parent, id=id, title=title, size=size)
580        self.parent = parent
581        self.panel = GridPanel(self, data)
582        menubar = wx.MenuBar()
583        self.SetMenuBar(menubar)
584        edit = wx.Menu()
585        menubar.Append(edit, "&Edit")
586        self.Bind(wx.EVT_CLOSE, self.on_close)
587       
588        add_col_menu = edit.Append(wx.NewId(), 'Add Column', 'Add column')
589        wx.EVT_MENU(self, add_col_menu.GetId(), self.on_add_column)
590        remove_col_menu = edit.Append(wx.NewId(), 'Remove Column', 
591                                      'Remove Column')
592        wx.EVT_MENU(self, remove_col_menu.GetId(), self.on_remove_column)
593
594    def on_close(self, event):
595        """
596        """
597        self.Hide()
598       
599    def on_remove_column(self, event):
600        """
601        Remove the selected column to the grid
602        """
603        self.panel.on_remove_column()
604       
605    def on_add_column(self, event):
606        """
607        Append a new column to the grid
608        """
609        self.panel.add_column()
610       
611    def set_data(self, data):
612        """
613        """
614        self.panel.set_data(data)
615     
616     
617if __name__ == "__main__":
618    app = wx.App()
619   
620    try:
621        data = {}
622        j = 0
623        for i in range(4):
624            j += 1
625            data["index"+str(i)] = [i/j, i*j, i, i+j]
626           
627        frame = GridFrame(data=data)
628        frame.Show(True)
629    except:
630        print sys.exc_value
631       
632    app.MainLoop()
Note: See TracBrowser for help on using the repository browser.