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

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

working on save state

  • Property mode set to 100644
File size: 13.6 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]20from DataLoader.data_info import Data1D as LoaderData1D
[4a2b054]21from sans.guiframe.dataFitting import Theory1D
22from sans.guiframe.dataFitting import Data1D
[c128284]23
[f1e06a8e]24from sans.guiframe.events import NewPlotEvent
25from sans.guiframe.events import ERR_DATA
26from .invariant_state import Reader as reader
[4e1c362]27from DataLoader.loader import Loader
[f1e06a8e]28from .invariant_panel import InvariantPanel
[75fbd17]29#from sans.guiframe.events import EVT_INVSTATE_UPDATE
[d7a39e5]30
[d65a00a]31from sans.guiframe.plugin_base import PluginBase
32
33class Plugin(PluginBase):
[c128284]34    """
[d7a39e5]35    This class defines the interface for invariant Plugin class
[4e1c362]36    that can be used by the gui_manager.       
[c128284]37    """
38   
39    def __init__(self, standalone=False):
[d65a00a]40        PluginBase.__init__(self, name="Invariant", standalone=standalone)
[c128284]41       
42        #dictionary containing data name and error on dy of that data
43        self.err_dy = {}
[d65a00a]44       
[4da35bc]45        #default state objects
46        self.state_reader = None 
[35f2f49]47        self._extensions = '.inv'
[4da35bc]48        self.temp_state = None 
49        self.__data = None 
[d65a00a]50       
[4e1c362]51        # Log startup
52        logging.info("Invariant plug-in started")
[c128284]53       
[f29a433]54    def help(self, evt):
55        """
[d7a39e5]56        Show a general help dialog.
[f29a433]57        """
[f1e06a8e]58        from .help_panel import  HelpWindow
[f29a433]59        frame = HelpWindow(None, -1)   
60        frame.Show(True)
61       
[35f2f49]62    def get_data(self):
63        """
64        """
65        return self.__data
66   
[c128284]67    def get_panels(self, parent):
68        """
[d7a39e5]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
[c128284]79        """
80        ## Save a reference to the parent
81        self.parent = parent
82        #add error back to the data
[272d91e]83        self.parent.Bind(ERR_DATA, self._on_data_error)
[75fbd17]84        #self.parent.Bind(EVT_INVSTATE_UPDATE, self.on_set_state_helper)
[4e1c362]85       
[c128284]86        self.invariant_panel = InvariantPanel(parent=self.parent)
87        self.invariant_panel.set_manager(manager=self)
[4e1c362]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)
[b35d3d1]94        loader.associate_file_reader(".svs", self.state_reader)
[c128284]95        # Return the list of panels
96        return [self.invariant_panel]
[d65a00a]97 
[c128284]98    def get_context_menu(self, graph=None):
99        """
[d7a39e5]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
[c128284]118        """
119        self.graph = graph
120        invariant_option = "Compute invariant"
[4a2b054]121        invariant_hint = "Will displays the invariant panel for"
[a1f2002]122        invariant_hint += " futher computation"
[c128284]123       
124        for item in self.graph.plottables:
[518d35d]125            if item.name == graph.selected_plottable :
[a1f2002]126                if issubclass(item.__class__, LoaderData1D):
[518d35d]127           
[4a2b054]128                    if item.name != "$I_{obs}(q)$" and \
129                        item.name != " $P_{fit}(r)$":
[518d35d]130                        if hasattr(item, "group_id"):
131                            return [[invariant_option, 
[4a2b054]132                                        invariant_hint, 
133                                        self._compute_invariant]]
[c128284]134        return []   
135
136    def copy_data(self, item, dy=None):
137        """
[d7a39e5]138        receive a data 1D and the list of errors on dy
139        and create a new data1D data
[c128284]140        """
141        id = None
142        if hasattr(item,"id"):
[6d55d81]143            id = item.id
[c128284]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
[f1e06a8e]150        data.title = item.title
[4e1c362]151       
[c128284]152        ## allow to highlight data when plotted
[6d55d81]153        data.interactive = item.interactive
[c128284]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        """
[d7a39e5]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
[c128284]163        """
164        self.err_dy = event.err_dy
165       
166    def _compute_invariant(self, event):   
167        """
[d7a39e5]168        Open the invariant panel to invariant computation
[c128284]169        """
170        self.panel = event.GetEventObject()
[4a2b054]171        Plugin.on_perspective(self, event=event)
[c128284]172        for plottable in self.panel.graph.plottables:
173            if plottable.name == self.panel.graph.selected_plottable:
[4a2b054]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:
[c128284]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
[343fdb6]183                self.compute_helper(data=data)
[4e1c362]184               
[f1e06a8e]185    def set_data(self, data_list):
186        """
187        receive a list of data and compute invariant
188        """
189        if len(data_list) > 1:
[cacbd7d]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))
[75fbd17]199                    self.compute_helper(data_list[0])
[cacbd7d]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'))
[f1e06a8e]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))
[75fbd17]209                self.compute_helper(data_list[0])
[f1e06a8e]210            else:
211                msg = "invariant cannot be computed for"
212                msg += " data of type %s" % (data_list[0].__class__.__name__)
[cacbd7d]213                wx.PostEvent(self.parent, 
214                             StatusEvent(status=msg, info='error'))
[f1e06a8e]215           
216           
[343fdb6]217    def compute_helper(self, data):
218        """
219        """
220        if data is None:
221            return 
[f24925ab]222        # set current data if not it's a state data
223        if not self.invariant_panel.is_state_data:
[9c1f463]224            # Store reference to data
225            self.__data = data
226            # Set the data set to be user for invariant calculation
[210ff4f]227            self.invariant_panel.set_data(data=data)
[f1e06a8e]228           
[4e1c362]229    def save_file(self, filepath, state=None):
230        """
231        Save data in provided state object.
232               
233        :param filepath: path of file to write to
234        :param state: invariant state
235        """     
236        # Write the state to file
237        # First, check that the data is of the right type
238        current_plottable = self.__data
239
240        if issubclass(current_plottable.__class__, LoaderData1D):
241            self.state_reader.write(filepath, current_plottable, state)
242        else:
[4a2b054]243            msg = "invariant.save_file: the data being saved is"
244            msg += " not a DataLoader.data_info.Data1D object" 
245            raise RuntimeError, msg
[4e1c362]246
[75fbd17]247    def set_state(self, state=None, datainfo=None):   
[4e1c362]248        """
249        Call-back method for the state reader.
[9b18735]250        This method is called when a .inv/.svs file is loaded.
[4e1c362]251       
252        :param state: State object
253        """
[4da35bc]254        self.temp_state = None
[4e1c362]255        try:
[75fbd17]256            if datainfo.__class__.__name__ == 'list':
257                data = datainfo[0]
258            if data is None:
[4a2b054]259                msg = "invariant.set_state: datainfo parameter cannot"
260                msg += " be None in standalone mode"
261                raise RuntimeError, msg
[9b18735]262           
[75fbd17]263            name = data.meta_data['invstate'].file
264            data.meta_data['invstate'].file = name
265            data.name = name
266            data.filename = name
267            #datainfo = self.parent.create_gui_data(datainfo,None)
268            #self.__data = datainfo
269            #self.__data.group_id = data.filename
270            #self.__data.id = datainfo.filename
271            self.__data = data
272            wx.PostEvent(self.parent, NewPlotEvent(plot=self.__data,
273                                        reset=True, title=self.__data.title))
274            #temp_state = copy.deepcopy(state)
275            temp_state = self.state_reader.get_state()
[f24925ab]276            # set state
277            self.invariant_panel.is_state_data = True
[9b18735]278           
[4e1c362]279            # Make sure the user sees the invariant panel after loading
[75fbd17]280            #self.parent.set_perspective(self.perspective)
281            self.on_perspective(event=None)
[9b18735]282            # Load the invariant states
[4da35bc]283            self.temp_state = temp_state
[75fbd17]284            self.invariant_panel.set_state(state=temp_state,data=self.__data)         
285           
286        except: 
[4e1c362]287            logging.error("invariant.set_state: %s" % sys.exc_value)
[4da35bc]288           
[9b18735]289    def on_set_state_helper(self, event=None):
[4da35bc]290        """
[9b18735]291        Set the state when called by EVT_STATE_UPDATE event from guiframe
292        after a .inv/.svs file is loaded
[4da35bc]293        """
[4a2b054]294        self.invariant_panel.set_state(state=self.temp_state,
295                                       data=self.__data)
[4da35bc]296        self.temp_state = None
[c128284]297       
[9b18735]298       
[2661d8b]299    def plot_theory(self, data=None, name=None):
[c128284]300        """
[d7a39e5]301        Receive a data set and post a NewPlotEvent to parent.
302       
303        :param data: extrapolated data to be plotted
304        :param name: Data's name to use for the legend
[c128284]305        """
[4a2b054]306        #import copy
[2661d8b]307        if data is None:
308            new_plot = Theory1D(x=[], y=[], dy=None)
309        else:
[4a2b054]310            scale = self.invariant_panel.get_scale()
[353f467]311            background = self.invariant_panel.get_background()
312           
313            if scale != 0:
314                # Put back the sacle and bkg for plotting
[8f2069d5]315                data.y = (data.y + background)/scale
[353f467]316                new_plot = Theory1D(x=data.x, y=data.y, dy=None)
317            else:
318                msg = "Scale can not be zero."
319                raise ValueError, msg
320
[c128284]321        new_plot.name = name
[2661d8b]322        new_plot.xaxis(self.__data._xaxis, self.__data._xunit)
323        new_plot.yaxis(self.__data._yaxis, self.__data._yunit)
324        new_plot.group_id = self.__data.group_id
325        new_plot.id = self.__data.id + name
[f1e06a8e]326        new_plot.title = self.__data.title
[4e1c362]327        # Save theory_data in a state
328        if data != None:
329            name_head = name.split('-')
[4a2b054]330            if name_head[0] == 'Low':
[4e1c362]331                self.invariant_panel.state.theory_lowQ = copy.deepcopy(new_plot)
[4a2b054]332            elif name_head[0] == 'High':
[f1e06a8e]333                self.invariant_panel.state.theory_highQ =copy.deepcopy(new_plot)
[4e1c362]334
[4a2b054]335        wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot,
[f1e06a8e]336                                               title=self.__data.title))
[6d55d81]337       
[18d0bba]338    def plot_data(self, scale, background):
[6d55d81]339        """
[d7a39e5]340        replot the current data if the user enters a new scale or background
[6d55d81]341        """
[18d0bba]342        new_plot = scale * self.__data - background
343        new_plot.name = self.__data.name
344        new_plot.group_id = self.__data.group_id
345        new_plot.id = self.__data.id
[f1e06a8e]346        new_plot.title = self.__data.title
[4e1c362]347       
348        # Save data in a state: but seems to never happen
349        if new_plot != None:
350            self.invariant_panel.state.data = copy.deepcopy(new_plot)
[4a2b054]351        wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot,
[f1e06a8e]352                                               title=new_plot.title))
[c128284]353       
Note: See TracBrowser for help on using the repository browser.