source: sasview/invariantview/perspectives/invariant/invariant_panel.py @ 59d8b56

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 59d8b56 was 1c271f2, checked in by Gervaise Alina <gervyh@…>, 15 years ago

print message on status bar

  • Property mode set to 100644
File size: 45.9 KB
Line 
1"""
2    This module provide GUI for the neutron scattering length density calculator
3    @author: Gervaise B. Alina
4"""
5
6import wx
7
8import sys
9from wx.lib.scrolledpanel import ScrolledPanel
10from sans.invariant import invariant
11from sans.guiframe.utils import format_number, check_float
12from sans.guicomm.events import NewPlotEvent, StatusEvent
13from invariant_details import InvariantDetailsPanel, InvariantContainer
14from invariant_widgets import OutputTextCtrl, InvTextCtrl
15
16# The minimum q-value to be used when extrapolating
17Q_MINIMUM  = 1e-5
18# The maximum q-value to be used when extrapolating
19Q_MAXIMUM  = 10
20# the maximum value to plot the theory data
21Q_MAXIMUM_PLOT = 2
22# the number of points to consider during fit
23NPTS = 10
24#Default value for background
25BACKGROUND = 0.0
26#default value for the scale
27SCALE = 1.0
28#default value of the contrast
29CONTRAST = 1.0
30#default value of the power used for power law
31POWER = 4.0
32#Invariant panel size
33_BOX_WIDTH = 76
34
35if sys.platform.count("win32")>0:
36    _STATICBOX_WIDTH = 450
37    PANEL_WIDTH = 500 
38    PANEL_HEIGHT = 700
39    FONT_VARIANT = 0
40else:
41    _STATICBOX_WIDTH = 480
42    PANEL_WIDTH = 530
43    PANEL_HEIGHT = 700
44    FONT_VARIANT = 1
45
46
47class InvariantPanel(ScrolledPanel):
48    """
49        Provides the Invariant GUI.
50    """
51    ## Internal nickname for the window, used by the AUI manager
52    window_name = "Invariant"
53    ## Name to appear on the window title bar
54    window_caption = "Invariant"
55    ## Flag to tell the AUI manager to put this panel in the center pane
56    CENTER_PANE = True
57    def __init__(self, parent, data=None, manager=None,*args, **kwds):
58        kwds["size"]= (PANEL_WIDTH, PANEL_HEIGHT)
59        kwds["style"]= wx.FULL_REPAINT_ON_RESIZE
60        ScrolledPanel.__init__(self, parent=parent, *args, **kwds)
61        #Font size
62        self.SetWindowVariant(variant=FONT_VARIANT)
63        #Object that receive status event
64        self.parent = parent
65        #plug-in using this panel
66        self._manager = manager
67        #Data uses for computation
68        self._data = data
69        self._scale = SCALE
70        self._background = BACKGROUND
71        #container of invariant value
72        self.inv_container = None
73        #Draw the panel
74        self._do_layout()
75        self.reset_panel()
76        if self.parent is not None:
77            msg = ""
78            wx.PostEvent(self.parent,StatusEvent(status=msg, info="info"))
79        self.SetupScrolling()
80       
81    def err_check_on_data(self):
82        """
83            Check if data is valid for further computation
84        """
85        flag = False
86        self.hint_msg_txt.SetLabel('')
87        #edit the panel
88        if self._data is not None:
89            if len(self._data.x[self._data.x==0]) > 0:
90                flag = True
91                msg = "Invariant: one of your q-values is zero. Delete that entry before proceeding"
92                self.hint_msg_txt.SetLabel(msg)
93                wx.PostEvent(self.parent, StatusEvent(status=msg,
94                                                      info="warning",
95                                                      type="stop")) 
96        return flag
97   
98    def set_data(self, data):
99        """
100            Set the data
101        """
102        self._data = data
103        #edit the panel
104        if self._data is not None:
105            self.err_check_on_data()
106            data_name = self._data.name
107            data_qmin = min (self._data.x)
108            data_qmax = max (self._data.x)
109            self.data_name_tcl.SetValue(str(data_name))
110            self.data_min_tcl.SetLabel(str(data_qmin))
111            self.data_max_tcl.SetLabel(str(data_qmax))
112            self.reset_panel()
113            self.compute_invariant(event=None)
114             
115    def set_message(self):
116        """
117            Display warning message if available
118        """
119        if self.inv_container is not None:
120            if self.inv_container.existing_warning:
121                msg = "Warning! Computations on invariant require your "
122                msg += "attention.\n Please click on Details button."
123                self.hint_msg_txt.SetForegroundColour("red")
124   
125                wx.PostEvent(self.parent,StatusEvent(status=msg,info="warning"))
126            else:
127                msg = "For more information, click on Details button."
128                self.hint_msg_txt.SetForegroundColour("black")
129                wx.PostEvent(self.parent,StatusEvent(status=msg,info="info"))
130            self.hint_msg_txt.SetLabel(msg)
131        self.data_name_boxsizer.Layout()
132       
133    def set_manager(self, manager):
134        """
135            set value for the manager
136        """
137        self._manager = manager
138   
139    def get_background(self):
140        """
141            @return the background textcrtl value as a float
142        """
143        background = self.background_tcl.GetValue().lstrip().rstrip()
144        if background == "":
145            raise ValueError, "Need a background"
146        if check_float(self.background_tcl):
147            return float(background)
148        else:
149            raise ValueError, "Receive invalid value for background : %s"%(background)
150   
151    def get_scale(self):
152        """
153            @return the scale textcrtl value as a float
154        """
155        scale = self.scale_tcl.GetValue().lstrip().rstrip()
156        if scale == "":
157            raise ValueError, "Need a background"
158        if check_float(self.scale_tcl):
159            if float(scale)<= 0.0:
160                self.scale_tcl.SetBackgroundColour("pink")
161                self.scale_tcl.Refresh()
162                raise ValueError, "Receive invalid value for scale: %s"%(scale)
163            return float(scale)
164        else:
165            raise ValueError, "Receive invalid value for scale : %s"%(scale)
166       
167    def get_contrast(self):
168        """
169            @return the contrast textcrtl value as a float
170        """
171        par_str = self.contrast_tcl.GetValue().strip()
172        contrast = None
173        if par_str !="" and check_float(self.contrast_tcl):
174            contrast = float(par_str)
175        return contrast
176   
177    def get_extrapolation_type(self, low_q, high_q):
178        """
179        """
180        extrapolation = None
181        if low_q  and not high_q:
182            extrapolation = "low"
183        elif not low_q  and high_q:
184            extrapolation = "high"
185        elif low_q and high_q:
186            extrapolation = "both"
187        return extrapolation
188           
189    def get_porod_const(self):
190        """
191            @return the porod constant textcrtl value as a float
192        """
193        par_str = self.porod_constant_tcl.GetValue().strip()
194        porod_const = None
195        if par_str !="" and check_float(self.porod_constant_tcl):
196            porod_const = float(par_str)
197        return porod_const
198   
199    def get_volume(self, inv, contrast, extrapolation):
200        """
201        """
202        if contrast is not None:
203            try:
204                v, dv = inv.get_volume_fraction_with_error(contrast=contrast, 
205                                                           extrapolation=extrapolation)
206                self.volume_tcl.SetValue(format_number(v))
207                self.volume_err_tcl.SetValue(format_number(dv))
208            except:
209                msg= "Error occurred computing volume fraction: %s"%sys.exc_value
210                wx.PostEvent(self.parent, StatusEvent(status=msg,
211                                                      info="error",
212                                                      type="stop"))
213               
214    def get_surface(self, inv, contrast, porod_const, extrapolation):
215        """
216        """
217        if contrast is not None and porod_const is not None:
218            try:
219                s, ds = inv.get_surface_with_error(contrast=contrast,
220                                        porod_const=porod_const,
221                                        extrapolation=extrapolation)
222                self.surface_tcl.SetValue(format_number(s))
223                self.surface_err_tcl.SetValue(format_number(ds))
224            except:
225                msg = "Error occurred computing specific surface: %s"%sys.exc_value
226                wx.PostEvent(self.parent, StatusEvent(status=msg, info="error",
227                                                       type="stop"))
228               
229    def get_total_qstar(self, inv, extrapolation):
230        """
231        """
232        try:
233            qstar_total, qstar_total_err = inv.get_qstar_with_error(extrapolation)
234            self.invariant_total_tcl.SetValue(format_number(qstar_total))
235            self.invariant_total_err_tcl.SetValue(format_number(qstar_total_err))
236            self.inv_container.qstar_total = qstar_total
237            self.inv_container.qstar_total_err = qstar_total_err
238         
239        except:
240            msg= "Error occurred computing invariant using extrapolation: %s"%sys.exc_value
241            wx.PostEvent(self.parent, StatusEvent(status= msg, type="stop")) 
242           
243    def get_low_qstar(self, inv, npts_low, low_q=False):
244        """
245        """
246        if low_q:
247            try: 
248                qstar_low, qstar_low_err = inv.get_qstar_low()
249                self.inv_container.qstar_low = qstar_low
250                self.inv_container.qstar_low_err = qstar_low_err
251                extrapolated_data = inv.get_extra_data_low(npts_in=npts_low) 
252                power_low = inv.get_extrapolation_power(range='low') 
253                if self.power_law_low.GetValue():
254                    self.power_low_tcl.SetValue(format_number(power_low))
255                self._manager.plot_theory(data=extrapolated_data,
256                                           name="Low-Q extrapolation")
257            except:
258                msg= "Error occurred computing low-Q invariant: %s"%sys.exc_value
259                wx.PostEvent(self.parent, StatusEvent(status= msg, type="stop"))
260        else:
261            self._manager.plot_theory(name="Low-Q extrapolation")
262           
263    def get_high_qstar(self, inv, high_q=False):
264        """
265        """
266        if high_q:
267            try: 
268                qstar_high, qstar_high_err = inv.get_qstar_high()
269                self.inv_container.qstar_high = qstar_high
270                self.inv_container.qstar_high_err = qstar_high_err
271                power_high = inv.get_extrapolation_power(range='high') 
272                self.power_high_tcl.SetValue(format_number(power_high))
273                high_out_data = inv.get_extra_data_high(q_end=Q_MAXIMUM_PLOT)
274                self._manager.plot_theory(data=high_out_data,
275                                           name="High-Q extrapolation")
276            except:
277                msg= "Error occurred computing high-Q invariant: %s"%sys.exc_value
278                wx.PostEvent(self.parent, StatusEvent(status= msg, type="stop"))
279        else:
280            self._manager.plot_theory(name="High-Q extrapolation")
281           
282    def get_qstar(self, inv):
283        """
284        """
285        qstar, qstar_err = inv.get_qstar_with_error()
286        self.inv_container.qstar = qstar
287        self.inv_container.qstar_err = qstar_err
288             
289    def set_extrapolation_low(self, inv, low_q=False):
290        """
291            @return float value necessary to compute invariant a low q
292        """
293        #get funtion
294        if self.guinier.GetValue():
295            function_low = "guinier"
296        # get the function
297        power_low = None #2.0/3.0
298        if self.power_law_low.GetValue():
299            function_low = "power_law"
300            if self.fit_enable_low.GetValue():
301                #set value of power_low to none to allow fitting
302                power_low = None
303            else:
304                power_low = self.power_low_tcl.GetValue().lstrip().rstrip()
305                if check_float(self.power_low_tcl):
306                    power_low = float(power_low)
307                else:
308                    if low_q :
309                        #Raise error only when qstar at low q is requested
310                        msg = "Expect float for power at low q , got %s"%(power_low)
311                        raise ValueError, msg
312       
313        #Get the number of points to extrapolated
314        npts_low = self.npts_low_tcl.GetValue().lstrip().rstrip()   
315        if check_float(self.npts_low_tcl):
316            npts_low = float(npts_low)
317        else:
318            if low_q:
319                msg = "Expect float for number of points at low q , got %s"%(npts_low)
320                raise ValueError, msg
321        #Set the invariant calculator
322        inv.set_extrapolation(range="low", npts=npts_low,
323                                   function=function_low, power=power_low)   
324        return inv, npts_low 
325       
326    def set_extrapolation_high(self, inv, high_q=False):
327        """
328            @return float value necessary to compute invariant a high q
329        """
330        power_high = None
331        #if self.power_law_high.GetValue():
332        function_high = "power_law"
333        if self.fit_enable_high.GetValue():
334            #set value of power_high to none to allow fitting
335            power_high = None
336        else:
337            power_high = self.power_high_tcl.GetValue().lstrip().rstrip()
338            if check_float(self.power_high_tcl):
339                power_high = float(power_high)
340            else:
341                if high_q :
342                    #Raise error only when qstar at high q is requested
343                    msg = "Expect float for power at high q , got %s"%(power_high)
344                    raise ValueError, msg
345                         
346        npts_high = self.npts_high_tcl.GetValue().lstrip().rstrip()   
347        if check_float(self.npts_high_tcl):
348            npts_high = float(npts_high)
349        else:
350            if high_q:
351                msg = "Expect float for number of points at high q , got %s"%(npts_high)
352                raise ValueError, msg
353        inv.set_extrapolation(range="high", npts=npts_high,
354                                   function=function_high, power=power_high)
355        return inv, npts_high
356   
357    def display_details(self, event):
358        """
359            open another panel for more details on invariant calculation
360        """
361        panel = InvariantDetailsPanel(parent=self, 
362                                           qstar_container=self.inv_container)
363        panel.ShowModal()
364        panel.Destroy()
365        self.button_calculate.SetFocus()
366       
367    def compute_invariant(self, event=None):
368        """
369            compute invariant
370        """
371        msg= ""
372        wx.PostEvent(self.parent, StatusEvent(status=msg))
373        if self._data is None or self.err_check_on_data():
374            return
375   
376        #clear outputs textctrl
377        self._reset_output()
378        try:
379            background = self.get_background()
380            scale = self.get_scale()
381        except:
382            msg= "Invariant Error: %s"%(sys.exc_value)
383            wx.PostEvent(self.parent, StatusEvent(status= msg, type="stop"))
384            return
385       
386        low_q = self.enable_low_cbox.GetValue()
387        high_q = self.enable_high_cbox.GetValue() 
388        #set invariant calculator
389        inv = invariant.InvariantCalculator(data=self._data,
390                                            background=background,
391                                            scale=scale)
392        try:
393            inv, npts_low = self.set_extrapolation_low(inv=inv, low_q=low_q)
394            inv, npts_high = self.set_extrapolation_high(inv=inv, high_q=high_q)
395        except:
396            msg = "Error occurred computing invariant: %s"%sys.exc_value
397            wx.PostEvent(self.parent, StatusEvent(status=msg,
398                                                 info="warning",type="stop"))
399            return
400        #check the type of extrapolation
401        extrapolation = self.get_extrapolation_type(low_q=low_q, high_q=high_q)
402       
403        #Compute invariant
404        bkg_changed = False
405        scale_changed = False
406        try:
407            self.get_qstar(inv=inv)
408            #if scale_changed or bkg_changed:
409            self._manager.plot_data(data=inv.get_data())
410           
411        except:
412            msg= "Error occurred computing invariant: %s"%sys.exc_value
413            wx.PostEvent(self.parent, StatusEvent(status=msg, 
414                                                  info="warning",type="stop"))
415            return
416        #Compute qstar extrapolated to low q range
417        self.get_low_qstar(inv=inv, npts_low=npts_low, low_q=low_q)
418        #Compute qstar extrapolated to high q range
419        self.get_high_qstar(inv=inv, high_q=high_q)
420        #Compute qstar extrapolated to total q range and set value to txtcrtl
421        self.get_total_qstar(inv=inv, extrapolation=extrapolation)
422        # Parse additional parameters
423        porod_const = self.get_porod_const()       
424        contrast = self.get_contrast()
425        try:
426            #Compute volume and set value to txtcrtl
427            self.get_volume(inv=inv, contrast=contrast, extrapolation=extrapolation)
428            #compute surface and set value to txtcrtl
429        except:
430            msg = "Error occurred computing invariant: %s"%sys.exc_value
431            wx.PostEvent(self.parent, StatusEvent(status=msg,
432                                                  info="warning",type="stop"))
433        try:
434            self.get_surface(inv=inv, contrast=contrast, porod_const=porod_const, 
435                                    extrapolation=extrapolation)
436        except:
437            msg = "Error occurred computing invariant: %s"%sys.exc_value
438            wx.PostEvent(self.parent, StatusEvent(status=msg,
439                                                  info="warning",type="stop"))
440           
441        #compute percentage of each invariant
442        self.inv_container.compute_percentage()
443        #display a message
444        self.set_message()
445        #enable the button_ok for more details
446        self.button_details.Enable()
447        self.button_details.SetFocus()
448       
449    def reset_panel(self):
450        """
451            set the panel at its initial state.
452        """
453        self.background_tcl.SetValue(str(BACKGROUND))
454        self.scale_tcl.SetValue(str(SCALE)) 
455        self.contrast_tcl.SetValue(str(CONTRAST))
456        self.porod_constant_tcl.SetValue('') 
457        self.npts_low_tcl.SetValue(str(NPTS))
458        self.enable_low_cbox.SetValue(False)
459        self.fix_enable_low.SetValue(True)
460        self.power_low_tcl.SetValue(str(POWER))
461        self.guinier.SetValue(True)
462        self.power_low_tcl.Disable()
463        self.enable_high_cbox.SetValue(False)
464        self.fix_enable_high.SetValue(True)
465        self.power_high_tcl.SetValue(str(POWER))
466        self.npts_high_tcl.SetValue(str(NPTS))
467        self.button_details.Disable()
468        #Change the state of txtcrtl to enable/disable
469        self._enable_low_q_section()
470        #Change the state of txtcrtl to enable/disable
471        self._enable_high_q_section()
472        self._reset_output()
473        self.button_calculate.SetFocus()
474       
475    def _reset_output(self):
476        """
477            clear outputs textcrtl
478        """
479        self.invariant_total_tcl.Clear()
480        self.invariant_total_err_tcl.Clear()
481        self.volume_tcl.Clear()
482        self.volume_err_tcl.Clear()
483        self.surface_tcl.Clear()
484        self.surface_err_tcl.Clear()
485        #prepare a new container to put result of invariant
486        self.inv_container = InvariantContainer()
487       
488    def _define_structure(self):
489        """
490            Define main sizers needed for this panel
491        """
492        ## Box sizers must be defined first before defining buttons/textctrls (MAC).
493        self.main_sizer = wx.BoxSizer(wx.VERTICAL)
494        #Sizer related to outputs
495        outputs_box = wx.StaticBox(self, -1, "Outputs")
496        self.outputs_sizer = wx.StaticBoxSizer(outputs_box, wx.VERTICAL)
497        self.outputs_sizer.SetMinSize((PANEL_WIDTH,-1))
498        #Sizer related to data
499        data_name_box = wx.StaticBox(self, -1, "I(q) Data Source")
500        self.data_name_boxsizer = wx.StaticBoxSizer(data_name_box, wx.VERTICAL)
501        self.data_name_boxsizer.SetMinSize((PANEL_WIDTH,-1))
502        self.hint_msg_sizer = wx.BoxSizer(wx.HORIZONTAL)
503        self.data_name_sizer = wx.BoxSizer(wx.HORIZONTAL)
504        self.data_range_sizer = wx.BoxSizer(wx.HORIZONTAL)
505        #Sizer related to background and scale
506        self.bkg_scale_sizer = wx.BoxSizer(wx.HORIZONTAL) 
507        #Sizer related to contrast and porod constant
508        self.contrast_porod_sizer = wx.BoxSizer(wx.HORIZONTAL) 
509        #Sizer related to inputs
510        inputs_box = wx.StaticBox(self, -1, "Customized Inputs")
511        self.inputs_sizer = wx.StaticBoxSizer(inputs_box, wx.VERTICAL)
512        #Sizer related to extrapolation
513        extrapolation_box = wx.StaticBox(self, -1, "Extrapolation")
514        self.extrapolation_sizer = wx.StaticBoxSizer(extrapolation_box,
515                                                        wx.VERTICAL)
516        self.extrapolation_sizer.SetMinSize((PANEL_WIDTH,-1))
517        self.extrapolation_range_sizer = wx.BoxSizer(wx.HORIZONTAL)
518        self.extrapolation_low_high_sizer = wx.BoxSizer(wx.HORIZONTAL)
519        #Sizer related to extrapolation at low q range
520        low_q_box = wx.StaticBox(self, -1, "Low Q")
521        self.low_extrapolation_sizer = wx.StaticBoxSizer(low_q_box, wx.VERTICAL)
522        self.low_q_sizer = wx.GridBagSizer(5,5)
523        #Sizer related to extrapolation at low q range
524        high_q_box = wx.StaticBox(self, -1, "High Q")
525        self.high_extrapolation_sizer = wx.StaticBoxSizer(high_q_box, wx.VERTICAL)
526        self.high_q_sizer = wx.GridBagSizer(5,5)
527        #sizer to define outputs
528        self.volume_surface_sizer = wx.GridBagSizer(5,5)
529        #Sizer related to invariant output
530        self.invariant_sizer = wx.GridBagSizer(5, 5)
531        #Sizer related to button
532        self.button_sizer = wx.BoxSizer(wx.HORIZONTAL)
533       
534    def _layout_data_name(self):
535        """
536            Draw widgets related to data's name
537        """
538        #Sizer hint
539        hint_msg = "First open data file from 'File' menu.  Then Highlight and right click on the data plot. \n"
540        hint_msg += "Finally, select 'Compute Invariant'. \n"
541        self.hint_msg_txt = wx.StaticText(self, -1, hint_msg) 
542        self.hint_msg_txt.SetForegroundColour("red")
543        msg = "Highlight = mouse the mouse's cursor on the data until the plot's color changes to yellow"
544        self.hint_msg_txt.SetToolTipString(msg)
545        self.hint_msg_sizer.Add(self.hint_msg_txt)
546        #Data name [string]
547        data_name_txt = wx.StaticText(self, -1, 'Data : ') 
548       
549        self.data_name_tcl = OutputTextCtrl(self, -1, size=(_BOX_WIDTH*5, 20), style=0) 
550        self.data_name_tcl.SetToolTipString("Data's name.")
551        self.data_name_sizer.AddMany([(data_name_txt, 0, wx.LEFT|wx.RIGHT, 10),
552                                       (self.data_name_tcl, 0, wx.EXPAND)])
553        #Data range [string]
554        data_range_txt = wx.StaticText(self, -1, 'Total Q Range (1/A): ') 
555        data_min_txt = wx.StaticText(self, -1, 'Min : ') 
556        self.data_min_tcl = OutputTextCtrl(self, -1, size=(_BOX_WIDTH, 20), style=0)
557        self.data_min_tcl.SetToolTipString("The minimum value of q range.")
558        data_max_txt = wx.StaticText(self, -1, 'Max : ') 
559        self.data_max_tcl = OutputTextCtrl(self, -1, size=(_BOX_WIDTH, 20), style=0) 
560        self.data_max_tcl.SetToolTipString("The maximum value of q range.")
561        self.data_range_sizer.AddMany([(data_range_txt, 0, wx.RIGHT, 10),
562                                       (data_min_txt, 0, wx.RIGHT, 10),
563                                       (self.data_min_tcl, 0, wx.RIGHT, 10),
564                                       (data_max_txt, 0, wx.RIGHT, 10),
565                                       (self.data_max_tcl, 0, wx.RIGHT, 10)])
566        self.data_name_boxsizer.AddMany([(self.hint_msg_sizer, 0 , wx.ALL, 10),
567                                         (self.data_name_sizer, 0 , wx.RIGHT, 10),
568                                         (self.data_range_sizer, 0 , wx.ALL, 10)])
569   
570    def _layout_bkg_scale(self):
571        """
572            Draw widgets related to background and scale
573        """
574        background_txt = wx.StaticText(self, -1, 'Background : ') 
575        self.background_tcl = InvTextCtrl(self, -1, size=(_BOX_WIDTH, 20), style=0) 
576        background_hint_txt = "background"
577        self.background_tcl.SetToolTipString(background_hint_txt)
578        background_unit_txt = wx.StaticText(self, -1, '[1/cm]') 
579        scale_txt = wx.StaticText(self, -1, 'Scale : ') 
580        self.scale_tcl = InvTextCtrl(self, -1, size=(_BOX_WIDTH, 20), style=0)
581        scale_hint_txt = "Scale"
582        self.scale_tcl.SetToolTipString(scale_hint_txt)
583        self.bkg_scale_sizer.AddMany([(background_txt, 0, wx.LEFT, 10),
584                                       (self.background_tcl, 0, wx.LEFT, 5),
585                                       (background_unit_txt, 0, wx.LEFT, 10),
586                                       (scale_txt, 0, wx.LEFT, 70),
587                                       (self.scale_tcl, 0, wx.LEFT, 40)])
588 
589    def _layout_contrast_porod(self):
590        """
591            Draw widgets related to porod constant and contrast
592        """
593        contrast_txt = wx.StaticText(self, -1, 'Contrast : ') 
594        self.contrast_tcl = InvTextCtrl(self, -1, size=(_BOX_WIDTH, 20), style=0)
595        contrast_hint_txt = "Contrast"
596        self.contrast_tcl.SetToolTipString(contrast_hint_txt)
597        contrast_unit_txt = wx.StaticText(self, -1, '[1/A^(2)]') 
598        porod_const_txt = wx.StaticText(self, -1, 'Porod Constant:') 
599        self.porod_constant_tcl = InvTextCtrl(self, -1, 
600                                              size=(_BOX_WIDTH, 20), style=0) 
601        porod_const_hint_txt = "Porod Constant"
602        self.porod_constant_tcl.SetToolTipString(porod_const_hint_txt)
603        optional_txt = wx.StaticText(self, -1, '(Optional)') 
604        self.contrast_porod_sizer.AddMany([(contrast_txt, 0, wx.LEFT, 10),
605                                           (self.contrast_tcl, 0, wx.LEFT, 20),
606                                           (contrast_unit_txt, 0, wx.LEFT, 10),
607                                           (porod_const_txt, 0, wx.LEFT, 50),
608                                       (self.porod_constant_tcl, 0, wx.LEFT, 0),
609                                       (optional_txt, 0, wx.LEFT, 10)])
610       
611    def _enable_fit_power_law_low(self, event=None):
612        """
613            Enable and disable the power value editing
614        """
615        if self.fix_enable_low.IsEnabled():
616            if self.fix_enable_low.GetValue():
617                self.power_low_tcl.Enable()
618            else:
619                self.power_low_tcl.Disable()
620           
621    def _enable_low_q_section(self, event=None):
622        """
623            Disable or enable some button if the user enable low q extrapolation
624        """
625        if self.enable_low_cbox.GetValue():
626            self.npts_low_tcl.Enable()
627            self.fix_enable_low.Enable()
628            self.fit_enable_low.Enable()
629            self.guinier.Enable()
630            self.power_law_low.Enable()
631
632        else:
633            self.npts_low_tcl.Disable()
634            self.fix_enable_low.Disable()
635            self.fit_enable_low.Disable()
636            self.guinier.Disable()
637            self.power_law_low.Disable()
638        self._enable_power_law_low()
639        self._enable_fit_power_law_low()
640        self.button_calculate.SetFocus()
641   
642    def _enable_power_law_low(self, event=None):
643        """
644            Enable editing power law section at low q range
645        """
646        if self.guinier.GetValue():
647            self.fix_enable_low.Disable()
648            self.fit_enable_low.Disable()
649            self.power_low_tcl.Disable()
650        else:
651            self.fix_enable_low.Enable()
652            self.fit_enable_low.Enable()
653            self.power_low_tcl.Enable()
654        self._enable_fit_power_law_low()
655           
656    def _layout_extrapolation_low(self):
657        """
658            Draw widgets related to extrapolation at low q range
659        """
660        self.enable_low_cbox = wx.CheckBox(self, -1, "Enable Extrapolate Low Q")
661        wx.EVT_CHECKBOX(self, self.enable_low_cbox.GetId(),
662                                         self._enable_low_q_section)
663        self.fix_enable_low = wx.RadioButton(self, -1, 'Fix',
664                                         (10, 10),style=wx.RB_GROUP)
665        self.fit_enable_low = wx.RadioButton(self, -1, 'Fit', (10, 10))
666        self.Bind(wx.EVT_RADIOBUTTON, self._enable_fit_power_law_low,
667                                     id=self.fix_enable_low.GetId())
668        self.Bind(wx.EVT_RADIOBUTTON, self._enable_fit_power_law_low, 
669                                        id=self.fit_enable_low.GetId())
670        self.guinier = wx.RadioButton(self, -1, 'Guinier',
671                                         (10, 10),style=wx.RB_GROUP)
672        self.power_law_low = wx.RadioButton(self, -1, 'Power Law', (10, 10))
673        self.Bind(wx.EVT_RADIOBUTTON, self._enable_power_law_low,
674                                     id=self.guinier.GetId())
675        self.Bind(wx.EVT_RADIOBUTTON, self._enable_power_law_low, 
676                                        id=self.power_law_low.GetId())
677       
678        npts_low_txt = wx.StaticText(self, -1, 'Npts')
679        self.npts_low_tcl = InvTextCtrl(self, -1, size=(_BOX_WIDTH*2/3, -1))
680        msg_hint = "Number of Q points to consider"
681        msg_hint +="while extrapolating the low-Q region"
682        self.npts_low_tcl.SetToolTipString(msg_hint)
683        power_txt = wx.StaticText(self, -1, 'Power')
684        self.power_low_tcl = InvTextCtrl(self, -1, size=(_BOX_WIDTH*2/3, -1))
685       
686        power_hint_txt = "Exponent to apply to the Power_law function."
687        self.power_low_tcl.SetToolTipString(power_hint_txt)
688        iy = 0
689        ix = 0
690        self.low_q_sizer.Add(self.enable_low_cbox,(iy, ix),(1,5),
691                            wx.TOP|wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
692        iy += 1
693        ix = 0
694        self.low_q_sizer.Add(npts_low_txt,(iy, ix),(1,1),
695                            wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
696        ix += 1
697        self.low_q_sizer.Add(self.npts_low_tcl, (iy, ix), (1,1),
698                            wx.EXPAND|wx.ADJUST_MINSIZE, 0)
699        iy += 1
700        ix = 0
701        self.low_q_sizer.Add(self.guinier,(iy, ix),(1,2),
702                             wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
703        iy += 1
704        ix = 0
705        self.low_q_sizer.Add(self.power_law_low,(iy, ix),(1,2),
706                            wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
707       
708        # Parameter controls for power law
709        ix = 1
710        iy += 1
711        self.low_q_sizer.Add(self.fix_enable_low,(iy, ix),(1,1),
712                            wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 0)
713        ix += 1
714        self.low_q_sizer.Add(self.fit_enable_low,(iy, ix),(1,1),
715                           wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 0)
716        ix = 1
717        iy += 1
718        self.low_q_sizer.Add(power_txt,(iy, ix),(1,1),
719                            wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 0)
720        ix += 1
721        self.low_q_sizer.Add(self.power_low_tcl, (iy, ix), (1,1),
722                            wx.EXPAND|wx.ADJUST_MINSIZE, 0)
723        self.low_extrapolation_sizer.AddMany([(self.low_q_sizer, 0,
724                                                wx.BOTTOM|wx.RIGHT, 15)])
725       
726    def _enable_fit_power_law_high(self, event=None):
727        """
728            Enable and disable the power value editing
729        """
730        if self.fix_enable_high.IsEnabled():
731            if self.fix_enable_high.GetValue():
732                self.power_high_tcl.Enable()
733            else:
734                self.power_high_tcl.Disable()
735       
736    def _enable_high_q_section(self, event=None):
737        """
738            Disable or enable some button if the user enable high q extrapolation
739        """
740        if self.enable_high_cbox.GetValue():
741            self.npts_high_tcl.Enable()
742            self.power_law_high.Enable()
743            self.power_high_tcl.Enable()
744            self.fix_enable_high.Enable()
745            self.fit_enable_high.Enable()
746        else:
747            self.npts_high_tcl.Disable()
748            self.power_law_high.Disable()
749            self.power_high_tcl.Disable()
750            self.fix_enable_high.Disable()
751            self.fit_enable_high.Disable()
752        self._enable_fit_power_law_high()
753        self.button_calculate.SetFocus()
754 
755    def _layout_extrapolation_high(self):
756        """
757            Draw widgets related to extrapolation at high q range
758        """
759        self.enable_high_cbox = wx.CheckBox(self, -1, "Enable Extrapolate high-Q")
760        wx.EVT_CHECKBOX(self, self.enable_high_cbox.GetId(),
761                                         self._enable_high_q_section)
762     
763        self.fix_enable_high = wx.RadioButton(self, -1, 'Fix',
764                                         (10, 10),style=wx.RB_GROUP)
765        self.fit_enable_high = wx.RadioButton(self, -1, 'Fit', (10, 10))
766        self.Bind(wx.EVT_RADIOBUTTON, self._enable_fit_power_law_high,
767                                     id=self.fix_enable_high.GetId())
768        self.Bind(wx.EVT_RADIOBUTTON, self._enable_fit_power_law_high, 
769                                        id=self.fit_enable_high.GetId())
770       
771        self.power_law_high = wx.StaticText(self, -1, 'Power Law')
772        msg_hint ="Check to extrapolate data at high-Q"
773        self.power_law_high.SetToolTipString(msg_hint)
774        npts_high_txt = wx.StaticText(self, -1, 'Npts')
775        self.npts_high_tcl = InvTextCtrl(self, -1, size=(_BOX_WIDTH*2/3, -1))
776        msg_hint = "Number of Q points to consider"
777        msg_hint += "while extrapolating the high-Q region"
778        self.npts_high_tcl.SetToolTipString(msg_hint)
779        power_txt = wx.StaticText(self, -1, 'Power')
780        self.power_high_tcl = InvTextCtrl(self, -1, size=(_BOX_WIDTH*2/3, -1))
781        power_hint_txt = "Exponent to apply to the Power_law function."
782        self.power_high_tcl.SetToolTipString(power_hint_txt)
783        iy = 0
784        ix = 0
785        self.high_q_sizer.Add(self.enable_high_cbox,(iy, ix),(1,5),
786                            wx.TOP|wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
787        iy += 1
788        ix = 0
789        self.high_q_sizer.Add(npts_high_txt,(iy, ix),(1,1),
790                            wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
791        ix += 1
792        self.high_q_sizer.Add(self.npts_high_tcl, (iy, ix), (1,1),
793                            wx.EXPAND|wx.ADJUST_MINSIZE, 0)
794        iy += 2
795        ix = 0
796        self.high_q_sizer.Add(self.power_law_high,(iy, ix),(1,2),
797                            wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
798       
799        # Parameter controls for power law
800        ix = 1
801        iy += 1
802        self.high_q_sizer.Add(self.fix_enable_high,(iy, ix),(1,1),
803                            wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 0)
804        ix += 1
805        self.high_q_sizer.Add(self.fit_enable_high,(iy, ix),(1,1),
806                           wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 0)
807        ix = 1
808        iy += 1
809        self.high_q_sizer.Add(power_txt,(iy, ix),(1,1),
810                            wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
811        ix += 1
812        self.high_q_sizer.Add(self.power_high_tcl, (iy, ix), (1,1),
813                            wx.EXPAND|wx.ADJUST_MINSIZE, 0)
814        self.high_extrapolation_sizer.AddMany([(self.high_q_sizer, 0, 
815                                                wx.BOTTOM|wx.RIGHT, 10)])
816       
817    def _layout_extrapolation(self):
818        """
819            Draw widgets related to extrapolation
820        """
821        extra_hint = "Extrapolation Maximum Q Range [1/A]: "
822        extra_hint_txt = wx.StaticText(self, -1, extra_hint)
823        #Extrapolation range [string]
824        extrapolation_min_txt = wx.StaticText(self, -1, 'Min : ') 
825        self.extrapolation_min_tcl = OutputTextCtrl(self, -1, 
826                                                size=(_BOX_WIDTH, 20), style=0)
827        self.extrapolation_min_tcl.SetValue(str(Q_MINIMUM))
828        self.extrapolation_min_tcl.SetToolTipString("The minimum extrapolated q value.")
829        extrapolation_max_txt = wx.StaticText(self, -1, 'Max : ') 
830        self.extrapolation_max_tcl = OutputTextCtrl(self, -1,
831                                                  size=(_BOX_WIDTH, 20), style=0) 
832        self.extrapolation_max_tcl.SetValue(str(Q_MAXIMUM))
833        self.extrapolation_max_tcl.SetToolTipString("The maximum extrapolated q value.")
834        self.extrapolation_range_sizer.AddMany([(extra_hint_txt, 0, wx.LEFT, 10),
835                                                (extrapolation_min_txt, 0, wx.LEFT, 10),
836                                                (self.extrapolation_min_tcl,
837                                                            0, wx.LEFT, 10),
838                                                (extrapolation_max_txt, 0, wx.LEFT, 10),
839                                                (self.extrapolation_max_tcl,
840                                                            0, wx.LEFT, 10),
841                                                ])
842        self._layout_extrapolation_low()
843        self._layout_extrapolation_high()
844        self.extrapolation_low_high_sizer.AddMany([(self.low_extrapolation_sizer,
845                                                     0, wx.ALL, 10),
846                                                   (self.high_extrapolation_sizer,
847                                                    0, wx.ALL, 10)])
848        self.extrapolation_sizer.AddMany([(self.extrapolation_range_sizer, 0,
849                                            wx.RIGHT, 10),
850                                        (self.extrapolation_low_high_sizer, 0,
851                                           wx.ALL, 10)])
852       
853    def _layout_volume_surface_sizer(self):
854        """
855            Draw widgets related to volume and surface
856        """
857        unit_volume = ''
858        unit_surface = ''
859        uncertainty = "+/-" 
860        volume_txt = wx.StaticText(self, -1, 'Volume Fraction      ')
861        self.volume_tcl = OutputTextCtrl(self, -1, size=(_BOX_WIDTH,-1))
862        self.volume_tcl.SetToolTipString("Volume fraction.")
863        self.volume_err_tcl = OutputTextCtrl(self, -1, size=(_BOX_WIDTH,-1))
864        self.volume_err_tcl.SetToolTipString("Uncertainty on the volume fraction.")
865        volume_units_txt = wx.StaticText(self, -1, unit_volume)
866       
867        surface_txt = wx.StaticText(self, -1, 'Specific Surface')
868        self.surface_tcl = OutputTextCtrl(self, -1, size=(_BOX_WIDTH,-1))
869        self.surface_tcl.SetToolTipString("Specific surface value.")
870        self.surface_err_tcl = OutputTextCtrl(self, -1, size=(_BOX_WIDTH,-1))
871        self.surface_err_tcl.SetToolTipString("Uncertainty on the specific surface.")
872        surface_units_txt = wx.StaticText(self, -1, unit_surface)
873        iy = 0
874        ix = 0
875        self.volume_surface_sizer.Add(volume_txt, (iy, ix), (1,1),
876                             wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
877        ix += 1
878        self.volume_surface_sizer.Add(self.volume_tcl, (iy, ix), (1,1),
879                            wx.EXPAND|wx.ADJUST_MINSIZE, 10)
880        ix += 1
881        self.volume_surface_sizer.Add(wx.StaticText(self, -1, uncertainty),
882                         (iy, ix),(1,1),wx.EXPAND|wx.ADJUST_MINSIZE, 10) 
883        ix += 1
884        self.volume_surface_sizer.Add(self.volume_err_tcl, (iy, ix), (1,1),
885                            wx.EXPAND|wx.ADJUST_MINSIZE, 10) 
886        ix += 1
887        self.volume_surface_sizer.Add(volume_units_txt, (iy, ix), (1,1),
888                             wx.EXPAND|wx.ADJUST_MINSIZE, 10)
889        iy += 1
890        ix = 0
891        self.volume_surface_sizer.Add(surface_txt, (iy, ix), (1,1),
892                             wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
893        ix += 1
894        self.volume_surface_sizer.Add(self.surface_tcl, (iy, ix), (1,1),
895                            wx.EXPAND|wx.ADJUST_MINSIZE, 0)
896        ix += 1
897        self.volume_surface_sizer.Add(wx.StaticText(self, -1, uncertainty),
898                         (iy, ix),(1,1),wx.EXPAND|wx.ADJUST_MINSIZE, 0) 
899        ix += 1
900        self.volume_surface_sizer.Add(self.surface_err_tcl, (iy, ix), (1,1),
901                            wx.EXPAND|wx.ADJUST_MINSIZE, 0) 
902        ix += 1
903        self.volume_surface_sizer.Add(surface_units_txt, (iy, ix), (1,1),
904                            wx.EXPAND|wx.ADJUST_MINSIZE, 10)
905       
906    def _layout_invariant_sizer(self):
907        """
908            Draw widgets related to invariant
909        """
910        uncertainty = "+/-" 
911        unit_invariant = '[1/(cm * A)]'
912        invariant_total_txt = wx.StaticText(self, -1, 'Invariant Total [Q*]')
913        self.invariant_total_tcl = OutputTextCtrl(self, -1, size=(_BOX_WIDTH,-1))
914        msg_hint = "Total invariant [Q*], including extrapolated regions."
915        self.invariant_total_tcl.SetToolTipString(msg_hint)
916        self.invariant_total_err_tcl = OutputTextCtrl(self, -1, size=(_BOX_WIDTH,-1))
917        self.invariant_total_err_tcl.SetToolTipString("Uncertainty on invariant.")
918        invariant_total_units_txt = wx.StaticText(self, -1, unit_invariant)
919   
920        #Invariant total
921        iy = 0
922        ix = 0
923        self.invariant_sizer.Add(invariant_total_txt, (iy, ix), (1,1),
924                             wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
925        ix += 1
926        self.invariant_sizer.Add(self.invariant_total_tcl, (iy, ix), (1,1),
927                          wx.EXPAND|wx.ADJUST_MINSIZE, 10)
928        ix += 1
929        self.invariant_sizer.Add( wx.StaticText(self, -1, uncertainty),
930                         (iy, ix),(1,1),wx.EXPAND|wx.ADJUST_MINSIZE, 10) 
931        ix += 1
932        self.invariant_sizer.Add(self.invariant_total_err_tcl, (iy, ix), (1,1),
933                             wx.EXPAND|wx.ADJUST_MINSIZE, 10)
934        ix += 1
935        self.invariant_sizer.Add(invariant_total_units_txt,(iy, ix), (1,1),
936                          wx.EXPAND|wx.ADJUST_MINSIZE, 10)
937 
938    def _layout_inputs_sizer(self):
939        """
940            Draw widgets related to inputs
941        """
942        self._layout_bkg_scale()
943        self._layout_contrast_porod()
944        self.inputs_sizer.AddMany([(self.bkg_scale_sizer, 0, wx.ALL, 5),
945                                    (self.contrast_porod_sizer, 0, wx.ALL, 5)])
946       
947    def _layout_outputs_sizer(self):
948        """
949            Draw widgets related to outputs
950        """
951        self._layout_volume_surface_sizer()
952        self._layout_invariant_sizer()
953        static_line = wx.StaticLine(self, -1)
954        self.outputs_sizer.AddMany([(self.volume_surface_sizer, 0, wx.ALL, 10),
955                                    (static_line, 0, wx.EXPAND, 0),
956                                    (self.invariant_sizer, 0, wx.ALL, 10)])
957    def _layout_button(self): 
958        """
959            Do the layout for the button widgets
960        """ 
961        #compute button
962        id = wx.NewId()
963        self.button_calculate = wx.Button(self, id, "Compute")
964        self.button_calculate.SetToolTipString("Compute invariant")
965        self.Bind(wx.EVT_BUTTON, self.compute_invariant, id=id)   
966        #detail button
967        id = wx.NewId()
968        self.button_details = wx.Button(self, id, "Details?")
969        self.button_details.SetToolTipString("Give Details on Computation")
970        self.Bind(wx.EVT_BUTTON, self.display_details, id=id)
971        details = "Details on Invariant Total Calculations"
972        details_txt = wx.StaticText(self, -1, details)
973        self.button_sizer.AddMany([((10,10), 0 , wx.LEFT,0),
974                                   (details_txt, 0 , 
975                                    wx.RIGHT|wx.BOTTOM|wx.TOP, 10),
976                                   (self.button_details, 0 , wx.ALL, 10),
977                        (self.button_calculate, 0 , wx.RIGHT|wx.TOP|wx.BOTTOM, 10)])
978       
979    def _do_layout(self):
980        """
981            Draw window content
982        """
983        self._define_structure()
984        self._layout_data_name()
985        self._layout_extrapolation()
986        self._layout_inputs_sizer()
987        self._layout_outputs_sizer()
988        self._layout_button()
989        self.main_sizer.AddMany([(self.data_name_boxsizer,0, wx.ALL, 10),
990                                  (self.outputs_sizer, 0,
991                                  wx.LEFT|wx.RIGHT|wx.BOTTOM, 10),
992                                  (self.button_sizer,0,
993                                  wx.LEFT|wx.RIGHT|wx.BOTTOM, 10),
994                                 (self.inputs_sizer, 0,
995                                  wx.LEFT|wx.RIGHT|wx.BOTTOM, 10),
996                                  (self.extrapolation_sizer, 0,
997                                  wx.LEFT|wx.RIGHT|wx.BOTTOM, 10)])
998        self.SetSizer(self.main_sizer)
999        self.SetAutoLayout(True)
1000   
1001class InvariantDialog(wx.Dialog):
1002    def __init__(self, parent=None, id=1,graph=None,
1003                 data=None, title="Invariant",base=None):
1004        wx.Dialog.__init__(self, parent, id, title, size=(PANEL_WIDTH,
1005                                                             PANEL_HEIGHT))
1006        self.panel = InvariantPanel(self)
1007        self.Centre()
1008        self.Show(True)
1009       
1010class InvariantWindow(wx.Frame):
1011    def __init__(self, parent=None, id=1,graph=None, 
1012                 data=None, title="Invariant",base=None):
1013       
1014        wx.Frame.__init__(self, parent, id, title, size=(PANEL_WIDTH +100,
1015                                                             PANEL_HEIGHT+100))
1016       
1017        self.panel = InvariantPanel(self)
1018        self.Centre()
1019        self.Show(True)
1020       
1021class MyApp(wx.App):
1022    def OnInit(self):
1023        wx.InitAllImageHandlers()
1024        frame = InvariantWindow()
1025        frame.Show(True)
1026        self.SetTopWindow(frame)
1027       
1028        return True
1029     
1030# end of class MyApp
1031
1032if __name__ == "__main__":
1033    app = MyApp(0)
1034    app.MainLoop()
Note: See TracBrowser for help on using the repository browser.