source: sasview/invariantview/perspectives/invariant/invariant.py @ 511c6810

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 511c6810 was 2f97794, checked in by Gervaise Alina <gervyh@…>, 14 years ago

fix invariant

  • Property mode set to 100644
File size: 12.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]20
[a07e72f]21from sans.guiframe.dataFitting import Data1D
[f1e06a8e]22from sans.guiframe.events import NewPlotEvent
[a07e72f]23from sans.guiframe.gui_style import GUIFRAME_ID
[f1e06a8e]24from .invariant_state import Reader as reader
[4e1c362]25from DataLoader.loader import Loader
[f1e06a8e]26from .invariant_panel import InvariantPanel
[d65a00a]27from sans.guiframe.plugin_base import PluginBase
28
29class Plugin(PluginBase):
[c128284]30    """
[d7a39e5]31    This class defines the interface for invariant Plugin class
[4e1c362]32    that can be used by the gui_manager.       
[c128284]33    """
34   
35    def __init__(self, standalone=False):
[d65a00a]36        PluginBase.__init__(self, name="Invariant", standalone=standalone)
[c128284]37       
38        #dictionary containing data name and error on dy of that data
39        self.err_dy = {}
[d65a00a]40       
[4da35bc]41        #default state objects
42        self.state_reader = None 
[35f2f49]43        self._extensions = '.inv'
[4da35bc]44        self.temp_state = None 
45        self.__data = None 
[d65a00a]46       
[4e1c362]47        # Log startup
48        logging.info("Invariant plug-in started")
[c128284]49       
[f29a433]50    def help(self, evt):
51        """
[d7a39e5]52        Show a general help dialog.
[f29a433]53        """
[f1e06a8e]54        from .help_panel import  HelpWindow
[f29a433]55        frame = HelpWindow(None, -1)   
56        frame.Show(True)
57       
[35f2f49]58    def get_data(self):
59        """
60        """
61        return self.__data
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        self.invariant_panel = InvariantPanel(parent=self.parent)
79        self.invariant_panel.set_manager(manager=self)
[4e1c362]80        self.perspective.append(self.invariant_panel.window_name) 
81        #Create reader when fitting panel are created
82        self.state_reader = reader(self.set_state)   
83        #append that reader to list of available reader
84        loader = Loader()
85        loader.associate_file_reader(".inv", self.state_reader)
[b35d3d1]86        loader.associate_file_reader(".svs", self.state_reader)
[c128284]87        # Return the list of panels
88        return [self.invariant_panel]
[d65a00a]89 
[a07e72f]90    def get_context_menu(self, plotpanel=None):
[c128284]91        """
[d7a39e5]92        This method is optional.
93   
94        When the context menu of a plot is rendered, the
95        get_context_menu method will be called to give you a
96        chance to add a menu item to the context menu.
97       
98        A ref to a Graph object is passed so that you can
99        investigate the plot content and decide whether you
100        need to add items to the context menu. 
101       
102        This method returns a list of menu items.
103        Each item is itself a list defining the text to
104        appear in the menu, a tool-tip help text, and a
105        call-back method.
106       
107        :param graph: the Graph object to which we attach the context menu
108       
109        :return: a list of menu items with call-back function
[c128284]110        """
[a07e72f]111        graph = plotpanel.graph
[c128284]112        invariant_option = "Compute invariant"
[4a2b054]113        invariant_hint = "Will displays the invariant panel for"
[a1f2002]114        invariant_hint += " futher computation"
[4e1c362]115       
[a07e72f]116        if graph.selected_plottable not in plotpanel.plots:
117            return []
118        data = plotpanel.plots[graph.selected_plottable]
[c128284]119       
[a07e72f]120        if not issubclass(data.__class__, Data1D):
121            name = data.__class__.__name__
122            msg = "Invariant use only Data1D got: [%s] " % str(name)
123            raise ValueError, msg
124       
125        if data.name != "$I_{obs}(q)$" and  data.name != " $P_{fit}(r)$":
126           return [[invariant_option, invariant_hint, 
127                                        self._compute_invariant]]
128        return []
129
[c128284]130    def _compute_invariant(self, event):   
131        """
[d7a39e5]132        Open the invariant panel to invariant computation
[c128284]133        """
134        self.panel = event.GetEventObject()
[4a2b054]135        Plugin.on_perspective(self, event=event)
[a07e72f]136        id = self.panel.graph.selected_plottable
137        data = self.panel.plots[self.panel.graph.selected_plottable]
138        if data is None:
139            return
140        if not issubclass(data.__class__, Data1D):
141            name = data.__class__.__name__
142            msg = "Invariant use only Data1D got: [%s] " % str(name)
143            raise ValueError, msg
144        self.compute_helper(data=data)
[4e1c362]145               
[e88ebfd]146    def set_data(self, data_list=None):
[f1e06a8e]147        """
148        receive a list of data and compute invariant
149        """
[a07e72f]150        data = None
[14cd91b1]151        if data_list is None:
152            data_list = []
[e88ebfd]153        if len(data_list) >= 1:
154            if len(data_list) == 1:
155                data = data_list[0]
156            else:
157                msg = "invariant panel does not allow multiple data!\n"
158                msg += "Please select one.\n"
159                from invariant_widgets import DataDialog
160                dlg = DataDialog(data_list=data_list, text=msg)
161                if dlg.ShowModal() == wx.ID_OK:
162                    data = dlg.get_data()
163            if data is None:
164                return
165            if issubclass(data.__class__, Data1D):
166                wx.PostEvent(self.parent, NewPlotEvent(plot=data,
167                                           title=data.title))
168                try:
169                    self.compute_helper(data)
170                except:
171                    msg = "Prview Set_data: " + str(sys.exc_value)
172                    wx.PostEvent(self.parent, StatusEvent(status=msg,
173                                                                info="error"))
[a07e72f]174        else:   
175            msg = "invariant cannot be computed for data of "
176            msg += "type %s" % (data.__class__.__name__)
177            wx.PostEvent(self.parent, 
178                     StatusEvent(status=msg, info='error'))
[20b482f]179    def delete_data(self, data_id):
180        """
181        """
182        for id in data_id:
183            if id == self.__data.id:
184                self.clear_panel()
185               
[cb69775]186    def clear_panel(self):
[a07e72f]187        """
188        """
[cb69775]189        self.invariant_panel.clear_panel()
190       
[343fdb6]191    def compute_helper(self, data):
192        """
193        """
194        if data is None:
195            return 
[f24925ab]196        # set current data if not it's a state data
197        if not self.invariant_panel.is_state_data:
[9c1f463]198            # Store reference to data
199            self.__data = data
200            # Set the data set to be user for invariant calculation
[210ff4f]201            self.invariant_panel.set_data(data=data)
[f1e06a8e]202           
[4e1c362]203    def save_file(self, filepath, state=None):
204        """
205        Save data in provided state object.
206               
207        :param filepath: path of file to write to
208        :param state: invariant state
209        """     
210        # Write the state to file
211        # First, check that the data is of the right type
212        current_plottable = self.__data
213
214        if issubclass(current_plottable.__class__, LoaderData1D):
215            self.state_reader.write(filepath, current_plottable, state)
216        else:
[4a2b054]217            msg = "invariant.save_file: the data being saved is"
218            msg += " not a DataLoader.data_info.Data1D object" 
219            raise RuntimeError, msg
[4e1c362]220
[75fbd17]221    def set_state(self, state=None, datainfo=None):   
[4e1c362]222        """
223        Call-back method for the state reader.
[9b18735]224        This method is called when a .inv/.svs file is loaded.
[4e1c362]225       
226        :param state: State object
227        """
[4da35bc]228        self.temp_state = None
[4e1c362]229        try:
[75fbd17]230            if datainfo.__class__.__name__ == 'list':
231                data = datainfo[0]
[cb69775]232            else:
233                data = datainfo
[75fbd17]234            if data is None:
[4a2b054]235                msg = "invariant.set_state: datainfo parameter cannot"
236                msg += " be None in standalone mode"
237                raise RuntimeError, msg
[9b18735]238           
[75fbd17]239            name = data.meta_data['invstate'].file
240            data.meta_data['invstate'].file = name
241            data.name = name
242            data.filename = name
[cb69775]243            data = self.parent.create_gui_data(data,None)
[75fbd17]244            self.__data = data
245            wx.PostEvent(self.parent, NewPlotEvent(plot=self.__data,
246                                        reset=True, title=self.__data.title))
[2f97794]247            data_dict = {self.__data.id:self.__data}
248            self.parent.add_data(data_list=data_dict)
[f24925ab]249            # set state
250            self.invariant_panel.is_state_data = True
[9b18735]251           
[4e1c362]252            # Make sure the user sees the invariant panel after loading
[75fbd17]253            #self.parent.set_perspective(self.perspective)
254            self.on_perspective(event=None)
[9b18735]255            # Load the invariant states
[cb69775]256            self.temp_state = state
257            self.invariant_panel.set_state(state=state,data=self.__data)         
[75fbd17]258           
259        except: 
[4e1c362]260            logging.error("invariant.set_state: %s" % sys.exc_value)
[4da35bc]261           
[9b18735]262    def on_set_state_helper(self, event=None):
[4da35bc]263        """
[9b18735]264        Set the state when called by EVT_STATE_UPDATE event from guiframe
265        after a .inv/.svs file is loaded
[4da35bc]266        """
[4a2b054]267        self.invariant_panel.set_state(state=self.temp_state,
268                                       data=self.__data)
[4da35bc]269        self.temp_state = None
[c128284]270       
[9b18735]271       
[2661d8b]272    def plot_theory(self, data=None, name=None):
[c128284]273        """
[d7a39e5]274        Receive a data set and post a NewPlotEvent to parent.
275       
276        :param data: extrapolated data to be plotted
277        :param name: Data's name to use for the legend
[c128284]278        """
[4a2b054]279        #import copy
[2661d8b]280        if data is None:
[a07e72f]281            id = str(self.__data.id) + name
[e88ebfd]282            group_id = self.__data.group_id
[a07e72f]283            wx.PostEvent(self.parent, NewPlotEvent(id=id,
284                                               group_id=group_id,
[c85c180]285                                               action='Remove'))
[a07e72f]286            return
287   
288        new_plot = Data1D(x=[], y=[], dy=None)
289        new_plot.symbol = GUIFRAME_ID.CURVE_SYMBOL_NUM
290        scale = self.invariant_panel.get_scale()
291        background = self.invariant_panel.get_background()
292       
293        if scale != 0:
294            # Put back the sacle and bkg for plotting
295            data.y = (data.y + background)/scale
296            new_plot = Data1D(x=data.x, y=data.y, dy=None)
297            new_plot.symbol = GUIFRAME_ID.CURVE_SYMBOL_NUM
[2661d8b]298        else:
[a07e72f]299            msg = "Scale can not be zero."
300            raise ValueError, msg
301        if len(new_plot.x)== 0 :
302            return
303       
[c128284]304        new_plot.name = name
[2661d8b]305        new_plot.xaxis(self.__data._xaxis, self.__data._xunit)
306        new_plot.yaxis(self.__data._yaxis, self.__data._yunit)
307        new_plot.group_id = self.__data.group_id
[a07e72f]308        new_plot.id = str(self.__data.id) + name
[f1e06a8e]309        new_plot.title = self.__data.title
[4e1c362]310        # Save theory_data in a state
311        if data != None:
312            name_head = name.split('-')
[4a2b054]313            if name_head[0] == 'Low':
[4e1c362]314                self.invariant_panel.state.theory_lowQ = copy.deepcopy(new_plot)
[4a2b054]315            elif name_head[0] == 'High':
[f1e06a8e]316                self.invariant_panel.state.theory_highQ =copy.deepcopy(new_plot)
[c85c180]317           
[27f4bee]318        self.parent.update_theory(data_id=self.__data.id, theory=new_plot)
[4a2b054]319        wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot,
[f1e06a8e]320                                               title=self.__data.title))
[6d55d81]321       
[18d0bba]322    def plot_data(self, scale, background):
[6d55d81]323        """
[d7a39e5]324        replot the current data if the user enters a new scale or background
[6d55d81]325        """
[18d0bba]326        new_plot = scale * self.__data - background
327        new_plot.name = self.__data.name
328        new_plot.group_id = self.__data.group_id
329        new_plot.id = self.__data.id
[f1e06a8e]330        new_plot.title = self.__data.title
[4e1c362]331       
332        # Save data in a state: but seems to never happen
333        if new_plot != None:
334            self.invariant_panel.state.data = copy.deepcopy(new_plot)
[4a2b054]335        wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot,
[f1e06a8e]336                                               title=new_plot.title))
[c128284]337       
Note: See TracBrowser for help on using the repository browser.