source: sasview/calculatorview/perspectives/calculator/resolution_calculator_panel.py @ 75a7ece

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 75a7ece was 943cacb, checked in by Jae Cho <jhjcho@…>, 14 years ago

Added callback(textEnter) method on param value changes

  • Property mode set to 100644
File size: 44.2 KB
Line 
1"""
2   This software was developed by the University of Tennessee as part of the
3Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
4project funded by the US National Science Foundation.
5
6See the license text in license.txt
7
8copyright 2008, 2009, 2010 University of Tennessee
9"""
10import wx
11import sys
12import matplotlib
13#Use the WxAgg back end. The Wx one takes too long to render
14matplotlib.use('WXAgg')
15from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas
16from matplotlib.backends.backend_wxagg import NavigationToolbar2Wx as Toolbar
17from matplotlib.backend_bases import FigureManagerBase
18# Wx-Pylab magic for displaying plots within an application's window.
19from matplotlib import _pylab_helpers
20# The Figure object is used to create backend-independent plot representations.
21from matplotlib.figure import Figure
22
23#from sans.guicomm.events import StatusEvent 
24from sans.calculator.resolution_calculator import ResolutionCalculator
25from sans.guicomm.events import StatusEvent 
26from calculator_widgets import OutputTextCtrl
27from calculator_widgets import InputTextCtrl
28from wx.lib.scrolledpanel import ScrolledPanel
29from math import fabs
30_BOX_WIDTH = 100
31_Q_DEFAULT = 0.0
32#Slit length panel size
33if sys.platform.count("win32") > 0:
34    PANEL_WIDTH = 535
35    PANEL_HEIGHT = 653
36    FONT_VARIANT = 0
37else:
38    PANEL_WIDTH = 560
39    PANEL_HEIGHT = 692
40    FONT_VARIANT = 1
41 
42class ResolutionCalculatorPanel(ScrolledPanel):
43    """
44    Provides the Resolution calculator GUI.
45    """
46    ## Internal nickname for the window, used by the AUI manager
47    window_name = "SANS Resolution Estimator"
48    ## Name to appear on the window title bar
49    window_caption = ""
50    ## Flag to tell the AUI manager to put this panel in the center pane
51    CENTER_PANE = True
52   
53    def __init__(self, parent,  *args, **kwds):
54        kwds["size"]= (PANEL_WIDTH * 2, PANEL_HEIGHT)
55        kwds["style"]= wx.FULL_REPAINT_ON_RESIZE
56        ScrolledPanel.__init__(self, parent, *args, **kwds)
57        self.SetupScrolling()
58        self.parent = parent
59       
60        # input defaults
61        self.qx = []
62        self.qy = []
63        # dQ defaults
64        self.sigma_r = None
65        self.sigma_phi = None
66        self.sigma_1d = None
67        # dQ 2d image
68        self.image = None
69        #Font size
70        self.SetWindowVariant(variant=FONT_VARIANT)
71        # Object that receive status event
72        self.resolution = ResolutionCalculator()
73     
74        #layout attribute
75        self.hint_sizer = None
76        # detector coordinate of estimation of sigmas
77        self.det_coordinate = 'polar'
78
79        self._do_layout()
80
81    def _define_structure(self):
82        """
83        Define the main sizers building to build this application.
84        """
85        self.main_sizer = wx.BoxSizer(wx.HORIZONTAL)
86        self.vertical_l_sizer = wx.BoxSizer(wx.VERTICAL)
87        self.vertical_r_spacer = wx.BoxSizer(wx.VERTICAL)
88        self.vertical_r_frame = wx.StaticBox(self, -1, '')
89        self.vertical_r_sizer = wx.StaticBoxSizer(self.vertical_r_frame,
90                                                  wx.VERTICAL)
91        self.box_source = wx.StaticBox(self, -1,
92                                str(self.window_caption))
93        self.boxsizer_source = wx.StaticBoxSizer(self.box_source,
94                                                    wx.VERTICAL)
95        self.mass_sizer = wx.BoxSizer(wx.HORIZONTAL)
96        self.intensity_sizer = wx.BoxSizer(wx.HORIZONTAL)
97        self.wavelength_sizer = wx.BoxSizer(wx.HORIZONTAL)
98        self.wavelength_spread_sizer = wx.BoxSizer(wx.HORIZONTAL)
99        self.source_aperture_sizer = wx.BoxSizer(wx.HORIZONTAL)
100        self.sample_aperture_sizer = wx.BoxSizer(wx.HORIZONTAL)
101        self.source2sample_distance_sizer = wx.BoxSizer(wx.HORIZONTAL)
102        self.sample2sample_distance_sizer = wx.BoxSizer(wx.HORIZONTAL)
103        self.sample2detector_distance_sizer = wx.BoxSizer(wx.HORIZONTAL)
104        self.detector_size_sizer = wx.BoxSizer(wx.HORIZONTAL)
105        self.detector_pix_size_sizer = wx.BoxSizer(wx.HORIZONTAL)
106        #self.detector_offset_sizer = wx.BoxSizer(wx.HORIZONTAL)
107        self.input_sizer = wx.BoxSizer(wx.VERTICAL)
108        self.output_sizer = wx.BoxSizer(wx.VERTICAL)
109        self.hint_sizer = wx.BoxSizer(wx.HORIZONTAL)
110        self.button_sizer = wx.BoxSizer(wx.HORIZONTAL)
111       
112    def _layout_mass(self):
113        """
114        Fill the sizer containing mass
115        """
116        # get the mass
117        mass_value = str(self.resolution.mass)
118        mass_unit_txt = wx.StaticText(self, -1, '[g]')
119        mass_txt = wx.StaticText(self, -1, 
120                                'Mass: ')
121        self.mass_tcl = InputTextCtrl(self, -1, 
122                                         size=(_BOX_WIDTH,-1))
123        mass_hint = "Mass of Neutrons"
124        self.mass_tcl.SetValue(mass_value)
125        self.mass_tcl.SetToolTipString(mass_hint)
126        self.mass_sizer.AddMany([(mass_txt, 0, wx.LEFT, 15),
127                                    (self.mass_tcl, 0, wx.LEFT, 15),
128                                    (mass_unit_txt,0, wx.LEFT, 10)])   
129       
130    def _layout_intensity(self):
131        """
132        Fill the sizer containing intensity
133        """
134        # get the intensity
135        intensity_value = str(self.resolution.intensity)
136        intensity_unit_txt = wx.StaticText(self, -1, '[counts/s]')
137        intensity_txt = wx.StaticText(self, -1, 
138                                'Intensity: ')
139        self.intensity_tcl = InputTextCtrl(self, -1, 
140                                        size=(_BOX_WIDTH,-1))
141        intensity_hint = "Intensity of Neutrons"
142        self.intensity_tcl.SetValue(intensity_value)
143        self.intensity_tcl.SetToolTipString(intensity_hint)
144        self.intensity_sizer.AddMany([(intensity_txt, 0, wx.LEFT, 15),
145                                    (self.intensity_tcl, 0, wx.LEFT, 15),
146                                    (intensity_unit_txt,0, wx.LEFT, 10)])   
147
148       
149    def _layout_wavelength(self):
150        """
151        Fill the sizer containing wavelength
152        """
153        # get the wavelength
154        wavelength_value = str(self.resolution.wavelength)
155        wavelength_unit_txt = wx.StaticText(self, -1, '[A]')
156        wavelength_txt = wx.StaticText(self, -1, 
157                                'Wavelength: ')
158        self.wavelength_tcl = InputTextCtrl(self, -1, 
159                                         size=(_BOX_WIDTH,-1))
160        wavelength_hint = "Wavelength of Neutrons"
161        self.wavelength_tcl.SetValue(wavelength_value)
162        self.wavelength_tcl.SetToolTipString(wavelength_hint)
163        self.wavelength_sizer.AddMany([(wavelength_txt, 0, wx.LEFT, 15),
164                                    (self.wavelength_tcl, 0, wx.LEFT, 15),
165                                    (wavelength_unit_txt,0, wx.LEFT, 10)])   
166         
167       
168    def _layout_wavelength_spread(self):
169        """
170        Fill the sizer containing wavelength
171        """
172        # get the wavelength
173        wavelength_spread_value = str(self.resolution.wavelength_spread)
174        wavelength_spread_unit_txt = wx.StaticText(self, -1, '')
175        wavelength_spread_txt = wx.StaticText(self, -1, 
176                                'Wavelength Spread: ')
177        self.wavelength_spread_tcl = InputTextCtrl(self, -1, 
178                                         size=(_BOX_WIDTH,-1))
179        wavelength_spread_hint = "Wavelength  Spread of Neutrons"
180        self.wavelength_spread_tcl.SetValue(wavelength_spread_value)
181        self.wavelength_spread_tcl.SetToolTipString(wavelength_spread_hint)
182        self.wavelength_spread_sizer.AddMany([(wavelength_spread_txt, 0, 
183                                               wx.LEFT, 15),
184                                (self.wavelength_spread_tcl, 0, wx.LEFT, 15),
185                                (wavelength_spread_unit_txt,0, wx.LEFT, 10)])     
186         
187       
188    def _layout_source_aperture(self):
189        """
190        Fill the sizer containing source aperture size
191        """
192        # get the wavelength
193        source_aperture_value = str(self.resolution.source_aperture_size[0])
194        if len(self.resolution.source_aperture_size)>1:
195            source_aperture_value += ", "
196            source_aperture_value += str(\
197                                    self.resolution.source_aperture_size[1])
198        source_aperture_unit_txt = wx.StaticText(self, -1, '[cm]')
199        source_aperture_txt = wx.StaticText(self, -1, 
200                                'Source Aperture Size: ')
201        self.source_aperture_tcl = InputTextCtrl(self, -1, 
202                                         size=(_BOX_WIDTH,-1))
203        source_aperture_hint = "Source Aperture Size"
204        self.source_aperture_tcl.SetValue(source_aperture_value)
205        self.source_aperture_tcl.SetToolTipString(source_aperture_hint)
206        self.source_aperture_sizer.AddMany([(source_aperture_txt, 0, 
207                                               wx.LEFT, 15),
208                                (self.source_aperture_tcl, 0, wx.LEFT, 15),
209                                    (source_aperture_unit_txt,0, wx.LEFT, 10)]) 
210
211       
212    def _layout_sample_aperture(self):
213        """
214        Fill the sizer containing sample aperture size
215        """
216        # get the wavelength
217        sample_aperture_value = str(self.resolution.sample_aperture_size[0])
218        if len(self.resolution.sample_aperture_size)>1:
219            sample_aperture_value += ", "
220            sample_aperture_value += str(\
221                                    self.resolution.sample_aperture_size[1])
222        sample_aperture_unit_txt = wx.StaticText(self, -1, '[cm]')
223        sample_aperture_txt = wx.StaticText(self, -1, 
224                                'Sample Aperture Size: ')
225        self.sample_aperture_tcl = InputTextCtrl(self, -1, 
226                                         size=(_BOX_WIDTH,-1))
227        sample_aperture_hint = "Sample Aperture Size"
228        self.sample_aperture_tcl.SetValue(sample_aperture_value)
229        self.sample_aperture_tcl.SetToolTipString(sample_aperture_hint)
230        self.sample_aperture_sizer.AddMany([(sample_aperture_txt, 0, 
231                                               wx.LEFT, 15),
232                                (self.sample_aperture_tcl, 0, wx.LEFT, 15),
233                                    (sample_aperture_unit_txt,0, wx.LEFT, 10)]) 
234
235
236    def _layout_source2sample_distance(self):
237        """
238        Fill the sizer containing souce2sample_distance
239        """
240        # get the wavelength
241        source2sample_distance_value = str(\
242                                    self.resolution.source2sample_distance[0])
243
244        source2sample_distance_unit_txt = wx.StaticText(self, -1, '[cm]')
245        source2sample_distance_txt = wx.StaticText(self, -1, 
246                                'Source to Sample Aperture Distance: ')
247        self.source2sample_distance_tcl = InputTextCtrl(self, -1, 
248                                         size=(_BOX_WIDTH,-1))
249        source2sample_distance_hint = "Source to Sample Aperture Distance"
250        self.source2sample_distance_tcl.SetValue(source2sample_distance_value)
251        self.source2sample_distance_tcl.SetToolTipString(\
252                                                source2sample_distance_hint)
253        self.source2sample_distance_sizer.AddMany([(source2sample_distance_txt, 
254                                               0, wx.LEFT, 15),
255                            (self.source2sample_distance_tcl, 0, wx.LEFT, 15),
256                            (source2sample_distance_unit_txt,0, wx.LEFT, 10)]) 
257
258    def _layout_sample2sample_distance(self):
259        """
260        Fill the sizer containing sampleslit2sample_distance
261        """
262        # get the distance
263        sample2sample_distance_value = str(\
264                                    self.resolution.sample2sample_distance[0])
265
266        sample2sample_distance_unit_txt = wx.StaticText(self, -1, '[cm]')
267        sample2sample_distance_txt = wx.StaticText(self, -1, 
268                                'Sample Offset: ')
269        self.sample2sample_distance_tcl = InputTextCtrl(self, -1, 
270                                         size=(_BOX_WIDTH,-1))
271        sample2sample_distance_hint = "Sample Aperture to Sample Distance"
272        self.sample2sample_distance_tcl.SetValue(sample2sample_distance_value)
273        self.sample2sample_distance_tcl.SetToolTipString(\
274                                                sample2sample_distance_hint)
275        self.sample2sample_distance_sizer.AddMany([(sample2sample_distance_txt, 
276                                               0, wx.LEFT, 15),
277                            (self.sample2sample_distance_tcl, 0, wx.LEFT, 15),
278                            (sample2sample_distance_unit_txt,0, wx.LEFT, 10)]) 
279
280
281
282    def _layout_sample2detector_distance(self):
283        """
284        Fill the sizer containing sample2detector_distance
285        """
286        # get the wavelength
287        sample2detector_distance_value = str(\
288                                    self.resolution.sample2detector_distance[0])
289
290        sample2detector_distance_unit_txt = wx.StaticText(self, -1, '[cm]')
291        sample2detector_distance_txt = wx.StaticText(self, -1, 
292                                'Sample Aperture to Detector Distance: ')
293        self.sample2detector_distance_tcl = InputTextCtrl(self, -1, 
294                                         size=(_BOX_WIDTH,-1))
295        sample2detector_distance_hint = \
296                                "Sample Aperture to Detector Distance"
297        self.sample2detector_distance_tcl.SetValue(\
298                                                sample2detector_distance_value)
299        self.sample2detector_distance_tcl.SetToolTipString(\
300                                                sample2detector_distance_hint)
301        self.sample2detector_distance_sizer.AddMany([\
302                            (sample2detector_distance_txt, 0, wx.LEFT, 15),       
303                            (self.sample2detector_distance_tcl, 0, wx.LEFT, 15),
304                            (sample2detector_distance_unit_txt,0, wx.LEFT, 10)]) 
305       
306    def _layout_detector_size(self):
307        """
308        Fill the sizer containing detector size
309        """
310        # get the wavelength
311        detector_size_value = str(self.resolution.detector_size[0])
312        if len(self.resolution.detector_size)>1:
313            detector_size_value += ", "
314            detector_size_value += str(self.resolution.detector_size[1])
315        detector_size_unit_txt = wx.StaticText(self, -1, '')
316        detector_size_txt = wx.StaticText(self, -1, 
317                                'Number of Pixels on Detector: ')
318        self.detector_size_tcl = InputTextCtrl(self, -1, 
319                                         size=(_BOX_WIDTH,-1))
320        detector_size_hint = "Number of Pixels on Detector"
321        self.detector_size_tcl.SetValue(detector_size_value)
322        self.detector_size_tcl.SetToolTipString(detector_size_hint)
323        self.detector_size_sizer.AddMany([(detector_size_txt, 0, 
324                                               wx.LEFT, 15),
325                                (self.detector_size_tcl, 0, wx.LEFT, 15),
326                                    (detector_size_unit_txt,0, wx.LEFT, 10)]) 
327
328       
329    def _layout_detector_pix_size(self):
330        """
331        Fill the sizer containing detector pixel size
332        """
333        # get the detector_pix_size
334        detector_pix_size_value = str(self.resolution.detector_pix_size[0])
335        if len(self.resolution.detector_pix_size)>1:
336            detector_pix_size_value += ", "
337            detector_pix_size_value += str(self.resolution.detector_pix_size[1])
338        detector_pix_size_unit_txt = wx.StaticText(self, -1, '[cm]')
339        detector_pix_size_txt = wx.StaticText(self, -1, 
340                                'Detector Pixel Size: ')
341        self.detector_pix_size_tcl = InputTextCtrl(self, -1, 
342                                         size=(_BOX_WIDTH,-1))
343        detector_pix_size_hint = "Detector Pixel Size"
344        self.detector_pix_size_tcl.SetValue(detector_pix_size_value)
345        self.detector_pix_size_tcl.SetToolTipString(detector_pix_size_hint)
346        self.detector_pix_size_sizer.AddMany([(detector_pix_size_txt, 0, 
347                                               wx.LEFT, 15),
348                                (self.detector_pix_size_tcl, 0, wx.LEFT, 15),
349                                (detector_pix_size_unit_txt,0, wx.LEFT, 10)])
350       
351    def _layout_input(self):
352        """
353        Fill the sizer containing inputs; qx, qy
354        """
355       
356        q_title = wx.StaticText(self, -1, 
357                            "[Q Location of the Estimation]:")
358        # sizers for inputs
359        inputQx_sizer = wx.BoxSizer(wx.HORIZONTAL)
360        inputQy_sizer = wx.BoxSizer(wx.HORIZONTAL)
361        # get the default dq
362        qx_value = str(_Q_DEFAULT)
363        qy_value = str(_Q_DEFAULT)
364        qx_unit_txt = wx.StaticText(self, -1, '[1/A]  ')
365        qy_unit_txt = wx.StaticText(self, -1, '[1/A]  ')
366        qx_name_txt = wx.StaticText(self, -1, 
367                                'Qx: ')
368        qy_name_txt = wx.StaticText(self, -1, 
369                                'Qy: ')
370        self.qx_tcl = InputTextCtrl(self, -1, 
371                                         size=(_BOX_WIDTH*3,-1))
372        self.qy_tcl = InputTextCtrl(self, -1, 
373                                         size=(_BOX_WIDTH*3,-1))
374        qx_hint = "Type the Qx value."
375        qy_hint = "Type the Qy value."
376        self.qx_tcl.SetValue(qx_value)
377        self.qy_tcl.SetValue(qy_value)
378        self.qx_tcl.SetToolTipString(qx_hint)
379        self.qy_tcl.SetToolTipString(qy_hint)
380        inputQx_sizer.AddMany([(qx_name_txt, 0, wx.LEFT, 15),
381                                    (self.qx_tcl, 0, wx.LEFT, 15),
382                                    (qx_unit_txt, 0, wx.LEFT, 15)])
383        inputQy_sizer.AddMany([(qy_name_txt, 0, wx.LEFT, 15),
384                                    (self.qy_tcl, 0, wx.LEFT, 15),
385                                    (qy_unit_txt, 0, wx.LEFT, 15)])
386        self.input_sizer.AddMany([(q_title, 0, wx.LEFT, 15), 
387                                    (inputQx_sizer, 0,
388                                     wx.EXPAND|wx.TOP|wx.BOTTOM, 5),
389                                    (inputQy_sizer, 0, 
390                                     wx.EXPAND|wx.TOP|wx.BOTTOM, 5)])
391                                #(self.compute_button, 0, wx.LEFT, 30)])
392       
393    def _layout_output(self):
394        """
395        Fill the sizer containing dQ|| and dQ+
396        """
397        sigma_title = wx.StaticText(self, -1, 
398                        "[Standard Deviation of the Resolution Distribution]:")
399         # sizers for inputs
400        outputQxy_sizer = wx.BoxSizer(wx.HORIZONTAL)
401        outputQ_sizer = wx.BoxSizer(wx.HORIZONTAL)
402        sigma_unit = '['+'1/A' +']'
403        self.sigma_r_txt = wx.StaticText(self, -1, 
404                                           'Sigma_r:   ')
405        self.sigma_r_tcl = OutputTextCtrl(self, -1, 
406                                                 size=(_BOX_WIDTH,-1))
407        self.sigma_phi_txt = wx.StaticText(self, -1, 
408                                           'Sigma_phi:')
409        self.sigma_phi_tcl = OutputTextCtrl(self, -1, 
410                                                 size=(_BOX_WIDTH,-1))
411        sigma_1d_txt = wx.StaticText(self, -1, '( 1D:   Sigma:')
412        self.sigma_1d_tcl = OutputTextCtrl(self, -1, 
413                                                 size=(_BOX_WIDTH,-1))
414        sigma_hint = " dQ_r or dQ_x, and dQ_phi or dQ_y"
415        sigma_hint_1d = " dQ for 1-dimension"
416        self.sigma_r_tcl.SetToolTipString(sigma_hint)
417        self.sigma_phi_tcl.SetToolTipString(sigma_hint)
418        self.sigma_1d_tcl.SetToolTipString(sigma_hint_1d)
419        sigma_r_unit_txt = wx.StaticText(self, -1, sigma_unit)
420        sigma_phi_unit_txt = wx.StaticText(self, -1, sigma_unit)
421        sigma_1d_unit_txt = wx.StaticText(self, -1, sigma_unit+' )')
422        outputQxy_sizer.AddMany([(self.sigma_r_txt, 0, wx.LEFT, 15),
423                                    (self.sigma_r_tcl, 0, wx.LEFT, 15),
424                                    (sigma_r_unit_txt, 0, wx.LEFT, 15),
425                                    (self.sigma_phi_txt, 0, wx.LEFT, 15),
426                                    (self.sigma_phi_tcl, 0, wx.LEFT, 15),
427                                    (sigma_phi_unit_txt, 0, wx.LEFT, 15)])
428        outputQ_sizer.AddMany([(sigma_1d_txt, 0, wx.LEFT, 15),
429                                    (self.sigma_1d_tcl, 0, wx.LEFT, 15),
430                                    (sigma_1d_unit_txt, 0, wx.LEFT, 15)])
431        self.output_sizer.AddMany([(sigma_title, 0, wx.LEFT, 15), 
432                                    (outputQxy_sizer, 0,
433                                     wx.EXPAND|wx.TOP|wx.BOTTOM, 5),
434                                    (outputQ_sizer, 0, 
435                                     wx.EXPAND|wx.TOP|wx.BOTTOM, 5)])
436       
437   
438    def _layout_hint(self):
439        """
440        Fill the sizer containing hint
441        """
442        hint_msg = ""
443        #hint_msg += "This tool is to approximately compute "
444        #hint_msg += "the resolution (dQ)."
445
446        self.hint_txt = wx.StaticText(self, -1, hint_msg)
447        self.hint_sizer.AddMany([(self.hint_txt, 0, wx.LEFT, 15)])
448   
449    def _layout_button(self): 
450        """
451        Do the layout for the button widgets
452        """ 
453        #outerbox_txt = wx.StaticText(self, -1, 'Outer Box')
454        self.x_y_rb = wx.RadioButton(self, -1,"Cartesian")
455        self.Bind(wx.EVT_RADIOBUTTON,
456                  self._on_xy_coordinate, id=self.x_y_rb.GetId())
457        self.r_phi_rb = wx.RadioButton(self, -1,"Polar")
458        self.Bind(wx.EVT_RADIOBUTTON,
459                  self._on_rp_coordinate, id=self.r_phi_rb.GetId())
460        self.r_phi_rb.SetValue(True)
461        #reset button
462        id = wx.NewId()
463        self.reset_button = wx.Button(self, id, "Reset")
464        hint_on_reset = "..."
465        self.reset_button.SetToolTipString(hint_on_reset)
466        self.Bind(wx.EVT_BUTTON, self.on_reset, id=id)
467        #compute button
468        id = wx.NewId()
469        self.compute_button = wx.Button(self, id, "Compute")
470        hint_on_compute = "..."
471        self.compute_button.SetToolTipString(hint_on_compute)
472        self.Bind(wx.EVT_BUTTON, self.on_compute, id=id)
473        # close button
474        self.bt_close = wx.Button(self, wx.ID_CANCEL,'Close')
475        self.bt_close.Bind(wx.EVT_BUTTON, self.on_close)
476        self.bt_close.SetToolTipString("Close this window.")
477        self.button_sizer.AddMany([(self.r_phi_rb,  0, wx.LEFT, 15),
478                                   (self.x_y_rb,  0, wx.LEFT, 15),
479                                   (self.reset_button, 0, wx.LEFT, 50),
480                                   (self.compute_button, 0, wx.LEFT, 15),
481                                   (self.bt_close, 0, wx.LEFT, 15)])#370)])
482        self.compute_button.SetFocus()
483       
484    def _layout_image(self):
485        """
486        Layout for image plot
487        """
488        color = wx.SystemSettings.GetColour(wx.SYS_COLOUR_BACKGROUND)
489
490        # Contribution by James C.
491        # Instantiate a figure object that will contain our plots.
492        # Make the fig a little smaller than the default
493        self.figure = Figure(figsize=(6.5, 6), facecolor = 'white')
494       
495        # Initialize the figure canvas, mapping the figure object to the plot
496        # engine backend.
497        self.canvas = FigureCanvas(self, wx.ID_ANY, self.figure)
498
499        # Wx-Pylab magic ...
500        # Make our canvas the active figure manager for pylab so that when
501        # pylab plotting statements are executed they will operate on our
502        # canvas and not create a new frame and canvas for display purposes.
503        # This technique allows this application to execute code that uses
504        # pylab stataments to generate plots and embed these plots in our
505        # application window(s).
506        self.fm = FigureManagerBase(self.canvas, 1)
507        _pylab_helpers.Gcf.set_active(self.fm)
508       
509        # Instantiate the matplotlib navigation toolbar and explicitly show it.
510        mpl_toolbar = Toolbar(self.canvas)
511        # Diable pan
512        mpl_toolbar.DeleteToolByPos(3)
513
514        # Add a toolbar into the frame
515        mpl_toolbar.Realize()
516
517        # Compute before adding the canvas to the sizer
518        self.on_compute()
519
520        # Fill up the sizer
521        self.vertical_r_sizer.Add(self.canvas, -1) 
522        self.vertical_r_spacer.Add((0, 24)) 
523        self.vertical_r_spacer.Add(self.vertical_r_sizer, 0, 
524                                       wx.ALL|wx.EXPAND, 2)
525        self.vertical_r_spacer.Add((0, 30)) 
526        self.vertical_r_spacer.Add(wx.StaticLine(self), 0, 
527                                       wx.ALL|wx.EXPAND, 2)
528        self.vertical_r_spacer.Add(mpl_toolbar, 0,  wx.ALL|wx.EXPAND, 2)
529
530       
531    def _do_layout(self):
532        """
533            Draw window layout
534        """
535        #  Title of parameters
536        instrument_txt = wx.StaticText(self, -1, 
537                                '[Instrumental Parameters]:')
538        # Build individual layouts
539        self._define_structure()
540        self._layout_mass()
541        #self._layout_intensity()
542        self._layout_wavelength()
543        self._layout_wavelength_spread()
544        self._layout_source_aperture()
545        self._layout_sample_aperture()
546        self._layout_source2sample_distance()
547        self._layout_sample2detector_distance()
548        self._layout_sample2sample_distance()
549        self._layout_detector_size()
550        self._layout_detector_pix_size()
551        self._layout_input()
552        self._layout_output()
553        self._layout_hint()
554        self._layout_button()
555        # Fill the sizers
556        self.boxsizer_source.AddMany([(instrument_txt, 0,
557                                       wx.EXPAND|wx.LEFT, 15),
558                                      (self.mass_sizer, 0,
559                                      wx.EXPAND|wx.TOP|wx.BOTTOM, 5),
560                                      #(self.intensity_sizer, 0,
561                                      #wx.EXPAND|wx.TOP|wx.BOTTOM, 5),
562                                      (self.wavelength_sizer, 0,
563                                      wx.EXPAND|wx.TOP|wx.BOTTOM, 5),
564                                      (self.wavelength_spread_sizer, 0,
565                                      wx.EXPAND|wx.TOP|wx.BOTTOM, 5),
566                                      (self.source_aperture_sizer, 0,
567                                      wx.EXPAND|wx.TOP|wx.BOTTOM, 5),
568                                      (self.sample_aperture_sizer, 0,
569                                      wx.EXPAND|wx.TOP|wx.BOTTOM, 5),
570                                      (self.source2sample_distance_sizer, 0,
571                                      wx.EXPAND|wx.TOP|wx.BOTTOM, 5),
572                                      (self.sample2detector_distance_sizer, 0,
573                                      wx.EXPAND|wx.TOP|wx.BOTTOM, 5),
574                                      (self.sample2sample_distance_sizer, 0,
575                                      wx.EXPAND|wx.TOP|wx.BOTTOM, 5),
576                                      (self.detector_size_sizer, 0,
577                                      wx.EXPAND|wx.TOP|wx.BOTTOM, 5),
578                                      (self.detector_pix_size_sizer, 0,
579                                      wx.EXPAND|wx.TOP|wx.BOTTOM, 5),
580                                      (wx.StaticLine(self), 0, 
581                                       wx.ALL|wx.EXPAND, 5),
582                                      (self.input_sizer, 0,
583                                      wx.EXPAND|wx.TOP|wx.BOTTOM, 5),
584                                      (wx.StaticLine(self), 0, 
585                                       wx.ALL|wx.EXPAND, 5),
586                                      (self.output_sizer, 0,
587                                      wx.EXPAND|wx.TOP|wx.BOTTOM, 5)])
588        self.vertical_l_sizer.AddMany([(self.boxsizer_source, 0, wx.ALL, 10),
589                                       (wx.StaticLine(self), 0, 
590                                       wx.ALL|wx.EXPAND, 5),
591                                  (self.button_sizer, 0,
592                                    wx.EXPAND|wx.TOP|wx.BOTTOM, 5)])
593        self.main_sizer.Add(self.vertical_l_sizer, 0, wx.ALL, 10)
594        # Build image plot layout                     
595        self._layout_image()
596        # Add a vertical static line
597        self.main_sizer.Add( wx.StaticLine(self, -1, (2,2), 
598                            (2,PANEL_HEIGHT * 0.94), style = wx.LI_VERTICAL))
599        # Add the plot to main sizer
600        self.main_sizer.Add(self.vertical_r_spacer, 0, wx.ALL, 10)
601        self.SetSizer(self.main_sizer)
602        self.SetAutoLayout(True)
603
604    def on_close(self, event):
605        """
606        close the window containing this panel
607        """
608        # get ready for other events
609        if event is not None:
610            event.Skip()
611        # Clear the plot
612        if self.image != None:
613            self.image.clf()
614            #self.image.draw()
615        # Close panel
616        self.parent.Close()
617        # reset image
618        self.image = None
619       
620    def on_compute(self, event = None):
621        """
622        Execute the computation of resolution
623        """
624        # Skip event for next event
625        if event != None:
626            event.Skip()
627            msg = "Please Check your input values "
628            msg += "before starting the computation..."
629
630        # message
631        status_type = 'progress' 
632        msg = 'Calculating...'
633        self._status_info(msg, status_type)
634
635        status_type = 'stop'           
636        # Q min max list default
637        qx_min = []   
638        qx_max = [] 
639        qy_min = [] 
640        qy_max = [] 
641        # Get all the values at set to compute
642        #intensity = self.intensity_tcl.GetValue()
643        #self.resolution.set_intensity(float(intensity))
644        wavelength = self.wavelength_tcl.GetValue()
645        self.resolution.set_wavelength(float(wavelength))
646        mass = self.mass_tcl.GetValue()
647        self.resolution.set_neutron_mass(float(mass))
648        wavelength_spread = self.wavelength_spread_tcl.GetValue()
649        self.resolution.set_wavelength_spread(float(wavelength_spread))
650        source_aperture_size = self.source_aperture_tcl.GetValue()
651        source_aperture_size = self._string2list(source_aperture_size)
652        self.resolution.set_source_aperture_size(source_aperture_size)
653        sample_aperture_size = self.sample_aperture_tcl.GetValue()
654        sample_aperture_size = self._string2list(sample_aperture_size)
655        self.resolution.set_sample_aperture_size(sample_aperture_size)
656        source2sample_distance = self.source2sample_distance_tcl.GetValue()
657        source2sample_distance = self._string2list(source2sample_distance)
658        self.resolution.set_source2sample_distance(source2sample_distance)
659        sample2sample_distance = self.sample2sample_distance_tcl.GetValue()
660        sample2sample_distance = self._string2list(sample2sample_distance)
661        self.resolution.set_sample2sample_distance(sample2sample_distance)
662        sample2detector_distance = self.sample2detector_distance_tcl.GetValue()
663        sample2detector_distance = self._string2list(sample2detector_distance)
664        self.resolution.set_sample2detector_distance(sample2detector_distance)
665        detector_size = self.detector_size_tcl.GetValue()
666        detector_size = self._string2list(detector_size)
667        self.resolution.set_detector_size(detector_size)
668        detector_pix_size = self.detector_pix_size_tcl.GetValue()
669        detector_pix_size = self._string2list(detector_pix_size)
670        self.resolution.set_detector_pix_size(detector_pix_size)
671        self.qx = self._string2inputlist(self.qx_tcl.GetValue())
672        self.qy = self._string2inputlist(self.qy_tcl.GetValue())
673       
674        # Find min max of qs
675        xmin = min(self.qx)
676        xmax = max(self.qx)
677        ymin = min(self.qy)
678        ymax = max(self.qy)
679
680        # Validate the q inputs
681        self._validate_q_input(self.qx, self.qy)
682       
683        # Make list of q min max for mapping
684        for length in range(len(self.qx)):
685            qx_min.append(xmin)
686            qx_max.append(xmax)
687        for length in range(len(self.qy)):
688            qy_min.append(ymin)
689            qy_max.append(ymax)
690       
691        # Compute the resolution
692        if self.image != None:
693            #_pylab_helpers.Gcf.set_active(self.fm)
694            # Clear the image before redraw
695            self.image.clf()
696            #self.image.draw()
697            # reset the image
698            self.resolution.reset_image()
699
700        # Compute and get the image plot
701        try:
702            self.image = map(self._map_func, self.qx, self.qy, 
703                             qx_min, qx_max, qy_min, qy_max)[0]
704            msg = "Finished the resolution computation..."
705            self._status_info(msg, status_type)
706        except:
707            msg = "An error occured during the resolution computation."
708            msg += "Please check your inputs..."
709            self._status_info(msg, status_type)
710            raise ValueError, "Invalid Q Input: Out of detector range..."
711       
712        # Draw lines in image before drawing
713        self._draw_lines(self.image)
714        # Draw image
715        self.image.draw()
716        #self.vertical_r_sizer.Layout()
717       
718        # Get and format the sigmas
719        sigma_r = self.format_number(self.resolution.sigma_1)
720        sigma_phi = self.format_number(self.resolution.sigma_2)
721        sigma_1d =  self.format_number(self.resolution.sigma_1d)
722
723        # Set output values
724        self.sigma_r_tcl.SetValue(str(sigma_r))
725        self.sigma_phi_tcl.SetValue(str(sigma_phi))
726        self.sigma_1d_tcl.SetValue(str(sigma_1d))
727       
728    def _draw_lines(self, image = None):
729        """
730        Draw lines in image if applicable
731        : Param image: pylab object
732        """
733        if image == None:
734            return
735       
736        # Get the params from resolution
737        # ploting range
738        qx_min = self.resolution.qx_min
739        qx_max = self.resolution.qx_max
740        qy_min = self.resolution.qy_min
741        qy_max = self.resolution.qy_max
742       
743        # detector range
744        detector_qx_min = self.resolution.detector_qx_min
745        detector_qx_max = self.resolution.detector_qx_max
746        detector_qy_min = self.resolution.detector_qy_min
747        detector_qy_max = self.resolution.detector_qy_max
748       
749        # Draw zero axis lines
750        if qy_min < 0 and qy_max >= 0:
751            image.axhline(linewidth = 1)
752        if qx_min < 0 and qx_max >= 0:
753            image.axvline(linewidth = 1)
754           
755        # Find x and y ratio values to draw the detector outline
756        x_min = fabs(detector_qx_min - qx_min) / (qx_max - qx_min)
757        x_max = fabs(detector_qx_max - qx_min) / (qx_max - qx_min)
758        y_min = fabs(detector_qy_min - qy_min) / (qy_max - qy_min)
759        y_max = fabs(detector_qy_max - qy_min) / (qy_max - qy_min)
760       
761        # Draw Detector outline
762        if detector_qy_min >= qy_min:
763            image.axhline(y = detector_qy_min + 0.0002,
764                               xmin = x_min,
765                               xmax = x_max, 
766                               linewidth = 2, color='r')
767        if detector_qy_max <= qy_max:
768            image.axhline(y = detector_qy_max - 0.0002, 
769                               xmin = x_min, 
770                               xmax = x_max, 
771                               linewidth = 2, color='r')
772        if detector_qx_min >= qx_min:
773            image.axvline(x = detector_qx_min + 0.0002, 
774                               ymin = y_min, 
775                               ymax = y_max, 
776                               linewidth = 2, color='r')
777        if detector_qx_max <= qx_max:
778            image.axvline(x = detector_qx_max - 0.0002, 
779                               ymin = y_min, 
780                               ymax = y_max, 
781                               linewidth = 2, color='r')
782
783    def _map_func(self, qx, qy, qx_min, qx_max, qy_min, qy_max):   
784        """
785        Prepare the Mapping for the computation
786        : params qx, qy, qx_min, qx_max, qy_min, qy_max:
787       
788        : return: image (pylab)
789        """
790        # calculate 2D resolution distribution image
791        image = self.resolution.compute_and_plot(float(qx), float(qy), 
792                                 qx_min, qx_max, qy_min, qy_max, 
793                                 self.det_coordinate)
794        return image
795   
796    def _validate_q_input(self, qx, qy):   
797        """
798        Check if q inputs are valid
799        : params qx:  qx as a list
800        : params qy:  qy as a list
801       
802        : return: True/False
803        """
804        # check qualifications
805        if qx.__class__.__name__ != 'list':
806            return False
807        if qy.__class__.__name__ != 'list' :
808            return False
809        if len(qx) < 1:
810            return False
811        if len(qy) < 1:
812            return False
813        # allow one input
814        if len(qx) == 1 and len(qy) > 1:
815            qx = [qx[0] for ind in range(len(qy))]
816            self.qx = qx
817        if len(qy) == 1 and len(qx) > 1:
818            qy = [qy[0] for ind in range(len(qx))]
819            self.qy = qy
820        # check length
821        if len(qx) != len(qy):
822            return False
823
824        return True 
825     
826    def on_reset(self, event):
827        """
828        Execute the reset
829        """
830        # skip for another event
831        if event != None:
832            event.Skip() 
833        # init resolution_calculator
834        self.resolution = ResolutionCalculator()
835        self.resolution.get_all_instrument_params()
836        # reset all param values
837        self.mass_tcl.SetValue(str(self.resolution.mass))
838        #self.intensity_tcl.SetValue(str(self.resolution.intensity))
839        self.wavelength_tcl.SetValue(str(self.resolution.wavelength))
840        self.wavelength_spread_tcl.SetValue(\
841                                        str(self.resolution.wavelength_spread))
842        source_aperture_value = str(self.resolution.source_aperture_size[0])
843        if len(self.resolution.source_aperture_size)>1:
844            source_aperture_value += ", "
845            source_aperture_value += \
846                str(self.resolution.source_aperture_size[1])
847        self.source_aperture_tcl.SetValue(str(source_aperture_value))
848        sample_aperture_value = str(self.resolution.sample_aperture_size[0])
849        if len(self.resolution.sample_aperture_size)>1:
850            sample_aperture_value += ", "
851            sample_aperture_value += \
852                str(self.resolution.sample_aperture_size[1])
853        self.sample_aperture_tcl.SetValue(sample_aperture_value)
854        source2sample_distance_value = \
855            str(self.resolution.source2sample_distance[0])
856        self.source2sample_distance_tcl.SetValue(source2sample_distance_value)
857        sample2sample_distance_value = \
858            str(self.resolution.sample2sample_distance[0])
859        self.sample2sample_distance_tcl.SetValue(sample2sample_distance_value)
860        sample2detector_distance_value = \
861            str(self.resolution.sample2detector_distance[0])
862        self.sample2detector_distance_tcl.SetValue(\
863                                            sample2detector_distance_value)
864        detector_size_value = str(self.resolution.detector_size[0])
865        if len(self.resolution.detector_size)>1:
866            detector_size_value += ", "
867            detector_size_value += str(self.resolution.detector_size[1])
868        self.detector_size_tcl.SetValue(detector_size_value)
869        detector_pix_size_value = str(self.resolution.detector_pix_size[0])
870        if len(self.resolution.detector_pix_size)>1:
871            detector_pix_size_value += ", "
872            detector_pix_size_value += str(self.resolution.detector_pix_size[1])
873        self.detector_pix_size_tcl.SetValue(detector_pix_size_value)
874        #layout attribute
875        self.hint_sizer = None
876        # reset q inputs
877        self.qx_tcl.SetValue(str(_Q_DEFAULT))
878        self.qy_tcl.SetValue(str(_Q_DEFAULT))
879        # reset sigma outputs
880        self.sigma_r_tcl.SetValue('')
881        self.sigma_phi_tcl.SetValue('')
882        self.sigma_1d_tcl.SetValue('')
883        # reset radio button
884        self.det_coordinate = 'polar'
885        self.r_phi_rb.SetValue(True)
886        # Finally re-compute
887        self.on_compute()
888        # msg on info
889        msg = " Finished the resetting..."
890        self._status_info(msg, 'stop')
891       
892    def format_number(self, value=None):
893        """
894        Return a float in a standardized, human-readable formatted string
895        """
896        try: 
897            value = float(value)
898        except:
899            output = None
900            return output
901
902        output = "%-7.4g" % value
903        return output.lstrip().rstrip() 
904     
905    def _string2list(self, string):
906        """
907        Change NNN, NNN to list,ie. [NNN, NNN] where NNN is a number
908        """
909        new_string = []
910        # check the number of floats
911        try:
912            strg = float(string)
913            new_string.append(strg)
914            #new_string.append(0)
915        except:
916            string_split = string.split(',')
917            if len(string_split) == 2:
918                str_1 = string_split[0]
919                str_2 = string_split[1]
920                new_string.append(float(str_1))
921                new_string.append(float(str_2))
922            elif len(string_split) == 1:
923                str_1 = string_split[0]
924                new_string.append(float(str_1))
925            else:
926                msg = "The numbers must be one or two (separated by ',')..."
927                self._status_info(msg, 'stop')
928                raise RuntimeError, msg
929
930        return new_string
931   
932    def _string2inputlist(self, string):
933        """
934        Change NNN, NNN,... to list,ie. [NNN, NNN,...] where NNN is a number
935       
936        : return new_string: string like list
937        """
938        new_string = []
939        string_split = string.split(',')
940        length = len(string_split)
941        for ind in range(length):
942            try:
943                value = float(string_split[ind])
944                new_string.append(value)
945            except:
946                pass
947       
948        return new_string
949
950    def _on_xy_coordinate(self,event=None):
951        """
952        Set the detector coordinate for sigmas to x-y coordinate
953        """
954        if event != None:
955            event.Skip()       
956        # Set the coordinate in Cartesian       
957        self.det_coordinate = 'cartesian'
958        self.sigma_r_txt.SetLabel('Sigma_x:')
959        self.sigma_phi_txt.SetLabel('Sigma_y:')
960        self._onparamEnter()
961       
962    def _on_rp_coordinate(self,event=None):
963        """
964        Set the detector coordinate for sigmas to polar coordinate
965        """
966        if event != None:
967            event.Skip()       
968        # Set the coordinate in polar           
969        self.det_coordinate = 'polar'
970        self.sigma_r_txt.SetLabel('Sigma_r:   ')
971        self.sigma_phi_txt.SetLabel('Sigma_phi:')
972        self._onparamEnter()
973       
974    def _status_info(self, msg = '', type = "update"):
975        """
976        Status msg
977        """
978        if self.parent.parent != None:
979                wx.PostEvent(self.parent.parent, 
980                             StatusEvent(status = msg, type = type ))
981
982
983    def _onparamEnter(self, event = None):
984        """
985        On Text_enter_callback, perform compute
986        """
987        self.on_compute()
988       
989       
990class ResolutionWindow(wx.Frame):
991    def __init__(self, parent = None, title = "SANS Resolution Estimator",
992                  size=(PANEL_WIDTH * 2, PANEL_HEIGHT), *args, **kwds):
993        kwds['title'] = title
994        kwds['size'] = size
995        wx.Frame.__init__(self, parent=None, *args, **kwds)
996        self.parent = parent
997        self.panel = ResolutionCalculatorPanel(parent=self)
998        self.Centre()
999        self.Show(True)
1000       
1001if __name__ == "__main__": 
1002    app = wx.PySimpleApp()
1003    frame = ResolutionWindow()   
1004    frame.Show(True)
1005    app.MainLoop()     
Note: See TracBrowser for help on using the repository browser.