source: sasview/calculatorview/src/sans/perspectives/calculator/gen_scatter_panel.py @ afd45674

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 afd45674 was afd45674, checked in by Jae Cho <jhjcho@…>, 11 years ago

Added total volume param in the sasgen model

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