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

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

mac: shape combobox problem fixed

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