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

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