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

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 38226d26 was ee54fcf0, checked in by Jae Cho <jhjcho@…>, 13 years ago

improved error msg in details dialog

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