source: sasview/prview/perspectives/pr/pr.py @ 229da98

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 229da98 was 229da98, checked in by Gervaise Alina <gervyh@…>, 13 years ago

working prview inversion state

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