source: sasview/invariantview/src/sans/perspectives/invariant/invariant_details.py @ e86455b

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 e86455b was a3efdeb, checked in by Mathieu Doucet <doucetm@…>, 13 years ago

Fixing code style problems and bugs

  • Property mode set to 100644
File size: 22.2 KB
Line 
1"""
2    Invariant panel
3"""
4import wx
5import sys
6
7from sans.guiframe.utils import format_number
8from invariant_widgets import OutputTextCtrl
9# Dimensions related to chart
10RECTANGLE_WIDTH  = 400.0 
11RECTANGLE_HEIGHT = 20
12#Invariant panel size
13_BOX_WIDTH = 76
14
15#scale to use for a bar of value zero
16RECTANGLE_SCALE  = 0.0001
17DEFAULT_QSTAR = 1.0 
18 
19if sys.platform.count("win32") > 0:
20    _STATICBOX_WIDTH = 450
21    PANEL_WIDTH = 500
22    PANEL_HEIGHT = 430
23    FONT_VARIANT = 0
24else:
25    _STATICBOX_WIDTH = 480
26    PANEL_WIDTH = 530
27    PANEL_HEIGHT = 430
28    FONT_VARIANT = 1
29   
30ERROR_COLOR = wx.Colour(255,  0, 0, 128)
31EXTRAPOLATION_COLOR = wx.Colour(169,  169, 168, 128)
32INVARIANT_COLOR =  wx.Colour(67,  208,  128, 128)   
33 
34 
35class InvariantContainer(wx.Object):
36    """
37    This class stores some values resulting resulting from invariant
38    calculations. Given the value of total invariant, this class can also
39    determine the percentage of invariants resulting from extrapolation.
40    """
41    def __init__(self):
42        #invariant at low range
43        self.qstar_low = None
44        #invariant at low range error
45        self.qstar_low_err = None
46        #invariant
47        self.qstar = None
48        #invariant error
49        self.qstar_err = None
50        #invariant at high range
51        self.qstar_high = None
52        #invariant at high range error
53        self.qstar_high_err = None
54        #invariant total
55        self.qstar_total = None
56        #invariant error
57        self.qstar_total_err = None
58        #scale
59        self.qstar_low_percent = None
60        self.qstar_high_percent = None
61        self.qstar_percent = None
62        # warning message
63        self.existing_warning = False
64        self.warning_msg = "No Details on calculations available...\n"
65       
66    def compute_percentage(self):
67        """
68        Compute percentage of each invariant
69        """
70        if self.qstar_total is None:
71            self.qstar_percent = None
72            self.qstar_low = None
73            self.qstar_high = None
74            self.check_values()
75            return 
76       
77        #compute invariant percentage
78        if self.qstar is None:
79            self.qstar_percent = None
80        else:
81            try:
82                self.qstar_percent = float(self.qstar)/float(self.qstar_total)
83            except:
84                self.qstar_percent = 'error'
85        #compute low q invariant percentage
86        if self.qstar_low is None:
87            self.qstar_low_percent = None
88        else:
89            try:
90                self.qstar_low_percent = float(self.qstar_low)\
91                                            /float(self.qstar_total)
92            except:
93                self.qstar_low_percent = 'error'
94        #compute high q invariant percentage
95        if self.qstar_high is None:
96            self.qstar_high_percent = None
97        else:
98            try:
99                self.qstar_high_percent = float(self.qstar_high)\
100                                                /float(self.qstar_total)
101            except:
102                self.qstar_high_percent = 'error'
103        self.check_values()
104   
105    def check_values(self):
106        """
107        check the validity if invariant
108        """
109        if self.qstar_total is None and self.qstar is None:
110            self.warning_msg = "Invariant not calculated.\n"
111            return 
112        if self.qstar_total == 0:
113            self.existing_warning = True
114            self.warning_msg = "Invariant is zero. \n"
115            self.warning_msg += "The calculations are likely "
116            self.warning_msg += "to be unreliable!\n"
117            return 
118        #warning to the user when the extrapolated invariant is greater than %5
119        msg = ''
120        if self.qstar_percent == 'error':
121            self.existing_warning = True
122            msg = 'Error occurred when computing invariant from data.\n '
123        if self.qstar_percent > 1:
124            self.existing_warning = True
125            msg += "Invariant Q  contribution is greater "
126            msg += "than 100% .\n"
127        if self.qstar_low_percent == 'error':
128            self.existing_warning = True
129            msg = "Error occurred when computing extrapolated invariant"
130            msg += " at low-Q region.\n"
131        elif self.qstar_low_percent is not None :
132            if self.qstar_low_percent >= 0.05:
133                self.existing_warning = True
134                msg += "Extrapolated contribution at Low Q is higher "
135                msg += "than 5% of the invariant.\n"
136            elif self.qstar_low_percent < 0:
137                self.existing_warning = True
138                msg += "Extrapolated contribution at Low Q < 0.\n"
139            elif self.qstar_low_percent > 1:
140                self.existing_warning = True
141                msg += "Extrapolated contribution at Low Q is greater "
142                msg += "than 100% .\n"
143        if self.qstar_high_percent == 'error':
144            self.existing_warning = True
145            msg += 'Error occurred when computing extrapolated'
146            msg += ' invariant at high-Q region.\n'
147        elif self.qstar_high_percent is not None:
148            if self.qstar_high_percent >= 0.05:
149                self.existing_warning = True
150                msg += "Extrapolated contribution at High Q is higher "
151                msg += "than 5% of the invariant.\n"
152            elif self.qstar_high_percent < 0:
153                self.existing_warning = True
154                msg += "Extrapolated contribution at High Q < 0.\n"
155            elif self.qstar_high_percent > 1:
156                self.existing_warning = True
157                msg += "Extrapolated contribution at High Q is greater "
158                msg += "than 100% .\n"
159        if (self.qstar_low_percent not in [None, "error"]) and \
160            (self.qstar_high_percent not in [None, "error"])\
161            and self.qstar_low_percent + self.qstar_high_percent >= 0.05:
162            self.existing_warning = True
163            msg += "The sum of all extrapolated contributions is higher "
164            msg += "than 5% of the invariant.\n"
165           
166        if self.existing_warning:
167            self.warning_msg = ''
168            self.warning_msg += msg
169            self.warning_msg += "The calculations are likely to be"
170            self.warning_msg += " unreliable!\n"
171        else:
172            self.warning_msg = "No Details on calculations available...\n"
173           
174class InvariantDetailsPanel(wx.Dialog):
175    """
176    This panel describes proportion of invariants
177    """
178    def __init__(self, parent=None, id=-1, qstar_container=None, 
179                                    title="Invariant Details",
180                                    size=(PANEL_WIDTH, PANEL_HEIGHT)):
181        wx.Dialog.__init__(self, parent=parent, id=id, title=title, size=size)
182       
183        #Font size
184        self.SetWindowVariant(variant=FONT_VARIANT)
185        self.parent = parent
186        #self.qstar_container
187        self.qstar_container = qstar_container
188        #warning message
189        self.warning_msg = self.qstar_container.warning_msg
190   
191        #Define scale of each bar
192        self.low_inv_percent = self.qstar_container.qstar_low_percent
193        self.low_scale = self.get_scale(percentage=self.low_inv_percent,
194                                         scale_name="Extrapolated at Low Q")
195        self.inv_percent = self.qstar_container.qstar_percent
196        self.inv_scale = self.get_scale(percentage=self.inv_percent, 
197                                            scale_name="Inv in Q range")
198        self.high_inv_percent = self.qstar_container.qstar_high_percent
199        self.high_scale = self.get_scale(percentage=self.high_inv_percent,
200                                         scale_name="Extrapolated at High Q")
201       
202        #Default color the extrapolation bar is grey
203        self.extrapolation_color_low = EXTRAPOLATION_COLOR
204        self.extrapolation_color_high = EXTRAPOLATION_COLOR
205        self.invariant_color = INVARIANT_COLOR
206        #change color of high and low bar when necessary
207        self.set_color_bar()
208        #draw the panel itself
209        self._do_layout()
210        self.set_values()
211 
212    def _define_structure(self):
213        """
214        Define main sizers needed for this panel
215        """
216        #Box sizers must be defined first before defining buttons/textctrls
217        # (MAC).
218        self.main_sizer = wx.BoxSizer(wx.VERTICAL)
219        #Sizer related to chart
220        chart_box = wx.StaticBox(self, -1, "Invariant Chart")
221        self.chart_sizer = wx.StaticBoxSizer(chart_box, wx.VERTICAL)
222        self.chart_sizer.SetMinSize((PANEL_WIDTH - 50, 110))
223        #Sizer related to invariant values
224        self.invariant_sizer =  wx.GridBagSizer(4, 4)
225        invariant_box = wx.StaticBox(self, -1, "Numerical Values")
226        self.invariant_box_sizer = wx.StaticBoxSizer(invariant_box,
227                                                      wx.HORIZONTAL)
228
229        self.invariant_box_sizer.SetMinSize((PANEL_WIDTH - 50, -1))
230        #Sizer related to warning message
231        warning_box = wx.StaticBox(self, -1, "Warning")
232        self.warning_sizer = wx.StaticBoxSizer(warning_box, wx.VERTICAL)
233        self.warning_sizer.SetMinSize((PANEL_WIDTH-50, -1))
234        #Sizer related to button
235        self.button_sizer = wx.BoxSizer(wx.HORIZONTAL)
236     
237    def _layout_shart(self):
238        """
239        Draw widgets related to chart
240        """
241        self.panel_chart = wx.Panel(self)
242        self.panel_chart.Bind(wx.EVT_PAINT, self.on_paint)
243        self.chart_sizer.Add(self.panel_chart, 1, wx.EXPAND|wx.ALL, 0)
244       
245    def _layout_invariant(self):
246        """
247        Draw widgets related to invariant
248        """
249        uncertainty = "+/-" 
250        unit_invariant = '[1/(cm * A)]'
251     
252        invariant_txt = wx.StaticText(self, -1, 'Q* from Data ')
253        invariant_txt.SetToolTipString("Invariant in the data set's Q range.")
254        self.invariant_tcl = OutputTextCtrl(self, -1, size=(_BOX_WIDTH, -1))
255        hint_msg = "Invariant in the data set's Q range."
256        self.invariant_tcl.SetToolTipString(hint_msg)
257        self.invariant_err_tcl = OutputTextCtrl(self, -1, size=(_BOX_WIDTH, -1))
258        hint_msg = "Uncertainty on the invariant from data's range."
259        self.invariant_err_tcl.SetToolTipString(hint_msg)
260        invariant_units_txt = wx.StaticText(self, -1, unit_invariant)
261        hint_msg = "Unit of the invariant from data's Q range"
262        invariant_units_txt.SetToolTipString(hint_msg)
263       
264        invariant_low_txt = wx.StaticText(self, -1, 'Q* from Low-Q')
265        hint_msg = "Extrapolated invariant from low-Q range."
266        invariant_low_txt.SetToolTipString(hint_msg)
267        self.invariant_low_tcl = OutputTextCtrl(self, -1, size=(_BOX_WIDTH, -1))
268        hint_msg = "Extrapolated invariant from low-Q range."
269        self.invariant_low_tcl.SetToolTipString(hint_msg)
270        self.invariant_low_err_tcl = OutputTextCtrl(self, -1,
271                                                    size=(_BOX_WIDTH, -1))
272        hint_msg = "Uncertainty on the invariant from low-Q range."
273        self.invariant_low_err_tcl.SetToolTipString(hint_msg)
274        invariant_low_units_txt = wx.StaticText(self, -1, unit_invariant)
275        hint_msg = "Unit of the extrapolated invariant from  low-Q range"
276        invariant_low_units_txt.SetToolTipString(hint_msg)
277       
278        invariant_high_txt = wx.StaticText(self, -1, 'Q* from High-Q')
279        hint_msg = "Extrapolated invariant from  high-Q range"
280        invariant_high_txt.SetToolTipString(hint_msg)
281        self.invariant_high_tcl = OutputTextCtrl(self, -1,
282                                                 size=(_BOX_WIDTH, -1))
283        hint_msg = "Extrapolated invariant from  high-Q range"
284        self.invariant_high_tcl.SetToolTipString(hint_msg)
285        self.invariant_high_err_tcl = OutputTextCtrl(self, -1,
286                                                     size=(_BOX_WIDTH, -1))
287        hint_msg = "Uncertainty on the invariant from high-Q range."
288        self.invariant_high_err_tcl.SetToolTipString(hint_msg)
289        invariant_high_units_txt = wx.StaticText(self, -1, unit_invariant)
290        hint_msg = "Unit of the extrapolated invariant from  high-Q range"
291        invariant_high_units_txt.SetToolTipString(hint_msg)
292   
293        #Invariant low
294        iy = 0
295        ix = 0 
296        self.invariant_sizer.Add(invariant_low_txt, (iy, ix), (1, 1),
297                             wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
298        ix += 1
299        self.invariant_sizer.Add(self.invariant_low_tcl, (iy, ix), (1, 1),
300                            wx.EXPAND|wx.ADJUST_MINSIZE, 0) 
301        ix += 1
302        self.invariant_sizer.Add( wx.StaticText(self, -1, uncertainty),
303                         (iy, ix), (1, 1),wx.EXPAND|wx.ADJUST_MINSIZE, 0) 
304        ix += 1
305        self.invariant_sizer.Add(self.invariant_low_err_tcl, (iy, ix), (1, 1),
306                            wx.EXPAND|wx.ADJUST_MINSIZE, 0)
307        ix += 1
308        self.invariant_sizer.Add(invariant_low_units_txt
309                         ,(iy, ix), (1, 1), wx.EXPAND|wx.ADJUST_MINSIZE, 0) 
310        #Invariant
311        iy += 1
312        ix = 0 
313        self.invariant_sizer.Add(invariant_txt, (iy, ix), (1, 1),
314                             wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
315        ix += 1
316        self.invariant_sizer.Add(self.invariant_tcl, (iy, ix), (1, 1),
317                            wx.EXPAND|wx.ADJUST_MINSIZE, 0) 
318        ix += 1
319        self.invariant_sizer.Add(wx.StaticText(self, -1, uncertainty),
320                         (iy, ix), (1, 1),wx.EXPAND|wx.ADJUST_MINSIZE, 0) 
321        ix += 1
322        self.invariant_sizer.Add(self.invariant_err_tcl, (iy, ix), (1, 1),
323                            wx.EXPAND|wx.ADJUST_MINSIZE, 0) 
324        ix +=1
325        self.invariant_sizer.Add(invariant_units_txt
326                         ,(iy, ix), (1, 1),wx.EXPAND|wx.ADJUST_MINSIZE, 0) 
327        #Invariant high
328        iy += 1
329        ix = 0 
330        self.invariant_sizer.Add(invariant_high_txt, (iy, ix), (1, 1),
331                             wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
332        ix += 1
333        self.invariant_sizer.Add(self.invariant_high_tcl, (iy, ix), (1, 1),
334                            wx.EXPAND|wx.ADJUST_MINSIZE, 0) 
335        ix += 1
336        self.invariant_sizer.Add(wx.StaticText(self, -1, uncertainty),
337                         (iy, ix), (1, 1),wx.EXPAND|wx.ADJUST_MINSIZE, 0) 
338        ix += 1
339        self.invariant_sizer.Add(self.invariant_high_err_tcl, (iy, ix), (1, 1),
340                            wx.EXPAND|wx.ADJUST_MINSIZE, 0) 
341        ix += 1
342        self.invariant_sizer.Add(invariant_high_units_txt
343                         ,(iy, ix), (1, 1),wx.EXPAND|wx.ADJUST_MINSIZE, 0)
344        self.invariant_box_sizer.Add(self.invariant_sizer, 0,
345                                     wx.TOP|wx.BOTTOM, 10) 
346       
347    def _layout_warning(self):
348        """
349        Draw widgets related to warning
350        """
351        #Warning [string]
352        self.warning_msg_txt = wx.StaticText(self, -1, self.warning_msg) 
353        if self.qstar_container.existing_warning:
354            self.warning_msg_txt.SetForegroundColour('red') 
355        self.warning_sizer.AddMany([(self.warning_msg_txt, 0,
356                                     wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 10)])
357       
358    def _layout_button(self):
359        """
360        Draw widgets related to button
361        """
362        #Close button
363        id = wx.NewId()
364        button_ok = wx.Button(self, id, "Ok")
365        button_ok.SetToolTipString("Give Details on Computation")
366        self.Bind(wx.EVT_BUTTON, self.on_close, id=id)
367        self.button_sizer.AddMany([((20, 20), 0 , wx.LEFT, 350),
368                                   (button_ok, 0 , wx.RIGHT, 10)])
369    def _do_layout(self):
370        """
371        Draw window content
372        """
373        self._define_structure()
374        self._layout_shart()
375        self._layout_invariant()
376        self._layout_warning()
377        self._layout_button()
378        self.main_sizer.AddMany([(self.chart_sizer, 0, wx.ALL, 10),
379                                 ( self.invariant_box_sizer, 0, wx.ALL, 10),
380                                  (self.warning_sizer, 0, wx.ALL, 10),
381                                  (self.button_sizer, 0, wx.ALL, 10)])
382        self.SetSizer(self.main_sizer)
383       
384       
385    def set_values(self):
386        """
387        Set value of txtcrtl
388        """
389        value = format_number(self.qstar_container.qstar)
390        self.invariant_tcl.SetValue(value)
391        value = format_number(self.qstar_container.qstar_err)
392        self.invariant_err_tcl.SetValue(value) 
393        value = format_number(self.qstar_container.qstar_low)
394        self.invariant_low_tcl.SetValue(value)
395        value = format_number(self.qstar_container.qstar_low_err)
396        self.invariant_low_err_tcl.SetValue(value) 
397        value = format_number(self.qstar_container.qstar_high)
398        self.invariant_high_tcl.SetValue(value)
399        value = format_number(self.qstar_container.qstar_high_err)
400        self.invariant_high_err_tcl.SetValue(value) 
401
402    def get_scale(self, percentage, scale_name='scale'):
403        """
404        Check scale receive in this panel.
405        """
406        scale = RECTANGLE_SCALE
407        try: 
408            if percentage in [None, 0.0, "error"]:
409                 scale = RECTANGLE_SCALE
410                 return scale
411            elif percentage < 0:
412                scale = RECTANGLE_SCALE
413                return scale
414            scale = float(percentage)
415        except:
416            scale = RECTANGLE_SCALE
417            self.warning_msg += "Recieve an invalid scale for %s\n"
418            self.warning_msg += "check this value : %s\n" % str(percentage)
419        return  scale
420   
421    def set_color_bar(self):
422        """
423        Change the color for low and high bar when necessary
424        """
425        self.extrapolation_color_low = EXTRAPOLATION_COLOR
426        self.extrapolation_color_high = EXTRAPOLATION_COLOR
427        self.invariant_color = INVARIANT_COLOR
428        #warning to the user when the extrapolated invariant is greater than %5
429        if self.low_scale >= 0.05 or self.low_scale > 1 or self.low_scale < 0:
430            self.extrapolation_color_low = ERROR_COLOR
431        if self.high_scale >= 0.05 or self.high_scale > 1 or self.high_scale < 0:
432            self.extrapolation_color_high = ERROR_COLOR
433        if self.inv_scale > 1 or self.inv_scale < 0:
434            self.invariant_color = ERROR_COLOR 
435   
436    def on_close(self, event):
437        """
438        Close the current window
439        """
440        self.Close()
441     
442    def on_paint(self, event):
443        """
444        Draw the chart
445        """
446        dc = wx.PaintDC(self.panel_chart)
447        try:
448            gc = wx.GraphicsContext.Create(dc)
449        except NotImplementedError:
450            msg = "This build of wxPython does not support "
451            msg += "the wx.GraphicsContext family of classes."
452            dc.DrawText(msg, 25, 25)
453            return
454        #Start the drawing
455        font = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT)
456        font.SetWeight(wx.BOLD)
457        gc.SetFont(font)
458        # Draw a rectangle
459        path = gc.CreatePath()
460        path.AddRectangle(-RECTANGLE_WIDTH/2,-RECTANGLE_HEIGHT/2,
461                          RECTANGLE_WIDTH/2,RECTANGLE_HEIGHT/2)
462        x_origine = 20
463        y_origine = 15
464        #Draw low rectangle
465        gc.PushState()       
466        label = "Q* from Low-Q "
467        PathFunc = gc.DrawPath
468        w, h = gc.GetTextExtent(label)
469        gc.DrawText(label, x_origine, y_origine)
470        #Translate the rectangle
471        x_center = x_origine + RECTANGLE_WIDTH * self.low_scale/2 + w +10
472        y_center = y_origine + h
473        gc.Translate(x_center, y_center)   
474        gc.SetPen(wx.Pen("black", 1))
475        gc.SetBrush(wx.Brush(self.extrapolation_color_low))
476        if self.low_inv_percent is None:
477            low_percent = 'Not Computed'
478        elif self.low_inv_percent == 'error':
479            low_percent = 'Error'
480        else:
481            low_percent = format_number(self.low_inv_percent*100)+ '%'
482        x_center = 20
483        y_center = -h
484        gc.DrawText(low_percent, x_center, y_center)
485        # Increase width by self.low_scale
486        gc.Scale(self.low_scale, 1.0) 
487        PathFunc(path)
488        gc.PopState() 
489        #Draw rectangle for invariant   
490        gc.PushState()    # save it again
491        y_origine += 20         
492        gc.DrawText("Q* from Data ", x_origine, y_origine)
493        # offset to the lower part of the window
494        x_center = x_origine + RECTANGLE_WIDTH * self.inv_scale/2 + w + 10
495        y_center = y_origine + h
496        gc.Translate(x_center, y_center)
497        # 128 == half transparent
498        gc.SetBrush(wx.Brush(self.invariant_color)) 
499        # Increase width by self.inv_scale
500        if self.inv_percent is None:
501            inv_percent = 'Not Computed'
502        elif self.inv_percent == 'error':
503            inv_percent = 'Error'
504        else:
505            inv_percent = format_number(self.inv_percent*100)+ '%'
506        x_center = 20 
507        y_center = -h
508        gc.DrawText(inv_percent, x_center, y_center)
509        gc.Scale(self.inv_scale, 1.0)   
510        gc.DrawPath(path)
511        gc.PopState()
512        # restore saved state
513        #Draw rectangle for high invariant
514        gc.PushState() 
515        y_origine += 20 
516        gc.DrawText("Q* from High-Q ", x_origine, y_origine) 
517        #define the position of the new rectangle
518        x_center = x_origine + RECTANGLE_WIDTH * self.high_scale/2 + w + 10
519        y_center = y_origine + h
520        gc.Translate(x_center, y_center)
521        gc.SetBrush(wx.Brush(self.extrapolation_color_high)) 
522        # increase scale by self.high_scale
523        if self.high_inv_percent is None:
524            high_percent = 'Not Computed'
525        elif self.high_inv_percent == 'error':
526            high_percent = 'Error'
527        else:
528            high_percent = format_number(self.high_inv_percent*100)+ '%'
529        x_center = 20
530        y_center = -h
531        gc.DrawText(high_percent, x_center, y_center)
532       
533        gc.Scale(self.high_scale, 1.0) 
534        gc.DrawPath(path)
535        gc.PopState()
Note: See TracBrowser for help on using the repository browser.