source: sasview/invariantview/src/sans/perspectives/invariant/invariant.py @ 4bdd4fdb

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 4bdd4fdb was 6813da7d, checked in by Jae Cho <jhjcho@…>, 13 years ago

dialog fixes

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