source: sasview/invariantview/perspectives/invariant/invariant.py @ 8cd029b

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 8cd029b was 75fbd17, checked in by Gervaise Alina <gervyh@…>, 14 years ago

working on save state

  • Property mode set to 100644
File size: 13.6 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
29#from 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                    wx.PostEvent(self.parent, NewPlotEvent(plot=data_list[0],
198                                               title=data_list[0].title))
199                    self.compute_helper(data_list[0])
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                wx.PostEvent(self.parent, NewPlotEvent(plot=data_list[0],
208                                               title=data_list[0].title))
209                self.compute_helper(data_list[0])
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=None, 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            if datainfo.__class__.__name__ == 'list':
257                data = datainfo[0]
258            if data is None:
259                msg = "invariant.set_state: datainfo parameter cannot"
260                msg += " be None in standalone mode"
261                raise RuntimeError, msg
262           
263            name = data.meta_data['invstate'].file
264            data.meta_data['invstate'].file = name
265            data.name = name
266            data.filename = name
267            #datainfo = self.parent.create_gui_data(datainfo,None)
268            #self.__data = datainfo
269            #self.__data.group_id = data.filename
270            #self.__data.id = datainfo.filename
271            self.__data = data
272            wx.PostEvent(self.parent, NewPlotEvent(plot=self.__data,
273                                        reset=True, title=self.__data.title))
274            #temp_state = copy.deepcopy(state)
275            temp_state = self.state_reader.get_state()
276            # set state
277            self.invariant_panel.is_state_data = True
278           
279            # Make sure the user sees the invariant panel after loading
280            #self.parent.set_perspective(self.perspective)
281            self.on_perspective(event=None)
282            # Load the invariant states
283            self.temp_state = temp_state
284            self.invariant_panel.set_state(state=temp_state,data=self.__data)         
285           
286        except: 
287            logging.error("invariant.set_state: %s" % sys.exc_value)
288           
289    def on_set_state_helper(self, event=None):
290        """
291        Set the state when called by EVT_STATE_UPDATE event from guiframe
292        after a .inv/.svs file is loaded
293        """
294        self.invariant_panel.set_state(state=self.temp_state,
295                                       data=self.__data)
296        self.temp_state = None
297       
298       
299    def plot_theory(self, data=None, name=None):
300        """
301        Receive a data set and post a NewPlotEvent to parent.
302       
303        :param data: extrapolated data to be plotted
304        :param name: Data's name to use for the legend
305        """
306        #import copy
307        if data is None:
308            new_plot = Theory1D(x=[], y=[], dy=None)
309        else:
310            scale = self.invariant_panel.get_scale()
311            background = self.invariant_panel.get_background()
312           
313            if scale != 0:
314                # Put back the sacle and bkg for plotting
315                data.y = (data.y + background)/scale
316                new_plot = Theory1D(x=data.x, y=data.y, dy=None)
317            else:
318                msg = "Scale can not be zero."
319                raise ValueError, msg
320
321        new_plot.name = name
322        new_plot.xaxis(self.__data._xaxis, self.__data._xunit)
323        new_plot.yaxis(self.__data._yaxis, self.__data._yunit)
324        new_plot.group_id = self.__data.group_id
325        new_plot.id = self.__data.id + name
326        new_plot.title = self.__data.title
327        # Save theory_data in a state
328        if data != None:
329            name_head = name.split('-')
330            if name_head[0] == 'Low':
331                self.invariant_panel.state.theory_lowQ = copy.deepcopy(new_plot)
332            elif name_head[0] == 'High':
333                self.invariant_panel.state.theory_highQ =copy.deepcopy(new_plot)
334
335        wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot,
336                                               title=self.__data.title))
337       
338    def plot_data(self, scale, background):
339        """
340        replot the current data if the user enters a new scale or background
341        """
342        new_plot = scale * self.__data - background
343        new_plot.name = self.__data.name
344        new_plot.group_id = self.__data.group_id
345        new_plot.id = self.__data.id
346        new_plot.title = self.__data.title
347       
348        # Save data in a state: but seems to never happen
349        if new_plot != None:
350            self.invariant_panel.state.data = copy.deepcopy(new_plot)
351        wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot,
352                                               title=new_plot.title))
353       
Note: See TracBrowser for help on using the repository browser.