source: sasview/src/sas/sasgui/perspectives/calculator/data_operator.py @ 230178b

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 230178b was e871a2d, checked in by butler, 9 years ago

links help from data operations panel in tools menu(data_operator.py)

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