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

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

working on loading data to invariant panel

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