source: sasview/invariantview/perspectives/invariant/invariant.py @ 5650ebf

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 5650ebf was 4a2b054, checked in by Gervaise Alina <gervyh@…>, 14 years ago

working on pylint

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