source: sasview/src/sas/sasgui/perspectives/invariant/invariant.py @ 07b50df9

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.2.2ticket-1009ticket-1094-headlessticket-1242-2d-resolutionticket-1243ticket-1249ticket885unittest-saveload
Last change on this file since 07b50df9 was 463e7ffc, checked in by Ricardo Ferraz Leal <ricleal@…>, 8 years ago

getLogger with module name

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