source: sasview/src/sans/perspectives/calculator/data_operator.py @ f468791

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 f468791 was f468791, checked in by Mathieu Doucet <doucetm@…>, 11 years ago

Move plottools under sans

  • Property mode set to 100644
File size: 34.8 KB
Line 
1"""
2GUI for the data operation
3"""
4import wx
5import sys
6import time
7import numpy
8from sans.dataloader.data_info import Data1D
9from sans.plottools.PlotPanel import PlotPanel
10from sans.plottools.plottables import Graph
11from sans.plottools import transform
12from matplotlib.font_manager import FontProperties
13from sans.guiframe.events import StatusEvent
14from sans.perspectives.calculator import calculator_widgets as widget   
15#Control panel width
16if sys.platform.count("win32") > 0:
17    PANEL_WIDTH = 790
18    PANEL_HEIGTH = 370
19    FONT_VARIANT = 0
20    _BOX_WIDTH = 200
21    ON_MAC = False
22else:
23    _BOX_WIDTH = 230
24    PANEL_WIDTH = 900
25    PANEL_HEIGTH = 430
26    FONT_VARIANT = 1
27    ON_MAC = True
28     
29class DataOperPanel(wx.ScrolledWindow):
30    """
31    :param data: when not empty the class can
32                same information into a data object
33        and post event containing the changed data object to some other frame
34    """
35    def __init__(self, parent, *args, **kwds):
36        kwds['name'] = "Data Operation"
37        kwds["size"] = (PANEL_WIDTH, PANEL_HEIGTH)
38        wx.ScrolledWindow.__init__(self, parent, *args, **kwds)
39        self.parent = parent
40        #sizers etc.
41        self.main_sizer = None
42        self.name_sizer = None
43        self.button_sizer = None
44        self.data_namectr = None
45        self.numberctr = None
46        self.data1_cbox = None
47        self.operator_cbox = None
48        self.data2_cbox = None
49        self.data_title_tcl = None
50        self.out_pic = None
51        self.equal_pic = None
52        self.data1_pic = None
53        self.operator_pic = None
54        self.data2_pic = None
55        self.output = None
56        self._notes = None
57        #text grayed color
58        self.color = wx.SystemSettings.GetColour(wx.SYS_COLOUR_BACKGROUND)
59        #data
60        self._data = self.get_datalist()
61        self._do_layout()
62        self.fill_data_combox()
63        self.fill_oprator_combox()
64        self.Bind(wx.EVT_PAINT, self.set_panel_on_focus)
65             
66    def _define_structure(self):
67        """
68        define initial sizer
69        """
70        self.main_sizer = wx.BoxSizer(wx.VERTICAL)
71        title = "Data Operation "
72        title += "[ + (add); - (subtract); "
73        title += "* (multiply); / (divide); "
74        title += "| (append) ]"
75        name_box = wx.StaticBox(self, -1, title)
76        self.name_sizer = wx.StaticBoxSizer(name_box, wx.HORIZONTAL)
77        self.button_sizer = wx.BoxSizer(wx.HORIZONTAL)
78     
79    def _layout_name(self):
80        """
81        Do the layout for data name related widgets
82        """
83        new_data_sizer = wx.BoxSizer(wx.VERTICAL)
84        equal_sizer =  wx.BoxSizer(wx.VERTICAL)
85        old_data1_sizer = wx.BoxSizer(wx.VERTICAL)
86        operator_sizer = wx.BoxSizer(wx.VERTICAL)
87        old_data2_sizer = wx.BoxSizer(wx.VERTICAL)
88        data2_hori_sizer = wx.BoxSizer(wx.HORIZONTAL)
89        data_name = wx.StaticText(self, -1, 'Output Data Name') 
90        equal_name = wx.StaticText(self, -1, ' =', size=(50, 25)) 
91        data1_name = wx.StaticText(self, -1, 'Data1')
92        operator_name = wx.StaticText(self, -1, 'Operator')
93        data2_name = wx.StaticText(self, -1, 'Data2 (or Number)')
94        self.data_namectr = wx.TextCtrl(self, -1, size=(_BOX_WIDTH, 25), style=wx.TE_PROCESS_ENTER) 
95        self.data_namectr.SetToolTipString("Hit 'Enter' key after typing.")
96        self.data_namectr.SetValue(str('MyNewDataName'))
97        self.numberctr = wx.TextCtrl(self, -1, size=(_BOX_WIDTH/3, 25), style=wx.TE_PROCESS_ENTER) 
98        self.numberctr.SetToolTipString("Hit 'Enter' key after typing.")
99        self.numberctr.SetValue(str(1.0))
100        self.data1_cbox = wx.ComboBox(self, -1, size=(_BOX_WIDTH, 25), 
101                                      style=wx.CB_READONLY)
102        self.operator_cbox = wx.ComboBox(self, -1, size=(70, 25), 
103                                         style=wx.CB_READONLY)
104        operation_tip = "Add: +, Subtract: -, "
105        operation_tip += "Multiply: *, Divide: /, "
106        operation_tip += "Append(Combine): | "
107        self.operator_cbox.SetToolTipString(operation_tip)
108        self.data2_cbox = wx.ComboBox(self, -1, size=(_BOX_WIDTH*2/3, 25),
109                                       style=wx.CB_READONLY)
110
111        self.out_pic = SmallPanel(self, -1, True, 
112                                    size=(_BOX_WIDTH, _BOX_WIDTH), 
113                                    style=wx.NO_BORDER)
114        self.equal_pic = SmallPanel(self, -1, True, '=', 
115                                    size=(50, _BOX_WIDTH), 
116                                    style=wx.NO_BORDER)
117        self.data1_pic = SmallPanel(self, -1, True, 
118                                    size=(_BOX_WIDTH, _BOX_WIDTH), 
119                                    style=wx.NO_BORDER)
120        self.operator_pic = SmallPanel(self, -1, True, '+',
121                                    size=(70, _BOX_WIDTH), 
122                                    style=wx.NO_BORDER)
123        self.data2_pic = SmallPanel(self, -1, True, 
124                                    size=(_BOX_WIDTH, _BOX_WIDTH), 
125                                    style=wx.NO_BORDER)
126        for ax in self.equal_pic.axes:
127            ax.set_frame_on(False)
128        for ax in self.operator_pic.axes:
129            ax.set_frame_on(False)
130
131        new_data_sizer.AddMany([(data_name, 0, wx.LEFT, 3),
132                                       (self.data_namectr, 0, wx.LEFT, 3),
133                                       (self.out_pic, 0, wx.LEFT, 3)])
134        equal_sizer.AddMany([(13, 13), (equal_name, 0, wx.LEFT, 3),
135                                       (self.equal_pic, 0, wx.LEFT, 3)])
136        old_data1_sizer.AddMany([(data1_name, 0, wx.LEFT, 3),
137                                       (self.data1_cbox, 0, wx.LEFT, 3),
138                                       (self.data1_pic, 0, wx.LEFT, 3)])
139        operator_sizer.AddMany([(operator_name, 0, wx.LEFT, 3),
140                                 (self.operator_cbox, 0, wx.LEFT, 3),
141                                 (self.operator_pic, 0, wx.LEFT, 3)])
142        data2_hori_sizer.AddMany([(self.data2_cbox, 0, wx.LEFT, 0),
143                                       (self.numberctr, 0, wx.RIGHT, 0)])
144        old_data2_sizer.AddMany([(data2_name, 0, wx.LEFT, 3),
145                                       (data2_hori_sizer, 0, wx.LEFT, 3),
146                                       (self.data2_pic, 0, wx.LEFT, 3)])
147        self.name_sizer.AddMany([(new_data_sizer, 0, wx.LEFT|wx.TOP, 5),
148                                       (equal_sizer, 0, wx.TOP, 5),
149                                       (old_data1_sizer, 0, wx.TOP, 5),
150                                       (operator_sizer, 0, wx.TOP, 5),
151                                       (old_data2_sizer, 0, wx.TOP, 5)])
152        self.data2_cbox.Show(True)
153
154        self._show_numctrl(self.numberctr, False)
155       
156        wx.EVT_TEXT_ENTER(self.data_namectr, -1, self.on_name)
157        wx.EVT_TEXT_ENTER(self.numberctr, -1, self.on_number) 
158        wx.EVT_COMBOBOX(self.data1_cbox, -1, self.on_select_data1) 
159        wx.EVT_COMBOBOX(self.operator_cbox, -1, self.on_select_operator) 
160        wx.EVT_COMBOBOX(self.data2_cbox, -1, self.on_select_data2)
161   
162    def _show_numctrl(self, ctrl, enable=True): 
163        """
164        Show/Hide on Win
165        Enable/Disable on MAC
166        """
167        if ON_MAC:
168            ctrl.Enable(enable)
169            children = ctrl.GetChildren()
170            if len(children) > 0:
171                ctrl.GetChildren()[0].SetBackGroundColour(self.color)
172            if enable:
173                wx.EVT_TEXT_ENTER(self.numberctr, -1, self.on_number) 
174        else:
175            if not ctrl.IsEnabled():
176                ctrl.Enable(True)
177            ctrl.Show(enable)
178           
179    def on_name(self, event=None):
180        """
181        On data name typing
182        """
183        if event != None:
184            event.Skip()
185        item = event.GetEventObject()
186        if item.IsEnabled():
187            self._set_textctrl_color(item, 'white')
188        else:
189            self._set_textctrl_color(item, self.color)
190        text = item.GetValue().strip()
191        self._check_newname(text)
192   
193    def _check_newname(self, name=None):
194        """
195        Check name ctr strings
196        """
197        self.send_warnings('')
198        msg = ''
199        if name == None:
200            text = self.data_namectr.GetValue().strip()
201        else:
202            text = name
203        state_list = self.get_datalist().values()
204        name_list = []
205        for state in state_list:
206            if state.data == None:
207                theory_list = state.get_theory()
208                theory, _ = theory_list.values()[0]
209                d_name = str(theory.name)
210            else:
211                d_name = str(state.data.name)
212            name_list.append(d_name)
213        if text in name_list:
214            self._set_textctrl_color(self.data_namectr, 'pink')
215            msg = "DataOperation: The name already exists."
216        if len(text) == 0:
217            self._set_textctrl_color(self.data_namectr, 'pink')
218            msg = "DataOperation: Type the data name first."
219        if self._notes:
220            self.send_warnings(msg, 'error')
221        self.name_sizer.Layout()
222        self.Refresh()
223   
224    def _set_textctrl_color(self, ctrl, color): 
225        """
226        Set TextCtrl color
227        """
228        if ON_MAC:
229            children = ctrl.GetChildren()
230            if len(children) > 0:
231                children[0].SetBackgroundColour(color) 
232        else:
233            ctrl.SetBackgroundColour(color) 
234        self.name_sizer.Layout()
235                     
236    def on_number(self, event=None):
237        """
238        On selecting Number for Data2
239        """
240        self.send_warnings('')
241        item = event.GetEventObject()
242        text = item.GetValue().strip()
243        if self.numberctr.IsShown():
244            if self.numberctr.IsEnabled():
245                self._set_textctrl_color(self.numberctr, 'white')
246                try:
247                    val = float(text)
248                    pos = self.data2_cbox.GetCurrentSelection()
249                    self.data2_cbox.SetClientData(pos, val)
250                except:
251                    self._set_textctrl_color(self.numberctr, 'pink')
252                    msg = "DataOperation: Number requires a float number."
253                    self.send_warnings(msg, 'error')
254                    return
255            else:
256                self._set_textctrl_color(self.numberctr, self.color)
257       
258        self.put_text_pic(self.data2_pic, content=str(val))
259        self.check_data_inputs()
260        if self.output != None:
261            self.output.name = str(self.data_namectr.GetValue())
262        self.draw_output(self.output)
263        self.Refresh()
264       
265    def on_select_data1(self, event=None):
266        """
267        On select data1
268        """
269        self.send_warnings('')
270        item = event.GetEventObject()
271        pos = item.GetCurrentSelection()
272        data = item.GetClientData(pos)
273        if data == None:
274            content = "?"
275            self.put_text_pic(self.data1_pic, content) 
276        else:
277            self.data1_pic.add_image(data)
278        self.check_data_inputs()
279        if self.output != None:
280            self.output.name = str(self.data_namectr.GetValue())
281        self.draw_output(self.output)
282       
283    def on_select_operator(self, event=None):
284        """
285        On Select an Operator
286        """
287        self.send_warnings('')
288        item = event.GetEventObject()
289        text = item.GetValue().strip()
290        self.put_text_pic(self.operator_pic, content=text) 
291        self.check_data_inputs()
292        if self.output != None:
293            self.output.name = str(self.data_namectr.GetValue())
294        self.draw_output(self.output)
295       
296    def on_select_data2(self, event=None):
297        """
298        On Selecting Data2
299        """
300        self.send_warnings('')
301        item = event.GetEventObject()
302        text = item.GetValue().strip().lower()
303        self._show_numctrl(self.numberctr, text=='number')
304        pos = item.GetCurrentSelection()
305        data = item.GetClientData(pos)
306        content = "?"
307        if not (self.numberctr.IsShown() and self.numberctr.IsEnabled()):
308            if data == None:
309                content = "?"
310                self.put_text_pic(self.data2_pic, content)
311            else:
312                self.data2_pic.add_image(data)
313            self.check_data_inputs() 
314        else:
315            content = str(self.numberctr.GetValue().strip())
316            try:
317                content = float(content)
318                data = content
319            except:
320                self._set_textctrl_color(self.numberctr, 'pink')
321                content = "?"
322                data = None
323            item.SetClientData(pos, data)
324            if data != None:
325                self.check_data_inputs()
326               
327            self.put_text_pic(self.data2_pic, content)   
328       
329        if self.output != None:
330            self.output.name = str(self.data_namectr.GetValue())
331        self.draw_output(self.output)
332       
333    def put_text_pic(self, pic=None, content=''): 
334        """
335        Put text to the pic
336        """
337        pic.set_content(content) 
338        pic.add_text()
339        pic.draw()
340                 
341    def check_data_inputs(self):
342        """
343        Check data1 and data2 whether or not they are ready for operation
344        """
345        self._set_textctrl_color(self.data1_cbox, 'white')
346        self._set_textctrl_color(self.data2_cbox, 'white')
347        flag = False
348        pos1 = self.data1_cbox.GetCurrentSelection()
349        data1 = self.data1_cbox.GetClientData(pos1)
350        if data1 == None:
351            self.output = None
352            return flag
353        pos2 = self.data2_cbox.GetCurrentSelection()
354        data2 = self.data2_cbox.GetClientData(pos2)
355       
356        if data2 == None:
357            self.output = None
358            return flag
359        if self.numberctr.IsShown():
360            if self.numberctr.IsEnabled():
361                self._set_textctrl_color(self.numberctr, 'white')
362                try:
363                    float(data2)
364                    if self.operator_cbox.GetValue().strip() == '|':
365                        msg = "DataOperation: This operation can not accept "
366                        msg += "a float number."
367                        self.send_warnings(msg, 'error')
368                        self._set_textctrl_color(self.numberctr, 'pink')
369                        self.output = None
370                        return flag
371                except:
372                    msg = "DataOperation: Number requires a float number."
373                    self.send_warnings(msg, 'error')
374                    self._set_textctrl_color(self.numberctr, 'pink')
375                    self.output = None
376                    return flag
377            else:
378                self._set_textctrl_color(self.numberctr, self.color )
379        elif data1.__class__.__name__ != data2.__class__.__name__:
380            self._set_textctrl_color(self.data1_cbox, 'pink')
381            self._set_textctrl_color(self.data2_cbox, 'pink')
382            msg = "DataOperation: Data types must be same."
383            self.send_warnings(msg, 'error')
384            self.output = None
385            return flag
386        try:
387            self.output = self.make_data_out(data1, data2)
388        except:
389            self._check_newname()
390            self._set_textctrl_color(self.data1_cbox, 'pink')
391            self._set_textctrl_color(self.data2_cbox, 'pink')
392            msg = "DataOperation: Data types must be same."
393            self.send_warnings(msg, 'error')
394            self.output = None
395            return flag
396        return True
397   
398    def make_data_out(self, data1, data2):
399        """
400        Make a temp. data output set
401        """
402        output = None
403        pos = self.operator_cbox.GetCurrentSelection()
404        operator = self.operator_cbox.GetClientData(pos)
405        try:
406            exec "output = data1 %s data2"% operator
407        except:
408            raise
409        return output
410   
411   
412    def draw_output(self, output):
413        """
414        Draw output data(temp)
415        """
416        out = self.out_pic
417        if output == None:
418            content = "?"
419            self.put_text_pic(out, content) 
420        else:
421            out.add_image(output)
422        wx.CallAfter(self.name_sizer.Layout)
423        self.Layout()
424        self.Refresh()
425                   
426    def _layout_button(self): 
427        """
428            Do the layout for the button widgets
429        """ 
430        self.bt_apply = wx.Button(self, -1, "Apply", size=(_BOX_WIDTH/2, -1))
431        app_tip = "Generate the Data and send to Data Explorer."
432        self.bt_apply.SetToolTipString(app_tip)
433        self.bt_apply.Bind(wx.EVT_BUTTON, self.on_click_apply)
434       
435        self.bt_close = wx.Button(self, -1, 'Close', size=(_BOX_WIDTH/2, -1))
436        self.bt_close.Bind(wx.EVT_BUTTON, self.on_close)
437        self.bt_close.SetToolTipString("Close this panel.")
438       
439        self.button_sizer.AddMany([(PANEL_WIDTH/2, 25),
440                                   (self.bt_apply, 0, wx.RIGHT, 10),
441                                   (self.bt_close, 0, wx.RIGHT, 10)])
442       
443    def _do_layout(self):
444        """
445        Draw the current panel
446        """
447        self._define_structure()
448        self._layout_name()
449        self._layout_button()
450        self.main_sizer.AddMany([(self.name_sizer, 0, wx.EXPAND|wx.ALL, 10),
451                                (self.button_sizer, 0,
452                                          wx.EXPAND|wx.TOP|wx.BOTTOM, 5)])
453        self.SetSizer(self.main_sizer)
454        self.SetScrollbars(20, 20, 25, 65)
455        self.SetAutoLayout(True)
456   
457    def set_panel_on_focus(self, event):
458        """
459        On Focus at this window
460        """
461        if event != None:
462            event.Skip()
463        self._data = self.get_datalist()
464        if ON_MAC:
465            self.fill_data_combox()
466        else:
467            children = self.GetChildren()
468            # update the list only when it is on the top
469            if self.FindFocus() in children:
470                self.fill_data_combox()
471         
472    def fill_oprator_combox(self):
473        """
474        fill the current combobox with the operator
475        """   
476        operator_list = [' +', ' -', ' *', " /", " |"]
477        for oper in operator_list:
478            pos = self.operator_cbox.Append(str(oper))
479            self.operator_cbox.SetClientData(pos, str(oper.strip()))
480        self.operator_cbox.SetSelection(0)
481       
482       
483    def fill_data_combox(self):
484        """
485        fill the current combobox with the available data
486        """
487        pos_pre1 = self.data1_cbox.GetCurrentSelection()
488        pos_pre2 = self.data2_cbox.GetCurrentSelection()
489        current1 = self.data1_cbox.GetLabel()
490        current2 = self.data2_cbox.GetLabel()
491        if pos_pre1 < 0:
492            pos_pre1 = 0
493        if pos_pre2 < 0:
494            pos_pre2 = 0
495        self.data1_cbox.Clear()
496        self.data2_cbox.Clear()
497
498        if not self._data:
499            pos = self.data1_cbox.Append('No Data Available')
500            self.data1_cbox.SetSelection(pos)
501            self.data1_cbox.SetClientData(pos, None)
502            pos2 = self.data2_cbox.Append('No Data Available')
503            self.data2_cbox.SetSelection(pos2)
504            self.data2_cbox.SetClientData(pos2, None)
505            return
506        pos1 = self.data1_cbox.Append('Select Data')
507        self.data1_cbox.SetSelection(pos1)
508        self.data1_cbox.SetClientData(pos1, None)
509        pos2 = self.data2_cbox.Append('Select Data')
510        self.data2_cbox.SetSelection(pos2)
511        self.data2_cbox.SetClientData(pos2, None)
512        pos3 = self.data2_cbox.Append('Number')
513        val = None
514        if (self.numberctr.IsShown() and self.numberctr.IsEnabled()):
515            try:
516                val = float(self.numberctr.GetValue())
517            except:
518                val = None
519        self.data2_cbox.SetClientData(pos3, val)
520        dnames = []
521        ids = self._data.keys()
522        for id in ids:
523            if id != None:
524                if self._data[id].data != None:
525                    dnames.append(self._data[id].data.name)
526                else:
527                    theory_list = self._data[id].get_theory()
528                    theory, _ = theory_list.values()[0]
529                    dnames.append(theory.name)
530        ind = numpy.argsort(dnames)
531        if len(ind) > 0:
532            val_list = numpy.array(self._data.values())[ind]
533            for datastate in val_list:
534                data = datastate.data
535                if data != None:
536                    name = data.name
537                    pos1 = self.data1_cbox.Append(str(name))
538                    self.data1_cbox.SetClientData(pos1, data)
539                    pos2 = self.data2_cbox.Append(str(name))
540                    self.data2_cbox.SetClientData(pos2, data)
541                    if str(current1) == str(name):
542                      pos_pre1 = pos1
543                    if str(current2) == str(name):
544                      pos_pre2 = pos2
545                try:
546                    theory_list = datastate.get_theory()
547                    for theory, _ in theory_list.values():
548                        th_name = theory.name
549                        posth1 = self.data1_cbox.Append(str(th_name))
550                        self.data1_cbox.SetClientData(posth1, theory)
551                        posth2 = self.data2_cbox.Append(str(th_name))
552                        self.data2_cbox.SetClientData(posth2, theory)
553                        if str(current1) == str(th_name):
554                            pos_pre1 = posth1
555                        if str(current2) == str(th_name):
556                            pos_pre2 = posth2
557                except:
558                    continue 
559        self.data1_cbox.SetSelection(pos_pre1)
560        self.data2_cbox.SetSelection(pos_pre2)
561   
562    def get_datalist(self):
563        """
564        """
565        data_manager = self.parent.parent.get_data_manager()
566        if data_manager != None:
567            return  data_manager.get_all_data()
568        else:
569            return {}
570           
571    def on_click_apply(self, event):
572        """   
573        changes are saved in data object imported to edit
574        """
575        self.send_warnings('')
576        self.data_namectr.SetBackgroundColour('white')
577        state_list = self.get_datalist().values()
578        name = self.data_namectr.GetValue().strip()
579        name_list = []
580        for state in state_list:
581            if state.data == None:
582                theory_list = state.get_theory()
583                theory, _ = theory_list.values()[0]
584                d_name = str(theory.name)
585            else:
586                d_name = str(state.data.name)
587            name_list.append(d_name)
588        if name in name_list:
589            self._set_textctrl_color(self.data_namectr, 'pink')
590            msg = "The Output Data Name already exists...   "
591            wx.MessageBox(msg, 'Error')
592            return
593        if name == '':
594            self._set_textctrl_color(self.data_namectr, 'pink')
595            msg = "Please type the output data name first...   "
596            wx.MessageBox(msg, 'Error')
597            return
598        if self.output == None:
599            msg = "No Output Data has been generated...   "
600            wx.MessageBox(msg, 'Error')
601            return
602        # send data to data manager
603        self.output.name = name
604        self.output.run = "Data Operation"
605        self.output.instrument = "SansView"
606        self.output.id = str(name) + str(time.time())
607        data = {self.output.id :self.output}
608        self.parent.parent.add_data(data)
609        self.name_sizer.Layout()
610        self.Refresh()
611        #must post event here
612        event.Skip()
613   
614    def disconnect_panels(self):
615        """
616        """
617        self.out_pic.connect.disconnect()
618        self.equal_pic.connect.disconnect()
619        self.data1_pic.connect.disconnect()
620        self.operator_pic.connect.disconnect()
621        self.data2_pic.connect.disconnect()
622   
623    def on_close(self, event):
624        """
625        leave data as it is and close
626        """
627        self.parent.OnClose()
628       
629    def set_plot_unfocus(self):
630        """
631        Unfocus on right click
632        """
633   
634    def send_warnings(self, msg='', info='info'):
635        """
636        Send warning to status bar
637        """
638        wx.PostEvent(self.parent.parent, StatusEvent(status=msg, info=info))
639         
640class SmallPanel(PlotPanel):
641    """
642    PlotPanel for Quick plot and masking plot
643    """
644    def __init__(self, parent, id=-1, is_number=False, content='?', **kwargs):
645        """
646        """ 
647        PlotPanel.__init__(self, parent, id=id, **kwargs)
648        self.is_number = is_number
649        self.content = content
650        self.point = None
651        self.position = (0.4, 0.5)
652        self.scale = 'linear'
653        self.prevXtrans = "x"
654        self.prevYtrans = "y"
655        self.viewModel = "--"
656        self.subplot.set_xticks([])
657        self.subplot.set_yticks([])
658        self.add_text()
659        self.figure.subplots_adjust(left=0.1, bottom=0.1)
660       
661    def set_content(self, content=''):
662        """
663        Set text content
664        """
665        self.content = str(content)
666         
667    def add_toolbar(self):
668        """
669        Add toolbar
670        """
671        # Not implemented
672        pass
673   
674    def on_set_focus(self, event):
675        """
676        send to the parenet the current panel on focus
677        """
678        pass
679
680    def add_image(self, plot):
681        """
682        Add Image
683        """
684        self.content = ''
685        self.textList = []
686        self.plots = {}
687        self.clear()
688        self.point = plot
689        try:
690            self.figure.delaxes(self.figure.axes[0])
691            self.subplot = self.figure.add_subplot(111)
692            #self.figure.delaxes(self.figure.axes[1])
693        except:
694            pass
695        try:
696            name = plot.name
697        except:
698            name = plot.filename
699        self.plots[name] = plot
700
701        #init graph
702        self.graph = Graph()
703
704        #add plot
705        self.graph.add(plot)
706        #draw       
707        self.graph.render(self)
708       
709        try:
710            self.figure.delaxes(self.figure.axes[1])
711        except:
712            pass
713        self.subplot.figure.canvas.resizing = False
714        self.subplot.tick_params(axis='both', labelsize=9)
715        # Draw zero axis lines
716        self.subplot.axhline(linewidth = 1, color='r') 
717        self.subplot.axvline(linewidth = 1, color='r')       
718
719        self.erase_legend()
720        try:
721            # mpl >= 1.1.0
722            self.figure.tight_layout()
723        except:
724            self.figure.subplots_adjust(left=0.1, bottom=0.1)
725        self.subplot.figure.canvas.draw()
726
727    def add_text(self):
728        """
729        Text in the plot
730        """
731        if not self.is_number:
732            return
733
734        self.clear()
735        try:
736            self.figure.delaxes(self.figure.axes[0])
737            self.subplot = self.figure.add_subplot(111)
738            self.figure.delaxes(self.figure.axes[1])
739        except:
740            pass
741        self.subplot.set_xticks([])
742        self.subplot.set_yticks([])
743        label = self.content
744        FONT = FontProperties()
745        xpos, ypos = (0.4, 0.5)
746        font = FONT.copy()
747        font.set_size(14)
748
749        self.textList = []
750        self.subplot.set_xlim((0, 1))
751        self.subplot.set_ylim((0, 1))
752       
753        try:
754            if self.content != '?':
755                float(label)
756        except:
757            self.subplot.set_frame_on(False)
758        try:
759            # mpl >= 1.1.0
760            self.figure.tight_layout()
761        except:
762            self.figure.subplots_adjust(left=0.1, bottom=0.1)
763        if len(label) > 0 and xpos > 0 and ypos > 0:
764            new_text = self.subplot.text(str(xpos), str(ypos), str(label),
765                                           fontproperties=font)
766            self.textList.append(new_text) 
767       
768    def erase_legend(self):
769        """
770        Remove Legend
771        """
772        #for ax in self.axes:
773        self.remove_legend(self.subplot)
774                     
775    def onMouseMotion(self, event):
776        """
777        Disable dragging 2D image
778        """
779   
780    def onWheel(self, event):
781        """
782        """
783     
784    def onLeftDown(self, event):
785        """
786        Disables LeftDown
787        """
788   
789    def onPick(self, event):
790        """
791        Remove Legend
792        """
793        for ax in self.axes:
794            self.remove_legend(ax)
795                       
796   
797    def draw(self):
798        """
799        Draw
800        """
801        if self.dimension == 3:
802            pass
803        else:
804            self.subplot.figure.canvas.resizing = False
805            self.subplot.tick_params(axis='both', labelsize=9)     
806            self.erase_legend()
807            self.subplot.figure.canvas.draw_idle() 
808            try:
809                self.figure.delaxes(self.figure.axes[1])
810            except:
811                pass
812           
813       
814    def onContextMenu(self, event):
815        """
816        Default context menu for a plot panel
817        """
818        id = wx.NewId()
819        slicerpop = wx.Menu()
820        data = self.point
821        if issubclass(data.__class__, Data1D):
822            slicerpop.Append(id, '&Change Scale')
823            wx.EVT_MENU(self, id, self._onProperties)
824        else:
825            slicerpop.Append(id, '&Toggle Linear/Log Scale')
826            wx.EVT_MENU(self, id, self.ontogglescale)     
827        try:
828            # mouse event
829            pos_evt = event.GetPosition()
830            pos = self.ScreenToClient(pos_evt)
831        except:
832            # toolbar event
833            pos_x, pos_y = self.toolbar.GetPositionTuple()
834            pos = (pos_x, pos_y + 5)
835        self.PopupMenu(slicerpop, pos)
836       
837    def ontogglescale(self, event): 
838        """
839        On toggle 2d scale
840        """
841        self._onToggleScale(event) 
842        try:
843            # mpl >= 1.1.0
844            self.figure.tight_layout()
845        except:
846            self.figure.subplots_adjust(left=0.1, bottom=0.1) 
847        try:
848            self.figure.delaxes(self.figure.axes[1])
849        except:
850            pass
851       
852    def _onProperties(self, event):
853        """
854        when clicking on Properties on context menu ,
855        The Property dialog is displayed
856        The user selects a transformation for x or y value and
857        a new plot is displayed
858        """
859        list = []
860        list = self.graph.returnPlottable()
861        if len(list.keys()) > 0:
862            first_item = list.keys()[0]
863            if first_item.x != []:
864                from sans.plottools.PropertyDialog import Properties
865                dial = Properties(self, -1, 'Change Scale')
866                # type of view or model used
867                dial.xvalue.Clear()
868                dial.yvalue.Clear()
869                dial.view.Clear()
870                dial.xvalue.Insert("x", 0)
871                dial.xvalue.Insert("log10(x)", 1)
872                dial.yvalue.Insert("y", 0)
873                dial.yvalue.Insert("log10(y)", 1)
874                dial.view.Insert("--", 0)
875                dial.view.Insert("Linear y vs x", 1)
876                dial.setValues(self.prevXtrans, self.prevYtrans, self.viewModel)
877                dial.Update()
878                if dial.ShowModal() == wx.ID_OK:
879                    self.xLabel, self.yLabel, self.viewModel = dial.getValues()
880                    if self.viewModel == "Linear y vs x":
881                        self.xLabel = "x"
882                        self.yLabel = "y"
883                        self.viewModel = "--"
884                        dial.setValues(self.xLabel, self.yLabel, self.viewModel)
885                    self._onEVT_FUNC_PROPERTY()
886                dial.Destroy()
887         
888    def _onEVT_FUNC_PROPERTY(self, remove_fit=True):
889        """
890        Receive the x and y transformation from myDialog,
891        Transforms x and y in View
892        and set the scale
893        """
894        list = []
895        list = self.graph.returnPlottable()
896        # Changing the scale might be incompatible with
897        # currently displayed data (for instance, going
898        # from ln to log when all plotted values have
899        # negative natural logs).
900        # Go linear and only change the scale at the end.
901        self.set_xscale("linear")
902        self.set_yscale("linear")
903        _xscale = 'linear'
904        _yscale = 'linear'
905        for item in list:
906            item.setLabel(self.xLabel, self.yLabel)
907            # control axis labels from the panel itself
908            yname, yunits = item.get_yaxis()
909            xname, xunits = item.get_xaxis()
910            # Goes through all possible scales
911            # Goes through all possible scales
912            if(self.xLabel == "x"):
913                item.transformX(transform.toX, transform.errToX)
914                self.graph._xaxis_transformed("%s" % xname, "%s" % xunits)
915            if(self.xLabel == "log10(x)"):
916                item.transformX(transform.toX_pos, transform.errToX_pos)
917                _xscale = 'log'
918                self.graph._xaxis_transformed("%s" % xname, "%s" % xunits)
919            if(self.yLabel == "y"):
920                item.transformY(transform.toX, transform.errToX)
921                self.graph._yaxis_transformed("%s" % yname, "%s" % yunits)
922            if(self.yLabel == "log10(y)"):
923                item.transformY(transform.toX_pos, transform.errToX_pos)
924                _yscale = 'log'
925                self.graph._yaxis_transformed("%s" % yname, "%s" % yunits)
926            item.transformView()
927        self.prevXtrans = self.xLabel
928        self.prevYtrans = self.yLabel
929        self.set_xscale(_xscale)
930        self.set_yscale(_yscale)
931        self.draw()
932       
933class DataOperatorWindow(widget.CHILD_FRAME):
934    def __init__(self, parent, manager, *args, **kwds):
935        kwds["size"] = (PANEL_WIDTH, PANEL_HEIGTH)
936        widget.CHILD_FRAME.__init__(self, parent, *args, **kwds)
937        self.parent = parent
938        self.manager = manager
939        self.panel = DataOperPanel(parent=self)
940        wx.EVT_CLOSE(self, self.OnClose)
941        self.SetPosition((25, 150))
942        self.Show()
943   
944    def OnClose(self, event=None): 
945        """
946        On close event
947        """
948        if self.manager != None:
949            self.manager.data_operator_frame = None
950        self.panel.disconnect_panels()
951        self.Destroy()
952
953       
954if __name__ == "__main__":
955
956    app  = wx.App()
957    widget.CHILD_FRAME = wx.Frame
958    window = DataOperatorWindow(parent=None, data=[], title="Data Editor")
959    app.MainLoop()
960 
Note: See TracBrowser for help on using the repository browser.