source: sasview/invariantview/perspectives/invariant/invariant_panel.py @ 518d35d

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 518d35d was 518d35d, checked in by Gervaise Alina <gervyh@…>, 15 years ago

change panel according to inputs or wed meeting

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