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

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 f4c0513 was 3db44fb, checked in by butler, 10 years ago

1) Fixed second issue that was caused by the recent cleanup of
DocumentationWindow?: loading html at anchor point for context help
(broken). In order to preserve the cleanup, the class was refactored to
take another parameter: html instruction string. This keeps it general
to accept not only the # anchor but alos queries of all sorts in the
future. Thus all modules using this class were also edited to match.

2) in process of editing the dozen or so instances did a bit of code
cleanup and pylint cleanup.

  • Property mode set to 100644
File size: 35.3 KB
RevLine 
[b9a5f0e]1"""
[d5419f7f]2GUI for the data operations panel (sum and multiply)
[b9a5f0e]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
[49ab5d7]13from sas.guiframe.events import StatusEvent
[c558b47]14from sas.perspectives.calculator import calculator_widgets as widget
15from sas.guiframe.documentation_window import DocumentationWindow
[49ab5d7]16
[b9a5f0e]17#Control panel width
18if sys.platform.count("win32") > 0:
[d5419f7f]19    PANEL_TOP = 0
[b9a5f0e]20    PANEL_WIDTH = 790
21    PANEL_HEIGTH = 370
22    FONT_VARIANT = 0
23    _BOX_WIDTH = 200
24    ON_MAC = False
25else:
[d5419f7f]26    PANEL_TOP = 60
[b9a5f0e]27    _BOX_WIDTH = 230
28    PANEL_WIDTH = 900
29    PANEL_HEIGTH = 430
30    FONT_VARIANT = 1
31    ON_MAC = True
[49ab5d7]32
[b9a5f0e]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()
[a27e8b8]65        self.Bind(wx.EVT_SET_FOCUS, self.set_panel_on_focus)
[49ab5d7]66
[b9a5f0e]67    def _define_structure(self):
68        """
[49ab5d7]69        define initial sizer
[b9a5f0e]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)
[49ab5d7]79
[b9a5f0e]80    def _layout_name(self):
81        """
82        Do the layout for data name related widgets
83        """
84        new_data_sizer = wx.BoxSizer(wx.VERTICAL)
[49ab5d7]85        equal_sizer = wx.BoxSizer(wx.VERTICAL)
[b9a5f0e]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)
[49ab5d7]90        data_name = wx.StaticText(self, -1, 'Output Data Name')
91        equal_name = wx.StaticText(self, -1, ' =', size=(50, 25))
[b9a5f0e]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)')
[49ab5d7]95        self.data_namectr = wx.TextCtrl(self, -1, size=(_BOX_WIDTH, 25), style=wx.TE_PROCESS_ENTER)
[b9a5f0e]96        self.data_namectr.SetToolTipString("Hit 'Enter' key after typing.")
97        self.data_namectr.SetValue(str('MyNewDataName'))
[49ab5d7]98        self.numberctr = wx.TextCtrl(self, -1, size=(_BOX_WIDTH / 3, 25), style=wx.TE_PROCESS_ENTER)
[b9a5f0e]99        self.numberctr.SetToolTipString("Hit 'Enter' key after typing.")
100        self.numberctr.SetValue(str(1.0))
[49ab5d7]101        self.data1_cbox = wx.ComboBox(self, -1, size=(_BOX_WIDTH, 25),
[b9a5f0e]102                                      style=wx.CB_READONLY)
[49ab5d7]103        self.operator_cbox = wx.ComboBox(self, -1, size=(70, 25),
[b9a5f0e]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)
[49ab5d7]109        self.data2_cbox = wx.ComboBox(self, -1, size=(_BOX_WIDTH * 2 / 3, 25),
[b9a5f0e]110                                       style=wx.CB_READONLY)
111
[49ab5d7]112        self.out_pic = SmallPanel(self, -1, True,
113                                    size=(_BOX_WIDTH, _BOX_WIDTH),
[b9a5f0e]114                                    style=wx.NO_BORDER)
[49ab5d7]115        self.equal_pic = SmallPanel(self, -1, True, '=',
116                                    size=(50, _BOX_WIDTH),
[b9a5f0e]117                                    style=wx.NO_BORDER)
[49ab5d7]118        self.data1_pic = SmallPanel(self, -1, True,
119                                    size=(_BOX_WIDTH, _BOX_WIDTH),
[b9a5f0e]120                                    style=wx.NO_BORDER)
121        self.operator_pic = SmallPanel(self, -1, True, '+',
[49ab5d7]122                                    size=(70, _BOX_WIDTH),
[b9a5f0e]123                                    style=wx.NO_BORDER)
[49ab5d7]124        self.data2_pic = SmallPanel(self, -1, True,
125                                    size=(_BOX_WIDTH, _BOX_WIDTH),
[b9a5f0e]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)])
[49ab5d7]148        self.name_sizer.AddMany([(new_data_sizer, 0, wx.LEFT | wx.TOP, 5),
[b9a5f0e]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)
[49ab5d7]156
[b9a5f0e]157        wx.EVT_TEXT_ENTER(self.data_namectr, -1, self.on_name)
[49ab5d7]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)
[b9a5f0e]161        wx.EVT_COMBOBOX(self.data2_cbox, -1, self.on_select_data2)
[49ab5d7]162
163    def _show_numctrl(self, ctrl, enable=True):
[b9a5f0e]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:
[49ab5d7]174                wx.EVT_TEXT_ENTER(self.numberctr, -1, self.on_number)
[b9a5f0e]175        else:
176            if not ctrl.IsEnabled():
177                ctrl.Enable(True)
178            ctrl.Show(enable)
[49ab5d7]179
[b9a5f0e]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)
[49ab5d7]193
[b9a5f0e]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()
[49ab5d7]224
225    def _set_textctrl_color(self, ctrl, color):
[b9a5f0e]226        """
[49ab5d7]227        Set TextCtrl color
[b9a5f0e]228        """
229        if ON_MAC:
230            children = ctrl.GetChildren()
231            if len(children) > 0:
[49ab5d7]232                children[0].SetBackgroundColour(color)
[b9a5f0e]233        else:
[49ab5d7]234            ctrl.SetBackgroundColour(color)
[b9a5f0e]235        self.name_sizer.Layout()
[49ab5d7]236
[b9a5f0e]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)
[49ab5d7]258
[b9a5f0e]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()
[49ab5d7]265
[b9a5f0e]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 = "?"
[49ab5d7]276            self.put_text_pic(self.data1_pic, content)
[b9a5f0e]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)
[49ab5d7]283
[b9a5f0e]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()
[49ab5d7]291        self.put_text_pic(self.operator_pic, content=text)
[b9a5f0e]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)
[49ab5d7]296
[b9a5f0e]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()
[49ab5d7]304        self._show_numctrl(self.numberctr, text == 'number')
[b9a5f0e]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)
[49ab5d7]314            self.check_data_inputs()
[b9a5f0e]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()
[49ab5d7]327
328            self.put_text_pic(self.data2_pic, content)
329
[b9a5f0e]330        if self.output != None:
331            self.output.name = str(self.data_namectr.GetValue())
332        self.draw_output(self.output)
[49ab5d7]333
334    def put_text_pic(self, pic=None, content=''):
[b9a5f0e]335        """
336        Put text to the pic
337        """
[49ab5d7]338        pic.set_content(content)
[b9a5f0e]339        pic.add_text()
340        pic.draw()
[49ab5d7]341
[b9a5f0e]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)
[49ab5d7]356
[b9a5f0e]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:
[49ab5d7]379                self._set_textctrl_color(self.numberctr, self.color)
[b9a5f0e]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
[49ab5d7]398
[b9a5f0e]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:
[49ab5d7]407            exec "output = data1 %s data2" % operator
[b9a5f0e]408        except:
409            raise
410        return output
[49ab5d7]411
412
[b9a5f0e]413    def draw_output(self, output):
414        """
415        Draw output data(temp)
416        """
417        out = self.out_pic
418        if output == None:
419            content = "?"
[49ab5d7]420            self.put_text_pic(out, content)
[b9a5f0e]421        else:
422            out.add_image(output)
423        wx.CallAfter(self.name_sizer.Layout)
424        self.Layout()
425        self.Refresh()
[49ab5d7]426
427    def _layout_button(self):
[b9a5f0e]428        """
429            Do the layout for the button widgets
[49ab5d7]430        """
431        self.bt_apply = wx.Button(self, -1, "Apply", size=(_BOX_WIDTH / 2, -1))
[b9a5f0e]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)
[49ab5d7]435
[c558b47]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)
[49ab5d7]440
441        self.bt_close = wx.Button(self, -1, 'Close', size=(_BOX_WIDTH / 2, -1))
[b9a5f0e]442        self.bt_close.Bind(wx.EVT_BUTTON, self.on_close)
443        self.bt_close.SetToolTipString("Close this panel.")
[49ab5d7]444
445        self.button_sizer.AddMany([(PANEL_WIDTH / 2, 25),
[b9a5f0e]446                                   (self.bt_apply, 0, wx.RIGHT, 10),
[c558b47]447                                   (self.bt_help, 0, wx.RIGHT, 10),
[b9a5f0e]448                                   (self.bt_close, 0, wx.RIGHT, 10)])
[49ab5d7]449
[b9a5f0e]450    def _do_layout(self):
451        """
452        Draw the current panel
453        """
454        self._define_structure()
455        self._layout_name()
456        self._layout_button()
[49ab5d7]457        self.main_sizer.AddMany([(self.name_sizer, 0, wx.EXPAND | wx.ALL, 10),
[b9a5f0e]458                                (self.button_sizer, 0,
[49ab5d7]459                                          wx.EXPAND | wx.TOP | wx.BOTTOM, 5)])
[b9a5f0e]460        self.SetSizer(self.main_sizer)
461        self.SetScrollbars(20, 20, 25, 65)
462        self.SetAutoLayout(True)
[49ab5d7]463
[b9a5f0e]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()
[49ab5d7]478
[b9a5f0e]479    def fill_oprator_combox(self):
480        """
481        fill the current combobox with the operator
[49ab5d7]482        """
[b9a5f0e]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)
[49ab5d7]488
489
[b9a5f0e]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):
[49ab5d7]549                      pos_pre1 = pos1
[b9a5f0e]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:
[49ab5d7]565                    continue
[b9a5f0e]566        self.data1_cbox.SetSelection(pos_pre1)
567        self.data2_cbox.SetSelection(pos_pre2)
[49ab5d7]568
[b9a5f0e]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 {}
[49ab5d7]577
[b9a5f0e]578    def on_click_apply(self, event):
[49ab5d7]579        """
[b9a5f0e]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()
[49ab5d7]620
621    def on_help(self, event):
[c558b47]622        """
[de69095]623        Bring up the Data Operations Panel Documentation whenever
[49ab5d7]624        the HELP button is clicked.
625
[c558b47]626        Calls DocumentationWindow with the path of the location within the
[49ab5d7]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
[c558b47]630        webbrowser does not pass anything past the # to the browser when it is
631        running "file:///...."
[49ab5d7]632
[c558b47]633    :param evt: Triggers on clicking the help button
634    """
[49ab5d7]635
[c558b47]636        _TreeLocation = "user/perspectives/calculator/data_operator_help.html"
[3db44fb]637        _doc_viewer = DocumentationWindow(self, -1, _TreeLocation, "",
638                                          "Data Operation Help")
[c558b47]639
[b9a5f0e]640    def disconnect_panels(self):
641        """
642        """
643        self.out_pic.connect.disconnect()
644        self.equal_pic.connect.disconnect()
645        self.data1_pic.connect.disconnect()
646        self.operator_pic.connect.disconnect()
647        self.data2_pic.connect.disconnect()
[49ab5d7]648
[b9a5f0e]649    def on_close(self, event):
650        """
651        leave data as it is and close
652        """
653        self.parent.OnClose()
[49ab5d7]654
[b9a5f0e]655    def set_plot_unfocus(self):
656        """
657        Unfocus on right click
658        """
[49ab5d7]659
[b9a5f0e]660    def send_warnings(self, msg='', info='info'):
661        """
662        Send warning to status bar
663        """
664        wx.PostEvent(self.parent.parent, StatusEvent(status=msg, info=info))
[49ab5d7]665
[b9a5f0e]666class SmallPanel(PlotPanel):
667    """
668    PlotPanel for Quick plot and masking plot
669    """
[49ab5d7]670    def __init__(self, parent, id= -1, is_number=False, content='?', **kwargs):
671        """
[b9a5f0e]672        """
673        PlotPanel.__init__(self, parent, id=id, **kwargs)
674        self.is_number = is_number
675        self.content = content
676        self.point = None
677        self.position = (0.4, 0.5)
678        self.scale = 'linear'
679        self.prevXtrans = "x"
680        self.prevYtrans = "y"
681        self.viewModel = "--"
682        self.subplot.set_xticks([])
683        self.subplot.set_yticks([])
684        self.add_text()
685        self.figure.subplots_adjust(left=0.1, bottom=0.1)
[49ab5d7]686
[b9a5f0e]687    def set_content(self, content=''):
688        """
689        Set text content
690        """
691        self.content = str(content)
[49ab5d7]692
[b9a5f0e]693    def add_toolbar(self):
[49ab5d7]694        """
[b9a5f0e]695        Add toolbar
696        """
697        # Not implemented
698        pass
[49ab5d7]699
[b9a5f0e]700    def on_set_focus(self, event):
701        """
702        send to the parenet the current panel on focus
703        """
704        pass
705
706    def add_image(self, plot):
707        """
708        Add Image
709        """
710        self.content = ''
711        self.textList = []
712        self.plots = {}
713        self.clear()
714        self.point = plot
715        try:
716            self.figure.delaxes(self.figure.axes[0])
717            self.subplot = self.figure.add_subplot(111)
718            #self.figure.delaxes(self.figure.axes[1])
719        except:
720            pass
721        try:
722            name = plot.name
723        except:
724            name = plot.filename
725        self.plots[name] = plot
726
727        #init graph
728        self.graph = Graph()
729
730        #add plot
731        self.graph.add(plot)
732        #draw       
733        self.graph.render(self)
[49ab5d7]734
[b9a5f0e]735        try:
736            self.figure.delaxes(self.figure.axes[1])
737        except:
738            pass
739        self.subplot.figure.canvas.resizing = False
740        self.subplot.tick_params(axis='both', labelsize=9)
741        # Draw zero axis lines
[49ab5d7]742        self.subplot.axhline(linewidth=1, color='r')
743        self.subplot.axvline(linewidth=1, color='r')
[b9a5f0e]744
745        self.erase_legend()
746        try:
747            # mpl >= 1.1.0
748            self.figure.tight_layout()
749        except:
750            self.figure.subplots_adjust(left=0.1, bottom=0.1)
751        self.subplot.figure.canvas.draw()
752
753    def add_text(self):
754        """
755        Text in the plot
756        """
757        if not self.is_number:
758            return
759
760        self.clear()
761        try:
762            self.figure.delaxes(self.figure.axes[0])
763            self.subplot = self.figure.add_subplot(111)
764            self.figure.delaxes(self.figure.axes[1])
765        except:
766            pass
767        self.subplot.set_xticks([])
768        self.subplot.set_yticks([])
769        label = self.content
770        FONT = FontProperties()
771        xpos, ypos = (0.4, 0.5)
772        font = FONT.copy()
773        font.set_size(14)
774
775        self.textList = []
776        self.subplot.set_xlim((0, 1))
777        self.subplot.set_ylim((0, 1))
[49ab5d7]778
[b9a5f0e]779        try:
780            if self.content != '?':
781                float(label)
782        except:
783            self.subplot.set_frame_on(False)
784        try:
785            # mpl >= 1.1.0
786            self.figure.tight_layout()
787        except:
788            self.figure.subplots_adjust(left=0.1, bottom=0.1)
789        if len(label) > 0 and xpos > 0 and ypos > 0:
790            new_text = self.subplot.text(str(xpos), str(ypos), str(label),
791                                           fontproperties=font)
[49ab5d7]792            self.textList.append(new_text)
793
[b9a5f0e]794    def erase_legend(self):
795        """
796        Remove Legend
797        """
798        #for ax in self.axes:
799        self.remove_legend(self.subplot)
[49ab5d7]800
[b9a5f0e]801    def onMouseMotion(self, event):
802        """
803        Disable dragging 2D image
804        """
[49ab5d7]805
[b9a5f0e]806    def onWheel(self, event):
807        """
808        """
[49ab5d7]809
[b9a5f0e]810    def onLeftDown(self, event):
811        """
812        Disables LeftDown
813        """
[49ab5d7]814
[b9a5f0e]815    def onPick(self, event):
816        """
817        Remove Legend
818        """
819        for ax in self.axes:
820            self.remove_legend(ax)
[49ab5d7]821
822
[b9a5f0e]823    def draw(self):
824        """
825        Draw
826        """
827        if self.dimension == 3:
828            pass
829        else:
830            self.subplot.figure.canvas.resizing = False
[49ab5d7]831            self.subplot.tick_params(axis='both', labelsize=9)
[b9a5f0e]832            self.erase_legend()
[49ab5d7]833            self.subplot.figure.canvas.draw_idle()
[b9a5f0e]834            try:
835                self.figure.delaxes(self.figure.axes[1])
836            except:
837                pass
[49ab5d7]838
839
[b9a5f0e]840    def onContextMenu(self, event):
841        """
842        Default context menu for a plot panel
843        """
844        id = wx.NewId()
845        slicerpop = wx.Menu()
846        data = self.point
847        if issubclass(data.__class__, Data1D):
848            slicerpop.Append(id, '&Change Scale')
849            wx.EVT_MENU(self, id, self._onProperties)
850        else:
851            slicerpop.Append(id, '&Toggle Linear/Log Scale')
[49ab5d7]852            wx.EVT_MENU(self, id, self.ontogglescale)
[b9a5f0e]853        try:
854            # mouse event
855            pos_evt = event.GetPosition()
856            pos = self.ScreenToClient(pos_evt)
857        except:
858            # toolbar event
859            pos_x, pos_y = self.toolbar.GetPositionTuple()
860            pos = (pos_x, pos_y + 5)
861        self.PopupMenu(slicerpop, pos)
[49ab5d7]862
863    def ontogglescale(self, event):
[b9a5f0e]864        """
865        On toggle 2d scale
866        """
[49ab5d7]867        self._onToggleScale(event)
[b9a5f0e]868        try:
869            # mpl >= 1.1.0
870            self.figure.tight_layout()
871        except:
[49ab5d7]872            self.figure.subplots_adjust(left=0.1, bottom=0.1)
[b9a5f0e]873        try:
874            self.figure.delaxes(self.figure.axes[1])
875        except:
876            pass
[49ab5d7]877
[b9a5f0e]878    def _onProperties(self, event):
879        """
880        when clicking on Properties on context menu ,
881        The Property dialog is displayed
882        The user selects a transformation for x or y value and
883        a new plot is displayed
884        """
885        list = []
886        list = self.graph.returnPlottable()
887        if len(list.keys()) > 0:
888            first_item = list.keys()[0]
889            if first_item.x != []:
890                from sas.plottools.PropertyDialog import Properties
891                dial = Properties(self, -1, 'Change Scale')
892                # type of view or model used
893                dial.xvalue.Clear()
894                dial.yvalue.Clear()
895                dial.view.Clear()
896                dial.xvalue.Insert("x", 0)
897                dial.xvalue.Insert("log10(x)", 1)
898                dial.yvalue.Insert("y", 0)
899                dial.yvalue.Insert("log10(y)", 1)
900                dial.view.Insert("--", 0)
901                dial.view.Insert("Linear y vs x", 1)
902                dial.setValues(self.prevXtrans, self.prevYtrans, self.viewModel)
903                dial.Update()
904                if dial.ShowModal() == wx.ID_OK:
905                    self.xLabel, self.yLabel, self.viewModel = dial.getValues()
906                    if self.viewModel == "Linear y vs x":
907                        self.xLabel = "x"
908                        self.yLabel = "y"
909                        self.viewModel = "--"
910                        dial.setValues(self.xLabel, self.yLabel, self.viewModel)
911                    self._onEVT_FUNC_PROPERTY()
912                dial.Destroy()
[49ab5d7]913
[b9a5f0e]914    def _onEVT_FUNC_PROPERTY(self, remove_fit=True):
915        """
916        Receive the x and y transformation from myDialog,
917        Transforms x and y in View
918        and set the scale
919        """
920        list = []
921        list = self.graph.returnPlottable()
922        # Changing the scale might be incompatible with
923        # currently displayed data (for instance, going
924        # from ln to log when all plotted values have
925        # negative natural logs).
926        # Go linear and only change the scale at the end.
927        self.set_xscale("linear")
928        self.set_yscale("linear")
929        _xscale = 'linear'
930        _yscale = 'linear'
931        for item in list:
932            item.setLabel(self.xLabel, self.yLabel)
933            # control axis labels from the panel itself
934            yname, yunits = item.get_yaxis()
935            xname, xunits = item.get_xaxis()
936            # Goes through all possible scales
937            # Goes through all possible scales
938            if(self.xLabel == "x"):
939                item.transformX(transform.toX, transform.errToX)
940                self.graph._xaxis_transformed("%s" % xname, "%s" % xunits)
941            if(self.xLabel == "log10(x)"):
942                item.transformX(transform.toX_pos, transform.errToX_pos)
943                _xscale = 'log'
944                self.graph._xaxis_transformed("%s" % xname, "%s" % xunits)
945            if(self.yLabel == "y"):
946                item.transformY(transform.toX, transform.errToX)
947                self.graph._yaxis_transformed("%s" % yname, "%s" % yunits)
948            if(self.yLabel == "log10(y)"):
949                item.transformY(transform.toX_pos, transform.errToX_pos)
950                _yscale = 'log'
951                self.graph._yaxis_transformed("%s" % yname, "%s" % yunits)
952            item.transformView()
953        self.prevXtrans = self.xLabel
954        self.prevYtrans = self.yLabel
955        self.set_xscale(_xscale)
956        self.set_yscale(_yscale)
957        self.draw()
[49ab5d7]958
[b9a5f0e]959class DataOperatorWindow(widget.CHILD_FRAME):
960    def __init__(self, parent, manager, *args, **kwds):
961        kwds["size"] = (PANEL_WIDTH, PANEL_HEIGTH)
962        widget.CHILD_FRAME.__init__(self, parent, *args, **kwds)
963        self.parent = parent
964        self.manager = manager
965        self.panel = DataOperPanel(parent=self)
966        wx.EVT_CLOSE(self, self.OnClose)
[d5419f7f]967        self.SetPosition((wx.LEFT, PANEL_TOP))
[b9a5f0e]968        self.Show()
[49ab5d7]969
970    def OnClose(self, event=None):
[b9a5f0e]971        """
972        On close event
973        """
974        if self.manager != None:
975            self.manager.data_operator_frame = None
976        self.panel.disconnect_panels()
977        self.Destroy()
978
[49ab5d7]979
[b9a5f0e]980if __name__ == "__main__":
981
[49ab5d7]982    app = wx.App()
[b9a5f0e]983    widget.CHILD_FRAME = wx.Frame
984    window = DataOperatorWindow(parent=None, data=[], title="Data Editor")
985    app.MainLoop()
[49ab5d7]986
Note: See TracBrowser for help on using the repository browser.