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

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

working on invariant save state

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