source: sasview/src/sas/sasgui/perspectives/calculator/gen_scatter_panel.py @ 9305b46

ticket-1249
Last change on this file since 9305b46 was 34f23c8, checked in by Paul Kienzle <pkienzle@…>, 5 years ago

py3/wx4 compatibility changes for gui. Refs #1249

  • Property mode set to 100644
File size: 70.9 KB
Line 
1"""
2Generic Scattering panel.
3This module relies on guiframe manager.
4"""
5from __future__ import print_function
6
7import wx
8import sys
9import os
10import numpy as np
11#import math
12import wx.aui as aui
13#import wx.lib.agw.aui as aui
14import logging
15import time
16
17import matplotlib
18matplotlib.interactive(False)
19#Use the WxAgg back end. The Wx one takes too long to render
20matplotlib.use('WXAgg')
21
22#from sas.sasgui.guiframe.gui_manager import MDIFrame
23from sas.sascalc.data_util.calcthread import CalcThread
24from sas.sasgui.guiframe.local_perspectives.plotting.SimplePlot import PlotFrame
25from sas.sasgui.guiframe.dataFitting import Data2D
26from sas.sasgui.guiframe.dataFitting import Data1D
27from sas.sascalc.dataloader.data_info import Detector
28from sas.sascalc.dataloader.data_info import Source
29from sas.sasgui.guiframe.panel_base import PanelBase
30from sas.sasgui.guiframe.utils import format_number
31from sas.sasgui.guiframe.events import StatusEvent
32from sas.sascalc.calculator import sas_gen
33from sas.sasgui.perspectives.calculator.calculator_widgets import OutputTextCtrl
34from sas.sasgui.perspectives.calculator.calculator_widgets import InputTextCtrl
35from wx.lib.scrolledpanel import ScrolledPanel
36from sas.sasgui.perspectives.calculator.load_thread import GenReader
37from sas.sasgui.plottools.arrow3d import Arrow3D
38from sas.sasgui.perspectives.calculator import calculator_widgets as widget
39from sas.sasgui.guiframe.events import NewPlotEvent
40from sas.sasgui.guiframe.documentation_window import DocumentationWindow
41
42logger = logging.getLogger(__name__)
43
44_BOX_WIDTH = 76
45#Slit length panel size
46if sys.platform.count("win32") > 0:
47    PANEL_TOP = 0
48    PANEL_WIDTH = 570
49    PANEL_HEIGHT = 370
50    FONT_VARIANT = 0
51else:
52    PANEL_TOP = 60
53    PANEL_WIDTH = 620
54    PANEL_HEIGHT = 370
55    FONT_VARIANT = 1
56_QMAX_DEFAULT = 0.3
57_NPTS_DEFAULT = 50
58_Q1D_MIN = 0.001
59
60def add_icon(parent, frame):
61    """
62    Add icon in the frame
63    """
64    if parent is not None:
65        if hasattr(frame, "IsIconized"):
66            if not frame.IsIconized():
67                try:
68                    icon = parent.GetIcon()
69                    frame.SetIcon(icon)
70                except:
71                    pass
72
73def _set_error(panel, item, show_msg=False):
74    """
75    Set_error dialog
76    """
77    if item is not None:
78        item.SetBackgroundColour("pink")
79        item.Refresh()
80    if show_msg:
81        msg = "Error: wrong (or out of range) value entered."
82        if panel.parent.parent is not None:
83            wx.PostEvent(panel.parent.parent,
84                     StatusEvent(status=msg, info='Error'))
85            panel.SetFocus()
86    return False
87
88
89
90class CalcGen(CalcThread):
91    """
92    Computation
93    """
94    def __init__(self,
95                 id= -1,
96                 input=None,
97                 completefn=None,
98                 updatefn=None,
99                 #elapsed = 0,
100                 yieldtime=0.01,
101                 worktime=0.01):
102        """
103        """
104        CalcThread.__init__(self, completefn,
105                 updatefn,
106                 yieldtime,
107                 worktime)
108        self.starttime = 0
109        self.id = id
110        self.input = input
111        self.update_fn = updatefn
112
113    def compute(self):
114        """
115        executing computation
116        """
117        #elapsed = time.time() - self.starttime
118        self.starttime = time.time()
119        self.complete(input=self.input, update=self.update_fn)
120
121class SasGenPanel(ScrolledPanel, PanelBase):
122    """
123        Provides the sas gen calculator GUI.
124    """
125    ## Internal nickname for the window, used by the AUI manager
126    window_name = "Generic SAS Calculator"
127    ## Name to appear on the window title bar
128    window_caption = "Generic SAS "
129
130    def __init__(self, parent, *args, **kwds):
131        ScrolledPanel.__init__(self, parent, style=wx.RAISED_BORDER,
132                               *args, **kwds)
133        #kwds['style'] = wx.SUNKEN_BORDER
134        PanelBase.__init__(self)
135        #Font size
136        self.SetWindowVariant(variant=FONT_VARIANT)
137        self.SetupScrolling()
138        #thread to read data
139        self.reader = None
140        self.ext = None
141        self.id = 'GenSAS'
142        self.file_name = ''
143        self.time_text = None
144        self.orient_combo = None
145        self.omfreader = sas_gen.OMFReader()
146        self.sldreader = sas_gen.SLDReader()
147        self.pdbreader = sas_gen.PDBReader()
148        self.model = sas_gen.GenSAS()
149        self.param_dic = self.model.params
150        self.parameters = []
151        self.data = None
152        self.scale2d = None
153        self.is_avg = False
154        self.plot_frame = None
155        self.qmax_x = _QMAX_DEFAULT
156        self.npts_x = _NPTS_DEFAULT
157        self.sld_data = None
158        self.graph_num = 1
159        self.default_shape = 'rectangular'
160        # Object that receive status event
161        self.parent = parent
162        self._do_layout()
163        self._create_default_sld_data()
164        self._create_default_2d_data()
165        wx.CallAfter(self._set_sld_data_helper)
166
167    def _define_structure(self):
168        """
169            Define the main sizers building to build this application.
170        """
171        self.main_sizer = wx.BoxSizer(wx.VERTICAL)
172        self.box_source = wx.StaticBox(self, -1, str("SLD Data File"))
173        self.box_parameters = wx.StaticBox(self, -1, str("Input Parameters"))
174        self.box_qrange = wx.StaticBox(self, -1, str("Q Range"))
175        self.boxsizer_source = wx.StaticBoxSizer(self.box_source,
176                                                    wx.VERTICAL)
177        self.boxsizer_parameters = wx.StaticBoxSizer(self.box_parameters,
178                                                    wx.VERTICAL)
179        self.boxsizer_qrange = wx.StaticBoxSizer(self.box_qrange,
180                                                    wx.VERTICAL)
181        self.data_name_sizer = wx.BoxSizer(wx.HORIZONTAL)
182        self.param_sizer = wx.BoxSizer(wx.HORIZONTAL)
183        self.shape_sizer = wx.BoxSizer(wx.HORIZONTAL)
184        self.hint_sizer = wx.BoxSizer(wx.HORIZONTAL)
185        self.qrange_sizer = wx.BoxSizer(wx.HORIZONTAL)
186        self.button_sizer = wx.BoxSizer(wx.VERTICAL)
187        self.button_sizer1 = wx.BoxSizer(wx.HORIZONTAL)
188        self.button_sizer2 = wx.BoxSizer(wx.HORIZONTAL)
189
190    def _layout_data_name(self):
191        """
192            Fill the sizer containing data's name
193        """
194        data_name_txt = wx.StaticText(self, -1, 'Data: ')
195        self.data_name_tcl = OutputTextCtrl(self, -1,
196                                            size=(_BOX_WIDTH * 4, -1))
197        data_hint = "Loaded data"
198        self.data_name_tcl.SetToolTipString(data_hint)
199        #control that triggers importing data
200        id = wx.NewId()
201        self.browse_button = wx.Button(self, id, "Load")
202        hint_on_browse = "Click to load data into this panel."
203        self.browse_button.SetToolTipString(hint_on_browse)
204        self.Bind(wx.EVT_BUTTON, self.on_load_data, id=id)
205        self.data_name_sizer.AddMany([(data_name_txt, 0, wx.LEFT, 15),
206                                      (self.data_name_tcl, 0, wx.LEFT, 10),
207                                      (self.browse_button, 0, wx.LEFT, 10)])
208    def _layout_param_size(self):
209        """
210            Fill the sizer containing slit size information
211        """
212        self.parameters = []
213        sizer = wx.GridBagSizer(3, 6)
214        model = self.model
215        details = self.model.details
216        params = self.model.params
217        ix = 0
218        iy = 0
219        param_title = wx.StaticText(self, -1, 'Parameter')
220        sizer.Add(param_title, (iy, ix), (1, 1),
221                  wx.EXPAND | wx.ADJUST_MINSIZE, 0)
222        ix += 1
223        value_title = wx.StaticText(self, -1, 'Value')
224        sizer.Add(value_title, (iy, ix), (1, 1),
225                  wx.EXPAND | wx.ADJUST_MINSIZE, 0)
226        ix += 1
227        unit_title = wx.StaticText(self, -1, 'Unit')
228        sizer.Add(unit_title, (iy, ix), (1, 1),
229                  wx.EXPAND | wx.ADJUST_MINSIZE, 0)
230        for param in sorted(params.keys()):
231            iy += 1
232            ix = 0
233            p_name = wx.StaticText(self, -1, param)
234            sizer.Add(p_name, (iy, ix), (1, 1),
235                      wx.EXPAND | wx.ADJUST_MINSIZE, 0)
236            ## add parameter value
237            ix += 1
238            value = model.getParam(param)
239            ctl = InputTextCtrl(self, -1, size=(_BOX_WIDTH * 2, 20),
240                                style=wx.TE_PROCESS_ENTER)
241            #ctl.SetToolTipString(
242            #            "Hit 'Enter' after typing to update the plot.")
243            ctl.SetValue(format_number(value, True))
244            sizer.Add(ctl, (iy, ix), (1, 1), wx.EXPAND)
245            ## add unit
246            ix += 1
247            unit = wx.StaticText(self, -1, details[param][0])
248            sizer.Add(unit, (iy, ix), (1, 1),
249                      wx.EXPAND | wx.ADJUST_MINSIZE, 0)
250            self.parameters.append([p_name, ctl, unit])
251
252        self.param_sizer.Add(sizer, 0, wx.LEFT, 10)
253
254    def _layout_hint(self):
255        """
256            Fill the sizer containing hint
257        """
258        hint_msg = "We support omf, sld or pdb data files only."
259        hint_msg += "         "
260        if FONT_VARIANT < 1:
261            hint_msg += "Very "
262        hint_msg += "SLOW drawing -->"
263        hint_txt = wx.StaticText(self, -1, hint_msg)
264
265        id = wx.NewId()
266        self.draw_button = wx.Button(self, id, "Arrow Draw")
267        hint_on_draw = "Draw with arrows. Caution: it is a very slow drawing."
268        self.draw_button.SetToolTipString(hint_on_draw)
269        self.draw_button.Bind(wx.EVT_BUTTON, self.sld_draw, id=id)
270
271        self.draw_button.Enable(False)
272        self.hint_sizer.AddMany([(hint_txt, 0, wx.LEFT, 15),
273                                 (self.draw_button, 0, wx.LEFT, 7)])
274
275    def _layout_shape(self):
276        """
277        Fill the shape sizer
278        """
279        label_txt = wx.StaticText(self, -1, "Shape:")
280        self.shape_combo = self._fill_shape_combo()
281        self.shape_sizer.AddMany([(label_txt, 0, wx.LEFT, 15),
282                                (self.shape_combo, 0, wx.LEFT, 5)])
283
284    def _fill_shape_combo(self):
285        """
286        Fill up the shape combo box
287        """
288        shape_combo = wx.ComboBox(self, -1, size=(150, -1),
289                                      style=wx.CB_READONLY)
290        shape_combo.Append('Rectangular')
291        shape_combo.Append('Ellipsoid')
292        shape_combo.Bind(wx.EVT_COMBOBOX, self._on_shape_select)
293        shape_combo.SetSelection(0)
294        return shape_combo
295
296    def _on_shape_select(self, event):
297        """
298        On selecting a shape
299        """
300        event.Skip()
301        label = event.GetEventObject().GetValue().lower()
302        self.default_shape = label
303        self.parent.set_omfpanel_default_shap(self.default_shape)
304        self.parent.set_omfpanel_npts()
305
306    def _fill_orient_combo(self):
307        """
308        Fill up the orientation combo box: used only for atomic structure
309        """
310        orient_combo = wx.ComboBox(self, -1, size=(150, -1),
311                                      style=wx.CB_READONLY)
312        orient_combo.Append('Fixed orientation')
313        orient_combo.Append('Debye full avg.')
314        #orient_combo.Append('Debye sph. sym.')
315
316        orient_combo.Bind(wx.EVT_COMBOBOX, self._on_orient_select)
317        orient_combo.SetSelection(0)
318        return orient_combo
319
320    def _on_orient_select(self, event):
321        """
322        On selecting a orientation
323        """
324        event.Skip()
325        cb = event.GetEventObject()
326        if cb.GetCurrentSelection() == 2:
327            self.is_avg = None
328        else:
329            is_avg = cb.GetCurrentSelection() == 1
330            self.is_avg = is_avg
331        self.model.set_is_avg(self.is_avg)
332        self.set_est_time()
333
334    def _layout_qrange(self):
335        """
336        Fill the sizer containing qrange
337        """
338        sizer = wx.GridBagSizer(2, 3)
339        ix = 0
340        iy = 0
341        name = wx.StaticText(self, -1, 'No. of Qx (Qy) bins: ')
342        sizer.Add(name, (iy, ix), (1, 1),
343                  wx.EXPAND | wx.ADJUST_MINSIZE, 0)
344        ## add parameter value
345        ix += 1
346        self.npt_ctl = InputTextCtrl(self, -1, size=(_BOX_WIDTH * 1.5, 20),
347                                     style=wx.TE_PROCESS_ENTER)
348        self.npt_ctl.Bind(wx.EVT_TEXT, self._onparamEnter)
349        self.npt_ctl.SetValue(format_number(self.npts_x, True))
350        sizer.Add(self.npt_ctl, (iy, ix), (1, 1), wx.EXPAND)
351        ## add unit
352        ix += 1
353        unit = wx.StaticText(self, -1, '')
354        sizer.Add(unit, (iy, ix), (1, 1),
355                  wx.EXPAND | wx.ADJUST_MINSIZE, 0)
356        iy += 1
357        ix = 0
358        name = wx.StaticText(self, -1, 'Qx (Qy) Max: ')
359        sizer.Add(name, (iy, ix), (1, 1),
360                  wx.EXPAND | wx.ADJUST_MINSIZE, 0)
361        ## add parameter value
362        ix += 1
363        self.qmax_ctl = InputTextCtrl(self, -1, size=(_BOX_WIDTH * 1.5, 20),
364                            style=wx.TE_PROCESS_ENTER)
365        self.qmax_ctl.Bind(wx.EVT_TEXT, self._onparamEnter)
366        self.qmax_ctl.SetValue(format_number(self.qmax_x, True))
367        sizer.Add(self.qmax_ctl, (iy, ix), (1, 1), wx.EXPAND)
368        ## add unit
369        ix += 1
370        unit = wx.StaticText(self, -1, '[1/A]')
371        sizer.Add(unit, (iy, ix), (1, 1),
372                  wx.EXPAND | wx.ADJUST_MINSIZE, 0)
373        self.qrange_sizer.Add(sizer, 0, wx.LEFT, 10)
374
375    def _layout_button(self):
376        """
377            Do the layout for the button widgets
378        """
379        self.est_time = '*Estimated Computation time :\n  %s'
380        self.time_text = wx.StaticText(self, -1, self.est_time % str('2 sec'))
381        self.orient_combo = self._fill_orient_combo()
382        self.orient_combo.Show(False)
383
384        self.bt_compute = wx.Button(self, wx.NewId(), 'Compute')
385        self.bt_compute.Bind(wx.EVT_BUTTON, self.on_compute)
386        self.bt_compute.SetToolTipString("Compute 2D Scattering Pattern.")
387
388        self.bt_help = wx.Button(self, wx.NewId(), 'HELP')
389        self.bt_help.Bind(wx.EVT_BUTTON, self.on_help)
390        self.bt_help.SetToolTipString("Help on Scatter Calculator")
391
392        self.bt_close = wx.Button(self, wx.ID_CANCEL, 'Close')
393        self.bt_close.Bind(wx.EVT_BUTTON, self.on_panel_close)
394        self.bt_close.SetToolTipString("Close this window")
395
396        self.button_sizer1.AddMany([(self.bt_compute, 0, wx.LEFT, 20),
397                                   (self.orient_combo , 0, wx.LEFT, 20)])
398        self.button_sizer2.AddMany([(self.time_text , 0, wx.LEFT, 20),
399                                   (self.bt_help, 0, wx.LEFT, 20),
400                                   (self.bt_close, 0, wx.LEFT, 20)])
401        self.button_sizer.AddMany([(self.button_sizer1 , 0, wx.BOTTOM|wx.LEFT, 10),
402                                   (self.button_sizer2 , 0, wx.LEFT, 10)])
403
404    def estimate_ctime(self):
405        """
406        Calculation time estimation
407        """
408        # magic equation: not very accurate
409        factor = 1
410        n_qbins = float(self.npt_ctl.GetValue())
411        n_qbins *= n_qbins
412        n_pixs = float(self.parent.get_npix())
413        if self.is_avg:
414            factor = 6
415            n_pixs *= (n_pixs / 200)
416        x_in = n_qbins * n_pixs / 100000
417        etime = factor + 0.085973 * x_in
418        return int(etime)
419
420    def set_est_time(self):
421        """
422        Set text for est. computation time
423        """
424        unit = 'sec'
425        if self.time_text is not None:
426            self.time_text.SetForegroundColour('black')
427            etime = self.estimate_ctime()
428            if etime > 60:
429                etime /= 60
430                unit = 'min'
431                self.time_text.SetForegroundColour('red')
432            time_str = str(etime) + ' ' + unit
433            self.time_text.SetLabel(self.est_time % time_str)
434
435    def _do_layout(self):
436        """
437        Draw window content
438        """
439        self._define_structure()
440        self._layout_data_name()
441        self._layout_param_size()
442        self._layout_qrange()
443        self._layout_hint()
444        self._layout_shape()
445        self._layout_button()
446        self.boxsizer_source.AddMany([(self.data_name_sizer, 0,
447                                        wx.EXPAND | wx.TOP | wx.BOTTOM, 5),
448                                      (self.hint_sizer, 0,
449                                        wx.EXPAND | wx.TOP | wx.BOTTOM, 5),
450                                      (self.shape_sizer, 0,
451                                        wx.EXPAND | wx.TOP | wx.BOTTOM, 5)])
452        self.boxsizer_parameters.AddMany([(self.param_sizer, 0,
453                                     wx.EXPAND | wx.TOP | wx.BOTTOM, 5), ])
454        self.boxsizer_qrange.AddMany([(self.qrange_sizer, 0,
455                                     wx.EXPAND | wx.TOP | wx.BOTTOM, 5), ])
456        self.main_sizer.AddMany([(self.boxsizer_source, 0,
457                                  wx.EXPAND | wx.ALL, 10),
458                                 (self.boxsizer_parameters, 0,
459                                  wx.EXPAND | wx.ALL, 10),
460                                 (self.boxsizer_qrange, 0,
461                                  wx.EXPAND | wx.ALL, 10),
462                                 (self.button_sizer, 0,
463                                  wx.EXPAND | wx.TOP | wx.BOTTOM, 5)])
464        self.SetSizer(self.main_sizer)
465        self.SetAutoLayout(True)
466
467    def _create_default_sld_data(self):
468        """
469        Making default sld-data
470        """
471        sld_n_default = 6.97e-06
472        omfdata = sas_gen.OMFData()
473        omf2sld = sas_gen.OMF2SLD()
474        omf2sld.set_data(omfdata, self.default_shape)
475        self.sld_data = omf2sld.output
476        self.sld_data.is_data = False
477        self.sld_data.filename = "Default SLD Profile"
478        self.sld_data.set_sldn(sld_n_default)
479        self.data_name_tcl.SetValue(self.sld_data.filename)
480
481    def choose_data_file(self, location=None):
482        """
483        Choosing a dtata file
484        """
485        path = None
486        filename = ''
487        if location is None:
488            location = os.getcwd()
489
490        exts = "*" + self.omfreader.ext[0]
491        exts += ", *" + self.sldreader.ext[0]
492        exts += ", *" + self.pdbreader.ext[0]
493        all_type = "All GEN files (%s, %s) | %s" % (exts.upper(), exts.lower(),
494                                               exts.lower().replace(',', ';'))
495        wildcard = [all_type]
496        omf_type = self.omfreader.type
497        sld_type = self.sldreader.type
498        pdb_type = self.pdbreader.type
499
500        for type in sld_type:
501            wildcard.append(type)
502        for type in omf_type:
503            wildcard.append(type)
504        for type in pdb_type:
505            wildcard.append(type)
506        wildcard = '|'.join(wildcard)
507        dlg = wx.FileDialog(self, "Choose a file", location,
508                            "", wildcard, wx.FD_OPEN)
509        if dlg.ShowModal() == wx.ID_OK:
510            path = dlg.GetPath()
511            filename = os.path.basename(path)
512        dlg.Destroy()
513        return path
514
515    def on_load_data(self, event):
516        """
517        Open a file dialog to allow the user to select a given file.
518        The user is only allow to load file with extension .omf, .txt, .sld.
519        Display the slit size corresponding to the loaded data.
520        """
521        location = self.parent.get_path()
522        path = self.choose_data_file(location=location)
523        if path is None:
524            return
525
526        self.shape_sizer.ShowItems(False)
527        self.default_shape = 'rectangular'
528        self.parent.set_omfpanel_default_shap(self.default_shape)
529
530        self.parent.set_file_location(os.path.dirname(path))
531        try:
532            #Load data
533            self.ext = os.path.splitext(path)[-1]
534            if self.ext in self.omfreader.ext:
535                loader = self.omfreader
536            elif self.ext in self.sldreader.ext:
537                loader = self.sldreader
538            elif self.ext in self.pdbreader.ext:
539                loader = self.pdbreader
540            else:
541                loader = None
542            if self.reader is not None and self.reader.isrunning():
543                self.reader.stop()
544            self.browse_button.Enable(False)
545            self.browse_button.SetLabel("Loading...")
546            if self.parent.parent is not None:
547                wx.PostEvent(self.parent.parent,
548                                StatusEvent(status="Loading...",
549                                type="progress"))
550            self.reader = GenReader(path=path, loader=loader,
551                                    completefn=self.complete_loading,
552                                    updatefn=self.load_update)
553            self.reader.queue()
554            #self.load_update()
555        except Exception as exc:
556            self.ext = None
557            if self.parent.parent is None:
558                return
559            msg = "Generic SAS Calculator: %s" % exc
560            wx.PostEvent(self.parent.parent,
561                          StatusEvent(status=msg, type='stop'))
562            self.SetFocus()
563            return
564
565    def load_update(self):
566        """
567        print update on the status bar
568        """
569        if self.parent.parent is None:
570                return
571        if self.reader.isrunning():
572            type = "progress"
573        else:
574            type = "stop"
575        wx.PostEvent(self.parent.parent, StatusEvent(status="",
576                                                  type=type))
577
578    def complete_loading(self, data=None, filename=''):
579        """
580        Complete the loading
581        """
582        #compute the slit size
583        self.browse_button.Enable(True)
584        self.browse_button.SetLabel('Load')
585        try:
586            is_pdbdata = False
587            filename = data.filename
588            self.data_name_tcl.SetValue(str(filename))
589            self.file_name = filename.split('.')[0]
590            self.orient_combo.SetSelection(0)
591            self.is_avg = False
592            if self.ext in self.omfreader.ext:
593                gen = sas_gen.OMF2SLD()
594                gen.set_data(data)
595                #omf_data = data
596                self.sld_data = gen.get_magsld()
597            elif self.ext in self.sldreader.ext:
598                self.sld_data = data
599            elif self.ext in self.pdbreader.ext:
600                self.sld_data = data
601                is_pdbdata = True
602                #omf_data = None
603            else:
604                raise
605            self.orient_combo.Show(is_pdbdata)
606            #self.button_sizer.Layout()
607            self.FitInside()
608            self._set_sld_data_helper(True)
609        except:
610            if self.parent.parent is None:
611                raise
612            msg = "Loading Error: This file format is not supported "
613            msg += "for GenSAS."
614            wx.PostEvent(self.parent.parent,
615                          StatusEvent(status=msg, type='stop', info='Error'))
616            self.SetFocus()
617            return
618        if self.parent.parent is None:
619            return
620
621        msg = "Load Complete"
622        wx.PostEvent(self.parent.parent, StatusEvent(status=msg, type='stop'))
623        self.SetFocus()
624
625    def _set_sld_data_helper(self, is_draw=False):
626        """
627        Set sld data helper
628        """
629        #is_avg = self.orient_combo.GetCurrentSelection() == 1
630        self.model.set_is_avg(self.is_avg)
631        self.model.set_sld_data(self.sld_data)
632
633        self.draw_button.Enable(self.sld_data is not None)
634        wx.CallAfter(self.parent.set_sld_data, self.sld_data)
635        self._update_model_params()
636        if is_draw:
637            wx.CallAfter(self.sld_draw, None, False)
638
639    def _update_model_params(self):
640        """
641        Update the model parameter values
642        """
643        for list in self.parameters:
644            param_name = list[0].GetLabelText()
645            val = str(self.model.params[param_name])
646            list[1].SetValue(val)
647
648    def set_volume_ctl_val(self, val):
649        """
650        Set volume txtctrl value
651        """
652        for list in self.parameters:
653            param_name = list[0].GetLabelText()
654            if param_name.lower() == 'total_volume':
655                list[1].SetValue(val)
656                list[1].Refresh()
657                break
658
659    def _onparamEnter(self, event):
660        """
661        On param enter
662        """
663        try:
664            item = event.GetEventObject()
665            self._check_value()
666            item.Refresh()
667        except:
668            pass
669
670    def sld_draw(self, event=None, has_arrow=True):
671        """
672        Draw 3D sld profile
673        """
674        flag = self.parent.check_omfpanel_inputs()
675        if not flag:
676            infor = 'Error'
677            msg = 'Error: Wrong inputs in the SLD info panel.'
678            # inform msg to wx
679            wx.PostEvent(self.parent.parent,
680                    StatusEvent(status=msg, info=infor))
681            self.SetFocus()
682            return
683
684        self.sld_data = self.parent.get_sld_from_omf()
685        output = self.sld_data
686        #frame_size = wx.Size(470, 470)
687        self.plot_frame = PlotFrame(self, -1, 'testView')
688        frame = self.plot_frame
689        frame.Show(False)
690        add_icon(self.parent, frame)
691        panel = frame.plotpanel
692        try:
693            # mpl >= 1.0.0
694            ax = panel.figure.gca(projection='3d')
695        except:
696            # mpl < 1.0.0
697            try:
698                from mpl_toolkits.mplot3d import Axes3D
699                ax = Axes3D(panel.figure)
700            except:
701                logger.error("PlotPanel could not import Axes3D")
702                raise
703        panel.dimension = 3
704        graph_title = self._sld_plot_helper(ax, output, has_arrow)
705        # Use y, z axes (in mpl 3d) as z, y axes
706        # that consistent with our SAS detector coords.
707        # Format Angstrom units (A) as latex $\AA$
708        units = output.pos_unit if output.pos_unit != "A" else r"$\AA$"
709        ax.set_xlabel('x (%s)' % units)
710        ax.set_ylabel('z (%s)' % units)
711        ax.set_zlabel('y (%s)' % units)
712        panel.subplot.figure.subplots_adjust(left=0.05, right=0.95,
713                                             bottom=0.05, top=0.96)
714        if output.pix_type == 'atom':
715            ax.legend(loc='upper left', prop={'size':10})
716        num_graph = str(self.graph_num)
717        frame.SetTitle('Graph %s: %s' % (num_graph, graph_title))
718        wx.CallAfter(frame.Show, True)
719        self.graph_num += 1
720
721    def _sld_plot_helper(self, ax, output, has_arrow=False):
722        """
723        Actual plot definition happens here
724        :Param ax: axis3d
725        :Param output: sld_data [MagSLD]
726        :Param has_arrow: whether or not draws M vector [bool]
727        """
728        # Set the locals
729        color_dic = {'H':'blue', 'D':'purple', 'N': 'orange',
730                     'O':'red', 'C':'green', 'P':'cyan', 'Other':'k'}
731        marker = ','
732        m_size = 2
733        graph_title = self.file_name
734        graph_title += "   3D SLD Profile "
735        pos_x = output.pos_x
736        pos_y = output.pos_y
737        pos_z = output.pos_z
738        sld_mx = output.sld_mx
739        sld_my = output.sld_my
740        sld_mz = output.sld_mz
741        pix_symbol = output.pix_symbol
742        if output.pix_type == 'atom':
743            marker = 'o'
744            m_size = 3.5
745        sld_tot = (np.fabs(sld_mx) + np.fabs(sld_my)
746                   + np.fabs(sld_mz) + np.fabs(output.sld_n))
747        is_nonzero = sld_tot > 0.0
748        is_zero = sld_tot == 0.0
749        # I. Plot null points
750        if is_zero.any():
751            ax.plot(pos_x[is_zero], pos_z[is_zero], pos_y[is_zero], marker,
752                    c="y", alpha=0.5, markeredgecolor='y', markersize=m_size)
753            pos_x = pos_x[is_nonzero]
754            pos_y = pos_y[is_nonzero]
755            pos_z = pos_z[is_nonzero]
756            sld_mx = sld_mx[is_nonzero]
757            sld_my = sld_my[is_nonzero]
758            sld_mz = sld_mz[is_nonzero]
759            pix_symbol = output.pix_symbol[is_nonzero]
760        # II. Plot selective points in color
761        other_color = np.ones(len(pix_symbol), dtype='bool')
762        for key in color_dic.keys():
763            chosen_color = pix_symbol == key
764            if np.any(chosen_color):
765                other_color = other_color & (chosen_color != True)
766                color = color_dic[key]
767                ax.plot(pos_x[chosen_color], pos_z[chosen_color],
768                        pos_y[chosen_color], marker, c=color, alpha=0.5,
769                        markeredgecolor=color, markersize=m_size, label=key)
770        # III. Plot All others
771        if np.any(other_color):
772            a_name = ''
773            if output.pix_type == 'atom':
774                # Get atom names not in the list
775                a_names = [symb  for symb in pix_symbol
776                           if symb not in color_dic]
777                a_name = a_names[0]
778                for name in a_names:
779                    new_name = ", " + name
780                    if a_name.count(name) == 0:
781                        a_name += new_name
782            # plot in black
783            ax.plot(pos_x[other_color], pos_z[other_color], pos_y[other_color],
784                    marker, c="k", alpha=0.5, markeredgecolor="k",
785                    markersize=m_size, label=a_name)
786        # IV. Draws atomic bond with grey lines if any
787        if output.has_conect:
788            for ind in range(len(output.line_x)):
789                ax.plot(output.line_x[ind], output.line_z[ind],
790                        output.line_y[ind], '-', lw=0.6, c="grey", alpha=0.3)
791        # V. Draws magnetic vectors
792        if has_arrow and len(pos_x) > 0:
793            graph_title += " - Magnetic Vector as Arrow -"
794            panel = self.plot_frame.plotpanel
795            def _draw_arrow(input=None, update=None):
796                """
797                draw magnetic vectors w/arrow
798                """
799                max_mx = max(np.fabs(sld_mx))
800                max_my = max(np.fabs(sld_my))
801                max_mz = max(np.fabs(sld_mz))
802                max_m = max(max_mx, max_my, max_mz)
803                try:
804                    max_step = max(output.xstepsize, output.ystepsize,
805                                   output.zstepsize)
806                except:
807                    max_step = 0
808                if max_step <= 0:
809                    max_step = 5
810                try:
811                    if max_m != 0:
812                        unit_x2 = sld_mx / max_m
813                        unit_y2 = sld_my / max_m
814                        unit_z2 = sld_mz / max_m
815                        # 0.8 is for avoiding the color becomes white=(1,1,1))
816                        color_x = np.fabs(unit_x2 * 0.8)
817                        color_y = np.fabs(unit_y2 * 0.8)
818                        color_z = np.fabs(unit_z2 * 0.8)
819                        x2 = pos_x + unit_x2 * max_step
820                        y2 = pos_y + unit_y2 * max_step
821                        z2 = pos_z + unit_z2 * max_step
822                        x_arrow = np.column_stack((pos_x, x2))
823                        y_arrow = np.column_stack((pos_y, y2))
824                        z_arrow = np.column_stack((pos_z, z2))
825                        colors = np.column_stack((color_x, color_y, color_z))
826                        arrows = Arrow3D(panel, x_arrow, z_arrow, y_arrow,
827                                        colors, mutation_scale=10, lw=1,
828                                        arrowstyle="->", alpha=0.5)
829                        ax.add_artist(arrows)
830                except:
831                    pass
832                msg = "Arrow Drawing completed.\n"
833                status_type = 'stop'
834                self._status_info(msg, status_type)
835            msg = "Arrow Drawing is in progress..."
836            status_type = 'progress'
837            self._status_info(msg, status_type)
838            draw_out = CalcGen(input=ax,
839                             completefn=_draw_arrow, updatefn=self._update)
840            draw_out.queue()
841        return graph_title
842
843    def set_input_params(self):
844        """
845        Set model parameters
846        """
847        for list in self.parameters:
848            param_name = list[0].GetLabelText()
849            param_value = float(list[1].GetValue())
850            self.model.setParam(param_name, param_value)
851
852    def on_compute(self, event):
853        """
854        Compute I(qx, qy)
855        """
856        flag = self.parent.check_omfpanel_inputs()
857        if not flag and self.parent.parent is not None:
858            infor = 'Error'
859            msg = 'Error: Wrong inputs in the SLD info panel.'
860            # inform msg to wx
861            wx.PostEvent(self.parent.parent,
862                    StatusEvent(status=msg, info=infor))
863            self.SetFocus()
864            return
865        self.sld_data = self.parent.get_sld_from_omf()
866        if self.sld_data is None:
867            if self.parent.parent is not None:
868                infor = 'Error'
869                msg = 'Error: No data has been selected.'
870                # inform msg to wx
871                wx.PostEvent(self.parent.parent,
872                        StatusEvent(status=msg, info=infor))
873                self.SetFocus()
874            return
875        flag = self._check_value()
876        if not flag:
877            _set_error(self, None, True)
878            return
879        try:
880            self.model.set_sld_data(self.sld_data)
881            self.set_input_params()
882            if self.is_avg or self.is_avg is None:
883                self._create_default_1d_data()
884                i_out = np.zeros(len(self.data.y))
885                inputs = [self.data.x, [], i_out]
886            else:
887                self._create_default_2d_data()
888                i_out = np.zeros(len(self.data.data))
889                inputs = [self.data.qx_data, self.data.qy_data, i_out]
890
891            msg = "Computation is in progress..."
892            status_type = 'progress'
893            self._status_info(msg, status_type)
894            cal_out = CalcGen(input=inputs,
895                              completefn=self.complete,
896                              updatefn=self._update)
897            cal_out.queue()
898
899        except Exception as exc:
900            msg = "%s." % exc
901            status_type = 'stop'
902            self._status_info(msg, status_type)
903            wx.PostEvent(self.parent.parent,
904                        StatusEvent(status=msg, info='Error'))
905            self.SetFocus()
906
907    def on_help(self, event):
908        """
909        Bring up the General scattering Calculator Documentation whenever
910        the HELP button is clicked.
911
912        Calls DocumentationWindow with the path of the location within the
913        documentation tree (after /doc/ ....".  Note that when using old
914        versions of Wx (before 2.9) and thus not the release version of
915        installers, the help comes up at the top level of the file as
916        webbrowser does not pass anything past the # to the browser when it is
917        running "file:///...."
918
919    :param evt: Triggers on clicking the help button
920    """
921
922        _TreeLocation = "user/sasgui/perspectives/calculator/"
923        _TreeLocation += "sas_calculator_help.html"
924        _doc_viewer = DocumentationWindow(self, -1, _TreeLocation, "",
925                                          "General Scattering Calculator Help")
926
927    def _check_value(self):
928        """
929        Check input values if float
930        """
931        flag = True
932        self.npt_ctl.SetBackgroundColour("white")
933        self.qmax_ctl.SetBackgroundColour("white")
934        try:
935            npt_val = float(self.npt_ctl.GetValue())
936            if npt_val < 2 or npt_val > 1000:
937                raise
938            self.npt_ctl.SetValue(str(int(npt_val)))
939            self.set_est_time()
940        except:
941            flag = _set_error(self, self.npt_ctl)
942        try:
943            qmax_val = float(self.qmax_ctl.GetValue())
944            if qmax_val <= 0 or qmax_val > 1000:
945                raise
946        except:
947            flag = _set_error(self, self.qmax_ctl)
948        for list in self.parameters:
949            list[1].SetBackgroundColour("white")
950            param_name = list[0].GetLabelText()
951            try:
952                param_val = float(list[1].GetValue())
953                if param_name.count('frac') > 0:
954                    if param_val < 0 or param_val > 1:
955                       raise
956            except:
957                flag = _set_error(self, list[1])
958        return flag
959
960    def _status_info(self, msg='', type="update"):
961        """
962        Status msg
963        """
964        if type == "stop":
965            label = "Compute"
966            able = True
967        else:
968            label = "Wait..."
969            able = False
970        self.bt_compute.Enable(able)
971        self.bt_compute.SetLabel(label)
972        self.bt_compute.SetToolTipString(label)
973        if self.parent.parent is not None:
974            wx.PostEvent(self.parent.parent,
975                             StatusEvent(status=msg, type=type))
976
977    def _update(self, time=None):
978        """
979        Update the progress bar
980        """
981        if self.parent.parent is None:
982            return
983        type = "progress"
984        msg = "Please wait. Computing... (Note: Window may look frozen.)"
985        wx.PostEvent(self.parent.parent, StatusEvent(status=msg,
986                                                  type=type))
987
988    def complete(self, input, update=None):
989        """
990        Gen compute complete function
991        :Param input: input list [qx_data, qy_data, i_out]
992        """
993        out = np.empty(0)
994        #s = time.time()
995        for ind in range(len(input[0])):
996            if self.is_avg:
997                if ind % 1 == 0 and update is not None:
998                    update()
999                    time.sleep(0.1)
1000                inputi = [input[0][ind:ind + 1], [], input[2][ind:ind + 1]]
1001                outi = self.model.run(inputi)
1002                out = np.append(out, outi)
1003            else:
1004                if ind % 50 == 0  and update is not None:
1005                    update()
1006                    time.sleep(0.001)
1007                inputi = [input[0][ind:ind + 1], input[1][ind:ind + 1],
1008                          input[2][ind:ind + 1]]
1009                outi = self.model.runXY(inputi)
1010                out = np.append(out, outi)
1011        #print time.time() - s
1012        if self.is_avg or self.is_avg is None:
1013            self._draw1D(out)
1014        else:
1015            #out = self.model.runXY(input)
1016            self._draw2D(out)
1017
1018        msg = "Gen computation completed.\n"
1019        status_type = 'stop'
1020        self._status_info(msg, status_type)
1021
1022    def _create_default_2d_data(self):
1023        """
1024        Create 2D data by default
1025        Only when the page is on theory mode.
1026        :warning: This data is never plotted.
1027        """
1028        self.qmax_x = float(self.qmax_ctl.GetValue())
1029        self.npts_x = int(float(self.npt_ctl.GetValue()))
1030        self.data = Data2D()
1031        qmax = self.qmax_x #/ np.sqrt(2)
1032        self.data.xaxis(r'\rm{Q_{x}}', r'\AA^{-1}')
1033        self.data.yaxis(r'\rm{Q_{y}}', r'\AA^{-1}')
1034        self.data.is_data = False
1035        self.data.id = str(self.uid) + " GenData"
1036        self.data.group_id = str(self.uid) + " Model2D"
1037        ## Default values
1038        self.data.detector.append(Detector())
1039        index = len(self.data.detector) - 1
1040        self.data.detector[index].distance = 8000   # mm
1041        self.data.source.wavelength = 6             # A
1042        self.data.detector[index].pixel_size.x = 5  # mm
1043        self.data.detector[index].pixel_size.y = 5  # mm
1044        self.data.detector[index].beam_center.x = qmax
1045        self.data.detector[index].beam_center.y = qmax
1046        xmax = qmax
1047        xmin = -qmax
1048        ymax = qmax
1049        ymin = -qmax
1050        qstep = self.npts_x
1051
1052        x = np.linspace(start=xmin, stop=xmax, num=qstep, endpoint=True)
1053        y = np.linspace(start=ymin, stop=ymax, num=qstep, endpoint=True)
1054        ## use data info instead
1055        new_x = np.tile(x, (len(y), 1))
1056        new_y = np.tile(y, (len(x), 1))
1057        new_y = new_y.swapaxes(0, 1)
1058        # all data reuire now in 1d array
1059        qx_data = new_x.flatten()
1060        qy_data = new_y.flatten()
1061        q_data = np.sqrt(qx_data * qx_data + qy_data * qy_data)
1062        # set all True (standing for unmasked) as default
1063        mask = np.ones(len(qx_data), dtype=bool)
1064        # store x and y bin centers in q space
1065        x_bins = x
1066        y_bins = y
1067        self.data.source = Source()
1068        self.data.data = np.ones(len(mask))
1069        self.data.err_data = np.ones(len(mask))
1070        self.data.qx_data = qx_data
1071        self.data.qy_data = qy_data
1072        self.data.q_data = q_data
1073        self.data.mask = mask
1074        self.data.x_bins = x_bins
1075        self.data.y_bins = y_bins
1076        # max and min taking account of the bin sizes
1077        self.data.xmin = xmin
1078        self.data.xmax = xmax
1079        self.data.ymin = ymin
1080        self.data.ymax = ymax
1081
1082    def _create_default_1d_data(self):
1083        """
1084        Create 2D data by default
1085        Only when the page is on theory mode.
1086        :warning: This data is never plotted.
1087                    residuals.x = data_copy.x[index]
1088            residuals.dy = np.ones(len(residuals.y))
1089            residuals.dx = None
1090            residuals.dxl = None
1091            residuals.dxw = None
1092        """
1093        self.qmax_x = float(self.qmax_ctl.GetValue())
1094        self.npts_x = int(float(self.npt_ctl.GetValue()))
1095        qmax = self.qmax_x #/ np.sqrt(2)
1096        ## Default values
1097        xmax = qmax
1098        xmin = qmax * _Q1D_MIN
1099        qstep = self.npts_x
1100        x = np.linspace(start=xmin, stop=xmax, num=qstep, endpoint=True)
1101        # store x and y bin centers in q space
1102        #self.data.source = Source()
1103        y = np.ones(len(x))
1104        dy = np.zeros(len(x))
1105        dx = np.zeros(len(x))
1106        self.data = Data1D(x=x, y=y)
1107        self.data.dx = dx
1108        self.data.dy = dy
1109
1110    def _draw1D(self, y_out):
1111        """
1112        Complete get the result of modelthread and create model 2D
1113        that can be plot.
1114        """
1115        page_id = self.id
1116        data = self.data
1117
1118        model = self.model
1119        state = None
1120
1121        new_plot = Data1D(x=data.x, y=y_out)
1122        new_plot.dx = data.dx
1123        new_plot.dy = data.dy
1124        new_plot.xaxis(r'\rm{Q_{x}}', r'\AA^{-1}')
1125        new_plot.yaxis(r'\rm{Intensity}', 'cm^{-1}')
1126        new_plot.is_data = False
1127        new_plot.id = str(self.uid) + " GenData1D"
1128        new_plot.group_id = str(self.uid) + " Model1D"
1129        new_plot.name = model.name + '1d'
1130        new_plot.title = "Generic model1D "
1131        new_plot.id = (str(page_id) + ': ' + self.file_name
1132                       + ' #%s' % str(self.graph_num) + "_1D")
1133        new_plot.group_id = (str(page_id) + " Model1D"
1134                             + ' #%s' % str(self.graph_num) + "_1D")
1135        new_plot.is_data = False
1136
1137        title = new_plot.title
1138        _yaxis, _yunit = new_plot.get_yaxis()
1139        _xaxis, _xunit = new_plot.get_xaxis()
1140        new_plot.xaxis(str(_xaxis), str(_xunit))
1141        new_plot.yaxis(str(_yaxis), str(_yunit))
1142
1143        if new_plot.is_data:
1144            data_name = str(new_plot.name)
1145        else:
1146            data_name = str(model.__class__.__name__) + '1d'
1147
1148        if len(title) > 1:
1149            new_plot.title = "Gen Theory for %s " % model.name + data_name
1150        new_plot.name = new_plot.id
1151        new_plot.label = new_plot.id
1152        #theory_data = deepcopy(new_plot)
1153        if self.parent.parent is not None:
1154            self.parent.parent.update_theory(data_id=new_plot.id,
1155                                           theory=new_plot,
1156                                           state=state)
1157        title = new_plot.title
1158        num_graph = str(self.graph_num)
1159        wx.CallAfter(self.parent.draw_graph, new_plot,
1160                     title="GEN Graph %s: " % num_graph + new_plot.id)
1161        self.graph_num += 1
1162
1163    def _draw2D(self, image):
1164        """
1165        Complete get the result of modelthread and create model 2D
1166        that can be plot.
1167        """
1168        page_id = self.id
1169        data = self.data
1170
1171        model = self.model
1172        qmin = 0.0
1173        state = None
1174
1175        np.nan_to_num(image)
1176        new_plot = Data2D(image=image, err_image=data.err_data)
1177        new_plot.name = model.name + '2d'
1178        new_plot.title = "Generic model 2D "
1179        new_plot.id = (str(page_id) + ': ' + self.file_name
1180                       + ' #%s' % str(self.graph_num) + "_2D")
1181        new_plot.group_id = (str(page_id) + " Model2D"
1182                             + ' #%s' % str(self.graph_num) + "_2D")
1183        new_plot.detector = data.detector
1184        new_plot.source = data.source
1185        new_plot.is_data = False
1186        new_plot.qx_data = data.qx_data
1187        new_plot.qy_data = data.qy_data
1188        new_plot.q_data = data.q_data
1189        new_plot.mask = data.mask
1190        ## plot boundaries
1191        new_plot.ymin = data.ymin
1192        new_plot.ymax = data.ymax
1193        new_plot.xmin = data.xmin
1194        new_plot.xmax = data.xmax
1195        title = data.title
1196        _yaxis, _yunit = data.get_yaxis()
1197        _xaxis, _xunit = data.get_xaxis()
1198        new_plot.xaxis(str(_xaxis), str(_xunit))
1199        new_plot.yaxis(str(_yaxis), str(_yunit))
1200
1201        new_plot.is_data = False
1202        if data.is_data:
1203            data_name = str(data.name)
1204        else:
1205            data_name = str(model.__class__.__name__) + '2d'
1206
1207        if len(title) > 1:
1208            new_plot.title = "Gen Theory for %s " % model.name + data_name
1209        new_plot.name = new_plot.id
1210        new_plot.label = new_plot.id
1211        #theory_data = deepcopy(new_plot)
1212        if self.parent.parent is not None:
1213            self.parent.parent.update_theory(data_id=data.id,
1214                                           theory=new_plot,
1215                                           state=state)
1216        title = new_plot.title
1217        num_graph = str(self.graph_num)
1218        wx.CallAfter(self.parent.draw_graph, new_plot,
1219                     title="GEN Graph %s: " % num_graph + new_plot.id)
1220        self.graph_num += 1
1221
1222    def set_scale2d(self, scale):
1223        """
1224        Set SLD plot scale
1225        """
1226        self.scale2d = None
1227
1228    def on_panel_close(self, event):
1229        """
1230        close the window containing this panel
1231        """
1232        self.parent.Close()
1233
1234class OmfPanel(ScrolledPanel, PanelBase):
1235    """
1236        Provides the sas gen calculator GUI.
1237    """
1238    ## Internal nickname for the window, used by the AUI manager
1239    window_name = "SLD Pixel Info"
1240    ## Name to appear on the window title bar
1241    window_caption = "SLD Pixel Info "
1242
1243    def __init__(self, parent, *args, **kwds):
1244        ScrolledPanel.__init__(self, parent, style=wx.RAISED_BORDER,
1245                               *args, **kwds)
1246        PanelBase.__init__(self)
1247        #Font size
1248        self.SetWindowVariant(variant=FONT_VARIANT)
1249        self.SetupScrolling()
1250        # Object that receive status event
1251        self.parent = parent
1252        self.sld_data = sas_gen.MagSLD([0], [0], [0])
1253        self.sld_ctl = None
1254        self.default_shape = 'rectangular'
1255        self._do_layout()
1256
1257    def set_slddata(self, slddata):
1258        """
1259        Set sld data related items
1260        """
1261        self.sld_data = slddata
1262        self._set_slddata_ctr_val(slddata)
1263        # Make sure that self._set_slddata_ctr_val() is finished
1264        wx.CallAfter(self._set_omfdata_ctr, slddata)
1265
1266    def get_sld_val(self):
1267        """
1268        Set sld_n of slddata on sld input
1269        """
1270        sld_sets = {}
1271        if not self.sld_data.is_data:
1272            self._get_other_val()
1273        for list in self.slds:
1274            if list[1].IsEnabled():
1275                list[1].SetBackgroundColour("white")
1276                list[1].Refresh()
1277                try:
1278                    val = float(list[1].GetValue())
1279                    sld_sets[list[0]] = val
1280                except:
1281                    flag = _set_error(self, list[1])
1282                    if not flag:
1283                        return self.sld_data
1284            else:
1285               sld_sets[list[0]] = None
1286        for key in sld_sets.keys():
1287            key_low = key.lower()
1288            if key_low.count('mx') > 0:
1289                if sld_sets[key] is None:
1290                    sld_sets[key] = self.sld_data.sld_mx
1291                mx = sld_sets[key]
1292            elif key_low.count('my') > 0:
1293                if sld_sets[key] is None:
1294                    sld_sets[key] = self.sld_data.sld_my
1295                my = sld_sets[key]
1296            elif key_low.count('mz') > 0:
1297                if sld_sets[key] is None:
1298                    sld_sets[key] = self.sld_data.sld_mz
1299                mz = sld_sets[key]
1300            else:
1301                if sld_sets[key] is not None:
1302                    self.sld_data.set_sldn(sld_sets[key])
1303        self.sld_data.set_sldms(mx, my, mz)
1304        self._set_slddata_ctr_val(self.sld_data)
1305
1306        return self.sld_data
1307
1308    def get_pix_volumes(self):
1309        """
1310        Get the pixel volume
1311        """
1312        vol = self.sld_data.vol_pix
1313
1314        return vol
1315
1316    def _get_other_val(self):
1317        """
1318        """
1319        omfdata = sas_gen.OMFData()
1320        sets = {}
1321        try:
1322            for lst in self.stepsize:
1323                if lst[1].IsEnabled():
1324                    val = float(lst[1].GetValue())
1325                    sets[lst[0]] = val
1326                else:
1327                    sets[lst[0]] = None
1328                    return
1329            for lst in self.nodes:
1330                if lst[1].IsEnabled():
1331                    val = float(lst[1].GetValue())
1332                    sets[lst[0]] = val
1333                else:
1334                    sets[lst[0]] = None
1335                    return
1336
1337            for key in sets.keys():
1338                setattr(omfdata, key, sets[key])
1339
1340            omf2sld = sas_gen.OMF2SLD()
1341            omf2sld.set_data(omfdata, self.default_shape)
1342            self.sld_data = omf2sld.output
1343            self.sld_data.is_data = False
1344            self.sld_data.filename = "Default SLD Profile"
1345        except Exception as exc:
1346            msg = "OMF Panel: %s" % exc
1347            infor = 'Error'
1348            #logger.error(msg)
1349            if self.parent.parent is not None:
1350                # inform msg to wx
1351                wx.PostEvent(self.parent.parent,
1352                        StatusEvent(status=msg, info=infor))
1353                self.SetFocus()
1354
1355    def _set_slddata_ctr_val(self, slddata):
1356        """
1357        Set slddata crl
1358        """
1359        try:
1360            val = str(len(slddata.sld_n))
1361        except:
1362            val = 'Unknown'
1363        self.npix_ctl.SetValue(val)
1364
1365    def _set_omfdata_ctr(self, omfdata):
1366        """
1367        Set the textctr box values
1368        """
1369
1370        if omfdata is None:
1371            self._set_none_text()
1372            return
1373        nodes_list = self._get_nodes_key_list(omfdata)
1374        step_list = self._get_step_key_list(omfdata)
1375        for ctr_list in self.nodes:
1376            for key in nodes_list.keys():
1377                if ctr_list[0] == key:
1378                    ctr_list[1].SetValue(format_number(nodes_list[key], True))
1379                    ctr_list[1].Enable(not omfdata.is_data)
1380                    break
1381        for ctr_list in self.stepsize:
1382            for key in step_list.keys():
1383                if ctr_list[0] == key:
1384                    ctr_list[1].SetValue(format_number(step_list[key], True))
1385                    ctr_list[1].Enable(not omfdata.is_data)
1386                    break
1387
1388    def _set_none_text(self):
1389        """
1390        Set Unknown in textctrls
1391        """
1392        val = 'Unknown'
1393        for ctr_list in self.nodes:
1394            ctr_list[1].SetValue(val)
1395        for ctr_list in self.stepsize:
1396            ctr_list[1].SetValue(val)
1397
1398    def _define_structure(self):
1399        """
1400        Define the main sizers building to build this application.
1401        """
1402        self.main_sizer = wx.BoxSizer(wx.VERTICAL)
1403
1404        self.npixels_sizer = wx.BoxSizer(wx.HORIZONTAL)
1405        self.box_sld = wx.StaticBox(self, -1,
1406                                    str("Mean SLD"))
1407        self.box_node = wx.StaticBox(self, -1, str("Nodes"))
1408        self.boxsizer_sld = wx.StaticBoxSizer(self.box_sld, wx.VERTICAL)
1409        self.box_stepsize = wx.StaticBox(self, -1, str("Step Size"))
1410        self.boxsizer_node = wx.StaticBoxSizer(self.box_node, wx.VERTICAL)
1411        self.boxsizer_stepsize = wx.StaticBoxSizer(self.box_stepsize,
1412                                                    wx.VERTICAL)
1413        self.sld_sizer = wx.BoxSizer(wx.HORIZONTAL)
1414        self.node_sizer = wx.BoxSizer(wx.HORIZONTAL)
1415        self.step_sizer = wx.BoxSizer(wx.HORIZONTAL)
1416        self.hint_sizer = wx.BoxSizer(wx.HORIZONTAL)
1417        self.button_sizer = wx.BoxSizer(wx.HORIZONTAL)
1418
1419    def _layout_npix(self):
1420        """
1421        Build No of pixels sizer
1422        """
1423        num_pix_text = wx.StaticText(self, -1, "No. of Pixels: ")
1424        self.npix_ctl = OutputTextCtrl(self, -1, size=(_BOX_WIDTH, 20),
1425                                style=wx.TE_PROCESS_ENTER)
1426        self._set_slddata_ctr_val(self.sld_data)
1427        self._set_omfdata_ctr(self.sld_data)
1428        self.npixels_sizer.AddMany([(num_pix_text, 0,
1429                                          wx.EXPAND | wx.LEFT | wx.TOP, 5),
1430                                     (self.npix_ctl, 0,
1431                                     wx.EXPAND | wx.TOP, 5)])
1432
1433    def _layout_slds(self):
1434        """
1435        Build nuclear sld sizer
1436        """
1437        self.slds = []
1438        omfdata = self.sld_data
1439        if omfdata is None:
1440            raise
1441        sld_key_list = self._get_slds_key_list(omfdata)
1442        is_data = self.sld_data.is_data
1443        sizer = wx.GridBagSizer(2, 3)
1444        ix = 0
1445        iy = -1
1446        for key, value in sorted(sld_key_list.items()):
1447            iy += 1
1448            ix = 0
1449            name = wx.StaticText(self, -1, key)
1450            sizer.Add(name, (iy, ix), (1, 1),
1451                      wx.EXPAND | wx.ADJUST_MINSIZE, 0)
1452            ## add parameter value
1453            ix += 1
1454            ctl = InputTextCtrl(self, -1, size=(_BOX_WIDTH, 20),
1455                                style=wx.TE_PROCESS_ENTER)
1456            ctl.SetValue(format_number(value, True))
1457            ctl.Enable(not is_data)
1458            sizer.Add(ctl, (iy, ix), (1, 1), wx.EXPAND)
1459            ## add unit
1460            ix += 1
1461            s_unit = '[' + omfdata.sld_unit + ']'
1462            unit = wx.StaticText(self, -1, s_unit)
1463            sizer.Add(unit, (iy, ix), (1, 1),
1464                      wx.EXPAND | wx.ADJUST_MINSIZE, 0)
1465            self.slds.append([key, ctl, unit])
1466        self.sld_sizer.Add(sizer, 0, wx.LEFT, 10)
1467
1468    def _layout_nodes(self):
1469        """
1470        Fill the sizer containing data's name
1471        """
1472        self.nodes = []
1473        omfdata = self.sld_data
1474        if omfdata is None:
1475            raise
1476        key_list = self._get_nodes_key_list(omfdata)
1477        is_data = self.sld_data.is_data
1478        sizer = wx.GridBagSizer(2, 3)
1479        ix = 0
1480        iy = -1
1481        for key, value in sorted(key_list.items()):
1482            iy += 1
1483            ix = 0
1484            name = wx.StaticText(self, -1, key)
1485            sizer.Add(name, (iy, ix), (1, 1),
1486                      wx.EXPAND | wx.ADJUST_MINSIZE, 0)
1487            ## add parameter value
1488            ix += 1
1489            ctl = InputTextCtrl(self, -1, size=(_BOX_WIDTH, 20),
1490                                style=wx.TE_PROCESS_ENTER)
1491            ctl.Bind(wx.EVT_TEXT, self._onparamEnter)
1492            ctl.SetValue(format_number(value, True))
1493            ctl.Enable(not is_data)
1494            sizer.Add(ctl, (iy, ix), (1, 1), wx.EXPAND)
1495            ## add unit
1496            ix += 1
1497            unit = wx.StaticText(self, -1, '')
1498            sizer.Add(unit, (iy, ix), (1, 1),
1499                      wx.EXPAND | wx.ADJUST_MINSIZE, 0)
1500            self.nodes.append([key, ctl, unit])
1501        self.node_sizer.Add(sizer, 0, wx.LEFT, 10)
1502
1503    def _layout_stepsize(self):
1504        """
1505        Fill the sizer containing slit size information
1506        """
1507        self.stepsize = []
1508        omfdata = self.sld_data
1509        if omfdata is None:
1510            raise
1511        key_list = self._get_step_key_list(omfdata)
1512        is_data = self.sld_data.is_data
1513        sizer = wx.GridBagSizer(2, 3)
1514        ix = 0
1515        iy = -1
1516        for key, value in sorted(key_list.items()):
1517            iy += 1
1518            ix = 0
1519            name = wx.StaticText(self, -1, key)
1520            sizer.Add(name, (iy, ix), (1, 1),
1521                      wx.EXPAND | wx.ADJUST_MINSIZE, 0)
1522            ## add parameter value
1523            ix += 1
1524            ctl = InputTextCtrl(self, -1, size=(_BOX_WIDTH, 20),
1525                                style=wx.TE_PROCESS_ENTER)
1526            ctl.Bind(wx.EVT_TEXT, self._onstepsize)
1527            ctl.SetValue(format_number(value, True))
1528            ctl.Enable(not is_data)
1529            sizer.Add(ctl, (iy, ix), (1, 1), wx.EXPAND)
1530            ## add unit
1531            ix += 1
1532            p_unit = '[' + omfdata.pos_unit + ']'
1533            unit = wx.StaticText(self, -1, p_unit)
1534            sizer.Add(unit, (iy, ix), (1, 1),
1535                      wx.EXPAND | wx.ADJUST_MINSIZE, 0)
1536            self.stepsize.append([key, ctl, unit])
1537        self.step_sizer.Add(sizer, 0, wx.LEFT, 10)
1538
1539    def _layout_hint(self):
1540        """
1541        Fill the sizer containing hint
1542        """
1543        hint_msg = "Load an omf or 3d sld profile data file."
1544        self.hint_txt = wx.StaticText(self, -1, hint_msg)
1545        self.hint_sizer.AddMany([(self.hint_txt, 0, wx.LEFT, 15)])
1546
1547    def _layout_button(self):
1548        """
1549        Do the layout for the button widgets
1550        """
1551        self.bt_draw = wx.Button(self, wx.NewId(), 'Draw Points')
1552        self.bt_draw.Bind(wx.EVT_BUTTON, self.on_sld_draw)
1553        self.bt_draw.SetToolTipString("Draw a scatter plot for sld profile.")
1554        self.bt_save = wx.Button(self, wx.NewId(), 'Save SLD Data')
1555        self.bt_save.Bind(wx.EVT_BUTTON, self.on_save)
1556        self.bt_save.Enable(False)
1557        self.bt_save.SetToolTipString("Save SLD data.")
1558        self.button_sizer.AddMany([(self.bt_draw, 0, wx.LEFT, 10),
1559                                   (self.bt_save, 0, wx.LEFT, 10)])
1560
1561    def _do_layout(self):
1562        """
1563        Draw omf panel content, used to define sld s.
1564
1565        """
1566        self._define_structure()
1567        self._layout_nodes()
1568        self._layout_stepsize()
1569        self._layout_npix()
1570        self._layout_slds()
1571        #self._layout_hint()
1572        self._layout_button()
1573        self.boxsizer_node.AddMany([(self.node_sizer, 0,
1574                                    wx.EXPAND | wx.TOP, 5),
1575                                     (self.hint_sizer, 0,
1576                                     wx.EXPAND | wx.TOP | wx.BOTTOM, 5)])
1577        self.boxsizer_stepsize.AddMany([(self.step_sizer, 0,
1578                                     wx.EXPAND | wx.TOP | wx.BOTTOM, 5), ])
1579        self.boxsizer_sld.AddMany([(self.sld_sizer, 0,
1580                                     wx.EXPAND | wx.BOTTOM, 5), ])
1581        self.main_sizer.AddMany([(self.npixels_sizer, 0, wx.EXPAND | wx.ALL, 10),
1582                        (self.boxsizer_sld, 0, wx.EXPAND | wx.ALL, 10),
1583                        (self.boxsizer_node, 0, wx.EXPAND | wx.ALL, 10),
1584                        (self.boxsizer_stepsize, 0, wx.EXPAND | wx.ALL, 10),
1585                        (self.button_sizer, 0, wx.EXPAND | wx.TOP | wx.BOTTOM, 5)])
1586        self.SetSizer(self.main_sizer)
1587        self.SetAutoLayout(True)
1588
1589    def _get_nodes_key_list(self, data):
1590        """
1591        Return nodes key list
1592
1593        :Param data: OMFData
1594        """
1595        key_list = {'xnodes' : data.xnodes,
1596                    'ynodes' : data.ynodes,
1597                    'znodes' : data.znodes}
1598        return key_list
1599
1600    def _get_slds_key_list(self, data):
1601        """
1602        Return nodes key list
1603
1604        :Param data: OMFData
1605        """
1606        key_list = {'Nucl.' : data.sld_n,
1607                    'Mx' : data.sld_mx,
1608                    'My' : data.sld_my,
1609                    'Mz' : data.sld_mz}
1610        return key_list
1611
1612    def _get_step_key_list(self, data):
1613        """
1614        Return step key list
1615
1616        :Param data: OMFData
1617        """
1618        key_list = {'xstepsize' : data.xstepsize,
1619                    'ystepsize' : data.ystepsize,
1620                    'zstepsize' : data.zstepsize}
1621        return key_list
1622
1623    def set_sld_ctr(self, sld_data):
1624        """
1625        Set sld textctrls
1626        """
1627        if sld_data is None:
1628            for ctr_list in self.slds:
1629                ctr_list[1].Enable(False)
1630                #break
1631            return
1632
1633        self.sld_data = sld_data
1634        sld_list = self._get_slds_key_list(sld_data)
1635        for ctr_list in self.slds:
1636            for key in sld_list.keys():
1637                if ctr_list[0] == key:
1638                    min_val = np.min(sld_list[key])
1639                    max_val = np.max(sld_list[key])
1640                    mean_val = np.mean(sld_list[key])
1641                    enable = ((min_val == max_val)
1642                              and sld_data.pix_type == 'pixel')
1643                    ctr_list[1].SetValue(format_number(mean_val, True))
1644                    ctr_list[1].Enable(enable)
1645                    #ctr_list[2].SetLabel("[" + sld_data.sld_unit + "]")
1646                    break
1647
1648    def on_sld_draw(self, event):
1649        """
1650        Draw sld profile as scattered plot
1651        """
1652        self.parent.sld_draw()
1653
1654    def on_save(self, event):
1655        """
1656        Close the window containing this panel
1657        """
1658        flag = True
1659        flag = self.check_inputs()
1660        if not flag:
1661            return
1662        self.sld_data = self.get_sld_val()
1663        self.parent.set_main_panel_sld_data(self.sld_data)
1664
1665        reader = sas_gen.SLDReader()
1666        extension = '*.sld'
1667        path = None
1668        data = None
1669        location = self.parent.get_path()
1670        dlg = wx.FileDialog(self, "Save sld file",
1671                            location, "sld_file",
1672                             extension,
1673                             wx.SAVE)
1674        if dlg.ShowModal() == wx.ID_OK:
1675            path = dlg.GetPath()
1676            self.parent.set_file_location(os.path.dirname(path))
1677        else:
1678            return None
1679        dlg.Destroy()
1680        try:
1681            if path is None:
1682                return
1683
1684            data = self.parent.get_sld_data()
1685            fName = os.path.splitext(path)[0] + '.' + extension.split('.')[-1]
1686            if data is not None:
1687                try:
1688                    reader.write(fName, data)
1689                except:
1690                    raise
1691            else:
1692                msg = "%s cannot write %s\n" % ('Generic Scattering', str(path))
1693                infor = 'Error'
1694                #logger.error(msg)
1695                if self.parent.parent is not None:
1696                    # inform msg to wx
1697                    wx.PostEvent(self.parent.parent,
1698                            StatusEvent(status=msg, info=infor))
1699                    self.SetFocus()
1700            return
1701        except:
1702            msg = "Error occurred while saving. "
1703            infor = 'Error'
1704            if self.parent.parent is not None:
1705                # inform msg to wx
1706                wx.PostEvent(self.parent.parent,
1707                        StatusEvent(status=msg, info=infor))
1708                self.SetFocus()
1709
1710    def _onparamEnter(self, event):
1711        """
1712        """
1713        flag = True
1714        if event is not None:
1715            event.Skip()
1716            ctl = event.GetEventObject()
1717            ctl.SetBackgroundColour("white")
1718            #_set_error(self, ctl)
1719        try:
1720            float(ctl.GetValue())
1721        except:
1722            flag = _set_error(self, ctl)
1723        if flag:
1724            npts = 1
1725            for item in self.nodes:
1726                n_val = float(item[1].GetValue())
1727                if n_val <= 0:
1728                    item[1].SetBackgroundColour("pink")
1729                    npts = -1
1730                    break
1731                if np.isfinite(n_val):
1732                    npts *= int(n_val)
1733            if npts > 0:
1734                nop = self.set_npts_from_slddata()
1735                if nop is None:
1736                    nop = npts
1737                self.display_npts(nop)
1738
1739        ctl.Refresh()
1740        return flag
1741
1742    def _set_volume_ctr_val(self, npts):
1743        """
1744        Set total volume
1745        """
1746        total_volume = npts * self.sld_data.vol_pix[0]
1747        self.parent.set_volume_ctr_val(total_volume)
1748
1749    def _onstepsize(self, event):
1750        """
1751        On stepsize event
1752        """
1753        flag = True
1754        if event is not None:
1755            event.Skip()
1756            ctl = event.GetEventObject()
1757            ctl.SetBackgroundColour("white")
1758
1759        if flag and not self.sld_data.is_data:#ctl.IsEnabled():
1760            s_size = 1.0
1761            try:
1762                for item in self.stepsize:
1763                    s_val = float(item[1].GetValue())
1764                    if s_val <= 0:
1765                        item[1].SetBackgroundColour("pink")
1766                        ctl.Refresh()
1767                        return
1768                    if np.isfinite(s_val):
1769                        s_size *= s_val
1770                self.sld_data.set_pixel_volumes(s_size)
1771                if ctl.IsEnabled():
1772                    total_volume = sum(self.sld_data.vol_pix)
1773                    self.parent.set_volume_ctr_val(total_volume)
1774            except:
1775                pass
1776        ctl.Refresh()
1777
1778
1779    def set_npts_from_slddata(self):
1780        """
1781        Set total n. of points form the sld data
1782        """
1783        try:
1784            sld_data = self.parent.get_sld_from_omf()
1785            #nop = (nop * np.pi) / 6
1786            nop = len(sld_data.sld_n)
1787        except:
1788            nop = None
1789        return nop
1790
1791    def display_npts(self, nop):
1792        """
1793        Displays Npts ctrl
1794        """
1795        try:
1796            self.npix_ctl.SetValue(str(nop))
1797            self.npix_ctl.Refresh()
1798            self.parent.set_etime()
1799            wx.CallAfter(self._set_volume_ctr_val, nop)
1800        except:
1801            # On Init
1802            pass
1803
1804    def check_inputs(self):
1805        """
1806        check if the inputs are valid
1807        """
1808        flag = self._check_input_helper(self.slds)
1809        if flag:
1810            flag = self._check_input_helper(self.nodes)
1811        if flag:
1812            flag = self._check_input_helper(self.stepsize)
1813        return flag
1814
1815    def _check_input_helper(self, list):
1816        """
1817        Check list values
1818        """
1819        flag = True
1820        for item in list:
1821            item[1].SetBackgroundColour("white")
1822            item[1].Refresh()
1823            try:
1824                float(item[1].GetValue())
1825            except:
1826                flag = _set_error(self, item[1])
1827                break
1828        return flag
1829
1830class SasGenWindow(widget.CHILD_FRAME):
1831    """
1832    GEN SAS main window
1833    """
1834    def __init__(self, parent=None, manager=None, title="Generic Scattering Calculator",
1835                size=(PANEL_WIDTH * 1.4, PANEL_HEIGHT * 1.65), *args, **kwds):
1836        """
1837        Init
1838        """
1839        kwds['size'] = size
1840        kwds['title'] = title
1841        widget.CHILD_FRAME.__init__(self, parent, *args, **kwds)
1842        self.parent = parent
1843        self.base = manager
1844        self.omfpanel = OmfPanel(parent=self)
1845        self.panel = SasGenPanel(parent=self)
1846        self.data = None
1847        self.omfdata = sas_gen.OMFData()
1848        self.sld_data = None
1849        self._default_save_location = os.getcwd()
1850
1851        self._mgr = aui.AuiManager(self)
1852        self._mgr.SetDockSizeConstraint(0.5, 0.5)
1853        self._plot_title = ''
1854        self.scale2d = 'log_{10}'
1855        self.Bind(wx.EVT_CLOSE, self.on_close)
1856
1857
1858        self.build_panels()
1859        self.SetPosition((wx.LEFT, PANEL_TOP))
1860        self.Show(True)
1861
1862    def build_panels(self):
1863        """
1864        """
1865
1866        self.set_sld_data(self.sld_data)
1867        self._mgr.AddPane(self.panel, aui.AuiPaneInfo().
1868                              Name(self.panel.window_name).
1869                              CenterPane().
1870                              # This is where we set the size of
1871                              # the application window
1872                              BestSize(wx.Size(PANEL_WIDTH,
1873                                               PANEL_HEIGHT)).
1874                              Show())
1875        self._mgr.AddPane(self.omfpanel, aui.AuiPaneInfo().
1876                              Name(self.omfpanel.window_name).
1877                              Caption(self.omfpanel.window_caption).
1878                              CloseButton(False).
1879                              Right().
1880                              Floatable(False).
1881                              BestSize(wx.Size(PANEL_WIDTH / 2.5, PANEL_HEIGHT)).
1882                              Show())
1883        self._mgr.Update()
1884
1885    def get_sld_data(self):
1886        """
1887        Return slddata
1888        """
1889        return self.sld_data
1890
1891    def get_sld_from_omf(self):
1892        """
1893        """
1894        self.sld_data = self.omfpanel.get_sld_val()
1895        return self.sld_data
1896
1897    def set_sld_n(self, sld):
1898        """
1899        """
1900        self.panel.sld_data = sld
1901        self.panel.model.set_sld_data(sld)
1902
1903    def set_sld_data(self, data):
1904        """
1905        Set omfdata
1906        """
1907        if data is None:
1908            return
1909        self.sld_data = data
1910        enable = (data is not None)
1911        self._set_omfpanel_sld_data(self.sld_data)
1912        self.omfpanel.bt_save.Enable(enable)
1913        self.set_etime()
1914
1915    def set_omfpanel_npts(self):
1916        """
1917        Set Npts in omf panel
1918        """
1919        nop = self.omfpanel.set_npts_from_slddata()
1920        self.omfpanel.display_npts(nop)
1921
1922    def _set_omfpanel_sld_data(self, data):
1923        """
1924        Set sld_data in omf panel
1925        """
1926        self.omfpanel.set_slddata(data)
1927        self.omfpanel.set_sld_ctr(data)
1928
1929    def check_omfpanel_inputs(self):
1930        """
1931        Check OMF panel inputs
1932        """
1933        return self.omfpanel.check_inputs()
1934
1935    def set_main_panel_sld_data(self, sld_data):
1936        """
1937        """
1938        self.sld_data = sld_data
1939
1940    def set_file_location(self, path):
1941        """
1942        File location
1943        """
1944        self._default_save_location = path
1945
1946    def get_path(self):
1947        """
1948        File location
1949        """
1950        return self._default_save_location
1951
1952    def draw_graph(self, plot, title=''):
1953        """
1954        """
1955        try:
1956            wx.PostEvent(self.parent, NewPlotEvent(plot=plot, title=title))
1957        except:
1958            # standalone
1959            frame = PlotFrame(self, -1, 'testView', self.scale2d)
1960            #add_icon(self.parent, frame)
1961            frame.add_plot(plot)
1962            frame.SetTitle(title)
1963            frame.Show(True)
1964            frame.SetFocus()
1965
1966    def set_schedule_full_draw(self, panel=None, func='del'):
1967        """
1968        Send full draw to gui frame
1969        """
1970        if self.parent is not None:
1971            self.parent.set_schedule_full_draw(panel, func)
1972
1973    def get_npix(self):
1974        """
1975        Get no. of pixels from omf panel
1976        """
1977        n_pix = self.omfpanel.npix_ctl.GetValue()
1978        return n_pix
1979
1980    def get_pix_volumes(self):
1981        """
1982        Get a pixel volume
1983        """
1984        vol = self.omfpanel.get_pix_volumes()
1985        return vol
1986
1987    def set_volume_ctr_val(self, val):
1988        """
1989        Set volume txtctl value
1990        """
1991        try:
1992            self.panel.set_volume_ctl_val(str(val))
1993        except:
1994            print("self.panel is not initialized yet")
1995
1996    def set_omfpanel_default_shap(self, shape):
1997        """
1998        Set default_shape in omfpanel
1999        """
2000        self.omfpanel.default_shape = shape
2001
2002    def set_etime(self):
2003        """
2004        Sets est. computation time on panel
2005        """
2006        self.panel.set_est_time()
2007
2008    def get_sld_data_from_omf(self):
2009        """
2010        """
2011        data = self.omfpanel.get_sld_val()
2012        return data
2013
2014    def set_scale2d(self, scale):
2015        """
2016        """
2017        self.scale2d = scale
2018
2019    def on_panel_close(self, event):
2020        """
2021        """
2022        #Not implemented
2023
2024    def on_open_file(self, event):
2025        """
2026        On Open
2027        """
2028        self.panel.on_load_data(event)
2029
2030    def sld_draw(self):
2031        """
2032        sld draw
2033        """
2034        self.panel.sld_draw(event=None, has_arrow=False)
2035
2036    def on_save_file(self, event):
2037        """
2038        On Close
2039        """
2040        self.omfpanel.on_save(event)
2041
2042    def on_close(self, event):
2043        """
2044        Close
2045        """
2046        if self.base is not None:
2047            self.base.gen_frame = None
2048        self.Destroy()
2049
2050if __name__ == "__main__":
2051    app = wx.PySimpleApp()
2052    widget.CHILD_FRAME = wx.Frame
2053    SGframe = SasGenWindow()
2054    SGframe.Show(True)
2055    app.MainLoop()
Note: See TracBrowser for help on using the repository browser.