source: sasview/invariantview/perspectives/invariant/invariant.py @ 8d8415f

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

remove .svs extensions

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