source: sasview/sansview/perspectives/fitting/fitting.py @ e0e22f2c

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

changed menu fitengine labels

  • Property mode set to 100644
File size: 64.8 KB
Line 
1
2
3################################################################################
4#This software was developed by the University of Tennessee as part of the
5#Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
6#project funded by the US National Science Foundation.
7#
8#See the license text in license.txt
9#
10#copyright 2009, University of Tennessee
11################################################################################
12
13
14import re
15import sys
16import wx
17import logging
18import numpy
19import string
20import time
21from copy import deepcopy
22import models
23import fitpage
24
25
26from DataLoader.loader import Loader
27from sans.guiframe.dataFitting import Data2D
28from sans.guiframe.dataFitting import Data1D
29from sans.guiframe.events import NewPlotEvent
30from sans.guiframe.events import StatusEvent 
31from sans.guiframe.events import EVT_SLICER_PANEL
32from sans.guiframe.events import EVT_SLICER_PARS_UPDATE
33from sans.guiframe.gui_style import GUIFRAME_ID
34from sans.guiframe.plugin_base import PluginBase
35
36from .console import ConsoleUpdate
37from .fitproblem import FitProblem
38from .fitpanel import FitPanel
39from .fit_thread import FitThread
40from .pagestate import Reader
41from .fitpage import Chi2UpdateEvent
42
43DEFAULT_BEAM = 0.005
44DEFAULT_QMIN = 0.001
45DEFAULT_QMAX = 0.13
46DEFAULT_NPTS = 50
47MAX_NBR_DATA = 4
48
49
50(PageInfoEvent, EVT_PAGE_INFO)   = wx.lib.newevent.NewEvent()
51
52   
53
54class Plugin(PluginBase):
55    """
56    Fitting plugin is used to perform fit
57    """
58    def __init__(self, standalone=False):
59        PluginBase.__init__(self, name="Fitting", standalone=standalone)
60       
61        #list of panel to send to guiframe
62        self.mypanels = []
63        # reference to the current running thread
64        self.calc_2D = None
65        self.calc_1D = None
66        self.fit_thread_list = {}
67        self.residuals = None
68        self.fit_panel = None
69        # Start with a good default
70        self.elapsed = 0.022
71        # the type of optimizer selected, park or scipy
72        self.fitter  = None
73        self.fit_panel = None
74        #let fit ready
75        self.fitproblem_count = None
76        #Flag to let the plug-in know that it is running stand alone
77        self.standalone = True
78        ## dictionary of page closed and id
79        self.closed_page_dict = {}
80        ## Fit engine
81        self._fit_engine = 'scipy'
82        ## Relative error desired in the sum of squares (float); scipy only
83        self.ftol=1.49012e-08
84        #List of selected data
85        self.selected_data_list = []
86        ## list of slicer panel created to display slicer parameters and results
87        self.slicer_panels = []
88        # model 2D view
89        self.model2D_id = None
90        #keep reference of the simultaneous fit page
91        self.sim_page = None
92        self.index_model = 0
93        #Create a reader for fit page's state
94        self.state_reader = None 
95        self._extensions = '.fitv'
96        self.scipy_id = wx.NewId()
97        self.park_id = wx.NewId()
98       
99        self.temp_state = []
100        self.state_index = 0
101        self.sfile_ext = None
102        # take care of saving  data, model and page associated with each other
103        self.page_finder = {}
104        # Log startup
105        logging.info("Fitting plug-in started") 
106       
107    def populate_menu(self, owner):
108        """
109        Create a menu for the Fitting plug-in
110       
111        :param id: id to create a menu
112        :param owner: owner of menu
113       
114        :return: list of information to populate the main menu
115       
116        """
117        #Menu for fitting
118        self.menu1 = wx.Menu()
119        id1 = wx.NewId()
120        simul_help = "Add new fit panel"
121        self.menu1.Append(id1, '&New Fit Page',simul_help)
122        wx.EVT_MENU(owner, id1, self.on_add_new_page)
123        self.menu1.AppendSeparator()
124        id1 = wx.NewId()
125        simul_help = "Simultaneous Fit"
126        self.menu1.Append(id1, '&Simultaneous Fit',simul_help)
127        wx.EVT_MENU(owner, id1, self.on_add_sim_page)
128        self.menu1.AppendSeparator()
129        #Set park engine
130       
131        scipy_help= "Scipy Engine: Perform Simple fit. More in Help window...."
132        self.menu1.AppendCheckItem(self.scipy_id, "Simple FitEngine  [LeastSq]",scipy_help) 
133        wx.EVT_MENU(owner, self.scipy_id,  self._onset_engine_scipy)
134       
135        park_help = "Park Engine: Perform Complex fit. More in Help window...."
136        self.menu1.AppendCheckItem(self.park_id, "Complex FitEngine [ParkMC]",park_help) 
137        wx.EVT_MENU(owner, self.park_id,  self._onset_engine_park)
138       
139        self.menu1.FindItemById(self.scipy_id).Check(True)
140        self.menu1.FindItemById(self.park_id).Check(False)
141        #create  menubar items
142        return [(self.menu1, self.sub_menu)]
143               
144    def on_add_sim_page(self, event):
145        """
146        Create a page to access simultaneous fit option
147        """
148        if self.sim_page != None:
149            msg= "Simultaneous Fit page already opened"
150            wx.PostEvent(self.parent, StatusEvent(status= msg))
151            return 
152       
153        self.sim_page= self.fit_panel.add_sim_page()
154       
155    def help(self, evt):
156        """
157        Show a general help dialog.
158        """
159        from help_panel import  HelpWindow
160        frame = HelpWindow(None, -1, 'HelpWindow')   
161        frame.Show(True)
162       
163    def get_context_menu(self, plotpanel=None):
164        """
165        Get the context menu items available for P(r).them allow fitting option
166        for Data2D and Data1D only.
167       
168        :param graph: the Graph object to which we attach the context menu
169       
170        :return: a list of menu items with call-back function
171       
172        :note: if Data1D was generated from Theory1D 
173                the fitting option is not allowed
174               
175        """
176        graph = plotpanel.graph
177        fit_option = "Select data for fitting"
178        fit_hint =  "Dialog with fitting parameters "
179       
180        if graph.selected_plottable not in plotpanel.plots:
181            return []
182        item = plotpanel.plots[graph.selected_plottable]
183        if item.__class__.__name__ is "Data2D": 
184            if hasattr(item,"is_data"):
185                if item.is_data:
186                    return [[fit_option, fit_hint, self._onSelect]]
187                else:
188                    return [] 
189            return [[fit_option, fit_hint, self._onSelect]]
190        else:
191           
192            # if is_data is true , this in an actual data loaded
193            #else it is a data created from a theory model
194            if hasattr(item,"is_data"):
195                if item.is_data:
196                    return [[fit_option, fit_hint,
197                              self._onSelect]]
198                else:
199                    return [] 
200        return []   
201
202
203    def get_panels(self, parent):
204        """
205        Create and return a list of panel objects
206        """
207        self.parent = parent
208        #self.parent.Bind(EVT_FITSTATE_UPDATE, self.on_set_state_helper)
209        # Creation of the fit panel
210        self.fit_panel = FitPanel(parent=self.parent, manager=self)
211        self.on_add_new_page(event=None)
212        #Set the manager for the main panel
213        self.fit_panel.set_manager(self)
214        # List of windows used for the perspective
215        self.perspective = []
216        self.perspective.append(self.fit_panel.window_name)
217       
218        #index number to create random model name
219        self.index_model = 0
220        self.index_theory= 0
221        self.parent.Bind(EVT_SLICER_PANEL, self._on_slicer_event)
222        self.parent.Bind(EVT_SLICER_PARS_UPDATE, self._onEVT_SLICER_PANEL)
223        self.parent._mgr.Bind(wx.aui.EVT_AUI_PANE_CLOSE,self._onclearslicer)   
224        #Create reader when fitting panel are created
225        self.state_reader = Reader(self.set_state)   
226        #append that reader to list of available reader
227        loader = Loader()
228        loader.associate_file_reader(".fitv", self.state_reader)
229        #loader.associate_file_reader(".svs", self.state_reader)
230        #from sans.perspectives.calculator.sld_panel import SldPanel
231        #Send the fitting panel to guiframe
232        self.mypanels.append(self.fit_panel) 
233        #self.mypanels.append(SldPanel(parent=self.parent, base=self.parent))
234        return self.mypanels
235   
236    def clear_panel(self):
237        """
238        """
239        self.fit_panel.clear_panel()
240       
241    def set_default_perspective(self):
242        """
243        Call back method that True to notify the parent that the current plug-in
244        can be set as default  perspective.
245        when returning False, the plug-in is not candidate for an automatic
246        default perspective setting
247        """
248        return True
249   
250    def delete_data(self, data):
251        """
252        delete  the given data from panel
253        """
254        self.fit_panel.delete_data(data)
255       
256    def set_data(self, data_list=None):
257        """
258        receive a list of data to fit
259        """
260        if data_list is None:
261            data_list = []
262        selected_data_list = []
263        if len(data_list) > MAX_NBR_DATA :
264            from fitting_widgets import DataDialog
265            dlg = DataDialog(data_list=data_list, nb_data=MAX_NBR_DATA)
266            if dlg.ShowModal() == wx.ID_OK:
267                selected_data_list = dlg.get_data()
268            dlg.Destroy()
269           
270        else:
271            selected_data_list = data_list
272        try:
273            for data in selected_data_list:
274                self.add_fit_page(data=data)
275                wx.PostEvent(self.parent, NewPlotEvent(plot=data, 
276                                                       title=str(data.title)))
277               
278        except:
279            raise
280            #msg = "Fitting Set_data: " + str(sys.exc_value)
281            #wx.PostEvent(self.parent, StatusEvent(status=msg, info="error"))
282   
283    def set_top_panel(self):
284        """
285        Close default (welcome) panel
286        """
287        if 'default' in self.parent.panels:
288            self.parent.on_close_welcome_panel()
289
290             
291    def set_theory(self,  theory_list=None):
292        """
293        """
294        #set the model state for a given theory_state:
295        for item in theory_list:
296            try:
297                _, theory_state = item
298                self.fit_panel.set_model_state(theory_state)
299            except:
300                msg = "Fitting: cannot deal with the theory received"
301                logging.error("set_theory " + msg + "\n" + str(sys.exc_value))
302                wx.PostEvent(self.parent, StatusEvent(status=msg, info="error"))
303           
304    def set_state(self, state=None, datainfo=None, format=None):
305        """
306        Call-back method for the fit page state reader.
307        This method is called when a .fitv/.svs file is loaded.
308       
309        : param state: PageState object
310        : param datainfo: data
311        """
312        #state = self.state_reader.get_state()
313        if state != None:
314            state = state.clone()
315            # store fitting state in temp_state
316            self.temp_state.append(state) 
317        else:
318            self.temp_state = []
319        # index to start with for a new set_state
320        self.state_index = 0
321        # state file format
322        self.sfile_ext = format
323       
324        self.on_set_state_helper(event=None)
325
326    def  on_set_state_helper(self,event=None):
327        """
328        Set_state_helper. This actually sets state after plotting data from state file.
329       
330        : event: FitStateUpdateEvent called by dataloader.plot_data from guiframe
331        """
332        if len(self.temp_state) == 0:
333            if self.state_index==0 and len(self.mypanels) <= 0 and self.sfile_ext =='.svs':
334                self.fit_panel.add_default_pages()
335                self.temp_state = []
336                self.state_index = 0
337            return
338       
339        try:
340            # Load fitting state
341            state = self.temp_state[self.state_index]
342            #panel state should have model selection to set_state
343            if state.formfactorcombobox != None:
344                #set state
345                data = self.parent.create_gui_data(state.data)
346                data.group_id = state.data.group_id
347                self.parent.add_data(data_list={data.id:data})
348                wx.PostEvent(self.parent, NewPlotEvent(plot=data,
349                                        title=data.title))
350                #need to be fix later make sure we are sendind guiframe.data
351                #to panel
352                state.data = data
353                page = self.fit_panel.set_state(state)   
354            else:
355                #just set data because set_state won't work
356                data = self.parent.create_gui_data(state.data)
357                data.group_id = state.data.group_id
358                self.parent.add_data(data_list={data.id:data})
359                wx.PostEvent(self.parent, NewPlotEvent(plot=data,
360                                        title=data.title))
361                page = self.add_fit_page(data)
362                caption = page.window_name
363                self.store_data(page=page.id, data=data, caption=caption)
364                self.mypanels.append(page) 
365               
366            # get ready for the next set_state
367            self.state_index += 1
368
369            #reset state variables to default when all set_state is finished.
370            if len(self.temp_state) == self.state_index:
371               
372                self.temp_state = []
373                #self.state_index = 0
374                # Make sure the user sees the fitting panel after loading
375                #self.parent.set_perspective(self.perspective)
376                self.on_perspective(event=None)
377        except:
378            self.state_index==0
379            self.temp_state = []
380            raise
381                 
382    def save_fit_state(self, filepath, fitstate): 
383        """
384        save fit page state into file
385        """
386        self.state_reader.write(filename=filepath, fitstate=fitstate)
387       
388    def set_fit_range(self, uid, qmin, qmax):
389        """
390        Set the fitting range of a given page
391        """
392        self.page_finder[uid].set_range(qmin=qmin, qmax=qmax)
393                   
394    def schedule_for_fit(self,value=0, uid=None,fitproblem =None): 
395        """
396        Set the fit problem field to 0 or 1 to schedule that problem to fit.
397        Schedule the specified fitproblem or get the fit problem related to
398        the current page and set value.
399       
400        :param value: integer 0 or 1
401        :param fitproblem: fitproblem to schedule or not to fit
402       
403        """   
404        if fitproblem !=None:
405            fitproblem.schedule_tofit(value)
406        else:
407            self.page_finder[uid].schedule_tofit(value)
408         
409    def get_page_finder(self):
410        """
411        return self.page_finder used also by simfitpage.py
412        """ 
413        return self.page_finder
414   
415    def set_page_finder(self,modelname,names,values):
416        """
417        Used by simfitpage.py to reset a parameter given the string constrainst.
418         
419        :param modelname: the name ot the model for with the parameter has to reset
420        :param value: can be a string in this case.
421        :param names: the paramter name
422         
423        :note: expecting park used for fit.
424         
425        """ 
426        sim_page_id = self.sim_page.uid
427        for uid, value in self.page_finder.iteritems():
428            if uid != sim_page_id:
429                list = value.get_model()
430                model = list[0]
431                if model.name == modelname:
432                    value.set_model_param(names, values)
433                    break
434         
435    def split_string(self,item): 
436        """
437        receive a word containing dot and split it. used to split parameterset
438        name into model name and parameter name example: ::
439       
440            paramaterset (item) = M1.A
441            Will return model_name = M1 , parameter name = A
442           
443        """
444        if string.find(item,".")!=-1:
445            param_names= re.split("\.",item)
446            model_name=param_names[0]           
447            ##Assume max len is 3; eg., M0.radius.width
448            if len(param_names) == 3:
449                param_name=param_names[1]+"."+param_names[2]
450            else:
451                param_name=param_names[1]                   
452            return model_name,param_name
453   
454    def set_ftol(self, ftol=None):
455        """
456        Set ftol: Relative error desired in the sum of chi squares. 
457        """
458        # check if it is flaot
459        try:
460            f_tol = float(ftol)
461        except:
462            # default
463            f_tol = 1.49012e-08
464           
465        self.ftol = f_tol
466             
467    def stop_fit(self, uid):
468        """
469        Stop the fit engine
470        """
471        if uid in self.fit_thread_list.keys():
472            calc_fit = self.fit_thread_list[uid]
473            if calc_fit is not  None and calc_fit.isrunning():
474                calc_fit.stop()
475                msg = "Fit stop!"
476                wx.PostEvent(self.parent, StatusEvent(status=msg, type="stop"))
477        #set the fit button label of page when fit stop is trigger from
478        #simultaneous fit pane
479        if  self.sim_page is not None and uid == self.sim_page.uid:
480            for uid, value in self.page_finder.iteritems():
481                if value.get_scheduled() == 1:
482                    if uid in self.fit_panel.opened_pages.keys():
483                        panel = self.fit_panel.opened_pages[uid]
484                        panel. _on_fit_complete()
485 
486    def set_smearer(self, uid, smearer, qmin=None, qmax=None, draw=True, 
487                    enable2D=False):
488        """
489        Get a smear object and store it to a fit problem
490       
491        :param smearer: smear object to allow smearing data
492       
493        """   
494        if uid not in self.page_finder.keys():
495            msg = "Cannot find ID: %s in page_finder" % str(uid)
496            raise ValueError, msg
497        self.page_finder[uid].set_smearer(smearer)
498        self.page_finder[uid].set_enable2D(enable2D)
499        if draw:
500            ## draw model 1D with smeared data
501            data =  self.page_finder[uid].get_fit_data()
502            model = self.page_finder[uid].get_model()
503            if model is None:
504                return
505            enable1D = True
506            enable2D = self.page_finder[uid].get_enable2D()
507            if enable2D:
508                enable1D = False
509
510            ## if user has already selected a model to plot
511            ## redraw the model with data smeared
512            smear = self.page_finder[uid].get_smearer()
513            self.draw_model(model=model, data=data, page_id=uid, smearer=smear,
514                enable1D=enable1D, enable2D=enable2D,
515                qmin=qmin, qmax=qmax)
516
517    def draw_model(self, model, page_id, data=None, smearer=None,
518                   enable1D=True, enable2D=False,
519                   state=None,
520                   toggle_mode_on=False,
521                   qmin=DEFAULT_QMIN, qmax=DEFAULT_QMAX, 
522                   qstep=DEFAULT_NPTS,
523                   update_chisqr=True):
524        """
525        Draw model.
526       
527        :param model: the model to draw
528        :param name: the name of the model to draw
529        :param data: the data on which the model is based to be drawn
530        :param description: model's description
531        :param enable1D: if true enable drawing model 1D
532        :param enable2D: if true enable drawing model 2D
533        :param qmin:  Range's minimum value to draw model
534        :param qmax:  Range's maximum value to draw model
535        :param qstep: number of step to divide the x and y-axis
536        :param update_chisqr: update chisqr [bool]
537             
538        """
539        if data.__class__.__name__ == "Data1D" or not enable2D:   
540            ## draw model 1D with no loaded data
541            self._draw_model1D(model=model, 
542                               data=data,
543                               page_id=page_id,
544                               enable1D=enable1D, 
545                               smearer=smearer,
546                               qmin=qmin,
547                               qmax=qmax, 
548                               toggle_mode_on=toggle_mode_on,
549                               state=state,
550                               qstep=qstep,
551                               update_chisqr=update_chisqr)
552        else:     
553            ## draw model 2D with no initial data
554            self._draw_model2D(model=model,
555                                page_id=page_id,
556                                data=data,
557                                enable2D=enable2D,
558                                smearer=smearer,
559                                qmin=qmin,
560                                qmax=qmax,
561                                state=state,
562                                toggle_mode_on=toggle_mode_on,
563                                qstep=qstep,
564                                update_chisqr=update_chisqr)
565           
566    def onFit(self):
567        """
568        perform fit
569        """
570        ##  count the number of fitproblem schedule to fit
571        fitproblem_count = 0
572        for value in self.page_finder.values():
573            if value.get_scheduled() == 1:
574                fitproblem_count += 1
575               
576        ## if simultaneous fit change automatically the engine to park
577        if fitproblem_count > 1:
578            self._on_change_engine(engine='park')
579           
580        self.fitproblem_count = fitproblem_count 
581         
582        from sans.fit.Fitting import Fit
583        fitter = Fit(self._fit_engine)
584       
585        if self._fit_engine == "park":
586            engineType = "Simultaneous Fit"
587        else:
588            engineType = "Single Fit"
589           
590        fproblemId = 0
591        self.current_pg = None
592        list_page_id = []
593        for page_id, value in self.page_finder.iteritems():
594            try:
595                if value.get_scheduled() == 1:
596                    #Get list of parameters name to fit
597                    pars = []
598                    templist = []
599                   
600                    page = self.fit_panel.get_page_by_id(page_id)
601                    templist = page.get_param_list()
602                    # missing fit parameters
603                    #if not templist:
604                    #    return
605                    # have the list
606                    for element in templist:
607                        name = str(element[1])
608                        pars.append(name)
609                    #Set Engine  (model , data) related to the page on
610                    self._fit_helper(value=value, pars=pars,
611                                     fitter=fitter,
612                                      fitproblem_id=fproblemId,
613                                      title=engineType) 
614                    list_page_id.append(page_id)
615                    fproblemId += 1 
616                    current_page_id = page_id
617            except:
618                #raise
619                msg= "%s error: %s" % (engineType, sys.exc_value)
620                wx.PostEvent(self.parent, StatusEvent(status=msg, info="error",
621                                                      type="stop"))
622                return 
623        ## If a thread is already started, stop it
624        #if self.calc_fit!= None and self.calc_fit.isrunning():
625        #    self.calc_fit.stop()
626         #Handler used for park engine displayed message
627        handler = ConsoleUpdate(parent=self.parent,
628                                manager=self,
629                                improvement_delta=0.1)
630       
631        ## perform single fit
632        if fitproblem_count == 1:
633            calc_fit = FitThread(handler = handler,
634                                    fn=fitter,
635                                    pars=pars,
636                                    page_id=list_page_id,
637                                    completefn=self._single_fit_completed,
638                                    ftol=self.ftol)
639        else:
640            current_page_id = self.sim_page.uid
641            ## Perform more than 1 fit at the time
642            calc_fit = FitThread(handler=handler,
643                                    fn=fitter,
644                                    page_id=list_page_id,
645                                    updatefn=handler.update_fit,
646                                    completefn=self._simul_fit_completed,
647                                    ftol=self.ftol)
648        self.fit_thread_list[current_page_id] = calc_fit
649        calc_fit.queue()
650        msg = "Fitting is in progress..."
651        wx.PostEvent( self.parent, StatusEvent(status=msg, type="progress" ))
652       
653        self.ready_fit(calc_fit=calc_fit)
654     
655           
656    def ready_fit(self, calc_fit):
657        """
658        Ready for another fit
659        """
660        if self.fitproblem_count != None and self.fitproblem_count > 1:
661            calc_fit.ready(2.5)
662           
663        else:
664            time.sleep(0.4)
665           
666    def remove_plot(self, uid, theory=False):
667        """
668        remove model plot when a fit page is closed
669        """
670        fitproblem = self.page_finder[uid]
671        data = fitproblem.get_fit_data()
672        model = fitproblem.get_model()
673        plot_id = None
674        if model is not None:
675            plot_id = data.id + name
676        if theory:
677            plot_id = data.id
678        group_id = data.group_id
679        wx.PostEvent(self.parent, NewPlotEvent(id=plot_id,
680                                                   group_id=group_id,
681                                                   action='remove'))
682           
683    def store_data(self, uid, data=None, caption=None):
684        """
685        Helper to save page reference into the plug-in
686       
687        :param page: page to store
688       
689        """
690        #create a fitproblem storing all link to data,model,page creation
691        if not uid in self.page_finder.keys():
692            self.page_finder[uid] = FitProblem()
693        self.page_finder[uid].set_fit_data(data)
694        self.page_finder[uid].set_fit_tab_caption(caption)
695       
696    def on_add_new_page(self, event=None):
697        """
698        ask fit panel to create a new empty page
699        """
700        try:
701            page = self.fit_panel.add_empty_page()
702            page_caption = page.window_name
703            # add data associated to the page created
704            if page != None: 
705                self.store_data(uid=page.uid, caption=page_caption,
706                                data=page.get_data())
707                wx.PostEvent(self.parent, StatusEvent(status="Page Created",
708                                               info="info"))
709            else:
710                msg = "Page was already Created"
711                wx.PostEvent(self.parent, StatusEvent(status=msg,
712                                                       info="warning"))
713            self.set_top_panel()
714        except:
715            raise
716            #msg = "Creating Fit page: %s"%sys.exc_value
717            #wx.PostEvent(self.parent, StatusEvent(status=msg, info="error"))
718       
719       
720    def add_fit_page(self, data):
721        """
722        given a data, ask to the fitting panel to create a new fitting page,
723        get this page and store it into the page_finder of this plug-in
724        """
725        page = self.fit_panel.set_data(data)
726        page_caption = page.window_name
727        #append Data1D to the panel containing its theory
728        #if theory already plotted
729        if page.uid in self.page_finder:
730            theory_data = self.page_finder[page.uid].get_theory_data()
731            if issubclass(data.__class__, Data2D):
732                data.group_id = wx.NewId()
733                if theory_data is not None:
734                    group_id = str(page.uid) + " Model1D"
735                    wx.PostEvent(self.parent, 
736                             NewPlotEvent(group_id=group_id,
737                                               action="delete"))
738                    self.parent.update_data(prev_data=theory_data, new_data=data)     
739            else:
740                if theory_data is not None:
741                    group_id = str(page.uid) + " Model2D"
742                    data.group_id = theory_data.group_id
743                    wx.PostEvent(self.parent, 
744                             NewPlotEvent(group_id=group_id,
745                                               action="delete"))
746                    self.parent.update_data(prev_data=theory_data, new_data=data)   
747             
748        self.store_data(uid=page.uid, data=data, caption=page.window_name)
749        if self.sim_page is not None:
750            self.sim_page.draw_page()
751        return page
752           
753    def _onEVT_SLICER_PANEL(self, event):
754        """
755        receive and event telling to update a panel with a name starting with
756        event.panel_name. this method update slicer panel for a given interactor.
757       
758        :param event: contains type of slicer , paramaters for updating the panel
759            and panel_name to find the slicer 's panel concerned.
760        """
761        for item in self.parent.panels:
762            if self.parent.panels[item].window_caption.startswith(event.panel_name):
763                self.parent.panels[item].set_slicer(event.type, event.params)
764               
765        self.parent._mgr.Update()
766   
767    def _closed_fitpage(self, event):   
768        """
769        request fitpanel to close a given page when its unique data is removed
770        from the plot. close fitpage only when the a loaded data is removed
771        """   
772        if event is None or event.data is None:
773            return
774        if hasattr(event.data,"is_data"):
775            if not event.data.is_data or \
776                event.data.__class__.__name__ == "Data1D":
777                self.fit_panel.close_page_with_data(event.data) 
778       
779    def _add_page_onmenu(self, name, fitproblem=None):
780        """
781        Add name of a closed page of fitpanel in a menu
782        """
783        list = self.menu1.GetMenuItems()
784        for item in list:
785            if name == item.GetItemLabel():
786                self.closed_page_dict[name][1] = fitproblem
787               
788        if not name in self.closed_page_dict.keys():   
789            # Post paramters
790            event_id = wx.NewId()
791            self.menu1.Append(event_id, name, "Show %s fit panel" % name)
792            self.closed_page_dict[name]= [event_id, fitproblem]
793            wx.EVT_MENU(self.parent, event_id, self._open_closed_page)
794       
795    def _open_closed_page(self, event):   
796        """
797        reopen a closed page
798        """
799        for name, value in self.closed_page_dict.iteritems():
800            if event.GetId() in value:
801                uid,fitproblem = value
802                if name !="Model":
803                    data= fitproblem.get_fit_data()
804                    page = self.fit_panel.add_fit_page(data=data, reset=True)
805                    if fitproblem != None:
806                        self.page_finder[uid] = fitproblem
807                        if self.sim_page != None:
808                            self.sim_page.draw_page()
809                           
810                else:
811                    model = fitproblem
812                    self.fit_panel.add_model_page(model=model, topmenu=True,
813                                                  reset= True)
814                    break
815   
816    def _reset_schedule_problem(self, value=0):
817        """
818        unschedule or schedule all fitproblem to be fit
819        """
820        for page_id in self.page_finder.keys():
821            self.page_finder[page_id].schedule_tofit(value)
822           
823    def _fit_helper(self, pars, value, fitproblem_id,fitter, title="Single Fit " ):
824        """
825        helper for fitting
826        """
827        metadata = value.get_fit_data()
828        model = value.get_model()
829        smearer = value.get_smearer()
830        qmin, qmax = value.get_range()
831        self.fit_id = fitproblem_id
832        #Create list of parameters for fitting used
833        templist = []
834       
835        try:
836            #Extra list of parameters and their constraints
837            listOfConstraint = []
838           
839            param = value.get_model_param()
840            if len(param) > 0:
841                for item in param:
842                    ## check if constraint
843                    if item[0] != None and item[1] != None:
844                        listOfConstraint.append((item[0],item[1]))
845                   
846            #Do the single fit
847            fitter.set_model(model, self.fit_id,
848                                   pars, constraints=listOfConstraint)
849           
850            fitter.set_data(data=metadata, id=self.fit_id,
851                                 smearer=smearer, qmin=qmin, qmax=qmax)
852           
853            fitter.select_problem_for_fit(id=self.fit_id,
854                                               value=value.get_scheduled())
855            value.clear_model_param()
856        except:
857            raise
858            #msg = title + " error: %s" % sys.exc_value
859            #wx.PostEvent(self.parent, StatusEvent(status=msg, type="stop"))
860         
861    def _onSelect(self,event):
862        """
863        when Select data to fit a new page is created .Its reference is
864        added to self.page_finder
865        """
866        self.panel = event.GetEventObject()
867        Plugin.on_perspective(self, event=event)
868        for plottable in self.panel.graph.plottables:
869            if plottable.__class__.__name__ in ["Data1D", "Theory1D"]:
870                data_id = self.panel.graph.selected_plottable
871                if plottable == self.panel.plots[data_id]:
872                    data = plottable
873                    self.add_fit_page(data=data)
874                    return
875            else:
876                data = plottable
877                self.add_fit_page(data=data)
878        self.set_top_panel()
879           
880    def update_fit(self, result=None, msg=""):
881        """
882        """
883        print "update_fit result", result
884       
885    def _single_fit_completed(self, result, pars, page_id, elapsed=None):
886        """
887        Display fit result on one page of the notebook.
888       
889        :param result: result of fit
890        :param pars: list of names of parameters fitted
891        :param current_pg: the page where information will be displayed
892        :param qmin: the minimum value of x to replot the model
893        :param qmax: the maximum value of x to replot model
894         
895        """     
896        try:
897            if result == None:
898                self._update_fit_button(page_id)
899                msg= "Single Fitting did not converge!!!"
900                wx.PostEvent(self.parent, 
901                             StatusEvent(status=msg, 
902                                         info="warning",
903                                         type="stop"))
904                return
905            if not numpy.isfinite(result.fitness) or \
906                    numpy.any(result.pvec == None) or \
907                    not numpy.all(numpy.isfinite(result.pvec)):
908                msg = "Single Fitting did not converge!!!"
909                wx.PostEvent(self.parent, 
910                             StatusEvent(status=msg, 
911                                         info="warning",
912                                         type="stop"))
913                self._update_fit_button(page_id)
914                return
915            for uid in page_id:
916                value = self.page_finder[uid]   
917                model = value.get_model()
918                page_id = uid
919                   
920                param_name = []
921                for name in pars:
922                    param_name.append(name)
923                   
924                cpage = self.fit_panel.get_page_by_id(uid)
925                cpage.onsetValues(result.fitness, 
926                                  param_name, result.pvec,result.stderr)
927                cpage._on_fit_complete()
928            if result.stderr == None:
929                msg = "Fit Abort: "
930            else:
931                msg = "Fitting: "
932            msg += "Completed!!!"
933            wx.PostEvent(self.parent, StatusEvent(status=msg))
934        except ValueError:
935            self._update_fit_button(page_id)
936            msg = "Single Fitting did not converge!!!"
937            wx.PostEvent(self.parent, StatusEvent(status=msg, info="error",
938                                                  type="stop"))
939            return 
940        except:
941            self._update_fit_button(page_id)
942            msg = "Single Fit completed but Following"
943            msg += " error occurred:%s" % sys.exc_value
944            wx.PostEvent(self.parent, StatusEvent(status=msg, info="error",
945                                                  type="stop"))
946            raise
947            return
948       
949    def _simul_fit_completed(self, result, page_id,pars=None, elapsed=None):
950        """
951        Parameter estimation completed,
952        display the results to the user
953       
954        :param alpha: estimated best alpha
955        :param elapsed: computation time
956       
957        """
958        if page_id is None:
959            page_id = []
960        ## fit more than 1 model at the same time
961        try:
962            msg = "" 
963            if result == None:
964                self._update_fit_button(page_id)
965                msg= "Complex Fitting did not converge!!!"
966                wx.PostEvent(self.parent, StatusEvent(status=msg,
967                                                      type="stop"))
968                return
969            if not numpy.isfinite(result.fitness) or \
970                numpy.any(result.pvec == None) or not \
971                numpy.all(numpy.isfinite(result.pvec)):
972                self._update_fit_button(page_id)
973                msg= "Simultaneous Fitting did not converge!!!"
974                wx.PostEvent(self.parent, StatusEvent(status=msg,type="stop"))
975                return
976             
977            for uid in page_id:   
978                value = self.page_finder[uid]
979                model = value.get_model()
980                data =  value.get_fit_data()
981                small_param_name = []
982                small_out = []
983                small_cov = []
984                #Separate result in to data corresponding to each page
985                for p in result.parameters:
986                    model_name, param_name = self.split_string(p.name) 
987                    if model.name == model_name:
988                        p_name= model.name+"."+param_name
989                        if p.name == p_name:     
990                            if p.value != None and numpy.isfinite(p.value):
991                                small_out.append(p.value)
992                                small_param_name.append(param_name)
993                                small_cov.append(p.stderr)
994                # Display result on each page
995                cpage = self.fit_panel.get_page_by_id(uid)
996                cpage.onsetValues(result.fitness,
997                                  small_param_name,
998                                  small_out,small_cov)
999                cpage._on_fit_complete()
1000                msg = "Fit completed!"
1001                wx.PostEvent(self.parent, StatusEvent(status=msg))
1002        except Exception:
1003            self._update_fit_button(page_id)
1004            msg = "Complex Fitting did not converge!!!"
1005            wx.PostEvent(self.parent, StatusEvent(status=msg, info="error",
1006                                                  type="stop"))
1007            return
1008
1009        except:
1010            self._update_fit_button(page_id)
1011            msg = "Simultaneous Fit completed"
1012            msg += " but Following error occurred:%s" % sys.exc_value
1013            wx.PostEvent(self.parent, StatusEvent(status=msg, type="stop"))
1014   
1015    def _update_fit_button(self, page_id):
1016        """
1017        Update Fit button when fit stopped
1018       
1019        : parameter page_id: fitpage where the button is
1020        """
1021        for uid in page_id: 
1022            page = self.fit_panel.get_page_by_id(uid)
1023            page._on_fit_complete()
1024       
1025    def _on_show_panel(self, event):
1026        """
1027        """
1028        pass
1029       
1030    def _onset_engine_park(self,event):
1031        """
1032        set engine to park
1033        """
1034        self._on_change_engine('park')
1035       
1036    def _onset_engine_scipy(self,event):
1037        """
1038        set engine to scipy
1039        """
1040        self._on_change_engine('scipy')
1041       
1042    def _on_slicer_event(self, event):
1043        """
1044        Receive a panel as event and send it to guiframe
1045       
1046        :param event: event containing a panel
1047       
1048        """
1049        if event.panel is not None:
1050            new_panel = event.panel
1051            self.slicer_panels.append(event.panel)
1052            # Set group ID if available
1053            event_id = self.parent.popup_panel(new_panel)
1054            #self.menu3.Append(event_id, new_panel.window_caption,
1055            #                 "Show %s plot panel" % new_panel.window_caption)
1056            # Set id to allow us to reference the panel later
1057         
1058            new_panel.uid = event_id
1059            self.mypanels.append(new_panel) 
1060       
1061    def _onclearslicer(self, event):
1062        """
1063        Clear the boxslicer when close the panel associate with this slicer
1064        """
1065        name =event.GetPane().caption
1066   
1067        for panel in self.slicer_panels:
1068            if panel.window_caption==name:
1069               
1070                for item in self.parent.panels:
1071                    if hasattr(self.parent.panels[item],"uid"):
1072                        if self.parent.panels[item].uid ==panel.base.uid:
1073                            self.parent.panels[item].onClearSlicer(event)
1074                            self.parent._mgr.Update()
1075                            break 
1076                break
1077   
1078    def _return_engine_type(self):
1079        """
1080        return the current type of engine
1081        """
1082        return self._fit_engine
1083     
1084     
1085    def _on_change_engine(self, engine='park'):
1086        """
1087        Allow to select the type of engine to perform fit
1088       
1089        :param engine: the key work of the engine
1090       
1091        """
1092        ## saving fit engine name
1093        self._fit_engine = engine
1094        ## change menu item state
1095        if engine=="park":
1096            self.menu1.FindItemById(self.park_id).Check(True)
1097            self.menu1.FindItemById(self.scipy_id).Check(False)
1098        else:
1099            self.menu1.FindItemById(self.park_id).Check(False)
1100            self.menu1.FindItemById(self.scipy_id).Check(True)
1101        ## post a message to status bar
1102        msg = "Engine set to: %s" % self._fit_engine
1103        wx.PostEvent(self.parent, 
1104                     StatusEvent(status=msg))
1105        ## send the current engine type to fitpanel
1106        self.fit_panel._on_engine_change(name=self._fit_engine)
1107       
1108    def _on_model_panel(self, evt):
1109        """
1110        react to model selection on any combo box or model menu.plot the model 
1111       
1112        :param evt: wx.combobox event
1113       
1114        """
1115        model = evt.model
1116        uid = evt.uid
1117        qmin = evt.qmin
1118        qmax = evt.qmax
1119        smearer = evt.smearer
1120       
1121        if model == None:
1122            return
1123       
1124        if self.page_finder[uid].get_model() is None:
1125            model.name = "M" + str(self.index_model)
1126            self.index_model += 1 
1127        else:
1128            model.name = self.page_finder[uid].get_model().name
1129        # save the name containing the data name with the appropriate model
1130        self.page_finder[uid].set_model(model)
1131        self.page_finder[uid].set_range(qmin=qmin, qmax=qmax)
1132        if self.sim_page is not None:
1133            self.sim_page.draw_page()
1134       
1135    def _update1D(self,x, output):
1136        """
1137        Update the output of plotting model 1D
1138        """
1139        msg = "Plot updating ... "
1140        wx.PostEvent(self.parent, StatusEvent(status=msg,type="update"))
1141        self.ready_fit()
1142       
1143   
1144    def _fill_default_model2D(self, theory, page_id, qmax,qstep, qmin=None):
1145        """
1146        fill Data2D with default value
1147       
1148        :param theory: Data2D to fill
1149       
1150        """
1151        from DataLoader.data_info import Detector, Source
1152       
1153        detector = Detector()
1154        theory.detector.append(detector)         
1155        theory.source= Source()
1156       
1157        ## Default values   
1158        theory.detector[0].distance= 8000   # mm       
1159        theory.source.wavelength= 6         # A     
1160        theory.detector[0].pixel_size.x= 5  # mm
1161        theory.detector[0].pixel_size.y= 5  # mm
1162       
1163        theory.detector[0].beam_center.x= qmax
1164        theory.detector[0].beam_center.y= qmax
1165   
1166        ## create x_bins and y_bins of the model 2D
1167        pixel_width_x = theory.detector[0].pixel_size.x
1168        pixel_width_y = theory.detector[0].pixel_size.y
1169        center_x      = theory.detector[0].beam_center.x/pixel_width_x
1170        center_y      = theory.detector[0].beam_center.y/pixel_width_y
1171
1172        # theory default: assume the beam
1173        #center is located at the center of sqr detector
1174        xmax = qmax
1175        xmin = -qmax
1176        ymax = qmax
1177        ymin = -qmax
1178       
1179        x=  numpy.linspace(start= -1*qmax,
1180                               stop=qmax,
1181                               num=qstep,
1182                               endpoint=True) 
1183        y = numpy.linspace(start=-1*qmax,
1184                               stop= qmax,
1185                               num= qstep,
1186                               endpoint=True)
1187         
1188        ## use data info instead
1189        new_x = numpy.tile(x, (len(y),1))
1190        new_y = numpy.tile(y, (len(x),1))
1191        new_y = new_y.swapaxes(0,1)
1192       
1193        # all data reuire now in 1d array
1194        qx_data = new_x.flatten()
1195        qy_data = new_y.flatten()
1196       
1197        q_data = numpy.sqrt(qx_data*qx_data+qy_data*qy_data)
1198        # set all True (standing for unmasked) as default
1199        mask    = numpy.ones(len(qx_data), dtype = bool)
1200       
1201        # calculate the range of qx and qy: this way,
1202        # it is a little more independent
1203        x_size = xmax- xmin
1204        y_size = ymax -ymin
1205       
1206        # store x and y bin centers in q space
1207        x_bins  = x
1208        y_bins  = y
1209        # bin size: x- & y-directions
1210        xstep = x_size/len(x_bins-1)
1211        ystep = y_size/len(y_bins-1)
1212       
1213        #theory.data = numpy.zeros(len(mask))
1214        theory.err_data = numpy.ones(len(mask))
1215        theory.qx_data = qx_data
1216        theory.qy_data = qy_data 
1217        theory.q_data = q_data
1218        theory.mask = mask           
1219        theory.x_bins = x_bins 
1220        theory.y_bins = y_bins   
1221       
1222        # max and min taking account of the bin sizes
1223        theory.xmin = xmin
1224        theory.xmax = xmax
1225        theory.ymin = ymin
1226        theory.ymax = ymax
1227        theory.group_id = str(page_id) + " Model2D"
1228        theory.id = str(page_id) + " Model2D"
1229 
1230    def _complete1D(self, x,y, page_id, elapsed,index,model,
1231                    toggle_mode_on=False,state=None, 
1232                    data=None, update_chisqr=True):
1233        """
1234        Complete plotting 1D data
1235        """ 
1236        try:
1237            new_plot = Data1D(x=x, y=y)
1238            new_plot.is_data = False
1239            new_plot.symbol = GUIFRAME_ID.CURVE_SYMBOL_NUM
1240            if data != None:
1241                _xaxis, _xunit = data.get_xaxis() 
1242                _yaxis, _yunit = data.get_yaxis() 
1243                new_plot.title = data.name
1244                #if the theory is already plotted use the same group id
1245                #to replot
1246                if page_id in self.page_finder:
1247                    theory_data = self.page_finder[page_id].get_theory_data()
1248                    if theory_data is not None:
1249                       data.group_id = theory_data.group_id
1250                #data is plotted before the theory, then take its group_id
1251                #assign to the new theory
1252                new_plot.group_id = data.group_id
1253               
1254            else:
1255                _xaxis, _xunit = "\\rm{Q}", 'A^{-1}'
1256                _yaxis, _yunit = "\\rm{Intensity} ", "cm^{-1}"
1257                new_plot.title = "Analytical model 1D "
1258                #find a group id to plot theory without data
1259                new_plot.group_id =  str(page_id) + " Model1D" 
1260            new_plot.id =  str(page_id) + " Model1D" 
1261           
1262            #find if this theory was already plotted and replace that plot given
1263            #the same id
1264           
1265            theory_data = self.page_finder[page_id].get_theory_data()
1266            if theory_data is not None:
1267                new_plot.id = theory_data.id
1268             
1269            new_plot.name = model.name + " ["+ str(model.__class__.__name__)+ "]"
1270            new_plot.xaxis(_xaxis, _xunit)
1271            new_plot.yaxis(_yaxis, _yunit)
1272            if toggle_mode_on:
1273                new_plot.id =  str(page_id) + " Model" 
1274                wx.PostEvent(self.parent, 
1275                             NewPlotEvent(group_id=str(page_id) + " Model2D",
1276                                               action="Hide"))
1277           
1278            self.page_finder[page_id].set_theory_data(new_plot)
1279            if data is None:
1280                data_id = None
1281            else:
1282                data_id = data.id
1283            self.parent.update_theory(data_id=data_id, 
1284                                       theory=new_plot,
1285                                       state=state)     
1286            current_pg = self.fit_panel.get_page_by_id(page_id)
1287            title = new_plot.title
1288            wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot,
1289                                            title= str(title)))
1290           
1291            self.page_finder[page_id].set_theory_data(new_plot)
1292           
1293            if update_chisqr:
1294                wx.PostEvent(current_pg,
1295                             Chi2UpdateEvent(output=self._cal_chisqr(data=data,
1296                                                        page_id=page_id,
1297                                                        index=index)))
1298            else:
1299                self._plot_residuals(page_id, data, index)
1300
1301            msg = "Computation  completed!"
1302            wx.PostEvent( self.parent, StatusEvent(status=msg, type="stop" ))
1303            #self.current_pg.state.theory_data = deepcopy(self.theory_data)
1304        except:
1305            raise
1306            #msg = " Error occurred when drawing %s Model 1D: " % new_plot.name
1307            #msg += " %s"  % sys.exc_value
1308            #wx.PostEvent(self.parent, StatusEvent(status=msg, type="stop"))
1309   
1310    def _update2D(self, output,time=None):
1311        """
1312        Update the output of plotting model
1313        """
1314        wx.PostEvent(self.parent, StatusEvent(status="Plot \
1315        #updating ... ", type="update"))
1316        self.ready_fit()
1317 
1318    def _complete2D(self, image, data, model, page_id,  elapsed, index, qmin,
1319                     qmax, toggle_mode_on=False,state=None,qstep=DEFAULT_NPTS, 
1320                     update_chisqr=True):
1321        """
1322        Complete get the result of modelthread and create model 2D
1323        that can be plot.
1324        """
1325        err_image = numpy.zeros(numpy.shape(image))
1326       
1327        new_plot= Data2D(image=image, err_image=err_image)
1328        new_plot.name = model.name
1329        new_plot.title = "Analytical model 2D "
1330        if data is None:
1331            self._fill_default_model2D(theory=new_plot, 
1332                                       qmax=qmax, 
1333                                       page_id=page_id,
1334                                       qstep=qstep,
1335                                        qmin= qmin)
1336           
1337        else:
1338            new_plot.id = str(page_id) + " Model2D"
1339            new_plot.group_id = str(page_id) + " Model2D"
1340            new_plot.x_bins = data.x_bins
1341            new_plot.y_bins = data.y_bins
1342            new_plot.detector = data.detector
1343            new_plot.source = data.source
1344            new_plot.is_data = False 
1345            new_plot.qx_data = data.qx_data
1346            new_plot.qy_data = data.qy_data
1347            new_plot.q_data = data.q_data
1348            #numpy.zeros(len(data.err_data))#data.err_data
1349            new_plot.err_data = err_image
1350            new_plot.mask = data.mask
1351            ## plot boundaries
1352            new_plot.ymin = data.ymin
1353            new_plot.ymax = data.ymax
1354            new_plot.xmin = data.xmin
1355            new_plot.xmax = data.xmax
1356            title = data.title
1357            if len(title) > 1:
1358                new_plot.title = "Model2D for " + data.name
1359        new_plot.is_data = False
1360        new_plot.name = model.name + " ["+ str(model.__class__.__name__)+ "]"
1361
1362        theory_data = deepcopy(new_plot)
1363        theory_data.name = "Unknown"
1364        if toggle_mode_on:
1365            new_plot.id = str(page_id) + " Model"     
1366            wx.PostEvent(self.parent, 
1367                             NewPlotEvent(group_id=str(page_id) + " Model1D",
1368                                               action="Hide"))
1369       
1370        self.page_finder[page_id].set_theory_data(new_plot)
1371        if data is None:
1372            data_id = None
1373        else:
1374            data_id = data.id
1375        self.parent.update_theory(data_id=data_id, 
1376                                       theory=new_plot,
1377                                       state=state) 
1378        current_pg = self.fit_panel.get_page_by_id(page_id)
1379        title = new_plot.title
1380
1381        wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot,
1382                                               title=title))
1383        self.page_finder[page_id].set_theory_data(new_plot)
1384        # Chisqr in fitpage
1385        if update_chisqr:
1386            wx.PostEvent(current_pg,
1387                         Chi2UpdateEvent(output=\
1388                                    self._cal_chisqr(data=data,
1389                                                     page_id=page_id,
1390                                                     index=index)))
1391        else:
1392            self._plot_residuals(page_id, data, index)
1393        msg = "Computation  completed!"
1394        wx.PostEvent(self.parent, StatusEvent(status=msg, type="stop"))
1395   
1396    def _draw_model2D(self, model, page_id, data=None, smearer=None,
1397                      description=None, enable2D=False,
1398                      state=None,
1399                      toggle_mode_on=False,
1400                      qmin=DEFAULT_QMIN, qmax=DEFAULT_QMAX,
1401                      qstep=DEFAULT_NPTS,
1402                      update_chisqr=True):
1403        """
1404        draw model in 2D
1405       
1406        :param model: instance of the model to draw
1407        :param description: the description of the model
1408        :param enable2D: when True allows to draw model 2D
1409        :param qmin: the minimum value to  draw model 2D
1410        :param qmax: the maximum value to draw model 2D
1411        :param qstep: the number of division of Qx and Qy of the model to draw
1412           
1413        """
1414        x=  numpy.linspace(start=-1*qmax,
1415                               stop=qmax,
1416                               num=qstep,
1417                               endpoint=True) 
1418        y = numpy.linspace(start= -1*qmax,
1419                               stop=qmax,
1420                               num=qstep,
1421                               endpoint=True)
1422        if model is None:
1423            msg = "Panel with ID: %s does not contained model" % str(page_id)
1424            raise ValueError, msg
1425        ## use data info instead
1426        if data is not None:
1427            ## check if data2D to plot
1428            if hasattr(data, "x_bins"):
1429                enable2D = True
1430                x = data.x_bins
1431                y = data.y_bins
1432               
1433        if not enable2D:
1434            return None, None
1435        try:
1436            from model_thread import Calc2D
1437            ## If a thread is already started, stop it
1438            if (self.calc_2D is not None) and self.calc_2D.isrunning():
1439                self.calc_2D.stop()
1440            self.calc_2D = Calc2D(x=x,
1441                                    y=y,
1442                                    model=model, 
1443                                    data=data,
1444                                    page_id=page_id,
1445                                    smearer=smearer,
1446                                    qmin=qmin,
1447                                    qmax=qmax,
1448                                    qstep=qstep,
1449                                    toggle_mode_on=toggle_mode_on,
1450                                    state=state,
1451                                    completefn=self._complete2D,
1452                                    #updatefn= self._update2D,
1453                                    update_chisqr=update_chisqr)
1454
1455            self.calc_2D.queue()
1456
1457        except:
1458            raise
1459            #msg = " Error occurred when drawing %s Model 2D: " % model.name
1460            #msg += " %s" % sys.exc_value
1461            #wx.PostEvent(self.parent, StatusEvent(status=msg))
1462
1463    def _draw_model1D(self, model, page_id, data=None, smearer=None,
1464                qmin=DEFAULT_QMIN, qmax=DEFAULT_QMAX, 
1465                state=None,
1466                toggle_mode_on=False,
1467                qstep=DEFAULT_NPTS, update_chisqr=True, 
1468                enable1D=True):
1469        """
1470        Draw model 1D from loaded data1D
1471       
1472        :param data: loaded data
1473        :param model: the model to plot
1474       
1475        """
1476        x=  numpy.linspace(start=qmin,
1477                           stop=qmax,
1478                           num=qstep,
1479                           endpoint=True
1480                           )
1481        if data is not None:
1482            ## check for data2D
1483            if hasattr(data,"x_bins"):
1484                return
1485            x = data.x
1486            if qmin == None :
1487                qmin == DEFAULT_QMIN
1488
1489            if qmax == None:
1490                qmax == DEFAULT_QMAX
1491        if not enable1D:
1492            return 
1493        try:
1494            from model_thread import Calc1D
1495            ## If a thread is already started, stop it
1496            if (self.calc_1D is not None) and self.calc_1D.isrunning():
1497                self.calc_1D.stop()
1498            self.calc_1D = Calc1D(x=x,
1499                                  data=data,
1500                                  model=model,
1501                                  page_id=page_id, 
1502                                  qmin=qmin,
1503                                  qmax=qmax,
1504                                  smearer=smearer,
1505                                  state=state,
1506                                  toggle_mode_on=toggle_mode_on,
1507                                  completefn=self._complete1D,
1508                                  #updatefn = self._update1D,
1509                                  update_chisqr=update_chisqr)
1510
1511            self.calc_1D.queue()
1512
1513        except:
1514            msg = " Error occurred when drawing %s Model 1D: " % model.name
1515            msg += " %s" % sys.exc_value
1516            wx.PostEvent(self.parent, StatusEvent(status=msg))
1517
1518    def _cal_chisqr(self, page_id, data=None, index=None): 
1519        """
1520        Get handy Chisqr using the output from draw1D and 2D,
1521        instead of calling expansive CalcChisqr in guithread
1522        """
1523        # default chisqr
1524        chisqr = None
1525
1526        # return None if data == None
1527        if data == None: return chisqr
1528       
1529        # Get data: data I, theory I, and data dI in order
1530        if data.__class__.__name__ == "Data2D":
1531            if index == None: 
1532                index = numpy.ones(len(data.data),ntype=bool)
1533            # get rid of zero error points
1534            index = index & (data.err_data != 0 ) 
1535            index = index & (numpy.isfinite(data.data)) 
1536            fn = data.data[index] 
1537            theory_data = self.page_finder[page_id].get_theory_data()
1538            gn = theory_data.data[index]
1539            en = data.err_data[index]
1540        else:
1541            # 1 d theory from model_thread is only in the range of index
1542            if index == None: 
1543                index = numpy.ones(len(data.y), ntype=bool)
1544            if data.dy == None or data.dy == []:
1545                dy = numpy.ones(len(data.y))
1546            else:
1547                ## Set consitently w/AbstractFitengine:
1548                # But this should be corrected later.
1549                dy = deepcopy(data.dy)
1550                dy[dy==0] = 1 
1551            fn = data.y[index] 
1552            theory_data = self.page_finder[page_id].get_theory_data()
1553            gn = theory_data.y
1554            en = dy[index]
1555
1556        # residual
1557        res = (fn - gn) / en
1558        residuals = res[numpy.isfinite(res)]
1559        # get chisqr only w/finite
1560        chisqr = numpy.average(residuals * residuals)
1561       
1562        self._plot_residuals(page_id, data, index)
1563        return chisqr
1564   
1565
1566       
1567    def _plot_residuals(self, page_id, data=None, index=None): 
1568        """
1569        Plot the residuals
1570       
1571        :param data: data
1572        :param index: index array (bool)
1573        : Note: this is different from the residuals in cal_chisqr()
1574        """
1575        if data == None: 
1576            return 
1577       
1578        # Get data: data I, theory I, and data dI in order
1579        if data.__class__.__name__ == "Data2D":
1580            # build residuals
1581            #print data
1582            residuals = Data2D()
1583            #residuals.copy_from_datainfo(data)
1584            # Not for trunk the line below, instead use the line above
1585            data.clone_without_data(len(data.data), residuals)
1586            residuals.data = None
1587            fn = data.data#[index]
1588            theory_data = self.page_finder[page_id].get_theory_data()
1589            gn = theory_data.data#[index]
1590            en = data.err_data#[index]
1591            residuals.data = (fn - gn) / en
1592            residuals.qx_data = data.qx_data#[index]
1593            residuals.qy_data = data.qy_data #[index]
1594            residuals.q_data = data.q_data#[index]
1595            residuals.err_data = numpy.ones(len(residuals.data))#[index]
1596            residuals.xmin = min(residuals.qx_data)
1597            residuals.xmax = max(residuals.qx_data)
1598            residuals.ymin = min(residuals.qy_data)
1599            residuals.ymax = max(residuals.qy_data)
1600            residuals.q_data = data.q_data#[index]
1601            residuals.mask = data.mask
1602            residuals.scale = 'linear'
1603            #print "print data",residuals
1604            # check the lengths
1605            if len(residuals.data) != len(residuals.q_data):
1606                return
1607
1608        else:
1609            # 1 d theory from model_thread is only in the range of index
1610            if data.dy == None or data.dy == []:
1611                dy = numpy.ones(len(data.y))
1612            else:
1613                ## Set consitently w/AbstractFitengine:
1614                ## But this should be corrected later.
1615                dy = deepcopy(data.dy)
1616                dy[dy==0] = 1 
1617            fn = data.y[index] 
1618            theory_data = self.page_finder[page_id].get_theory_data()
1619            gn = theory_data.y
1620            en = dy[index]
1621            # build residuals
1622            residuals = Data1D()
1623            residuals.y = (fn - gn) / en
1624            residuals.x = data.x[index]
1625            residuals.dy = numpy.ones(len(residuals.y))
1626            residuals.dx = None
1627            residuals.dxl = None
1628            residuals.dxw = None
1629            residuals.ytransform = 'y'
1630            # For latter scale changes
1631            residuals.xaxis('\\rm{Q} ', 'A^{-1}')
1632            residuals.yaxis('\\rm{Residuals} ', 'normalized')
1633           
1634        new_plot = residuals
1635        if data.id == None:
1636            data.id = data.name
1637        name  = data.id
1638        new_plot.name = "Residuals for " + str(data.name)
1639        ## allow to highlight data when plotted
1640        new_plot.interactive = True
1641        ## when 2 data have the same id override the 1 st plotted
1642        new_plot.id = new_plot.name#name + " residuals"
1643        ##group_id specify on which panel to plot this data
1644        new_plot.group_id = new_plot.id
1645        #new_plot.is_data = True
1646        ##post data to plot
1647        title = new_plot.name
1648       
1649        # plot data
1650        wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot, title=title))   
1651       
1652#def profile(fn, *args, **kw):
1653#    import cProfile, pstats, os
1654#    global call_result
1655#    def call():
1656#        global call_result
1657#        call_result = fn(*args, **kw)
1658#    cProfile.runctx('call()', dict(call=call), {}, 'profile.out')
1659#    stats = pstats.Stats('profile.out')
1660#    #stats.sort_stats('time')
1661#    stats.sort_stats('calls')
1662#    stats.print_stats()
1663#    os.unlink('profile.out')
1664#    return call_result
1665if __name__ == "__main__":
1666    i = Plugin()
1667   
1668   
1669   
1670   
Note: See TracBrowser for help on using the repository browser.