source: sasview/src/sas/sasgui/perspectives/calculator/slit_length_calculator_panel.py @ d788619

magnetic_scattrelease-4.2.2ticket-1009ticket-1094-headlessticket-1242-2d-resolutionticket-1243ticket-1249unittest-saveload
Last change on this file since d788619 was d788619, checked in by krzywon, 6 years ago

Use first data object from list when loading slit length data files.

  • Property mode set to 100644
File size: 11.9 KB
RevLine 
[51f14603]1"""
2This software was developed by the University of Tennessee as part of the
3Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
[49ab5d7]4project funded by the US National Science Foundation.
[51f14603]5
6See the license text in license.txt
7
8copyright 2008, 2009, University of Tennessee
9"""
10
11import wx
12import sys
13import os
14
[d85c194]15from sas.sasgui.guiframe.panel_base import PanelBase
[51f14603]16
[d85c194]17from sas.sasgui.guiframe.events import StatusEvent
[b699768]18from sas.sascalc.calculator.slit_length_calculator import SlitlengthCalculator
[51f14603]19from calculator_widgets import OutputTextCtrl
20from calculator_widgets import InterActiveOutputTextCtrl
[d85c194]21from sas.sasgui.perspectives.calculator import calculator_widgets as widget
22from sas.sasgui.guiframe.documentation_window import DocumentationWindow
[51f14603]23
24_BOX_WIDTH = 76
25#Slit length panel size
26if sys.platform.count("win32") > 0:
[d5419f7f]27    PANEL_TOP = 0
[51f14603]28    PANEL_WIDTH = 500
[491e916]29    PANEL_HEIGHT = 210
[51f14603]30    FONT_VARIANT = 0
31else:
[d5419f7f]32    PANEL_TOP = 60
[51f14603]33    PANEL_WIDTH = 530
34    PANEL_HEIGHT = 210
35    FONT_VARIANT = 1
[49ab5d7]36
[51f14603]37class SlitLengthCalculatorPanel(wx.Panel, PanelBase):
38    """
39        Provides the slit length calculator GUI.
40    """
41    ## Internal nickname for the window, used by the AUI manager
42    window_name = "Slit Size Calculator"
43    ## Name to appear on the window title bar
44    window_caption = "Slit Size Calculator"
45    ## Flag to tell the AUI manager to put this panel in the center pane
46    CENTER_PANE = True
[49ab5d7]47
[51f14603]48    def __init__(self, parent, *args, **kwds):
49        wx.Panel.__init__(self, parent, *args, **kwds)
50        PanelBase.__init__(self)
51        #Font size
52        self.SetWindowVariant(variant=FONT_VARIANT)
53        #thread to read data
54        self.reader = None
55        # Default location
[49ab5d7]56        self._default_save_location = os.getcwd()
[51f14603]57        # Object that receive status event
58        self.parent = parent
59        self._do_layout()
[49ab5d7]60
[51f14603]61    def _define_structure(self):
62        """
63            Define the main sizers building to build this application.
64        """
65        self.main_sizer = wx.BoxSizer(wx.VERTICAL)
[49ab5d7]66        self.box_source = wx.StaticBox(self, -1, str("Slit Size Calculator"))
[51f14603]67        self.boxsizer_source = wx.StaticBoxSizer(self.box_source,
68                                                    wx.VERTICAL)
69        self.data_name_sizer = wx.BoxSizer(wx.HORIZONTAL)
70        self.slit_size_sizer = wx.BoxSizer(wx.HORIZONTAL)
71        self.hint_sizer = wx.BoxSizer(wx.HORIZONTAL)
72        self.button_sizer = wx.BoxSizer(wx.HORIZONTAL)
[49ab5d7]73
[51f14603]74    def _layout_data_name(self):
75        """
76            Fill the sizer containing data's name
77        """
78        data_name_txt = wx.StaticText(self, -1, 'Data: ')
[49ab5d7]79        self.data_name_tcl = OutputTextCtrl(self, -1,
80                                            size=(_BOX_WIDTH * 4, -1))
[51f14603]81        data_hint = "Loaded data"
82        self.data_name_tcl.SetToolTipString(data_hint)
83        #control that triggers importing data
84        id = wx.NewId()
85        self.browse_button = wx.Button(self, id, "Browse")
86        hint_on_browse = "Click on this button to import data in this panel."
87        self.browse_button.SetToolTipString(hint_on_browse)
88        self.Bind(wx.EVT_BUTTON, self.on_load_data, id=id)
89        self.data_name_sizer.AddMany([(data_name_txt, 0, wx.LEFT, 15),
90                                      (self.data_name_tcl, 0, wx.LEFT, 10),
91                                      (self.browse_button, 0, wx.LEFT, 10)])
92    def _layout_slit_size(self):
93        """
94            Fill the sizer containing slit size information
95        """
96        slit_size_txt = wx.StaticText(self, -1, 'Slit Size (FWHM/2): ')
97        self.slit_size_tcl = InterActiveOutputTextCtrl(self, -1,
98                                                       size=(_BOX_WIDTH, -1))
99        slit_size_hint = " Estimated full slit size"
100        self.slit_size_tcl.SetToolTipString(slit_size_hint)
101        slit_size_unit_txt = wx.StaticText(self, -1, 'Unit: ')
[49ab5d7]102        self.slit_size_unit_tcl = OutputTextCtrl(self, -1,
103                                                 size=(_BOX_WIDTH, -1))
[51f14603]104        slit_size_unit_hint = "Full slit size's unit"
105        self.slit_size_unit_tcl.SetToolTipString(slit_size_unit_hint)
106        self.slit_size_sizer.AddMany([(slit_size_txt, 0, wx.LEFT, 15),
107                                      (self.slit_size_tcl, 0, wx.LEFT, 10),
108                                      (slit_size_unit_txt, 0, wx.LEFT, 10),
109                                    (self.slit_size_unit_tcl, 0, wx.LEFT, 10)])
[49ab5d7]110
[51f14603]111    def _layout_hint(self):
112        """
[49ab5d7]113            Fill the sizer containing hint
[51f14603]114        """
115        hint_msg = "This calculation works only for  SAXSess beam profile data."
116        self.hint_txt = wx.StaticText(self, -1, hint_msg)
117        self.hint_sizer.AddMany([(self.hint_txt, 0, wx.LEFT, 15)])
[49ab5d7]118
119    def _layout_button(self):
[51f14603]120        """
121            Do the layout for the button widgets
[49ab5d7]122        """
123        self.bt_close = wx.Button(self, wx.ID_CANCEL, 'Close')
[51f14603]124        self.bt_close.Bind(wx.EVT_BUTTON, self.on_close)
125        self.bt_close.SetToolTipString("Close this window.")
[49ab5d7]126
[491e916]127        id = wx.NewId()
128        self.button_help = wx.Button(self, id, "HELP")
129        self.button_help.SetToolTipString("Help for slit length calculator.")
[49ab5d7]130        self.Bind(wx.EVT_BUTTON, self.on_help, id=id)
[491e916]131
[9654baf]132        self.button_sizer.AddMany([(self.button_help, 0, wx.LEFT, 280),
133                                   (self.bt_close, 0, wx.LEFT, 20)])
[49ab5d7]134
[51f14603]135    def _do_layout(self):
136        """
137            Draw window content
138        """
139        self._define_structure()
140        self._layout_data_name()
141        self._layout_slit_size()
142        self._layout_hint()
143        self._layout_button()
144        self.boxsizer_source.AddMany([(self.data_name_sizer, 0,
[49ab5d7]145                                          wx.EXPAND | wx.TOP | wx.BOTTOM, 5),
[51f14603]146                                   (self.slit_size_sizer, 0,
[49ab5d7]147                                     wx.EXPAND | wx.TOP | wx.BOTTOM, 5),
[51f14603]148                                     (self.hint_sizer, 0,
[49ab5d7]149                                     wx.EXPAND | wx.TOP | wx.BOTTOM, 5)])
[51f14603]150        self.main_sizer.AddMany([(self.boxsizer_source, 0, wx.ALL, 10),
151                                  (self.button_sizer, 0,
[49ab5d7]152                                    wx.EXPAND | wx.TOP | wx.BOTTOM, 5)])
[51f14603]153        self.SetSizer(self.main_sizer)
154        self.SetAutoLayout(True)
[49ab5d7]155
[51f14603]156    def choose_data_file(self, location=None):
157        path = None
158        filename = ''
[235f514]159        if location is None:
[51f14603]160            location = os.getcwd()
[49ab5d7]161
162        wildcard = "SAXSess Data 1D (*.DAT, *.dat)|*.DAT"
163
[51f14603]164        dlg = wx.FileDialog(self, "Choose a file", location,
165                            "", wildcard, wx.OPEN)
166        if dlg.ShowModal() == wx.ID_OK:
167            path = dlg.GetPath()
168            filename = os.path.basename(path)
169        dlg.Destroy()
[49ab5d7]170
[51f14603]171        return path
172
[49ab5d7]173    def on_help(self, event):
[491e916]174        """
175        Bring up the slit length calculator Documentation whenever
[49ab5d7]176        the HELP button is clicked.
177
[491e916]178        Calls DocumentationWindow with the path of the location within the
[49ab5d7]179        documentation tree (after /doc/ ....".  Note that when using old
180        versions of Wx (before 2.9) and thus not the release version of
181        installers, the help comes up at the top level of the file as
[491e916]182        webbrowser does not pass anything past the # to the browser when it is
183        running "file:///...."
[49ab5d7]184
[491e916]185    :param evt: Triggers on clicking the help button
186    """
[49ab5d7]187
[d0248bd]188        _TreeLocation = "user/sasgui/perspectives/calculator/"
189        _TreeLocation += "slit_calculator_help.html"
[3db44fb]190        _doc_viewer = DocumentationWindow(self, -1, _TreeLocation, "",
191                                          "Slit Length Calculator Help")
[491e916]192
[51f14603]193    def on_close(self, event):
194        """
195            close the window containing this panel
196        """
197        self.parent.Close()
[49ab5d7]198
[51f14603]199    def on_load_data(self, event):
200        """
201            Open a file dialog to allow the user to select a given file.
202            The user is only allow to load file with extension .DAT or .dat.
203            Display the slit size corresponding to the loaded data.
204        """
205        path = self.choose_data_file(location=self._default_save_location)
[49ab5d7]206
[51f14603]207        if path is None:
[49ab5d7]208            return
[51f14603]209        self._default_save_location = path
210        try:
211            #Load data
212            from load_thread import DataReader
213            ## If a thread is already started, stop it
214            if self.reader is not None and self.reader.isrunning():
215                self.reader.stop()
216            if self.parent.parent is not None:
[49ab5d7]217                wx.PostEvent(self.parent.parent,
[51f14603]218                                StatusEvent(status="Loading...",
219                                type="progress"))
220            self.reader = DataReader(path=path,
221                                    completefn=self.complete_loading,
222                                    updatefn=self.load_update)
223            self.reader.queue()
224            self.load_update()
225        except:
226            if self.parent.parent is None:
[49ab5d7]227                return
[51f14603]228            msg = "Slit Length Calculator: %s" % (sys.exc_value)
229            wx.PostEvent(self.parent.parent,
230                          StatusEvent(status=msg, type='stop'))
[49ab5d7]231            return
232
[51f14603]233    def load_update(self):
234        """
235        print update on the status bar
236        """
237        if self.parent.parent is None:
[49ab5d7]238                return
[51f14603]239        if self.reader.isrunning():
240            type = "progress"
241        else:
242            type = "stop"
243        wx.PostEvent(self.parent.parent, StatusEvent(status="",
244                                                  type=type))
[49ab5d7]245
[51f14603]246    def complete_loading(self, data=None, filename=''):
247        """
248            Complete the loading and compute the slit size
249        """
[d788619]250        if isinstance(data, list):
251            data = data[0]
[51f14603]252        if data is None or data.__class__.__name__ == 'Data2D':
253            if self.parent.parent is None:
[49ab5d7]254                return
[51f14603]255            msg = "Slit Length cannot be computed for 2D Data"
[49ab5d7]256            wx.PostEvent(self.parent.parent,
[51f14603]257                         StatusEvent(status=msg, type='stop'))
[49ab5d7]258            return
[51f14603]259        self.data_name_tcl.SetValue(str(data.filename))
260        #compute the slit size
261        try:
262            x = data.x
263            y = data.y
264            if x == [] or  x is None or y == [] or y is None:
265                msg = "The current data is empty please check x and y"
266                raise ValueError, msg
267            slit_length_calculator = SlitlengthCalculator()
268            slit_length_calculator.set_data(x=x, y=y)
269            slit_length = slit_length_calculator.calculate_slit_length()
270        except:
271            if self.parent.parent is None:
[49ab5d7]272                return
[51f14603]273            msg = "Slit Size Calculator: %s" % (sys.exc_value)
274            wx.PostEvent(self.parent.parent,
275                          StatusEvent(status=msg, type='stop'))
[49ab5d7]276            return
[51f14603]277        self.slit_size_tcl.SetValue(str(slit_length))
278        #Display unit
279        self.slit_size_unit_tcl.SetValue('[Unknown]')
280        if self.parent.parent is None:
[49ab5d7]281            return
[51f14603]282        msg = "Load Complete"
283        wx.PostEvent(self.parent.parent, StatusEvent(status=msg, type='stop'))
[49ab5d7]284
285
[51f14603]286class SlitLengthCalculatorWindow(widget.CHILD_FRAME):
287    """
288    """
289    def __init__(self, parent=None, manager=None, title="Slit Size Calculator",
[49ab5d7]290                size=(PANEL_WIDTH, PANEL_HEIGHT), *args, **kwds):
[51f14603]291        """
292        """
[49ab5d7]293        kwds['size'] = size
294        kwds['title'] = title
[51f14603]295        widget.CHILD_FRAME.__init__(self, parent, *args, **kwds)
296        self.parent = parent
297        self.manager = manager
298        self.panel = SlitLengthCalculatorPanel(parent=self)
299        self.Bind(wx.EVT_CLOSE, self.on_close)
[d5419f7f]300        self.SetPosition((wx.LEFT, PANEL_TOP))
[51f14603]301        self.Show(True)
302
303    def on_close(self, event):
304        """
305        Close event
306        """
[7432acb]307        if self.manager is not None:
[51f14603]308            self.manager.cal_slit_frame = None
309        self.Destroy()
[49ab5d7]310
311if __name__ == "__main__":
[51f14603]312    app = wx.PySimpleApp()
313    widget.CHILD_FRAME = wx.Frame
[49ab5d7]314    frame = SlitLengthCalculatorWindow()
[51f14603]315    frame.Show(True)
[49ab5d7]316    app.MainLoop()
Note: See TracBrowser for help on using the repository browser.