source: sasview/invariantview/src/sans/perspectives/invariant/invariant.py @ 6813da7d

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

dialog fixes

  • Property mode set to 100644
File size: 14.4 KB
Line 
1
2
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################################################################################
13
14
15import sys
16import wx
17import copy
18import logging
19
20from sans.guiframe.dataFitting import Data1D
21from sans.guiframe.events import NewPlotEvent
22from sans.guiframe.events import StatusEvent
23from sans.guiframe.gui_style import GUIFRAME_ID
24from .invariant_state import Reader as reader
25from sans.dataloader.loader import Loader
26from .invariant_panel import InvariantPanel
27from sans.guiframe.plugin_base import PluginBase
28
29class Plugin(PluginBase):
30    """
31    This class defines the interface for invariant Plugin class
32    that can be used by the gui_manager.       
33    """
34   
35    def __init__(self, standalone=False):
36        PluginBase.__init__(self, name="Invariant", standalone=standalone)
37       
38        #dictionary containing data name and error on dy of that data
39        self.err_dy = {}
40       
41        #default state objects
42        self.state_reader = None 
43        self._extensions = '.inv'
44        self.temp_state = None 
45        self.__data = None 
46       
47        # Log startup
48        logging.info("Invariant plug-in started")
49       
50    def help(self, evt):
51        """
52        Show a general help dialog.
53        """
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 
63        frame.Show(True)
64       
65    def get_data(self):
66        """
67        """
68        return self.__data
69   
70    def get_panels(self, parent):
71        """
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
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)
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)
93        #loader.associate_file_reader(".svs", self.state_reader)
94        # Return the list of panels
95        return [self.invariant_panel]
96 
97    def get_context_menu(self, plotpanel=None):
98        """
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
117        """
118        graph = plotpanel.graph
119        invariant_option = "Compute invariant"
120        invariant_hint = "Will displays the invariant panel for"
121        invariant_hint += " further computation"
122       
123        if graph.selected_plottable not in plotpanel.plots:
124            return []
125        data = plotpanel.plots[graph.selected_plottable]
126       
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, 
130                                        self._compute_invariant]]
131        return []
132
133    def _compute_invariant(self, event):   
134        """
135        Open the invariant panel to invariant computation
136        """
137        self.panel = event.GetEventObject()
138        Plugin.on_perspective(self, event=event)
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)
148               
149    def set_data(self, data_list=None):
150        """
151        receive a list of data and compute invariant
152        """
153        msg = ""
154        data = None
155        if data_list is None:
156            data_list = []
157        if len(data_list) >= 1:
158            if len(data_list) == 1:
159                data = data_list[0]
160            else:
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"
181                msg += "Please select one.\n"
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
191            if data is None:
192                msg += "invariant receives no data. \n"
193                wx.PostEvent(self.parent, 
194                     StatusEvent(status=msg, info='error'))
195                return
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:
203                wx.PostEvent(self.parent, NewPlotEvent(plot=data,
204                                           title=data.title))
205                try:
206                    self.compute_helper(data)
207                except:
208                    msg = "Invariant Set_data: " + str(sys.exc_value)
209                    wx.PostEvent(self.parent, StatusEvent(status=msg,
210                                                                info="error"))
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'))
216    def delete_data(self, data_id):
217        """
218        """
219        if self.__data is None:
220            return
221        for id in data_id:
222            if id == self.__data.id:
223                self.clear_panel()
224               
225    def clear_panel(self):
226        """
227        """
228        self.invariant_panel.clear_panel()
229       
230    def compute_helper(self, data):
231        """
232        """
233        if data is None:
234            return 
235        # set current data if not it's a state data
236        if not self.invariant_panel.is_state_data:
237            # Store reference to data
238            self.__data = data
239            # Set the data set to be user for invariant calculation
240            self.invariant_panel.set_data(data=data)
241           
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
253        if issubclass(current_plottable.__class__, Data1D):
254            self.state_reader.write(filepath, current_plottable, state)
255        else:
256            msg = "invariant.save_file: the data being saved is"
257            msg += " not a sans.dataloader.data_info.Data1D object" 
258            raise RuntimeError, msg
259
260    def set_state(self, state=None, datainfo=None):   
261        """
262        Call-back method for the state reader.
263        This method is called when a .inv/.svs file is loaded.
264       
265        :param state: State object
266        """
267        self.temp_state = None
268        try:
269            if datainfo.__class__.__name__ == 'list':
270                data = datainfo[0]
271            else:
272                data = datainfo
273            if data is None:
274                msg = "invariant.set_state: datainfo parameter cannot"
275                msg += " be None in standalone mode"
276                raise RuntimeError, msg
277            # Make sure the user sees the invariant panel after loading
278            #self.parent.set_perspective(self.perspective)
279            self.on_perspective(event=None)
280            name = data.meta_data['invstate'].file
281            data.meta_data['invstate'].file = name
282            data.name = name
283            data.filename = name
284
285            data = self.parent.create_gui_data(data,None)
286            self.__data = data
287            wx.PostEvent(self.parent, NewPlotEvent(plot=self.__data,
288                                        reset=True, title=self.__data.title))
289            data_dict = {self.__data.id:self.__data}
290            self.parent.add_data(data_list=data_dict)
291            # set state
292            self.invariant_panel.is_state_data = True
293           
294            # Load the invariant states
295            self.temp_state = state
296            # Requires to have self.__data and self.temp_state  first.
297            self.on_set_state_helper(None)
298
299        except: 
300            logging.error("invariant.set_state: %s" % sys.exc_value)
301           
302    def on_set_state_helper(self, event=None):
303        """
304        Set the state when called by EVT_STATE_UPDATE event from guiframe
305        after a .inv/.svs file is loaded
306        """
307        self.invariant_panel.set_state(state=self.temp_state,
308                                       data=self.__data)
309        self.temp_state = None
310       
311       
312    def plot_theory(self, data=None, name=None):
313        """
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
318        """
319        #import copy
320        if data is None:
321            id = str(self.__data.id) + name
322            group_id = self.__data.group_id
323            wx.PostEvent(self.parent, NewPlotEvent(id=id,
324                                               group_id=group_id,
325                                               action='Remove'))
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
338        else:
339            msg = "Scale can not be zero."
340            raise ValueError, msg
341        if len(new_plot.x)== 0 :
342            return
343       
344        new_plot.name = name
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
348        new_plot.id = str(self.__data.id) + name
349        new_plot.title = self.__data.title
350        # Save theory_data in a state
351        if data != None:
352            name_head = name.split('-')
353            if name_head[0] == 'Low':
354                self.invariant_panel.state.theory_lowQ = copy.deepcopy(new_plot)
355            elif name_head[0] == 'High':
356                self.invariant_panel.state.theory_highQ =copy.deepcopy(new_plot)
357           
358        self.parent.update_theory(data_id=self.__data.id, theory=new_plot)
359        wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot,
360                                               title=self.__data.title))
361       
362    def plot_data(self, scale, background):
363        """
364        replot the current data if the user enters a new scale or background
365        """
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
370        new_plot.title = self.__data.title
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)
375        wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot,
376                                               title=new_plot.title))
377       
Note: See TracBrowser for help on using the repository browser.