source: sasview/invariantview/perspectives/invariant/invariant.py @ 1db4a53

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 1db4a53 was 7a07864, checked in by Jae Cho <jhjcho@…>, 14 years ago

a bit generalized the plotdata

  • Property mode set to 100644
File size: 12.9 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################################################################################
[4e1c362]13import os
14import sys
[272d91e]15import wx
[4e1c362]16import copy
17import logging, time
[c128284]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
[4e1c362]25from invariant_state import Reader as reader
26from DataLoader.loader import Loader
27from invariant_panel import InvariantPanel
[7a07864]28from sans.guicomm.events import EVT_INVSTATE_UPDATE
[d7a39e5]29
[c128284]30class Plugin:
31    """
[d7a39e5]32    This class defines the interface for invariant Plugin class
[4e1c362]33    that can be used by the gui_manager.       
[c128284]34    """
35   
36    def __init__(self, standalone=False):
37        """
[d7a39e5]38        Abstract class for gui_manager Plugins.
[c128284]39        """
40        ## Plug-in name. It will appear on the application menu.
[53b6b74]41        self.sub_menu = "Invariant"
[c128284]42       
43        ## Reference to the parent window. Filled by get_panels() below.
44        self.parent = None
45        #dictionary containing data name and error on dy of that data
46        self.err_dy = {}
47        ## List of panels that you would like to open in AUI windows
48        #  for your plug-in. This defines your plug-in "perspective"
49        self.perspective = []
[4da35bc]50        #default state objects
51        self.state_reader = None 
52        self.temp_state = None 
53        self.__data = None 
[4e1c362]54        """
55        # Create a CanSAS/Pr reader
56        self.state_reader = Reader(self.set_state)
57        l = Loader()
58        l.associate_file_reader('.inv', self.state_reader) 
59        """   
60        # Log startup
61        logging.info("Invariant plug-in started")
[c128284]62       
63    def populate_menu(self, id, parent):
64        """
[d7a39e5]65        Create and return the list of application menu
66        items for the plug-in.
67       
68        :param id: deprecated. Un-used.
69        :param parent: parent window
70       
71        :return: plug-in menu
[c128284]72        """
73        return []
74   
[f29a433]75    def help(self, evt):
76        """
[d7a39e5]77        Show a general help dialog.
[f29a433]78        """
79        from help_panel import  HelpWindow
80        frame = HelpWindow(None, -1)   
81        frame.Show(True)
82       
[c128284]83    def get_panels(self, parent):
84        """
[d7a39e5]85        Create and return the list of wx.Panels for your plug-in.
86        Define the plug-in perspective.
87       
88        Panels should inherit from DefaultPanel defined below,
89        or should present the same interface. They must define
90        "window_caption" and "window_name".
91       
92        :param parent: parent window
93       
94        :return: list of panels
[c128284]95        """
96        ## Save a reference to the parent
97        self.parent = parent
98        #add error back to the data
[272d91e]99        self.parent.Bind(ERR_DATA, self._on_data_error)
[7a07864]100        self.parent.Bind(EVT_INVSTATE_UPDATE, self.on_set_state_helper)
[4e1c362]101       
[c128284]102        self.invariant_panel = InvariantPanel(parent=self.parent)
103        self.invariant_panel.set_manager(manager=self)
[4e1c362]104        self.perspective.append(self.invariant_panel.window_name) 
105        #Create reader when fitting panel are created
106        self.state_reader = reader(self.set_state)   
107        #append that reader to list of available reader
108        loader = Loader()
109        loader.associate_file_reader(".inv", self.state_reader)
[b35d3d1]110        loader.associate_file_reader(".svs", self.state_reader)
[c128284]111        # Return the list of panels
112        return [self.invariant_panel]
113   
114    def get_tools(self):
115        """
[d7a39e5]116        Returns a set of menu entries for tools
[c128284]117        """
118        return []
119       
120   
121    def get_context_menu(self, graph=None):
122        """
[d7a39e5]123        This method is optional.
124   
125        When the context menu of a plot is rendered, the
126        get_context_menu method will be called to give you a
127        chance to add a menu item to the context menu.
128       
129        A ref to a Graph object is passed so that you can
130        investigate the plot content and decide whether you
131        need to add items to the context menu. 
132       
133        This method returns a list of menu items.
134        Each item is itself a list defining the text to
135        appear in the menu, a tool-tip help text, and a
136        call-back method.
137       
138        :param graph: the Graph object to which we attach the context menu
139       
140        :return: a list of menu items with call-back function
[c128284]141        """
142        self.graph = graph
143        invariant_option = "Compute invariant"
144        invariant_hint = "Will displays the invariant panel for futher computation"
145       
146        for item in self.graph.plottables:
[518d35d]147            if item.name == graph.selected_plottable :
148                if issubclass(item.__class__,LoaderData1D):
149           
150                    if item.name !="$I_{obs}(q)$" and item.name !="$P_{fit}(r)$":
151                        if hasattr(item, "group_id"):
152                            return [[invariant_option, 
153                                        invariant_hint, self._compute_invariant]]
[c128284]154        return []   
155
156   
157    def get_perspective(self):
158        """
[d7a39e5]159        Get the list of panel names for this perspective
[c128284]160        """
161        return self.perspective
162   
163    def on_perspective(self, event):
164        """
[d7a39e5]165        Call back function for the perspective menu item.
166        We notify the parent window that the perspective
167        has changed.
168       
169        :param event: menu event
[c128284]170        """
171        self.parent.set_perspective(self.perspective)
172   
173    def post_init(self):
174        """
[d7a39e5]175        Post initialization call back to close the loose ends
[c128284]176        """
177        pass
178   
179    def set_default_perspective(self):
180        """
[d7a39e5]181        Call back method that True to notify the parent that the current plug-in
182        can be set as default  perspective.
183        when returning False, the plug-in is not candidate for an automatic
184        default perspective setting
[c128284]185        """
186        return False
187   
188    def copy_data(self, item, dy=None):
189        """
[d7a39e5]190        receive a data 1D and the list of errors on dy
191        and create a new data1D data
[c128284]192        """
193        id = None
194        if hasattr(item,"id"):
[6d55d81]195            id = item.id
[c128284]196
197        data = Data1D(x=item.x, y=item.y, dx=None, dy=None)
198        data.copy_from_datainfo(item)
199        item.clone_without_data(clone=data)   
200        data.dy = dy
201        data.name = item.name
[4e1c362]202       
[c128284]203        ## allow to highlight data when plotted
[6d55d81]204        data.interactive = item.interactive
[c128284]205        ## when 2 data have the same id override the 1 st plotted
206        data.id = id
207        data.group_id = item.group_id
208        return data
209   
210    def _on_data_error(self, event):
211        """
[d7a39e5]212        receives and event from plotting plu-gins to store the data name and
213        their errors of y coordinates for 1Data hide and show error
[c128284]214        """
215        self.err_dy = event.err_dy
216       
217    def _compute_invariant(self, event):   
218        """
[d7a39e5]219        Open the invariant panel to invariant computation
[c128284]220        """
221        self.panel = event.GetEventObject()
222        Plugin.on_perspective(self,event=event)
223        for plottable in self.panel.graph.plottables:
224            if plottable.name == self.panel.graph.selected_plottable:
225                ## put the errors values back to the model if the errors were hiden
226                ## before sending them to the fit engine
227                if len(self.err_dy)>0:
228                    dy = plottable.dy
229                    if plottable.name in  self.err_dy.iterkeys():
230                        dy = self.err_dy[plottable.name]
231                    data = self.copy_data(plottable, dy)
232                else:
233                    data = plottable
[343fdb6]234                self.compute_helper(data=data)
[4e1c362]235               
[343fdb6]236    def compute_helper(self, data):
237        """
238        """
239        if data is None:
240            return 
[f24925ab]241        # set current data if not it's a state data
242        if not self.invariant_panel.is_state_data:
[9c1f463]243            # Store reference to data
244            self.__data = data
245            # Set the data set to be user for invariant calculation
[210ff4f]246            self.invariant_panel.set_data(data=data)
[343fdb6]247       
[4e1c362]248    def save_file(self, filepath, state=None):
249        """
250        Save data in provided state object.
251               
252        :param filepath: path of file to write to
253        :param state: invariant state
254        """     
255        # Write the state to file
256        # First, check that the data is of the right type
257        current_plottable = self.__data
258
259        if issubclass(current_plottable.__class__, LoaderData1D):
260            self.state_reader.write(filepath, current_plottable, state)
261        else:
262            raise RuntimeError, "invariant.save_file: the data being saved is not a DataLoader.data_info.Data1D object" 
263
264    def set_state(self, state, datainfo=None):   
265        """
266        Call-back method for the state reader.
[9b18735]267        This method is called when a .inv/.svs file is loaded.
[4e1c362]268       
269        :param state: State object
270        """
[4da35bc]271        self.temp_state = None
[4e1c362]272        try:
[9b18735]273           
[4e1c362]274            if datainfo is None:
275                raise RuntimeError, "invariant.set_state: datainfo parameter cannot be None in standalone mode"
[9b18735]276           
[cb463b4]277            datainfo.meta_data['invstate'].file = datainfo.meta_data['invstate'].file
[4e1c362]278            datainfo.name = datainfo.meta_data['invstate'].file
279            datainfo.filename = datainfo.meta_data['invstate'].file
280            self.__data = datainfo
281            self.__data.group_id = datainfo.filename
282            self.__data.id = datainfo.filename
[f24925ab]283
[4e1c362]284            temp_state = copy.deepcopy(state)
[f24925ab]285            # set state
286            self.invariant_panel.is_state_data = True
[9b18735]287           
[4e1c362]288            # Make sure the user sees the invariant panel after loading
289            self.parent.set_perspective(self.perspective)
[9b18735]290            # Load the invariant states
[4da35bc]291            self.temp_state = temp_state
292            #self.invariant_panel.set_state(state=temp_state,data=self.__data)         
[9b18735]293           
[4e1c362]294        except:
295            logging.error("invariant.set_state: %s" % sys.exc_value)
[4da35bc]296           
[9b18735]297    def on_set_state_helper(self, event=None):
[4da35bc]298        """
[9b18735]299        Set the state when called by EVT_STATE_UPDATE event from guiframe
300        after a .inv/.svs file is loaded
[4da35bc]301        """
302        self.invariant_panel.set_state(state=self.temp_state,data=self.__data)
303        self.temp_state = None
[c128284]304       
[9b18735]305       
306       
[2661d8b]307    def plot_theory(self, data=None, name=None):
[c128284]308        """
[d7a39e5]309        Receive a data set and post a NewPlotEvent to parent.
310       
311        :param data: extrapolated data to be plotted
312        :param name: Data's name to use for the legend
[c128284]313        """
[4e1c362]314        import copy
[2661d8b]315        if data is None:
316            new_plot = Theory1D(x=[], y=[], dy=None)
317        else:
[353f467]318            scale =self.invariant_panel.get_scale()
319            background = self.invariant_panel.get_background()
320           
321            if scale != 0:
322                # Put back the sacle and bkg for plotting
[8f2069d5]323                data.y = (data.y + background)/scale
[353f467]324                new_plot = Theory1D(x=data.x, y=data.y, dy=None)
325            else:
326                msg = "Scale can not be zero."
327                raise ValueError, msg
328
[c128284]329        new_plot.name = name
[2661d8b]330        new_plot.xaxis(self.__data._xaxis, self.__data._xunit)
331        new_plot.yaxis(self.__data._yaxis, self.__data._yunit)
332        new_plot.group_id = self.__data.group_id
333        new_plot.id = self.__data.id + name
[4e1c362]334        # Save theory_data in a state
335        if data != None:
336            name_head = name.split('-')
337            if name_head[0]=='Low':
338                self.invariant_panel.state.theory_lowQ = copy.deepcopy(new_plot)
339            elif name_head[0]=='High':
340                self.invariant_panel.state.theory_highQ = copy.deepcopy(new_plot)
341
[2661d8b]342        wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot, title=self.__data.name))
[6d55d81]343       
[18d0bba]344    def plot_data(self, scale, background):
[6d55d81]345        """
[d7a39e5]346        replot the current data if the user enters a new scale or background
[6d55d81]347        """
[18d0bba]348        new_plot = scale * self.__data - background
349        new_plot.name = self.__data.name
350        new_plot.group_id = self.__data.group_id
351        new_plot.id = self.__data.id
[4e1c362]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)
[6d55d81]356        wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot, title=new_plot.name))
[c128284]357       
Note: See TracBrowser for help on using the repository browser.