source: sasview/invariantview/perspectives/invariant/invariant.py @ 18ec684

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

add bookmark button to toolbar

  • Property mode set to 100644
File size: 13.7 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 clear_panel(self):
218        self.invariant_panel.clear_panel()
219       
220    def compute_helper(self, data):
221        """
222        """
223        if data is None:
224            return 
225        # set current data if not it's a state data
226        if not self.invariant_panel.is_state_data:
227            # Store reference to data
228            self.__data = data
229            # Set the data set to be user for invariant calculation
230            self.invariant_panel.set_data(data=data)
231           
232    def save_file(self, filepath, state=None):
233        """
234        Save data in provided state object.
235               
236        :param filepath: path of file to write to
237        :param state: invariant state
238        """     
239        # Write the state to file
240        # First, check that the data is of the right type
241        current_plottable = self.__data
242
243        if issubclass(current_plottable.__class__, LoaderData1D):
244            self.state_reader.write(filepath, current_plottable, state)
245        else:
246            msg = "invariant.save_file: the data being saved is"
247            msg += " not a DataLoader.data_info.Data1D object" 
248            raise RuntimeError, msg
249
250    def set_state(self, state=None, datainfo=None):   
251        """
252        Call-back method for the state reader.
253        This method is called when a .inv/.svs file is loaded.
254       
255        :param state: State object
256        """
257        self.temp_state = None
258        try:
259            if datainfo.__class__.__name__ == 'list':
260                data = datainfo[0]
261            else:
262                data = datainfo
263            if data is None:
264                msg = "invariant.set_state: datainfo parameter cannot"
265                msg += " be None in standalone mode"
266                raise RuntimeError, msg
267           
268            name = data.meta_data['invstate'].file
269            data.meta_data['invstate'].file = name
270            data.name = name
271            data.filename = name
272            data = self.parent.create_gui_data(data,None)
273            #self.__data = datainfo
274            #self.__data.group_id = data.filename
275            #self.__data.id = datainfo.filename
276            self.__data = data
277            wx.PostEvent(self.parent, NewPlotEvent(plot=self.__data,
278                                        reset=True, title=self.__data.title))
279            #temp_state = copy.deepcopy(state)
280            #temp_state = self.state_reader.get_state()
281            # set state
282            self.invariant_panel.is_state_data = True
283           
284            # Make sure the user sees the invariant panel after loading
285            #self.parent.set_perspective(self.perspective)
286            self.on_perspective(event=None)
287            # Load the invariant states
288            self.temp_state = state
289            self.invariant_panel.set_state(state=state,data=self.__data)         
290           
291        except: 
292            logging.error("invariant.set_state: %s" % sys.exc_value)
293           
294    def on_set_state_helper(self, event=None):
295        """
296        Set the state when called by EVT_STATE_UPDATE event from guiframe
297        after a .inv/.svs file is loaded
298        """
299        self.invariant_panel.set_state(state=self.temp_state,
300                                       data=self.__data)
301        self.temp_state = None
302       
303       
304    def plot_theory(self, data=None, name=None):
305        """
306        Receive a data set and post a NewPlotEvent to parent.
307       
308        :param data: extrapolated data to be plotted
309        :param name: Data's name to use for the legend
310        """
311        #import copy
312        if data is None:
313            new_plot = Theory1D(x=[], y=[], dy=None)
314        else:
315            scale = self.invariant_panel.get_scale()
316            background = self.invariant_panel.get_background()
317           
318            if scale != 0:
319                # Put back the sacle and bkg for plotting
320                data.y = (data.y + background)/scale
321                new_plot = Theory1D(x=data.x, y=data.y, dy=None)
322            else:
323                msg = "Scale can not be zero."
324                raise ValueError, msg
325
326        new_plot.name = name
327        new_plot.xaxis(self.__data._xaxis, self.__data._xunit)
328        new_plot.yaxis(self.__data._yaxis, self.__data._yunit)
329        new_plot.group_id = self.__data.group_id
330        new_plot.id = self.__data.id + name
331        new_plot.title = self.__data.title
332        # Save theory_data in a state
333        if data != None:
334            name_head = name.split('-')
335            if name_head[0] == 'Low':
336                self.invariant_panel.state.theory_lowQ = copy.deepcopy(new_plot)
337            elif name_head[0] == 'High':
338                self.invariant_panel.state.theory_highQ =copy.deepcopy(new_plot)
339
340        wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot,
341                                               title=self.__data.title))
342       
343    def plot_data(self, scale, background):
344        """
345        replot the current data if the user enters a new scale or background
346        """
347        new_plot = scale * self.__data - background
348        new_plot.name = self.__data.name
349        new_plot.group_id = self.__data.group_id
350        new_plot.id = self.__data.id
351        new_plot.title = self.__data.title
352       
353        # Save data in a state: but seems to never happen
354        if new_plot != None:
355            self.invariant_panel.state.data = copy.deepcopy(new_plot)
356        wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot,
357                                               title=new_plot.title))
358       
Note: See TracBrowser for help on using the repository browser.