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

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 3641881 was 9c1f463, checked in by Jae Cho <jhjcho@…>, 14 years ago

fixed conflict w/new data-manager

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