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

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 4793734 was 9cec2dd, checked in by Gervaise Alina <gervyh@…>, 13 years ago

working on layout mac

  • Property mode set to 100644
File size: 22.7 KB
Line 
1
2import wx
3import sys
4
5import numpy
6from sans.guiframe.utils import format_number
7from sans.guiframe.utils import check_float
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 += "Receive an invalid scale for %s\n"
418            self.warning_msg += "check this value : %s\n"%(str(scale_name),
419                                                           str(percentage))
420        return  scale
421   
422    def set_color_bar(self):
423        """
424        Change the color for low and high bar when necessary
425        """
426        self.extrapolation_color_low = EXTRAPOLATION_COLOR
427        self.extrapolation_color_high = EXTRAPOLATION_COLOR
428        self.invariant_color = INVARIANT_COLOR
429        #warning to the user when the extrapolated invariant is greater than %5
430        if self.low_scale >= 0.05 or self.low_scale > 1 or self.low_scale < 0:
431            self.extrapolation_color_low = ERROR_COLOR
432        if self.high_scale >= 0.05 or self.high_scale > 1 or self.high_scale < 0:
433            self.extrapolation_color_high = ERROR_COLOR
434        if self.inv_scale > 1 or self.inv_scale < 0:
435            self.invariant_color = ERROR_COLOR 
436   
437    def on_close(self, event):
438        """
439        Close the current window
440        """
441        self.Close()
442     
443    def on_paint(self, event):
444        """
445        Draw the chart
446        """
447        dc = wx.PaintDC(self.panel_chart)
448        try:
449            gc = wx.GraphicsContext.Create(dc)
450        except NotImplementedError:
451            msg = "This build of wxPython does not support "
452            msg += "the wx.GraphicsContext family of classes."
453            dc.DrawText(msg, 25, 25)
454            return
455        #Start the drawing
456        font = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT)
457        font.SetWeight(wx.BOLD)
458        gc.SetFont(font)
459        # Draw a rectangle
460        path = gc.CreatePath()
461        path.AddRectangle(-RECTANGLE_WIDTH/2,-RECTANGLE_HEIGHT/2,
462                          RECTANGLE_WIDTH/2,RECTANGLE_HEIGHT/2)
463        x_origine = 20
464        y_origine = 15
465        #Draw low rectangle
466        gc.PushState()       
467        label = "Q* from Low-Q "
468        PathFunc = gc.DrawPath
469        w, h = gc.GetTextExtent(label)
470        gc.DrawText(label, x_origine, y_origine)
471        #Translate the rectangle
472        x_center = x_origine + RECTANGLE_WIDTH * self.low_scale/2 + w +10
473        y_center = y_origine + h
474        gc.Translate(x_center, y_center)   
475        gc.SetPen(wx.Pen("black", 1))
476        gc.SetBrush(wx.Brush(self.extrapolation_color_low))
477        if self.low_inv_percent is None:
478            low_percent = 'Not Computed'
479        elif self.low_inv_percent == 'error':
480            low_percent = 'Error'
481        else:
482            low_percent = format_number(self.low_inv_percent*100)+ '%'
483        x_center = 20
484        y_center = -h
485        gc.DrawText(low_percent, x_center, y_center)
486        # Increase width by self.low_scale
487        gc.Scale(self.low_scale, 1.0) 
488        PathFunc(path)
489        gc.PopState() 
490        #Draw rectangle for invariant   
491        gc.PushState()    # save it again
492        y_origine += 20         
493        gc.DrawText("Q* from Data ", x_origine, y_origine)
494        # offset to the lower part of the window
495        x_center = x_origine + RECTANGLE_WIDTH * self.inv_scale/2 + w + 10
496        y_center = y_origine + h
497        gc.Translate(x_center, y_center)
498        # 128 == half transparent
499        gc.SetBrush(wx.Brush(self.invariant_color)) 
500        # Increase width by self.inv_scale
501        if self.inv_percent is None:
502            inv_percent = 'Not Computed'
503        elif self.inv_percent == 'error':
504            inv_percent = 'Error'
505        else:
506            inv_percent = format_number(self.inv_percent*100)+ '%'
507        x_center = 20 
508        y_center = -h
509        gc.DrawText(inv_percent, x_center, y_center)
510        gc.Scale(self.inv_scale, 1.0)   
511        gc.DrawPath(path)
512        gc.PopState()
513        # restore saved state
514        #Draw rectangle for high invariant
515        gc.PushState() 
516        y_origine += 20 
517        gc.DrawText("Q* from High-Q ", x_origine, y_origine) 
518        #define the position of the new rectangle
519        x_center = x_origine + RECTANGLE_WIDTH * self.high_scale/2 + w + 10
520        y_center = y_origine + h
521        gc.Translate(x_center, y_center)
522        gc.SetBrush(wx.Brush(self.extrapolation_color_high)) 
523        # increase scale by self.high_scale
524        if self.high_inv_percent is None:
525            high_percent = 'Not Computed'
526        elif self.high_inv_percent == 'error':
527            high_percent = 'Error'
528        else:
529            high_percent = format_number(self.high_inv_percent*100)+ '%'
530        x_center = 20
531        y_center = -h
532        gc.DrawText(high_percent, x_center, y_center)
533       
534        gc.Scale(self.high_scale, 1.0) 
535        gc.DrawPath(path)
536        gc.PopState()
537
538
539if __name__ =="__main__":
540    app  = wx.App()
541    container = InvariantContainer()
542    container.qstar_total = 100.0
543    container.qstar = 50
544    container.qstar_low = None
545    container.qstar_high = "alina"
546    container.compute_percentage()
547   
548    dlg = InvariantDetailsPanel(qstar_container=container)
549    dlg.ShowModal()
550    app.MainLoop()
Note: See TracBrowser for help on using the repository browser.