source: sasview/src/sas/perspectives/calculator/data_operator.py @ 49ab5d7

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

Take care of white spaces (pylint)

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