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

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

make invariant plugin inheriting from pluginbase in guiframe

  • Property mode set to 100644
File size: 11.4 KB
RevLine 
[c128284]1
2
[d7a39e5]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################################################################################
[d65a00a]13
14
[4e1c362]15import sys
[272d91e]16import wx
[4e1c362]17import copy
[4a2b054]18import logging
[d65a00a]19
[c128284]20
21from DataLoader.data_info import Data1D as LoaderData1D
[4a2b054]22from sans.guiframe.dataFitting import Theory1D
23from sans.guiframe.dataFitting import Data1D
[c128284]24
[4a2b054]25from sans.guicomm.events import NewPlotEvent
[c128284]26from sans.guicomm.events import ERR_DATA
[4e1c362]27from invariant_state import Reader as reader
28from DataLoader.loader import Loader
29from invariant_panel import InvariantPanel
[7a07864]30from sans.guicomm.events import EVT_INVSTATE_UPDATE
[d7a39e5]31
[d65a00a]32from sans.guiframe.plugin_base import PluginBase
33
34class Plugin(PluginBase):
[c128284]35    """
[d7a39e5]36    This class defines the interface for invariant Plugin class
[4e1c362]37    that can be used by the gui_manager.       
[c128284]38    """
39   
40    def __init__(self, standalone=False):
[d65a00a]41        PluginBase.__init__(self, name="Invariant", standalone=standalone)
[c128284]42       
43        #dictionary containing data name and error on dy of that data
44        self.err_dy = {}
[d65a00a]45       
[4da35bc]46        #default state objects
47        self.state_reader = None 
48        self.temp_state = None 
49        self.__data = None 
[d65a00a]50       
[4e1c362]51        # Log startup
52        logging.info("Invariant plug-in started")
[c128284]53       
[d65a00a]54 
[f29a433]55    def help(self, evt):
56        """
[d7a39e5]57        Show a general help dialog.
[f29a433]58        """
59        from help_panel import  HelpWindow
60        frame = HelpWindow(None, -1)   
61        frame.Show(True)
62       
[c128284]63    def get_panels(self, parent):
64        """
[d7a39e5]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
[c128284]75        """
76        ## Save a reference to the parent
77        self.parent = parent
78        #add error back to the data
[272d91e]79        self.parent.Bind(ERR_DATA, self._on_data_error)
[7a07864]80        self.parent.Bind(EVT_INVSTATE_UPDATE, self.on_set_state_helper)
[4e1c362]81       
[c128284]82        self.invariant_panel = InvariantPanel(parent=self.parent)
83        self.invariant_panel.set_manager(manager=self)
[4e1c362]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)
[b35d3d1]90        loader.associate_file_reader(".svs", self.state_reader)
[c128284]91        # Return the list of panels
92        return [self.invariant_panel]
[d65a00a]93 
[c128284]94    def get_context_menu(self, graph=None):
95        """
[d7a39e5]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
[c128284]114        """
115        self.graph = graph
116        invariant_option = "Compute invariant"
[4a2b054]117        invariant_hint = "Will displays the invariant panel for"
[a1f2002]118        invariant_hint += " futher computation"
[c128284]119       
120        for item in self.graph.plottables:
[518d35d]121            if item.name == graph.selected_plottable :
[a1f2002]122                if issubclass(item.__class__, LoaderData1D):
[518d35d]123           
[4a2b054]124                    if item.name != "$I_{obs}(q)$" and \
125                        item.name != " $P_{fit}(r)$":
[518d35d]126                        if hasattr(item, "group_id"):
127                            return [[invariant_option, 
[4a2b054]128                                        invariant_hint, 
129                                        self._compute_invariant]]
[c128284]130        return []   
131
132    def copy_data(self, item, dy=None):
133        """
[d7a39e5]134        receive a data 1D and the list of errors on dy
135        and create a new data1D data
[c128284]136        """
137        id = None
138        if hasattr(item,"id"):
[6d55d81]139            id = item.id
[c128284]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
[4e1c362]146       
[c128284]147        ## allow to highlight data when plotted
[6d55d81]148        data.interactive = item.interactive
[c128284]149        ## when 2 data have the same id override the 1 st plotted
150        data.id = id
151        data.group_id = item.group_id
152        return data
153   
154    def _on_data_error(self, event):
155        """
[d7a39e5]156        receives and event from plotting plu-gins to store the data name and
157        their errors of y coordinates for 1Data hide and show error
[c128284]158        """
159        self.err_dy = event.err_dy
160       
161    def _compute_invariant(self, event):   
162        """
[d7a39e5]163        Open the invariant panel to invariant computation
[c128284]164        """
165        self.panel = event.GetEventObject()
[4a2b054]166        Plugin.on_perspective(self, event=event)
[c128284]167        for plottable in self.panel.graph.plottables:
168            if plottable.name == self.panel.graph.selected_plottable:
[4a2b054]169                ## put the errors values back to the model if the errors
170                ## were hiden before sending them to the fit engine
171                if len(self.err_dy) > 0:
[c128284]172                    dy = plottable.dy
173                    if plottable.name in  self.err_dy.iterkeys():
174                        dy = self.err_dy[plottable.name]
175                    data = self.copy_data(plottable, dy)
176                else:
177                    data = plottable
[343fdb6]178                self.compute_helper(data=data)
[4e1c362]179               
[343fdb6]180    def compute_helper(self, data):
181        """
182        """
183        if data is None:
184            return 
[f24925ab]185        # set current data if not it's a state data
186        if not self.invariant_panel.is_state_data:
[9c1f463]187            # Store reference to data
188            self.__data = data
189            # Set the data set to be user for invariant calculation
[210ff4f]190            self.invariant_panel.set_data(data=data)
[343fdb6]191       
[4e1c362]192    def save_file(self, filepath, state=None):
193        """
194        Save data in provided state object.
195               
196        :param filepath: path of file to write to
197        :param state: invariant state
198        """     
199        # Write the state to file
200        # First, check that the data is of the right type
201        current_plottable = self.__data
202
203        if issubclass(current_plottable.__class__, LoaderData1D):
204            self.state_reader.write(filepath, current_plottable, state)
205        else:
[4a2b054]206            msg = "invariant.save_file: the data being saved is"
207            msg += " not a DataLoader.data_info.Data1D object" 
208            raise RuntimeError, msg
[4e1c362]209
210    def set_state(self, state, datainfo=None):   
211        """
212        Call-back method for the state reader.
[9b18735]213        This method is called when a .inv/.svs file is loaded.
[4e1c362]214       
215        :param state: State object
216        """
[4da35bc]217        self.temp_state = None
[4e1c362]218        try:
[9b18735]219           
[4e1c362]220            if datainfo is None:
[4a2b054]221                msg = "invariant.set_state: datainfo parameter cannot"
222                msg += " be None in standalone mode"
223                raise RuntimeError, msg
[9b18735]224           
[4a2b054]225            name = datainfo.meta_data['invstate'].file
226            datainfo.meta_data['invstate'].file = name
227            datainfo.name = name
228            datainfo.filename = name
[4e1c362]229            self.__data = datainfo
230            self.__data.group_id = datainfo.filename
231            self.__data.id = datainfo.filename
[f24925ab]232
[4e1c362]233            temp_state = copy.deepcopy(state)
[f24925ab]234            # set state
235            self.invariant_panel.is_state_data = True
[9b18735]236           
[4e1c362]237            # Make sure the user sees the invariant panel after loading
238            self.parent.set_perspective(self.perspective)
[9b18735]239            # Load the invariant states
[4da35bc]240            self.temp_state = temp_state
241            #self.invariant_panel.set_state(state=temp_state,data=self.__data)         
[9b18735]242           
[4e1c362]243        except:
244            logging.error("invariant.set_state: %s" % sys.exc_value)
[4da35bc]245           
[9b18735]246    def on_set_state_helper(self, event=None):
[4da35bc]247        """
[9b18735]248        Set the state when called by EVT_STATE_UPDATE event from guiframe
249        after a .inv/.svs file is loaded
[4da35bc]250        """
[4a2b054]251        self.invariant_panel.set_state(state=self.temp_state,
252                                       data=self.__data)
[4da35bc]253        self.temp_state = None
[c128284]254       
[9b18735]255       
256       
[2661d8b]257    def plot_theory(self, data=None, name=None):
[c128284]258        """
[d7a39e5]259        Receive a data set and post a NewPlotEvent to parent.
260       
261        :param data: extrapolated data to be plotted
262        :param name: Data's name to use for the legend
[c128284]263        """
[4a2b054]264        #import copy
[2661d8b]265        if data is None:
266            new_plot = Theory1D(x=[], y=[], dy=None)
267        else:
[4a2b054]268            scale = self.invariant_panel.get_scale()
[353f467]269            background = self.invariant_panel.get_background()
270           
271            if scale != 0:
272                # Put back the sacle and bkg for plotting
[8f2069d5]273                data.y = (data.y + background)/scale
[353f467]274                new_plot = Theory1D(x=data.x, y=data.y, dy=None)
275            else:
276                msg = "Scale can not be zero."
277                raise ValueError, msg
278
[c128284]279        new_plot.name = name
[2661d8b]280        new_plot.xaxis(self.__data._xaxis, self.__data._xunit)
281        new_plot.yaxis(self.__data._yaxis, self.__data._yunit)
282        new_plot.group_id = self.__data.group_id
283        new_plot.id = self.__data.id + name
[4e1c362]284        # Save theory_data in a state
285        if data != None:
286            name_head = name.split('-')
[4a2b054]287            if name_head[0] == 'Low':
[4e1c362]288                self.invariant_panel.state.theory_lowQ = copy.deepcopy(new_plot)
[4a2b054]289            elif name_head[0] == 'High':
[4e1c362]290                self.invariant_panel.state.theory_highQ = copy.deepcopy(new_plot)
291
[4a2b054]292        wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot,
293                                               title=self.__data.name))
[6d55d81]294       
[18d0bba]295    def plot_data(self, scale, background):
[6d55d81]296        """
[d7a39e5]297        replot the current data if the user enters a new scale or background
[6d55d81]298        """
[18d0bba]299        new_plot = scale * self.__data - background
300        new_plot.name = self.__data.name
301        new_plot.group_id = self.__data.group_id
302        new_plot.id = self.__data.id
[4e1c362]303       
304        # Save data in a state: but seems to never happen
305        if new_plot != None:
306            self.invariant_panel.state.data = copy.deepcopy(new_plot)
[4a2b054]307        wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot,
308                                               title=new_plot.name))
[c128284]309       
Note: See TracBrowser for help on using the repository browser.