source: sasview/invariantview/perspectives/invariant/invariant.py @ 5b03122

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 5b03122 was f24925ab, checked in by Jae Cho <jhjcho@…>, 14 years ago

made better gui flow when loading data or state file

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