source: sasview/invariantview/perspectives/invariant/invariant.py @ df7046f

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 df7046f was cacbd7d, checked in by Gervaise Alina <gervyh@…>, 14 years ago

work on loading multplie data to invariant panel

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