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

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 1b28ff5 was dbc01f2, checked in by Jae Cho <jhjcho@…>, 12 years ago

fixed and added some features in pdb reader

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