source: sasview/invariantview/src/sans/perspectives/invariant/invariant.py @ 657490af

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 657490af was 18476d6, checked in by Jae Cho <jhjcho@…>, 13 years ago

dlg destroy

  • Property mode set to 100644
File size: 14.3 KB
Line 
1
2
3
4################################################################################
5#This software was developed by the University of Tennessee as part of the
6#Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
7#project funded by the US National Science Foundation.
8#
9#See the license text in license.txt
10#
11#copyright 2009, University of Tennessee
12################################################################################
13
14
15import sys
16import wx
17import copy
18import logging
19
20from sans.guiframe.dataFitting import Data1D
21from sans.guiframe.events import NewPlotEvent
22from sans.guiframe.events import StatusEvent
23from sans.guiframe.gui_style import GUIFRAME_ID
24from .invariant_state import Reader as reader
25from sans.dataloader.loader import Loader
26from .invariant_panel import InvariantPanel
27from sans.guiframe.plugin_base import PluginBase
28
29class Plugin(PluginBase):
30    """
31    This class defines the interface for invariant Plugin class
32    that can be used by the gui_manager.       
33    """
34   
35    def __init__(self, standalone=False):
36        PluginBase.__init__(self, name="Invariant", standalone=standalone)
37       
38        #dictionary containing data name and error on dy of that data
39        self.err_dy = {}
40       
41        #default state objects
42        self.state_reader = None 
43        self._extensions = '.inv'
44        self.temp_state = None 
45        self.__data = None 
46       
47        # Log startup
48        logging.info("Invariant plug-in started")
49       
50    def help(self, evt):
51        """
52        Show a general help dialog.
53        """
54        from help_panel import  HelpWindow
55        frame = HelpWindow(None, -1) 
56        if hasattr(frame, "IsIconized"):
57            if not frame.IsIconized():
58                try:
59                    icon = self.parent.GetIcon()
60                    frame.SetIcon(icon)
61                except:
62                    pass 
63        frame.Show(True)
64       
65    def get_data(self):
66        """
67        """
68        return self.__data
69   
70    def get_panels(self, parent):
71        """
72        Create and return the list of wx.Panels for your plug-in.
73        Define the plug-in perspective.
74       
75        Panels should inherit from DefaultPanel defined below,
76        or should present the same interface. They must define
77        "window_caption" and "window_name".
78       
79        :param parent: parent window
80       
81        :return: list of panels
82        """
83        ## Save a reference to the parent
84        self.parent = parent
85        self.invariant_panel = InvariantPanel(parent=self.parent)
86        self.invariant_panel.set_manager(manager=self)
87        self.perspective.append(self.invariant_panel.window_name) 
88        #Create reader when fitting panel are created
89        self.state_reader = reader(self.set_state)   
90        #append that reader to list of available reader
91        loader = Loader()
92        loader.associate_file_reader(".inv", self.state_reader)
93        #loader.associate_file_reader(".svs", self.state_reader)
94        # Return the list of panels
95        return [self.invariant_panel]
96 
97    def get_context_menu(self, plotpanel=None):
98        """
99        This method is optional.
100   
101        When the context menu of a plot is rendered, the
102        get_context_menu method will be called to give you a
103        chance to add a menu item to the context menu.
104       
105        A ref to a Graph object is passed so that you can
106        investigate the plot content and decide whether you
107        need to add items to the context menu. 
108       
109        This method returns a list of menu items.
110        Each item is itself a list defining the text to
111        appear in the menu, a tool-tip help text, and a
112        call-back method.
113       
114        :param graph: the Graph object to which we attach the context menu
115       
116        :return: a list of menu items with call-back function
117        """
118        graph = plotpanel.graph
119        invariant_option = "Compute invariant"
120        invariant_hint = "Will displays the invariant panel for"
121        invariant_hint += " further computation"
122       
123        if graph.selected_plottable not in plotpanel.plots:
124            return []
125        data = plotpanel.plots[graph.selected_plottable]
126       
127        if issubclass(data.__class__, Data1D):
128           if data.name != "$I_{obs}(q)$" and  data.name != " $P_{fit}(r)$":
129               return [[invariant_option, invariant_hint, 
130                                        self._compute_invariant]]
131        return []
132
133    def _compute_invariant(self, event):   
134        """
135        Open the invariant panel to invariant computation
136        """
137        self.panel = event.GetEventObject()
138        Plugin.on_perspective(self, event=event)
139        id = self.panel.graph.selected_plottable
140        data = self.panel.plots[self.panel.graph.selected_plottable]
141        if data is None:
142            return
143        if not issubclass(data.__class__, Data1D):
144            name = data.__class__.__name__
145            msg = "Invariant use only Data1D got: [%s] " % str(name)
146            raise ValueError, msg
147        self.compute_helper(data=data)
148               
149    def set_data(self, data_list=None):
150        """
151        receive a list of data and compute invariant
152        """
153        msg = ""
154        data = None
155        if data_list is None:
156            data_list = []
157        if len(data_list) >= 1:
158            if len(data_list) == 1:
159                data = data_list[0]
160            else:
161                data_1d_list = []
162                data_2d_list = []
163                error_msg = ""
164                # separate data into data1d and data2d list
165                for data in data_list:
166                    if data is not None:
167                        if issubclass(data.__class__, Data1D):
168                            data_1d_list.append(data)
169                        else:
170                            error_msg += " %s  type %s \n" % (str(data.name),
171                                             str(data.__class__.__name__))
172                            data_2d_list.append(data)
173                if len(data_2d_list) > 0:
174                    msg = "Invariant does not support the following data types:\n"
175                    msg += error_msg
176                if len(data_1d_list) == 0:
177                    wx.PostEvent(self.parent, 
178                    StatusEvent(status=msg, info='error'))
179                    return
180                msg += "Invariant panel does not allow multiple data!\n"
181                msg += "Please select one.\n"
182                from invariant_widgets import DataDialog
183                dlg = DataDialog(data_list=data_1d_list, text=msg)
184                if dlg.ShowModal() == wx.ID_OK:
185                    data = dlg.get_data()
186                dlg.Destroy()
187            if data is None:
188                msg += "invariant receives no data. \n"
189                wx.PostEvent(self.parent, 
190                     StatusEvent(status=msg, info='error'))
191                return
192            if not issubclass(data.__class__, Data1D):
193                 msg += "invariant cannot be computed for data of "
194                 msg += "type %s\n" % (data.__class__.__name__)
195                 wx.PostEvent(self.parent, 
196                     StatusEvent(status=msg, info='error'))
197                 return
198            else:
199                wx.PostEvent(self.parent, NewPlotEvent(plot=data,
200                                           title=data.title))
201                try:
202                    self.compute_helper(data)
203                except:
204                    msg = "Invariant Set_data: " + str(sys.exc_value)
205                    wx.PostEvent(self.parent, StatusEvent(status=msg,
206                                                                info="error"))
207        else:   
208            msg = "invariant cannot be computed for data of "
209            msg += "type %s" % (data.__class__.__name__)
210            wx.PostEvent(self.parent, 
211                     StatusEvent(status=msg, info='error'))
212    def delete_data(self, data_id):
213        """
214        """
215        if self.__data is None:
216            return
217        for id in data_id:
218            if id == self.__data.id:
219                self.clear_panel()
220               
221    def clear_panel(self):
222        """
223        """
224        self.invariant_panel.clear_panel()
225       
226    def compute_helper(self, data):
227        """
228        """
229        if data is None:
230            return 
231        # set current data if not it's a state data
232        if not self.invariant_panel.is_state_data:
233            # Store reference to data
234            self.__data = data
235            # Set the data set to be user for invariant calculation
236            self.invariant_panel.set_data(data=data)
237           
238    def save_file(self, filepath, state=None):
239        """
240        Save data in provided state object.
241               
242        :param filepath: path of file to write to
243        :param state: invariant state
244        """     
245        # Write the state to file
246        # First, check that the data is of the right type
247        current_plottable = self.__data
248
249        if issubclass(current_plottable.__class__, Data1D):
250            self.state_reader.write(filepath, current_plottable, state)
251        else:
252            msg = "invariant.save_file: the data being saved is"
253            msg += " not a sans.dataloader.data_info.Data1D object" 
254            raise RuntimeError, msg
255
256    def set_state(self, state=None, datainfo=None):   
257        """
258        Call-back method for the state reader.
259        This method is called when a .inv/.svs file is loaded.
260       
261        :param state: State object
262        """
263        self.temp_state = None
264        try:
265            if datainfo.__class__.__name__ == 'list':
266                data = datainfo[0]
267            else:
268                data = datainfo
269            if data is None:
270                msg = "invariant.set_state: datainfo parameter cannot"
271                msg += " be None in standalone mode"
272                raise RuntimeError, msg
273            # Make sure the user sees the invariant panel after loading
274            #self.parent.set_perspective(self.perspective)
275            self.on_perspective(event=None)
276            name = data.meta_data['invstate'].file
277            data.meta_data['invstate'].file = name
278            data.name = name
279            data.filename = name
280
281            data = self.parent.create_gui_data(data,None)
282            self.__data = data
283            wx.PostEvent(self.parent, NewPlotEvent(plot=self.__data,
284                                        reset=True, title=self.__data.title))
285            data_dict = {self.__data.id:self.__data}
286            self.parent.add_data(data_list=data_dict)
287            # set state
288            self.invariant_panel.is_state_data = True
289           
290            # Load the invariant states
291            self.temp_state = state
292            # Requires to have self.__data and self.temp_state  first.
293            self.on_set_state_helper(None)
294
295        except: 
296            logging.error("invariant.set_state: %s" % sys.exc_value)
297           
298    def on_set_state_helper(self, event=None):
299        """
300        Set the state when called by EVT_STATE_UPDATE event from guiframe
301        after a .inv/.svs file is loaded
302        """
303        self.invariant_panel.set_state(state=self.temp_state,
304                                       data=self.__data)
305        self.temp_state = None
306       
307       
308    def plot_theory(self, data=None, name=None):
309        """
310        Receive a data set and post a NewPlotEvent to parent.
311       
312        :param data: extrapolated data to be plotted
313        :param name: Data's name to use for the legend
314        """
315        #import copy
316        if data is None:
317            id = str(self.__data.id) + name
318            group_id = self.__data.group_id
319            wx.PostEvent(self.parent, NewPlotEvent(id=id,
320                                               group_id=group_id,
321                                               action='Remove'))
322            return
323   
324        new_plot = Data1D(x=[], y=[], dy=None)
325        new_plot.symbol = GUIFRAME_ID.CURVE_SYMBOL_NUM
326        scale = self.invariant_panel.get_scale()
327        background = self.invariant_panel.get_background()
328       
329        if scale != 0:
330            # Put back the sacle and bkg for plotting
331            data.y = (data.y + background)/scale
332            new_plot = Data1D(x=data.x, y=data.y, dy=None)
333            new_plot.symbol = GUIFRAME_ID.CURVE_SYMBOL_NUM
334        else:
335            msg = "Scale can not be zero."
336            raise ValueError, msg
337        if len(new_plot.x)== 0 :
338            return
339       
340        new_plot.name = name
341        new_plot.xaxis(self.__data._xaxis, self.__data._xunit)
342        new_plot.yaxis(self.__data._yaxis, self.__data._yunit)
343        new_plot.group_id = self.__data.group_id
344        new_plot.id = str(self.__data.id) + name
345        new_plot.title = self.__data.title
346        # Save theory_data in a state
347        if data != None:
348            name_head = name.split('-')
349            if name_head[0] == 'Low':
350                self.invariant_panel.state.theory_lowQ = copy.deepcopy(new_plot)
351            elif name_head[0] == 'High':
352                self.invariant_panel.state.theory_highQ =copy.deepcopy(new_plot)
353           
354        self.parent.update_theory(data_id=self.__data.id, theory=new_plot)
355        wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot,
356                                               title=self.__data.title))
357       
358    def plot_data(self, scale, background):
359        """
360        replot the current data if the user enters a new scale or background
361        """
362        new_plot = scale * self.__data - background
363        new_plot.name = self.__data.name
364        new_plot.group_id = self.__data.group_id
365        new_plot.id = self.__data.id
366        new_plot.title = self.__data.title
367       
368        # Save data in a state: but seems to never happen
369        if new_plot != None:
370            self.invariant_panel.state.data = copy.deepcopy(new_plot)
371        wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot,
372                                               title=new_plot.title))
373       
Note: See TracBrowser for help on using the repository browser.