source: sasview/prview/perspectives/pr/pr.py @ 0769202

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 0769202 was 6d3d5ff, checked in by Gervaise Alina <gervyh@…>, 14 years ago

working on save state for prview

  • Property mode set to 100644
File size: 47.7 KB
RevLine 
[9ff861b]1
[7116b6e0]2################################################################################
3#This software was developed by the University of Tennessee as part of the
4#Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
5#project funded by the US National Science Foundation.
6#
7#See the license text in license.txt
8#
9#copyright 2009, University of Tennessee
10################################################################################
[9ff861b]11
12
[f3d51f6]13# Make sure the option of saving each curve is available
14# Use the I(q) curve as input and compare the output to P(r)
15
16import os
[4a5de6f]17import sys
[f3d51f6]18import wx
[aa4b8379]19import logging
[302510b]20import time
[75df58b]21import copy
22import math
23import numpy
24import pylab
25from sans.guiframe.dataFitting import Data1D
26from sans.guiframe.dataFitting import Theory1D
27from sans.guiframe.events import NewPlotEvent
28from sans.guiframe.events import StatusEvent   
29
[f3d51f6]30from sans.pr.invertor import Invertor
[aab8ad7]31from DataLoader.loader import Loader
[75df58b]32from DataLoader.data_info import Data1D as LoaderData1D
[80d2872]33import DataLoader
[af91b68]34from pr_widgets import load_error
[75df58b]35from sans.guiframe.plugin_base import PluginBase
[f3d51f6]36
[0d88a09]37
[f1181977]38PR_FIT_LABEL       = r"$P_{fit}(r)$"
39PR_LOADED_LABEL    = r"$P_{loaded}(r)$"
40IQ_DATA_LABEL      = r"$I_{obs}(q)$"
41IQ_FIT_LABEL       = r"$I_{fit}(q)$"
42IQ_SMEARED_LABEL   = r"$I_{smeared}(q)$"
[aa4b8379]43
[75df58b]44#import wx.lib
45#(NewPrFileEvent, EVT_PR_FILE) = wx.lib.newevent.NewEvent()
46
[aa4b8379]47
48
[3e41f43]49class Plugin(PluginBase):
[7116b6e0]50    """
51    """
[b659551]52    DEFAULT_ALPHA = 0.0001
53    DEFAULT_NFUNC = 10
54    DEFAULT_DMAX  = 140.0
55   
[d2ee6f6]56    def __init__(self, standalone=True):
[3e41f43]57        PluginBase.__init__(self, name="Pr inversion", standalone=standalone)
[f3d51f6]58        ## Simulation window manager
59        self.simview = None
[3e41f43]60       
[f3d51f6]61        ## State data
[b659551]62        self.alpha      = self.DEFAULT_ALPHA
63        self.nfunc      = self.DEFAULT_NFUNC
64        self.max_length = self.DEFAULT_DMAX
[634f1cf]65        self.q_min      = None
66        self.q_max      = None
[a4bd2ac]67        self.has_bck    = False
[2a92852]68        self.slit_height = 0
69        self.slit_width  = 0
[f3d51f6]70        ## Remember last plottable processed
71        self.last_data  = "sphere_60_q0_2.txt"
[0bae207]72        self._current_file_data = None
[f3d51f6]73        ## Time elapsed for last computation [sec]
74        # Start with a good default
75        self.elapsed = 0.022
[aa4b8379]76        self.iq_data_shown = False
[f3d51f6]77       
78        ## Current invertor
79        self.invertor    = None
[3fd1ebc]80        self.pr          = None
[feb21d8]81        # Copy of the last result in case we need to display it.
82        self._last_pr    = None
83        self._last_out   = None
84        self._last_cov   = None
[f3d51f6]85        ## Calculation thread
86        self.calc_thread = None
87        ## Estimation thread
88        self.estimation_thread = None
89        ## Result panel
90        self.control_panel = None
91        ## Currently views plottable
92        self.current_plottable = None
[b659551]93        ## Number of P(r) points to display on the output plot
94        self._pr_npts = 51
[aa4b8379]95        ## Flag to let the plug-in know that it is running standalone
[d2ee6f6]96        self.standalone = standalone
[feb21d8]97        self._normalize_output = False
98        self._scale_output_unity = False
[aa4b8379]99       
[f1181977]100        ## List of added P(r) plots
101        self._added_plots = {}
102        self._default_Iq  = {}
103       
[6f1f129]104        # Associate the inversion state reader with .prv files
105        from DataLoader.loader import Loader
106        from inversion_state import Reader
107         
[0d88a09]108        # Create a CanSAS/Pr reader
109        self.state_reader = Reader(self.set_state)
[6d3d5ff]110        self._extensions = '.prv'
[6f1f129]111        l = Loader()
[410aad8]112        l.associate_file_reader('.prv', self.state_reader)
[6d3d5ff]113        l.associate_file_reader(".svs", self.state_reader)
[6f1f129]114               
[aa4b8379]115        # Log startup
116        logging.info("Pr(r) plug-in started")
117       
[6d3d5ff]118    def get_data(self):
119        """
120        """
121        return self.current_plottable
122   
[410aad8]123    def set_state(self, state, datainfo=None):
[6f1f129]124        """
[7116b6e0]125        Call-back method for the inversion state reader.
126        This method is called when a .prv file is loaded.
127       
128        :param state: InversionState object
129        :param datainfo: Data1D object [optional]
130       
[6f1f129]131        """
[410aad8]132        try:
[0d88a09]133            if datainfo is None:
134                raise RuntimeError, "Pr.set_state: datainfo parameter cannot be None in standalone mode"
[302510b]135
[0d88a09]136            # Ensuring that plots are coordinated correctly
137            t = time.localtime(datainfo.meta_data['prstate'].timestamp)
138            time_str = time.strftime("%b %d %H:%M", t)
139           
140            # Check that no time stamp is already appended
141            max_char = datainfo.meta_data['prstate'].file.find("[")
142            if max_char < 0:
143                max_char = len(datainfo.meta_data['prstate'].file)
144           
145            datainfo.meta_data['prstate'].file = datainfo.meta_data['prstate'].file[0:max_char] +' [' + time_str + ']'
146            datainfo.filename = datainfo.meta_data['prstate'].file
[410aad8]147               
[0d88a09]148            self.current_plottable = datainfo
149            self.current_plottable.group_id = datainfo.meta_data['prstate'].file
150           
[410aad8]151            # Load the P(r) results
152            self.control_panel.set_state(state)
153                       
154            # Make sure the user sees the P(r) panel after loading
155            self.parent.set_perspective(self.perspective)           
156
157        except:
158            logging.error("prview.set_state: %s" % sys.exc_value)
[f3d51f6]159
[8994b6b]160 
[119a11d]161    def help(self, evt):
162        """
[7116b6e0]163        Show a general help dialog.
164       
165        :TODO: replace the text with a nice image
166       
[119a11d]167        """
168        from inversion_panel import HelpDialog
169        dialog = HelpDialog(None, -1)
170        if dialog.ShowModal() == wx.ID_OK:
171            dialog.Destroy()
172        else:
173            dialog.Destroy()
174   
[f3d51f6]175    def _fit_pr(self, evt):
[7116b6e0]176        """
177        """
[f3d51f6]178        from sans.pr.invertor import Invertor
[75df58b]179           
180        from danse.common.plottools import Data1D as PlotData1D
181        from danse.common.plottools import Theory1D as Theory1D
[f3d51f6]182       
183        # Generate P(r) for sphere
184        radius = 60.0
185        d_max  = 2*radius
186       
187        r = pylab.arange(0.01, d_max, d_max/51.0)
188        M = len(r)
189        y = numpy.zeros(M)
190        pr_err = numpy.zeros(M)
191       
192        sum = 0.0
193        for j in range(M):
194            value = self.pr_theory(r[j], radius)
195            sum += value
196            y[j] = value
197            pr_err[j] = math.sqrt(y[j])
198
199        y = y/sum*d_max/len(r)
200
201        # Perform fit
202        pr = Invertor()
203        pr.d_max = d_max
204        pr.alpha = 0
205        pr.x = r
206        pr.y = y
207        pr.err = pr_err
208        out, cov = pr.pr_fit()
209        for i in range(len(out)):
210            print "%g +- %g" % (out[i], math.sqrt(cov[i][i]))
211
212        # Show input P(r)
[75df58b]213        new_plot = PlotData1D(pr.x, pr.y, dy=pr.err)
[f3d51f6]214        new_plot.name = "P_{obs}(r)"
215        new_plot.xaxis("\\rm{r}", 'A')
216        new_plot.yaxis("\\rm{P(r)} ","cm^{-3}")
[75df58b]217        print "_fit_pr"
[f3d51f6]218        wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot, title="Pr"))
219
220        # Show P(r) fit
221        self.show_pr(out, pr)
222       
223        # Show I(q) fit
224        q = pylab.arange(0.001, 0.1, 0.01/51.0)
225        self.show_iq(out, pr, q)
226       
227    def show_shpere(self, x, radius=70.0, x_range=70.0):
[7116b6e0]228        """
229        """
[75df58b]230        from danse.common.plottools import Theory1D as PlotTheory1D
[f3d51f6]231        # Show P(r)
232        y_true = numpy.zeros(len(x))
233
234        sum_true = 0.0
235        for i in range(len(x)):
236            y_true[i] = self.pr_theory(x[i], radius)           
237            sum_true += y_true[i]
238           
239        y_true = y_true/sum_true*x_range/len(x)
240       
241        # Show the theory P(r)
[75df58b]242        new_plot = PlotTheory1D(x, y_true)
[f3d51f6]243        new_plot.name = "P_{true}(r)"
244        new_plot.xaxis("\\rm{r}", 'A')
245        new_plot.yaxis("\\rm{P(r)} ","cm^{-3}")
246       
247        #Put this call in plottables/guitools   
248        wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot, title="Sphere P(r)"))
[75df58b]249       
[f3d51f6]250       
[b659551]251    def get_npts(self):
252        """
[7116b6e0]253        Returns the number of points in the I(q) data
[b659551]254        """
255        try:
256            return len(self.pr.x)
257        except:
258            return 0
259       
[f3d51f6]260    def show_iq(self, out, pr, q=None):
[7116b6e0]261        """
[75df58b]262        """ 
263        from danse.common.plottools import Theory1D as PlotTheory1D
[f3d51f6]264
265        qtemp = pr.x
266        if not q==None:
267            qtemp = q
268
269        # Make a plot
270        maxq = -1
271        for q_i in qtemp:
272            if q_i>maxq:
273                maxq=q_i
274               
[634f1cf]275        minq = 0.001
276       
277        # Check for user min/max
278        if not pr.q_min==None:
279            minq = pr.q_min
280        if not pr.q_max==None:
281            maxq = pr.q_max
282               
283        x = pylab.arange(minq, maxq, maxq/301.0)
[f3d51f6]284        y = numpy.zeros(len(x))
285        err = numpy.zeros(len(x))
286        for i in range(len(x)):
287            value = pr.iq(out, x[i])
288            y[i] = value
289            try:
290                err[i] = math.sqrt(math.fabs(value))
291            except:
292                err[i] = 1.0
293                print "Error getting error", value, x[i]
294               
[75df58b]295        new_plot = PlotTheory1D(x, y)
[2a92852]296        new_plot.name = IQ_FIT_LABEL
[f3d51f6]297        new_plot.xaxis("\\rm{Q}", 'A^{-1}')
298        new_plot.yaxis("\\rm{Intensity} ","cm^{-1}")
[d2ee6f6]299       
300        title = "I(q)"
301        # If we have a group ID, use it
302        if pr.info.has_key("plot_group_id"):
303            new_plot.group_id = pr.info["plot_group_id"]
304            title = pr.info["plot_group_id"]
305           
306        wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot, title=title))
[f3d51f6]307       
[2a92852]308        # If we have used slit smearing, plot the smeared I(q) too
309        if pr.slit_width>0 or pr.slit_height>0:
310            x = pylab.arange(minq, maxq, maxq/301.0)
311            y = numpy.zeros(len(x))
312            err = numpy.zeros(len(x))
313            for i in range(len(x)):
314                value = pr.iq_smeared(out, x[i])
315                y[i] = value
316                try:
317                    err[i] = math.sqrt(math.fabs(value))
318                except:
319                    err[i] = 1.0
320                    print "Error getting error", value, x[i]
321                   
322            new_plot = Theory1D(x, y)
323            new_plot.name = IQ_SMEARED_LABEL
324            new_plot.xaxis("\\rm{Q}", 'A^{-1}')
325            new_plot.yaxis("\\rm{Intensity} ","cm^{-1}")
[f0ff8d65]326            # If we have a group ID, use it
327            if pr.info.has_key("plot_group_id"):
328                new_plot.group_id = pr.info["plot_group_id"]
329            wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot, title=title))
[2a92852]330       
[f3d51f6]331       
[b659551]332    def _on_pr_npts(self, evt):
333        """
[7116b6e0]334        Redisplay P(r) with a different number of points
[b659551]335        """   
336        from inversion_panel import PrDistDialog
337        dialog = PrDistDialog(None, -1)
338        dialog.set_content(self._pr_npts)
339        if dialog.ShowModal() == wx.ID_OK:
340            self._pr_npts= dialog.get_content()
341            dialog.Destroy()
[feb21d8]342            self.show_pr(self._last_out, self._last_pr, self._last_cov)
[b659551]343        else:
344            dialog.Destroy()
[f3d51f6]345       
346       
347    def show_pr(self, out, pr, cov=None):
[7116b6e0]348        """
[75df58b]349        """     
350        from danse.common.plottools import Data1D as PlotData1D
351        from danse.common.plottools import Theory1D as PlotTheory1D
[f3d51f6]352       
353        # Show P(r)
[b659551]354        x = pylab.arange(0.0, pr.d_max, pr.d_max/self._pr_npts)
[f3d51f6]355   
356        y = numpy.zeros(len(x))
357        dy = numpy.zeros(len(x))
358        y_true = numpy.zeros(len(x))
359
360        sum = 0.0
[feb21d8]361        pmax = 0.0
[dfb58f8]362        cov2 = numpy.ascontiguousarray(cov)
363       
[f3d51f6]364        for i in range(len(x)):
[dfb58f8]365            if cov2==None:
[f3d51f6]366                value = pr.pr(out, x[i])
367            else:
[dfb58f8]368                (value, dy[i]) = pr.pr_err(out, cov2, x[i])
[660b1e6]369            sum += value*pr.d_max/len(x)
[f3d51f6]370           
[feb21d8]371            # keep track of the maximum P(r) value
372            if value>pmax:
373                pmax = value
374               
375            y[i] = value
376               
377        if self._normalize_output==True:
378            y = y/sum
379            dy = dy/sum
380        elif self._scale_output_unity==True:
381            y = y/pmax
382            dy = dy/pmax
[f3d51f6]383       
[dfb58f8]384        if cov2==None:
[75df58b]385            new_plot = PlotTheory1D(x, y)
[f3d51f6]386        else:
[75df58b]387            new_plot = PlotData1D(x, y, dy=dy)
[f1181977]388        new_plot.name = PR_FIT_LABEL
[f3d51f6]389        new_plot.xaxis("\\rm{r}", 'A')
390        new_plot.yaxis("\\rm{P(r)} ","cm^{-3}")
[75df58b]391        new_plot.title = "P(r) fit"
[d2ee6f6]392        # Make sure that the plot is linear
393        new_plot.xtransform="x"
394        new_plot.ytransform="y"                 
[f3d51f6]395        wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot, title="P(r) fit"))
396       
397        return x, pr.d_max
398       
399               
[75df58b]400    def load(self, data):
[0bae207]401        """
[7116b6e0]402        Load data. This will eventually be replaced
403        by our standard DataLoader class.
[0bae207]404        """
405        class FileData:
406            x = None
407            y = None
408            err = None
409            path = None
410           
411            def __init__(self, path):
412                self.path = path
413               
[75df58b]414        self._current_file_data = FileData(data.path)
[0bae207]415       
[aab8ad7]416        # Use data loader to load file
[75df58b]417        #dataread = Loader().load(path)
418        dataread = data
[ceaf16e]419        # Notify the user if we could not read the file
420        if dataread is None:
421            raise RuntimeError, "Invalid data"
422           
[aab8ad7]423        x = None
424        y = None
425        err = None
426        if dataread.__class__.__name__ == 'Data1D':
427            x = dataread.x
428            y = dataread.y
429            err = dataread.dy
430        else:
[e43c012]431            if isinstance(dataread, list) and len(dataread)>0:
432                x = dataread[0].x
433                y = dataread[0].y
434                err = dataread[0].dy
435                msg = "PrView only allows a single data set at a time. "
436                msg += "Only the first data set was loaded." 
437                wx.PostEvent(self.parent, StatusEvent(status=msg))
438            else:
[6f1f129]439                if dataread is None:
440                    return x, y, err
[e43c012]441                raise RuntimeError, "This tool can only read 1D data"
[aab8ad7]442       
[0bae207]443        self._current_file_data.x = x
444        self._current_file_data.y = y
445        self._current_file_data.err = err
446        return x, y, err
447               
448    def load_columns(self, path = "sphere_60_q0_2.txt"):
449        """
[7116b6e0]450        Load 2- or 3- column ascii
[0bae207]451        """
[f3d51f6]452        import numpy, math, sys
453        # Read the data from the data file
454        data_x   = numpy.zeros(0)
455        data_y   = numpy.zeros(0)
456        data_err = numpy.zeros(0)
[b659551]457        scale    = None
458        min_err  = 0.0
[f3d51f6]459        if not path == None:
460            input_f = open(path,'r')
461            buff    = input_f.read()
462            lines   = buff.split('\n')
463            for line in lines:
464                try:
465                    toks = line.split()
466                    x = float(toks[0])
467                    y = float(toks[1])
[b659551]468                    if len(toks)>2:
469                        err = float(toks[2])
470                    else:
471                        if scale==None:
472                            scale = 0.05*math.sqrt(y)
473                            #scale = 0.05/math.sqrt(y)
474                            min_err = 0.01*y
475                        err = scale*math.sqrt(y)+min_err
476                        #err = 0
477                       
[4a5de6f]478                    data_x = numpy.append(data_x, x)
479                    data_y = numpy.append(data_y, y)
[b659551]480                    data_err = numpy.append(data_err, err)
[f3d51f6]481                except:
[b659551]482                    pass
[f3d51f6]483                   
[357b79b]484        if not scale==None:
485            message = "The loaded file had no error bars, statistical errors are assumed."
486            wx.PostEvent(self.parent, StatusEvent(status=message))
487        else:
488            wx.PostEvent(self.parent, StatusEvent(status=''))
489                       
[b659551]490        return data_x, data_y, data_err     
[f3d51f6]491       
[0bae207]492    def load_abs(self, path):
493        """
[7116b6e0]494        Load an IGOR .ABS reduced file
495       
496        :param path: file path
497       
498        :return: x, y, err vectors
499       
[0bae207]500        """
501        import numpy, math, sys
502        # Read the data from the data file
503        data_x   = numpy.zeros(0)
504        data_y   = numpy.zeros(0)
505        data_err = numpy.zeros(0)
506        scale    = None
507        min_err  = 0.0
508       
509        data_started = False
510        if not path == None:
511            input_f = open(path,'r')
512            buff    = input_f.read()
513            lines   = buff.split('\n')
514            for line in lines:
515                if data_started==True:
516                    try:
517                        toks = line.split()
518                        x = float(toks[0])
519                        y = float(toks[1])
520                        if len(toks)>2:
521                            err = float(toks[2])
522                        else:
523                            if scale==None:
524                                scale = 0.05*math.sqrt(y)
525                                #scale = 0.05/math.sqrt(y)
526                                min_err = 0.01*y
527                            err = scale*math.sqrt(y)+min_err
528                            #err = 0
529                           
530                        data_x = numpy.append(data_x, x)
531                        data_y = numpy.append(data_y, y)
532                        data_err = numpy.append(data_err, err)
533                    except:
534                        pass
535                elif line.find("The 6 columns")>=0:
536                    data_started = True     
537                   
538        if not scale==None:
539            message = "The loaded file had no error bars, statistical errors are assumed."
540            wx.PostEvent(self.parent, StatusEvent(status=message))
541        else:
542            wx.PostEvent(self.parent, StatusEvent(status=''))
543                       
544        return data_x, data_y, data_err     
545       
[f3d51f6]546    def pr_theory(self, r, R):
[7116b6e0]547        """ 
[f3d51f6]548        """
549        if r<=2*R:
550            return 12.0* ((0.5*r/R)**2) * ((1.0-0.5*r/R)**2) * ( 2.0 + 0.5*r/R )
551        else:
552            return 0.0
553
[660b1e6]554    def get_context_menu(self, graph=None):
[f3d51f6]555        """
[7116b6e0]556        Get the context menu items available for P(r)
557       
558        :param graph: the Graph object to which we attach the context menu
559       
560        :return: a list of menu items with call-back function
561       
[f3d51f6]562        """
[660b1e6]563        # Look whether this Graph contains P(r) data
[aa4b8379]564        #if graph.selected_plottable==IQ_DATA_LABEL:
[660b1e6]565        for item in graph.plottables:
[75df58b]566            if item.name == PR_FIT_LABEL:
567                #add_data_hint = "Load a data file and display it on this plot"
568                #["Add P(r) data",add_data_hint , self._on_add_data],
569                change_n_hint = "Change the number of"
570                change_n_hint += " points on the P(r) output"
571                change_n_label = "Change number of P(r) points"
572                m_list = [[change_n_label, change_n_hint , self._on_pr_npts]]
[aa4b8379]573
[75df58b]574                if self._scale_output_unity or self._normalize_output:
575                    hint = "Let the output P(r) keep the scale of the data"
576                    m_list.append(["Disable P(r) scaling", hint, 
[900c787]577                                   self._on_disable_scaling])
[75df58b]578                if not self._scale_output_unity:
[feb21d8]579                    m_list.append(["Scale P_max(r) to unity", 
580                                   "Scale P(r) so that its maximum is 1", 
581                                   self._on_scale_unity])
[75df58b]582                if not self._normalize_output:
[feb21d8]583                    m_list.append(["Normalize P(r) to unity", 
584                                   "Normalize the integral of P(r) to 1", 
585                                   self._on_normalize])
586                   
587                return m_list
[75df58b]588                #return [["Add P(r) data",
589                #"Load a data file and display it on this plot",
590                # self._on_add_data],
591                #       ["Change number of P(r) points",
592                # "Change the number of points on the P(r) output",
593                # self._on_pr_npts]]
[feb21d8]594
[75df58b]595            elif item.name == graph.selected_plottable:
596                    #TODO: we might want to check that the units are
597                    #     consistent with I(q) before allowing this menu item
598                if not self.standalone and \
599                issubclass(item.__class__, DataLoader.data_info.Data1D):
600                    return [["Compute P(r)", 
601                             "Compute P(r) from distribution", 
602                             self._on_context_inversion]]     
[660b1e6]603               
[aa4b8379]604        return []
[660b1e6]605
[feb21d8]606    def _on_disable_scaling(self, evt):
607        """
[7116b6e0]608        Disable P(r) scaling
609           
610        :param evt: Menu event
611       
[feb21d8]612        """
613        self._normalize_output = False
614        self._scale_output_unity = False
615        self.show_pr(self._last_out, self._last_pr, self._last_cov)
616       
[f1181977]617        # Now replot the original added data
618        for plot in self._added_plots:
619            self._added_plots[plot].y = numpy.copy(self._default_Iq[plot])
[75df58b]620            wx.PostEvent(self.parent, 
621                         NewPlotEvent(plot=self._added_plots[plot], 
622                                      title=self._added_plots[plot].name,
[f1181977]623                                                   update=True))       
624       
625        # Need the update flag in the NewPlotEvent to protect against
626        # the plot no longer being there...
627       
[feb21d8]628    def _on_normalize(self, evt):
629        """
[7116b6e0]630        Normalize the area under the P(r) curve to 1.
631        This operation is done for all displayed plots.
632       
633        :param evt: Menu event
634       
[feb21d8]635        """
636        self._normalize_output = True
637        self._scale_output_unity = False
638           
639        self.show_pr(self._last_out, self._last_pr, self._last_cov)
640       
[f1181977]641        # Now scale the added plots too
642        for plot in self._added_plots:
643            sum = numpy.sum(self._added_plots[plot].y)
644            npts = len(self._added_plots[plot].x)
645            sum *= self._added_plots[plot].x[npts-1]/npts
646            y = self._added_plots[plot].y/sum
647           
648            new_plot = Theory1D(self._added_plots[plot].x, y)
649            new_plot.name = self._added_plots[plot].name
650            new_plot.xaxis("\\rm{r}", 'A')
651            new_plot.yaxis("\\rm{P(r)} ","cm^{-3}")
652           
[75df58b]653            wx.PostEvent(self.parent, 
654                         NewPlotEvent(plot=new_plot, update=True,
655                                         title=self._added_plots[plot].name))
[f1181977]656       
[feb21d8]657    def _on_scale_unity(self, evt):
658        """
[7116b6e0]659        Scale the maximum P(r) value on each displayed plot to 1.
660       
661        :param evt: Menu event
662       
[feb21d8]663        """
664        self._scale_output_unity = True
665        self._normalize_output = False
666           
667        self.show_pr(self._last_out, self._last_pr, self._last_cov)
668       
[f1181977]669        # Now scale the added plots too
670        for plot in self._added_plots:
671            _max = 0
672            for y in self._added_plots[plot].y:
673                if y>_max: 
674                    _max = y
675            y = self._added_plots[plot].y/_max
676           
677            new_plot = Theory1D(self._added_plots[plot].x, y)
678            new_plot.name = self._added_plots[plot].name
679            new_plot.xaxis("\\rm{r}", 'A')
680            new_plot.yaxis("\\rm{P(r)} ","cm^{-3}")
681           
[75df58b]682            wx.PostEvent(self.parent, 
683                         NewPlotEvent(plot=new_plot, update=True,
684                                title=self._added_plots[plot].name))       
[f1181977]685       
686       
[660b1e6]687    def _on_add_data(self, evt):
688        """
[7116b6e0]689        Add a data curve to the plot
690       
691        :WARNING: this will be removed once guiframe.plotting has
692             its full functionality
[660b1e6]693        """
694        path = self.choose_file()
695        if path==None:
696            return
697       
[14d05ba]698        #x, y, err = self.parent.load_ascii_1D(path)
699        # Use data loader to load file
700        try:
701            dataread = Loader().load(path)
702            x = None
703            y = None
704            err = None
705            if dataread.__class__.__name__ == 'Data1D':
706                x = dataread.x
707                y = dataread.y
708                err = dataread.dy
709            else:
[e43c012]710                if isinstance(dataread, list) and len(dataread)>0:
711                    x = dataread[0].x
712                    y = dataread[0].y
713                    err = dataread[0].dy
714                    msg = "PrView only allows a single data set at a time. "
715                    msg += "Only the first data set was loaded." 
716                    wx.PostEvent(self.parent, StatusEvent(status=msg))
717                else:
[75df58b]718                    msg = "This tool can only read 1D data"
719                    wx.PostEvent(self.parent, StatusEvent(status=msg))
[e43c012]720                    return
721           
[14d05ba]722        except:
723            wx.PostEvent(self.parent, StatusEvent(status=sys.exc_value))
724            return
[660b1e6]725       
[f1181977]726        filename = os.path.basename(path)
727       
[b659551]728        #new_plot = Data1D(x, y, dy=err)
729        new_plot = Theory1D(x, y)
[f1181977]730        new_plot.name = filename
[660b1e6]731        new_plot.xaxis("\\rm{r}", 'A')
732        new_plot.yaxis("\\rm{P(r)} ","cm^{-3}")
733           
[f1181977]734        # Store a ref to the plottable for later use
735        self._added_plots[filename] = new_plot
736        self._default_Iq[filename]  = numpy.copy(y)
737       
738        wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot, title=filename))
[660b1e6]739       
740       
[f3d51f6]741
742    def start_thread(self):
[7116b6e0]743        """
744        """
[f3d51f6]745        from pr_thread import CalcPr
746        from copy import deepcopy
747       
748        # If a thread is already started, stop it
749        if self.calc_thread != None and self.calc_thread.isrunning():
750            self.calc_thread.stop()
751               
752        pr = self.pr.clone()
[75df58b]753        self.calc_thread = CalcPr(pr, self.nfunc,
754                                   error_func=self._thread_error, 
755                                   completefn=self._completed, updatefn=None)
[f3d51f6]756        self.calc_thread.queue()
757        self.calc_thread.ready(2.5)
758   
759    def _thread_error(self, error):
[7116b6e0]760        """
761        """
[f3d51f6]762        wx.PostEvent(self.parent, StatusEvent(status=error))
763   
[32dffae4]764    def _estimate_completed(self, alpha, message, elapsed):
[f3d51f6]765        """
[7116b6e0]766        Parameter estimation completed,
767        display the results to the user
768       
769        :param alpha: estimated best alpha
770        :param elapsed: computation time
771       
[f3d51f6]772        """
773        # Save useful info
774        self.elapsed = elapsed
775        self.control_panel.alpha_estimate = alpha
[32dffae4]776        if not message==None:
777            wx.PostEvent(self.parent, StatusEvent(status=str(message)))
[35adaf6]778           
779        self.perform_estimateNT()
780   
781
782   
783    def _estimateNT_completed(self, nterms, alpha, message, elapsed):
784        """
[7116b6e0]785        Parameter estimation completed,
786        display the results to the user
787       
788        :param alpha: estimated best alpha
789        :param nterms: estimated number of terms
790        :param elapsed: computation time
791       
[35adaf6]792        """
793        # Save useful info
794        self.elapsed = elapsed
795        self.control_panel.nterms_estimate = nterms
796        self.control_panel.alpha_estimate = alpha
797        if not message==None:
798            wx.PostEvent(self.parent, StatusEvent(status=str(message)))
[f3d51f6]799   
800    def _completed(self, out, cov, pr, elapsed):
801        """
[7116b6e0]802        Method called with the results when the inversion
803        is done
804       
805        :param out: output coefficient for the base functions
806        :param cov: covariance matrix
807        :param pr: Invertor instance
808        :param elapsed: time spent computing
809       
[f3d51f6]810        """
[dfb58f8]811        from copy import deepcopy
[f3d51f6]812        # Save useful info
813        self.elapsed = elapsed
[feb21d8]814        # Keep a copy of the last result
815        self._last_pr  = pr.clone()
816        self._last_out = out
817        self._last_cov = cov
818       
[b659551]819        # Save Pr invertor
820        self.pr = pr
821       
[75df58b]822        #message = "Computation completed in"
823        #message +=  %g seconds [chi2=%g]" % (elapsed, pr.chi2)
[d6113849]824        #wx.PostEvent(self.parent, StatusEvent(status=message))
[f3d51f6]825
[dfb58f8]826        cov = numpy.ascontiguousarray(cov)
827
[f3d51f6]828        # Show result on control panel
829        self.control_panel.chi2 = pr.chi2
830        self.control_panel.elapsed = elapsed
831        self.control_panel.oscillation = pr.oscillations(out)
832        #print "OSCILL", pr.oscillations(out)
[d6113849]833        #print "PEAKS:", pr.get_peaks(out)
[dfb58f8]834        self.control_panel.positive = pr.get_positive(out)
835        self.control_panel.pos_err  = pr.get_pos_err(out, cov)
[a4bd2ac]836        self.control_panel.rg = pr.rg(out)
837        self.control_panel.iq0 = pr.iq0(out)
838        self.control_panel.bck = pr.background
[f3d51f6]839       
[aa4b8379]840        if False:
[0bae207]841            for i in range(len(out)):
842                try:
[75df58b]843                    print "%d: %g +- %g" % (i, out[i],
844                                             math.sqrt(math.fabs(cov[i][i])))
[0bae207]845                except: 
846                    print sys.exc_value
847                    print "%d: %g +- ?" % (i, out[i])       
848       
849            # Make a plot of I(q) data
[aa4b8379]850            new_plot = Data1D(self.pr.x, self.pr.y, dy=self.pr.err)
[f1181977]851            new_plot.name = IQ_DATA_LABEL
[aa4b8379]852            new_plot.xaxis("\\rm{Q}", 'A^{-1}')
853            new_plot.yaxis("\\rm{Intensity} ","cm^{-1}")
854            #new_plot.group_id = "test group"
855            wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot, title="Iq"))
[f3d51f6]856               
857        # Show I(q) fit
858        self.show_iq(out, self.pr)
859       
860        # Show P(r) fit
[dfb58f8]861        x_values, x_range = self.show_pr(out, self.pr, cov) 
[f3d51f6]862       
863        # Popup result panel
[75df58b]864        #result_panel = InversionResults(self.parent,
865        #-1, style=wx.RAISED_BORDER)
[f3d51f6]866       
[75df58b]867    def show_data(self, path=None, data=None, reset=False):
[2a92852]868        """
[7116b6e0]869        Show data read from a file
870       
871        :param path: file path
872        :param reset: if True all other plottables will be cleared
873       
[2a92852]874        """
[75df58b]875        print "show_data", data.name
876        #if path is not None:
877        if data is not None:
[ea5551f]878            try:
[75df58b]879                #pr = self._create_file_pr(path)
880                pr = self._create_file_pr(data)
[ceaf16e]881            except:
[75df58b]882                status = "Problem reading data: %s" % sys.exc_value
[ceaf16e]883                wx.PostEvent(self.parent, StatusEvent(status=status))
884                raise RuntimeError, status
[6f1f129]885               
[ceaf16e]886            # If the file contains nothing, just return
887            if pr is None:
888                raise RuntimeError, "Loaded data is invalid"
889           
890            self.pr = pr
[75df58b]891       
[660b1e6]892        # Make a plot of I(q) data
[357b79b]893        if self.pr.err==None:
894            new_plot = Theory1D(self.pr.x, self.pr.y)
895        else:
896            new_plot = Data1D(self.pr.x, self.pr.y, dy=self.pr.err)
[f1181977]897        new_plot.name = IQ_DATA_LABEL
[660b1e6]898        new_plot.xaxis("\\rm{Q}", 'A^{-1}')
899        new_plot.yaxis("\\rm{Intensity} ","cm^{-1}")
[aa4b8379]900        new_plot.interactive = True
[660b1e6]901        #new_plot.group_id = "test group"
[75df58b]902        wx.PostEvent(self.parent, 
903                     NewPlotEvent(plot=new_plot, title="I(q)", reset=reset))
[660b1e6]904       
[0d88a09]905        self.current_plottable = new_plot
906        self.current_plottable.group_id = IQ_DATA_LABEL
907       
908       
[aa4b8379]909        # Get Q range
910        self.control_panel.q_min = self.pr.x.min()
911        self.control_panel.q_max = self.pr.x.max()
912           
[410aad8]913    def save_data(self, filepath, prstate=None):
914        """
[7116b6e0]915        Save data in provided state object.
916       
917        :TODO: move the state code away from inversion_panel and move it here.
918                Then remove the "prstate" input and make this method private.
919               
920        :param filepath: path of file to write to
921        :param prstate: P(r) inversion state
922       
[410aad8]923        """
924        #TODO: do we need this or can we use DataLoader.loader.save directly?
925       
926        # Add output data and coefficients to state
927        prstate.coefficients = self._last_out
928        prstate.covariance = self._last_cov
929       
930        # Write the output to file
[0ab485b]931        # First, check that the data is of the right type
[75df58b]932        if issubclass(self.current_plottable.__class__,
933                       DataLoader.data_info.Data1D):
[0ab485b]934            self.state_reader.write(filepath, self.current_plottable, prstate)
935        else:
[75df58b]936            msg = "pr.save_data: the data being saved is not a"
937            msg += " DataLoader.data_info.Data1D object" 
938            raise RuntimeError, msg
[410aad8]939       
[660b1e6]940       
[2a92852]941    def setup_plot_inversion(self, alpha, nfunc, d_max, q_min=None, q_max=None, 
942                             bck=False, height=0, width=0):
[7116b6e0]943        """
944        """
[f3d51f6]945        self.alpha = alpha
946        self.nfunc = nfunc
947        self.max_length = d_max
[634f1cf]948        self.q_min = q_min
949        self.q_max = q_max
[a4bd2ac]950        self.has_bck = bck
[2a92852]951        self.slit_height = height
952        self.slit_width  = width
[f3d51f6]953       
[4a5de6f]954        try:
[2a92852]955            pr = self._create_plot_pr()
956            if not pr==None:
957                self.pr = pr
958                self.perform_inversion()
[4a5de6f]959        except:
960            wx.PostEvent(self.parent, StatusEvent(status=sys.exc_value))
[f3d51f6]961
[75df58b]962    def estimate_plot_inversion(self, alpha, nfunc, d_max, 
963                                q_min=None, q_max=None, 
[2a92852]964                                bck=False, height=0, width=0):
[7116b6e0]965        """
966        """
[f3d51f6]967        self.alpha = alpha
968        self.nfunc = nfunc
969        self.max_length = d_max
[634f1cf]970        self.q_min = q_min
971        self.q_max = q_max
[a4bd2ac]972        self.has_bck = bck
[2a92852]973        self.slit_height = height
974        self.slit_width  = width
[f3d51f6]975       
[4a5de6f]976        try:
[2a92852]977            pr = self._create_plot_pr()
978            if not pr==None:
979                self.pr = pr
980                self.perform_estimate()
[4a5de6f]981        except:
982            wx.PostEvent(self.parent, StatusEvent(status=sys.exc_value))           
[f3d51f6]983
[2a92852]984    def _create_plot_pr(self, estimate=False):
[f3d51f6]985        """
[7116b6e0]986        Create and prepare invertor instance from
987        a plottable data set.
988       
989        :param path: path of the file to read in
990       
[f3d51f6]991        """
[ceaf16e]992        # Sanity check
993        if self.current_plottable is None:
994            msg = "Please load a valid data set before proceeding."
995            wx.PostEvent(self.parent, StatusEvent(status=msg)) 
996            return None   
997       
[f3d51f6]998        # Get the data from the chosen data set and perform inversion
999        pr = Invertor()
1000        pr.d_max = self.max_length
1001        pr.alpha = self.alpha
[634f1cf]1002        pr.q_min = self.q_min
1003        pr.q_max = self.q_max
[f3d51f6]1004        pr.x = self.current_plottable.x
1005        pr.y = self.current_plottable.y
[a4bd2ac]1006        pr.has_bck = self.has_bck
[2a92852]1007        pr.slit_height = self.slit_height
1008        pr.slit_width = self.slit_width
[f3d51f6]1009       
[d2ee6f6]1010        # Keep track of the plot window title to ensure that
1011        # we can overlay the plots
1012        if hasattr(self.current_plottable, "group_id"):
1013            pr.info["plot_group_id"] = self.current_plottable.group_id
1014       
[f3d51f6]1015        # Fill in errors if none were provided
[d2ee6f6]1016        err = self.current_plottable.dy
1017        all_zeros = True
1018        if err == None:
[d483799]1019            err = numpy.zeros(len(pr.y)) 
[d2ee6f6]1020        else:   
1021            for i in range(len(err)):
1022                if err[i]>0:
1023                    all_zeros = False
1024       
1025        if all_zeros:       
1026            scale = None
1027            min_err = 0.0
[f3d51f6]1028            for i in range(len(pr.y)):
[d2ee6f6]1029                # Scale the error so that we can fit over several decades of Q
1030                if scale==None:
1031                    scale = 0.05*math.sqrt(pr.y[i])
1032                    min_err = 0.01*pr.y[i]
1033                err[i] = scale*math.sqrt( math.fabs(pr.y[i]) ) + min_err
[75df58b]1034            message = "The loaded file had no error bars, "
1035            message += "statistical errors are assumed."
[d2ee6f6]1036            wx.PostEvent(self.parent, StatusEvent(status=message))
1037
1038        pr.err = err
[2a92852]1039       
1040        return pr
[f3d51f6]1041
1042         
[75df58b]1043    def setup_file_inversion(self, alpha, nfunc, d_max, data,
1044                             path=None, q_min=None, q_max=None, 
[2a92852]1045                             bck=False, height=0, width=0):
[7116b6e0]1046        """
1047        """
[f3d51f6]1048        self.alpha = alpha
1049        self.nfunc = nfunc
1050        self.max_length = d_max
[634f1cf]1051        self.q_min = q_min
1052        self.q_max = q_max
[a4bd2ac]1053        self.has_bck = bck
[2a92852]1054        self.slit_height = height
1055        self.slit_width  = width
[f3d51f6]1056       
[4a5de6f]1057        try:
[75df58b]1058            #pr = self._create_file_pr(path)
1059            pr = self._create_file_pr(data)
[2a92852]1060            if not pr==None:
1061                self.pr = pr
[4a5de6f]1062                self.perform_inversion()
1063        except:
1064            wx.PostEvent(self.parent, StatusEvent(status=sys.exc_value))
[f3d51f6]1065         
[75df58b]1066    def estimate_file_inversion(self, alpha, nfunc, d_max, data,
1067                                path=None, q_min=None, q_max=None, 
[2a92852]1068                                bck=False, height=0, width=0):
[7116b6e0]1069        """
1070        """
[f3d51f6]1071        self.alpha = alpha
1072        self.nfunc = nfunc
1073        self.max_length = d_max
[634f1cf]1074        self.q_min = q_min
1075        self.q_max = q_max
[a4bd2ac]1076        self.has_bck = bck
[2a92852]1077        self.slit_height = height
1078        self.slit_width  = width
[f3d51f6]1079       
[4a5de6f]1080        try:
[75df58b]1081            pr = self._create_file_pr(data)
1082            #pr = self._create_file_pr(path)
1083            if not pr is None:
[2a92852]1084                self.pr = pr
[4a5de6f]1085                self.perform_estimate()
1086        except:
1087            wx.PostEvent(self.parent, StatusEvent(status=sys.exc_value))
1088               
[f3d51f6]1089         
[75df58b]1090    def _create_file_pr(self, data):
[f3d51f6]1091        """
[7116b6e0]1092        Create and prepare invertor instance from
1093        a file data set.
1094       
1095        :param path: path of the file to read in
1096       
[f3d51f6]1097        """
1098        # Load data
[75df58b]1099        #if os.path.isfile(path):
1100        """   
1101        if self._current_file_data is not None \
1102            and self._current_file_data.path==path:
1103            # Protect against corrupted data from
1104            # previous failed load attempt
1105            if self._current_file_data.x is None:
1106                return None
1107            x = self._current_file_data.x
1108            y = self._current_file_data.y
1109            err = self._current_file_data.err
[357b79b]1110           
[75df58b]1111            message = "The data from this file has already been loaded."
1112            wx.PostEvent(self.parent, StatusEvent(status=message))
1113        else:
1114        """
1115        # Reset the status bar so that we don't get mixed up
1116        # with old messages.
1117        #TODO: refactor this into a proper status handling
1118        wx.PostEvent(self.parent, StatusEvent(status=''))
1119        try:
1120            class FileData:
1121                x = None
1122                y = None
1123                err = None
1124                path = None
1125                def __init__(self, path):
1126                    self.path = path
[6f1f129]1127               
[75df58b]1128            self._current_file_data = FileData(data.path)
1129            self._current_file_data.x = data.x
1130            self._current_file_data.y = data.y
1131            self._current_file_data.err = data.dy
1132            x, y, err = data.x, data.y, data.dy
1133        except:
1134            load_error(sys.exc_value)
1135            return None
1136       
1137        # If the file contains no data, just return
1138        if x is None or len(x) == 0:
1139            load_error("The loaded file contains no data")
1140            return None
1141       
1142        # If we have not errors, add statistical errors
1143        if err is not None and y is not None:
1144            err = numpy.zeros(len(y))
1145            scale = None
1146            min_err = 0.0
1147            for i in range(len(y)):
1148                # Scale the error so that we can fit over several decades of Q
1149                if scale == None:
1150                    scale = 0.05 * math.sqrt(y[i])
1151                    min_err = 0.01 * y[i]
1152                err[i] = scale * math.sqrt(math.fabs(y[i])) + min_err
1153            message = "The loaded file had no error bars, "
1154            message += "statistical errors are assumed."
1155            wx.PostEvent(self.parent, StatusEvent(status=message))
1156       
1157        try:
1158            # Get the data from the chosen data set and perform inversion
1159            pr = Invertor()
1160            pr.d_max = self.max_length
1161            pr.alpha = self.alpha
1162            pr.q_min = self.q_min
1163            pr.q_max = self.q_max
1164            pr.x = x
1165            pr.y = y
1166            pr.err = err
1167            pr.has_bck = self.has_bck
1168            pr.slit_height = self.slit_height
1169            pr.slit_width = self.slit_width
1170            return pr
1171        except:
1172            load_error(sys.exc_value)
[2a92852]1173        return None
[f3d51f6]1174       
1175    def perform_estimate(self):
[7116b6e0]1176        """
1177        """
[f3d51f6]1178        from pr_thread import EstimatePr
1179        from copy import deepcopy
1180       
1181        # If a thread is already started, stop it
[75df58b]1182        if self.estimation_thread != None and \
1183            self.estimation_thread.isrunning():
[f3d51f6]1184            self.estimation_thread.stop()
1185               
1186        pr = self.pr.clone()
[75df58b]1187        self.estimation_thread = EstimatePr(pr, self.nfunc,
1188                                             error_func=self._thread_error, 
1189                                         completefn = self._estimate_completed, 
[f3d51f6]1190                                            updatefn   = None)
1191        self.estimation_thread.queue()
1192        self.estimation_thread.ready(2.5)
[35adaf6]1193   
1194    def perform_estimateNT(self):
[7116b6e0]1195        """
1196        """
[35adaf6]1197        from pr_thread import EstimateNT
1198        from copy import deepcopy
1199       
1200        # If a thread is already started, stop it
1201        if self.estimation_thread != None and self.estimation_thread.isrunning():
1202            self.estimation_thread.stop()
1203               
1204        pr = self.pr.clone()
[2a92852]1205        # Skip the slit settings for the estimation
1206        # It slows down the application and it doesn't change the estimates
1207        pr.slit_height = 0.0
1208        pr.slit_width  = 0.0
[75df58b]1209        self.estimation_thread = EstimateNT(pr, self.nfunc, 
1210                                            error_func=self._thread_error, 
1211                                        completefn = self._estimateNT_completed, 
[35adaf6]1212                                            updatefn   = None)
1213        self.estimation_thread.queue()
1214        self.estimation_thread.ready(2.5)
[f3d51f6]1215       
1216    def perform_inversion(self):
[7116b6e0]1217        """
1218        """
[f3d51f6]1219        # Time estimate
1220        #estimated = self.elapsed*self.nfunc**2
[2a92852]1221        #message = "Computation time may take up to %g seconds" % self.elapsed
1222        #wx.PostEvent(self.parent, StatusEvent(status=message))
[f3d51f6]1223       
1224        # Start inversion thread
1225        self.start_thread()
1226        return
1227       
1228        out, cov = self.pr.lstsq(self.nfunc)
1229       
1230        # Save useful info
1231        self.elapsed = self.pr.elapsed
1232       
1233        for i in range(len(out)):
1234            try:
[75df58b]1235                print "%d: %g +- %g" % (i, out[i],
1236                                         math.sqrt(math.fabs(cov[i][i])))
[f3d51f6]1237            except: 
1238                print "%d: %g +- ?" % (i, out[i])       
1239       
1240        # Make a plot of I(q) data
1241        new_plot = Data1D(self.pr.x, self.pr.y, dy=self.pr.err)
1242        new_plot.name = "I_{obs}(q)"
1243        new_plot.xaxis("\\rm{Q}", 'A^{-1}')
1244        new_plot.yaxis("\\rm{Intensity} ","cm^{-1}")
1245        wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot, title="Iq"))
1246        # Show I(q) fit
1247        self.show_iq(out, self.pr)
1248        # Show P(r) fit
1249        x_values, x_range = self.show_pr(out, self.pr, cov=cov)
1250       
1251    def _on_context_inversion(self, event):
[75df58b]1252        """
1253        """
[f3d51f6]1254        panel = event.GetEventObject()
1255
1256        # If we have more than one displayed plot, make the user choose
[75df58b]1257        if len(panel.plots) > 1 and \
1258            panel.graph.selected_plottable in panel.plots:
[aa4b8379]1259            dataset = panel.graph.selected_plottable
[75df58b]1260        elif len(panel.plots) == 1:
[f3d51f6]1261            dataset = panel.plots.keys()[0]
1262        else:
[75df58b]1263            logging.info("Prview Error: No data is available")
[f3d51f6]1264            return
1265       
1266        # Store a reference to the current plottable
[3fd1ebc]1267        # If we have a suggested value, use it.
1268        try:
1269            estimate = float(self.control_panel.alpha_estimate)
1270            self.control_panel.alpha = estimate
1271        except:
1272            self.control_panel.alpha = self.alpha
[75df58b]1273            logging.info("Prview :Alpha Not estimate yet")
[3fd1ebc]1274            pass
[d6113849]1275        try:
1276            estimate = int(self.control_panel.nterms_estimate)
1277            self.control_panel.nfunc = estimate
1278        except:
1279            self.control_panel.nfunc = self.nfunc
[75df58b]1280            logging.info("Prview : ntemrs Not estimate yet")
[d6113849]1281            pass
[3fd1ebc]1282       
[f3d51f6]1283        self.current_plottable = panel.plots[dataset]
1284        self.control_panel.plotname = dataset
[d6113849]1285        #self.control_panel.nfunc = self.nfunc
[f3d51f6]1286        self.control_panel.d_max = self.max_length
1287        self.parent.set_perspective(self.perspective)
[aa4b8379]1288        self.control_panel._on_invert(None)
[f3d51f6]1289           
1290    def get_panels(self, parent):
1291        """
1292            Create and return a list of panel objects
1293        """
1294        from inversion_panel import InversionControl
1295       
1296        self.parent = parent
[aa4b8379]1297        self.control_panel = InversionControl(self.parent, -1, 
1298                                              style=wx.RAISED_BORDER,
1299                                              standalone=self.standalone)
[f3d51f6]1300        self.control_panel.set_manager(self)
1301        self.control_panel.nfunc = self.nfunc
1302        self.control_panel.d_max = self.max_length
1303        self.control_panel.alpha = self.alpha
1304        self.perspective = []
1305        self.perspective.append(self.control_panel.window_name)
[75df58b]1306     
[f3d51f6]1307        return [self.control_panel]
1308   
[75df58b]1309    def set_data(self, data_list):
[aa4b8379]1310        """
[75df58b]1311        receive a list of data to compute pr
[aa4b8379]1312        """
[75df58b]1313        if len(data_list) > 1:
[75a7ece]1314            msg = "Pr panel does not allow multiple Data.\n"
1315            msg += "Please select one!\n"
1316            from pr_widgets import DataDialog
1317            dlg = DataDialog(data_list=data_list, text=msg)
1318            if dlg.ShowModal() == wx.ID_OK:
1319                data = dlg.get_data()
1320                if issubclass(data.__class__, LoaderData1D):
1321                    self.control_panel._change_file(evt=None, data=data)
1322                else:   
1323                    msg = "Pr cannot be computed for data of "
1324                    msg += "type %s" % (data_list[0].__class__.__name__)
1325                    wx.PostEvent(self.parent, 
1326                             StatusEvent(status=msg, info='error'))
[75df58b]1327        elif len(data_list) == 1:
1328            if issubclass(data_list[0].__class__, LoaderData1D):
1329                self.control_panel._change_file(evt=None, data=data_list[0])
1330            else:
1331                msg = "Pr cannot be computed for"
1332                msg += " data of type %s" % (data_list[0].__class__.__name__)
[75a7ece]1333                wx.PostEvent(self.parent, 
1334                             StatusEvent(status=msg, info='error'))
1335        else:
1336            msg = "Pr contain no data"
1337            wx.PostEvent(self.parent, StatusEvent(status=msg, info='warning'))
[75df58b]1338           
[f3d51f6]1339    def post_init(self):
1340        """
1341            Post initialization call back to close the loose ends
1342            [Somehow openGL needs this call]
1343        """
[3e41f43]1344        if self.standalone:
[d2ee6f6]1345            self.parent.set_perspective(self.perspective)
[35adaf6]1346 
1347if __name__ == "__main__":
1348    i = Plugin()
1349    print i.perform_estimateNT()
1350   
1351   
1352   
[660b1e6]1353   
Note: See TracBrowser for help on using the repository browser.