source: sasview/fittingview/src/sans/perspectives/fitting/fitting.py @ 8f5b34a

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 8f5b34a was 26e1001, checked in by Jae Cho <jhjcho@…>, 13 years ago

fixed the problem in batch fitting with one param set fittable

  • Property mode set to 100644
File size: 84.0 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 os
17import wx
18import logging
19import numpy
20import string
21import time
22from copy import deepcopy
23import models
24import fitpage
25
26
27from sans.dataloader.loader import Loader
28from sans.guiframe.dataFitting import Data2D
29from sans.guiframe.dataFitting import Data1D
30from sans.guiframe.dataFitting import check_data_validity
31from sans.guiframe.events import NewPlotEvent
32from sans.guiframe.events import StatusEvent 
33from sans.guiframe.events import EVT_SLICER_PANEL
34from sans.guiframe.events import EVT_SLICER_PARS_UPDATE
35from sans.guiframe.gui_style import GUIFRAME_ID
36from sans.guiframe.plugin_base import PluginBase
37from sans.guiframe.data_processor import BatchCell
38from sans.fit.Fitting import Fit
39from .console import ConsoleUpdate
40from .fitproblem import FitProblemDictionary
41from .fitpanel import FitPanel
42from .fit_thread import FitThread
43from .pagestate import Reader
44from .fitpage import Chi2UpdateEvent
45
46MAX_NBR_DATA = 4
47SANS_F_TOL = 5e-05
48
49(PageInfoEvent, EVT_PAGE_INFO)   = wx.lib.newevent.NewEvent()
50
51
52if sys.platform.count("darwin")==0:
53    ON_MAC = False
54else:
55    ON_MAC = True   
56
57class Plugin(PluginBase):
58    """
59    Fitting plugin is used to perform fit
60    """
61    def __init__(self, standalone=False):
62        PluginBase.__init__(self, name="Fitting", standalone=standalone)
63       
64        #list of panel to send to guiframe
65        self.mypanels = []
66        # reference to the current running thread
67        self.calc_2D = None
68        self.calc_1D = None
69       
70        self.color_dict = {}
71       
72        self.fit_thread_list = {}
73        self.residuals = None
74        self.weight = None
75        self.fit_panel = None
76        # Start with a good default
77        self.elapsed = 0.022
78        # the type of optimizer selected, park or scipy
79        self.fitter  = None
80        self.fit_panel = None
81        #let fit ready
82        self.fitproblem_count = None
83        #Flag to let the plug-in know that it is running stand alone
84        self.standalone = True
85        ## dictionary of page closed and id
86        self.closed_page_dict = {}
87        ## Fit engine
88        self._fit_engine = 'scipy'
89        self._gui_engine = None
90        ## Relative error desired in the sum of squares (float); scipy only
91        self.ftol = SANS_F_TOL
92        self.batch_reset_flag = True
93        #List of selected data
94        self.selected_data_list = []
95        ## list of slicer panel created to display slicer parameters and results
96        self.slicer_panels = []
97        # model 2D view
98        self.model2D_id = None
99        #keep reference of the simultaneous fit page
100        self.sim_page = None
101        self.sim_menu = None
102        self.batch_page = None
103        self.batch_menu = None
104        self.index_model = 0
105        self.test_model_color = None
106        #Create a reader for fit page's state
107        self.state_reader = None 
108        self._extensions = '.fitv'
109        self.scipy_id = wx.NewId()
110        self.park_id = wx.NewId()
111        self.menu1 = None
112       
113        self.temp_state = []
114        self.state_index = 0
115        self.sfile_ext = None
116        # take care of saving  data, model and page associated with each other
117        self.page_finder = {}
118        # Log startup
119        logging.info("Fitting plug-in started") 
120        self.batch_capable = self.get_batch_capable()
121   
122    def get_batch_capable(self):
123        """
124        Check if the plugin has a batch capability
125        """
126        return True
127   
128    def create_fit_problem(self, page_id):
129        """
130        Given an ID create a fitproblem container
131        """
132        self.page_finder[page_id] = FitProblemDictionary()
133       
134    def delete_fit_problem(self, page_id):
135        """
136        Given an ID create a fitproblem container
137        """
138        if page_id in self.page_finder.iterkeys():
139            del self.page_finder[page_id]
140       
141    def add_color(self, color, id):
142        """
143        adds a color as a key with a plot id as its value to a dictionary
144        """
145        self.color_dict[id] = color
146       
147    def on_batch_selection(self, flag):
148        """
149        switch the the notebook of batch mode or not
150        """
151        self.batch_on = flag
152        if self.fit_panel is not None:
153            self.fit_panel.batch_on = self.batch_on
154       
155    def populate_menu(self, owner):
156        """
157        Create a menu for the Fitting plug-in
158       
159        :param id: id to create a menu
160        :param owner: owner of menu
161       
162        :return: list of information to populate the main menu
163       
164        """
165        #Menu for fitting
166        self.menu1 = wx.Menu()
167        id1 = wx.NewId()
168        simul_help = "Add new fit panel"
169        self.menu1.Append(id1, '&New Fit Page',simul_help)
170        wx.EVT_MENU(owner, id1, self.on_add_new_page)
171        self.menu1.AppendSeparator()
172        self.id_simfit = wx.NewId()
173        simul_help = "Simultaneous Fit"
174        self.menu1.Append(self.id_simfit, '&Simultaneous Fit',simul_help)
175        wx.EVT_MENU(owner, self.id_simfit, self.on_add_sim_page)
176        self.sim_menu = self.menu1.FindItemById(self.id_simfit)
177        self.sim_menu.Enable(False) 
178        #combined Batch
179        self.id_batchfit = wx.NewId()
180        batch_help = "Combined Batch"
181        self.menu1.Append(self.id_batchfit, '&Combine Batch Fit', batch_help)
182        wx.EVT_MENU(owner, self.id_batchfit,  self.on_add_sim_page)
183        self.batch_menu = self.menu1.FindItemById(self.id_batchfit)
184        self.batch_menu.Enable(False) 
185        self.menu1.AppendSeparator()
186        #Set park engine
187        scipy_help = "Scipy Engine: Perform Simple fit. More in Help window...."
188        self.menu1.AppendCheckItem(self.scipy_id, "Simple FitEngine [LeastSq]",
189                                   scipy_help) 
190        wx.EVT_MENU(owner, self.scipy_id,  self._onset_engine_scipy)
191       
192        park_help = "Park Engine: Perform Complex fit. More in Help window...."
193        self.menu1.AppendCheckItem(self.park_id, "Complex FitEngine [ParkMC]",
194                                   park_help) 
195        wx.EVT_MENU(owner, self.park_id,  self._onset_engine_park)
196       
197        self.menu1.FindItemById(self.scipy_id).Check(True)
198        self.menu1.FindItemById(self.park_id).Check(False)
199        self.menu1.AppendSeparator()
200        self.id_tol = wx.NewId()
201        ftol_help = "Change the current FTolerance (=%s) " % str(self.ftol)
202        ftol_help += "of Simple FitEngine..." 
203        self.menu1.Append(self.id_tol, "Change FTolerance", 
204                                   ftol_help) 
205        wx.EVT_MENU(owner, self.id_tol,  self.show_ftol_dialog)
206        self.menu1.AppendSeparator()
207       
208        self.id_reset_flag = wx.NewId()
209        resetf_help = "BatchFit: If checked, the initial param values will be "
210        resetf_help += "propagated from the previous results. " 
211        resetf_help += "Otherwise, the same initial param values will be used "
212        resetf_help += "for all fittings." 
213        self.menu1.AppendCheckItem(self.id_reset_flag, "Chain Fitting [BatchFit Only]", 
214                                   resetf_help) 
215        wx.EVT_MENU(owner, self.id_reset_flag,  self.on_reset_batch_flag)
216        chain_menu = self.menu1.FindItemById(self.id_reset_flag)
217        chain_menu.Check(not self.batch_reset_flag)
218        chain_menu.Enable(self.batch_on)
219       
220        self.menu1.AppendSeparator()
221        self.edit_model_menu = wx.Menu()
222        # Find and put files name in menu
223        try:
224            self.set_edit_menu(owner=owner)
225        except:
226            raise
227       
228        self.id_edit = wx.NewId()
229        editmodel_help = "Edit cusomized model sample file" 
230        self.menu1.AppendMenu(self.id_edit, "Edit Custom Model", 
231                              self.edit_model_menu, editmodel_help)
232        #create  menubar items
233        return [(self.menu1, self.sub_menu)]
234   
235    def edit_custom_model(self, event):
236        """
237        Get the python editor panel
238        """
239        id = event.GetId()
240        label = self.edit_model_menu.GetLabel(id)
241        from sans.perspectives.calculator.pyconsole import PyConsole
242        filename = os.path.join(models.find_plugins_dir(), label)
243        frame = PyConsole(parent=self.parent, manager=self, panel= self.fit_panel,
244                          title='Custom Model Editor', filename=filename)
245        self.put_icon(frame)
246        frame.Show(True) 
247       
248    def set_edit_menu(self, owner):   
249        """
250        Set list of the edit model menu labels
251        """
252        list_fnames = os.listdir(models.find_plugins_dir())
253        for item in list_fnames:
254            name = os.path.basename(item)
255            toks = os.path.splitext(name)
256            if toks[1]=='.py' and not toks[0]=='__init__':
257                has_file = False
258                for item in self.edit_model_menu.GetMenuItems():
259                    if name == self.edit_model_menu.GetLabel(item.GetId()):
260                        has_file = True
261                if not has_file:
262                    id = wx.NewId()
263                    self.edit_model_menu.Append(id, name) 
264                    wx.EVT_MENU(owner, id,  self.edit_custom_model)
265                    has_file = False
266
267    def put_icon(self, frame):
268        """
269        Put icon in the frame title bar
270        """
271        if hasattr(frame, "IsIconized"):
272            if not frame.IsIconized():
273                try:
274                    icon = self.parent.GetIcon()
275                    frame.SetIcon(icon)
276                except:
277                    pass     
278                     
279    def on_add_sim_page(self, event):
280        """
281        Create a page to access simultaneous fit option
282        """
283        id = event.GetId()
284        caption = "Simultaneous Fit"
285        page = self.sim_page
286        if id == self.id_batchfit:
287            caption = "Combined Batch"
288            page = self.batch_page
289           
290        def set_focus_page(page):
291            page.Show(True)
292            page.Refresh()
293            page.SetFocus()
294            self.parent._mgr.Update()
295            msg = "%s already opened\n" % str(page.window_caption)
296            wx.PostEvent(self.parent, StatusEvent(status=msg))
297           
298        if page != None:
299            return set_focus_page(page)
300        if caption == "Simultaneous Fit":
301            self.sim_page = self.fit_panel.add_sim_page(caption=caption)
302        else:
303            self.batch_page = self.fit_panel.add_sim_page(caption=caption)
304       
305    def help(self, evt):
306        """
307        Show a general help dialog.
308        """
309        from help_panel import  HelpWindow
310        frame = HelpWindow(None, -1, 'HelpWindow') 
311        if hasattr(frame, "IsIconized"):
312            if not frame.IsIconized():
313                try:
314                    icon = self.parent.GetIcon()
315                    frame.SetIcon(icon)
316                except:
317                    pass 
318        frame.Show(True)
319       
320    def get_context_menu(self, plotpanel=None):
321        """
322        Get the context menu items available for P(r).them allow fitting option
323        for Data2D and Data1D only.
324       
325        :param graph: the Graph object to which we attach the context menu
326       
327        :return: a list of menu items with call-back function
328       
329        :note: if Data1D was generated from Theory1D 
330                the fitting option is not allowed
331               
332        """
333        graph = plotpanel.graph
334        fit_option = "Select data for fitting"
335        fit_hint =  "Dialog with fitting parameters "
336       
337        if graph.selected_plottable not in plotpanel.plots:
338            return []
339        item = plotpanel.plots[graph.selected_plottable]
340        if item.__class__.__name__ is "Data2D": 
341            if hasattr(item,"is_data"):
342                if item.is_data:
343                    return [[fit_option, fit_hint, self._onSelect]]
344                else:
345                    return [] 
346            return [[fit_option, fit_hint, self._onSelect]]
347        else:
348           
349            # if is_data is true , this in an actual data loaded
350            #else it is a data created from a theory model
351            if hasattr(item,"is_data"):
352                if item.is_data:
353                    return [[fit_option, fit_hint,
354                              self._onSelect]]
355                else:
356                    return [] 
357        return []   
358
359
360    def get_panels(self, parent):
361        """
362        Create and return a list of panel objects
363        """
364        self.parent = parent
365        #self.parent.Bind(EVT_FITSTATE_UPDATE, self.on_set_state_helper)
366        # Creation of the fit panel
367        self.fit_panel = FitPanel(parent=self.parent, manager=self)
368        self.on_add_new_page(event=None)
369        #Set the manager for the main panel
370        self.fit_panel.set_manager(self)
371        # List of windows used for the perspective
372        self.perspective = []
373        self.perspective.append(self.fit_panel.window_name)
374       
375        #index number to create random model name
376        self.index_model = 0
377        self.index_theory= 0
378        self.parent.Bind(EVT_SLICER_PANEL, self._on_slicer_event)
379        self.parent.Bind(EVT_SLICER_PARS_UPDATE, self._onEVT_SLICER_PANEL)
380        self.parent._mgr.Bind(wx.aui.EVT_AUI_PANE_CLOSE,self._onclearslicer)   
381        #Create reader when fitting panel are created
382        self.state_reader = Reader(self.set_state)   
383        #append that reader to list of available reader
384        loader = Loader()
385        loader.associate_file_reader(".fitv", self.state_reader)
386        #loader.associate_file_reader(".svs", self.state_reader)
387        #from sans.perspectives.calculator.sld_panel import SldPanel
388        #Send the fitting panel to guiframe
389        self.mypanels.append(self.fit_panel) 
390        #self.mypanels.append(SldPanel(parent=self.parent, base=self.parent))
391        return self.mypanels
392   
393    def clear_panel(self):
394        """
395        """
396        self.fit_panel.clear_panel()
397       
398    def set_default_perspective(self):
399        """
400        Call back method that True to notify the parent that the current plug-in
401        can be set as default  perspective.
402        when returning False, the plug-in is not candidate for an automatic
403        default perspective setting
404        """
405        return True
406   
407    def delete_data(self, data):
408        """
409        delete  the given data from panel
410        """
411        self.fit_panel.delete_data(data)
412       
413    def set_data(self, data_list=None):
414        """
415        receive a list of data to fit
416        """
417        if data_list is None:
418            data_list = []
419        selected_data_list = []
420        if self.batch_on:
421            page = self.add_fit_page(data=data_list)
422        else:
423            if len(data_list) > MAX_NBR_DATA:
424                from fitting_widgets import DataDialog
425                dlg = DataDialog(data_list=data_list, nb_data=MAX_NBR_DATA)
426                if dlg.ShowModal() == wx.ID_OK:
427                    selected_data_list = dlg.get_data()
428                dlg.Destroy()
429               
430            else:
431                selected_data_list = data_list
432            try:
433                group_id = wx.NewId()
434                for data in selected_data_list:
435                    if data is not None:
436                        data.group_id = group_id
437                        if group_id not in data.list_group_id:
438                            data.list_group_id.append(group_id)
439                        page = self.add_fit_page(data=[data])
440            except:
441                msg = "Fitting Set_data: " + str(sys.exc_value)
442                wx.PostEvent(self.parent, StatusEvent(status=msg, info="error"))
443   
444    def set_top_panel(self):
445        """
446        Close default (welcome) panel
447        """
448        if 'default' in self.parent.panels:
449            self.parent.on_close_welcome_panel()
450
451       
452    def set_theory(self,  theory_list=None):
453        """
454        """
455        #set the model state for a given theory_state:
456        for item in theory_list:
457            try:
458                _, theory_state = item
459                self.fit_panel.set_model_state(theory_state)
460            except:
461                msg = "Fitting: cannot deal with the theory received"
462                logging.error("set_theory " + msg + "\n" + str(sys.exc_value))
463                wx.PostEvent(self.parent, StatusEvent(status=msg, info="error"))
464           
465    def set_state(self, state=None, datainfo=None, format=None):
466        """
467        Call-back method for the fit page state reader.
468        This method is called when a .fitv/.svs file is loaded.
469       
470        : param state: PageState object
471        : param datainfo: data
472        """
473        #state = self.state_reader.get_state()
474        if state != None:
475            state = state.clone()
476            # store fitting state in temp_state
477            self.temp_state.append(state) 
478        else:
479            self.temp_state = []
480        # index to start with for a new set_state
481        self.state_index = 0
482        # state file format
483        self.sfile_ext = format
484       
485        self.on_set_state_helper(event=None)
486
487    def  on_set_state_helper(self,event=None):
488        """
489        Set_state_helper. This actually sets state
490        after plotting data from state file.
491       
492        : event: FitStateUpdateEvent called
493            by dataloader.plot_data from guiframe
494        """
495        if len(self.temp_state) == 0:
496            if self.state_index==0 and len(self.mypanels) <= 0 \
497            and self.sfile_ext =='.svs':
498                self.fit_panel.add_default_pages()
499                self.temp_state = []
500                self.state_index = 0
501            return
502       
503        try:
504            # Load fitting state
505            state = self.temp_state[self.state_index]
506            #panel state should have model selection to set_state
507            if state.formfactorcombobox != None:
508                #set state
509                data = self.parent.create_gui_data(state.data)
510                data.group_id = state.data.group_id
511                self.parent.add_data(data_list={data.id:data})
512                wx.PostEvent(self.parent, NewPlotEvent(plot=data,
513                                        title=data.title))
514                #need to be fix later make sure we are sendind guiframe.data
515                #to panel
516                state.data = data
517                page = self.fit_panel.set_state(state)   
518            else:
519                #just set data because set_state won't work
520                data = self.parent.create_gui_data(state.data)
521                data.group_id = state.data.group_id
522                self.parent.add_data(data_list={data.id:data})
523                wx.PostEvent(self.parent, NewPlotEvent(plot=data,
524                                        title=data.title))
525                page = self.add_fit_page([data])
526                caption = page.window_caption
527                self.store_data(uid=page.uid, data_list=page.get_data_list(), 
528                        caption=caption)
529                self.mypanels.append(page) 
530               
531            # get ready for the next set_state
532            self.state_index += 1
533
534            #reset state variables to default when all set_state is finished.
535            if len(self.temp_state) == self.state_index:
536               
537                self.temp_state = []
538                #self.state_index = 0
539                # Make sure the user sees the fitting panel after loading
540                #self.parent.set_perspective(self.perspective)
541                self.on_perspective(event=None)
542        except:
543            self.state_index==0
544            self.temp_state = []
545            raise
546       
547    def set_param2fit(self, uid, param2fit):
548        """
549        Set the list of param names to fit for fitprobelm
550        """
551        self.page_finder[uid].set_param2fit(param2fit)
552       
553    def set_graph_id(self, uid, graph_id):
554        """
555        Set graph_id for fitprobelm
556        """
557        self.page_finder[uid].set_graph_id(graph_id)
558       
559    def get_graph_id(self, uid):
560        """
561        Set graph_id for fitprobelm
562        """
563        return self.page_finder[uid].get_graph_id()   
564                         
565    def save_fit_state(self, filepath, fitstate): 
566        """
567        save fit page state into file
568        """
569        self.state_reader.write(filename=filepath, fitstate=fitstate)
570
571    def set_fit_weight(self, uid, flag, is2d=False, fid=None):
572        """
573        Set the fit weights of a given page for all
574        its data by default. If fid is provide then set the range
575        only for the data with fid as id
576        :param uid: id corresponding to a fit page
577        :param fid: id corresponding to a fit problem (data, model)
578        :param weight: current dy data
579        """
580        if uid in self.page_finder.keys():
581            self.page_finder[uid].set_weight(flag=flag, is2d=is2d)
582                   
583    def set_fit_range(self, uid, qmin, qmax, fid=None):
584        """
585        Set the fitting range of a given page for all
586        its data by default. If fid is provide then set the range
587        only for the data with fid as id
588        :param uid: id corresponding to a fit page
589        :param fid: id corresponding to a fit problem (data, model)
590        :param qmin: minimum  value of the fit range
591        :param qmax: maximum  value of the fit range
592        """
593        if uid in self.page_finder.keys():
594            self.page_finder[uid].set_range(qmin=qmin, qmax=qmax, fid=fid)
595     
596    def schedule_for_fit(self, value=0, uid=None): 
597        """
598        Set the fit problem field to 0 or 1 to schedule that problem to fit.
599        Schedule the specified fitproblem or get the fit problem related to
600        the current page and set value.
601        :param value: integer 0 or 1
602        :param uid: the id related to a page contaning fitting information
603        """
604        if uid in self.page_finder.keys(): 
605            self.page_finder[uid].schedule_tofit(value)
606         
607    def get_page_finder(self):
608        """
609        return self.page_finder used also by simfitpage.py
610        """ 
611        return self.page_finder
612   
613    def set_page_finder(self,modelname,names,values):
614        """
615        Used by simfitpage.py to reset a parameter given the string constrainst.
616         
617        :param modelname: the name ot the model for with the parameter
618                            has to reset
619        :param value: can be a string in this case.
620        :param names: the paramter name
621         
622        :note: expecting park used for fit.
623         
624        """ 
625        sim_page_id = self.sim_page.uid
626        for uid, value in self.page_finder.iteritems():
627            if uid != sim_page_id and uid != self.batch_page.uid:
628                list = value.get_model()
629                model = list[0]
630                if model.name == modelname:
631                    value.set_model_param(names, values)
632                    break
633         
634    def split_string(self,item): 
635        """
636        receive a word containing dot and split it. used to split parameterset
637        name into model name and parameter name example: ::
638       
639            paramaterset (item) = M1.A
640            Will return model_name = M1 , parameter name = A
641           
642        """
643        if string.find(item,".")!=-1:
644            param_names= re.split("\.",item)
645            model_name=param_names[0]           
646            ##Assume max len is 3; eg., M0.radius.width
647            if len(param_names) == 3:
648                param_name=param_names[1]+"."+param_names[2]
649            else:
650                param_name=param_names[1]                   
651            return model_name,param_name
652   
653    def set_ftol(self, ftol=None):
654        """
655        Set ftol: Relative error desired in the sum of chi squares. 
656        """
657        # check if it is flaot
658        try:
659            f_tol = float(ftol)
660        except:
661            # default
662            f_tol = SANS_F_TOL
663           
664        self.ftol = f_tol
665        # update ftol menu help strings
666        ftol_help = "Change the current FTolerance (=%s) " % str(self.ftol)
667        ftol_help += "of Simple FitEngine..." 
668        if self.menu1 != None:
669            self.menu1.SetHelpString(self.id_tol, ftol_help)
670       
671    def show_ftol_dialog(self, event=None):
672        """
673        Dialog to select ftol for Scipy
674        """
675        #if event != None:
676        #    event.Skip()
677        from ftol_dialog import ChangeFtol
678        panel = ChangeFtol(self.parent, self)
679        panel.ShowModal()
680                 
681    def stop_fit(self, uid):
682        """
683        Stop the fit engine
684        """
685        if uid in self.fit_thread_list.keys():
686            calc_fit = self.fit_thread_list[uid]
687            if calc_fit is not  None and calc_fit.isrunning():
688                calc_fit.stop()
689                msg = "Fit stop!"
690                wx.PostEvent(self.parent, StatusEvent(status=msg, type="stop"))
691            del self.fit_thread_list[uid]
692        #set the fit button label of page when fit stop is trigger from
693        #simultaneous fit pane
694        sim_flag = self.sim_page is not None and uid == self.sim_page.uid
695        batch_flag = self.batch_page is not None and uid == self.batch_page.uid
696        if sim_flag or batch_flag:
697            for uid, value in self.page_finder.iteritems():
698                if value.get_scheduled() == 1:
699                    if uid in self.fit_panel.opened_pages.keys():
700                        panel = self.fit_panel.opened_pages[uid]
701                        panel._on_fit_complete()
702 
703    def set_smearer(self, uid, smearer, fid, qmin=None, qmax=None, draw=True,
704                    enable_smearer=False):
705        """
706        Get a smear object and store it to a fit problem of fid as id. If proper
707        flag is enable , will plot the theory with smearing information.
708       
709        :param smearer: smear object to allow smearing data of id fid
710        :param enable_smearer: Define whether or not all (data, model) contained
711            in the structure of id uid will be smeared before fitting.
712        :param qmin: the maximum value of the theory plotting range
713        :param qmax: the maximum value of the theory plotting range
714        :param draw: Determine if the theory needs to be plot
715        """   
716        if uid not in self.page_finder.keys():
717            return
718        self.page_finder[uid].enable_smearing(flag=enable_smearer)
719        self.page_finder[uid].set_smearer(smearer, fid=fid)
720        if draw:
721            ## draw model 1D with smeared data
722            data =  self.page_finder[uid].get_fit_data(fid=fid)
723            if data is None:
724                msg = "set_mearer requires at least data.\n"
725                msg += "Got data = %s .\n" % str(data)
726                return
727                #raise ValueError, msg
728            model = self.page_finder[uid].get_model(fid=fid)
729            if model is None:
730                return
731            enable1D = issubclass(data.__class__, Data1D)
732            enable2D = issubclass(data.__class__, Data2D)
733            ## if user has already selected a model to plot
734            ## redraw the model with data smeared
735            smear = self.page_finder[uid].get_smearer(fid=fid)
736
737            # compute weight for the current data
738            weight = self.page_finder[uid].get_weight(fid=fid)
739
740            self.draw_model(model=model, data=data, page_id=uid, smearer=smear,
741                enable1D=enable1D, enable2D=enable2D,
742                qmin=qmin, qmax=qmax, weight=weight)
743            self._mac_sleep(0.2)
744           
745    def _mac_sleep(self, sec=0.2):
746        """
747        Give sleep to MAC
748        """
749        if ON_MAC:
750           time.sleep(sec)
751       
752    def draw_model(self, model, page_id, data=None, smearer=None,
753                   enable1D=True, enable2D=False,
754                   state=None,
755                   fid=None,
756                   toggle_mode_on=False,
757                   qmin=None, qmax=None, 
758                   update_chisqr=True, weight=None, source='model'):
759        """
760        Draw model.
761       
762        :param model: the model to draw
763        :param name: the name of the model to draw
764        :param data: the data on which the model is based to be drawn
765        :param description: model's description
766        :param enable1D: if true enable drawing model 1D
767        :param enable2D: if true enable drawing model 2D
768        :param qmin:  Range's minimum value to draw model
769        :param qmax:  Range's maximum value to draw model
770        :param qstep: number of step to divide the x and y-axis
771        :param update_chisqr: update chisqr [bool]
772             
773        """
774        #self.weight = weight
775        if issubclass(data.__class__, Data1D) or not enable2D:   
776            ## draw model 1D with no loaded data
777            self._draw_model1D(model=model, 
778                               data=data,
779                               page_id=page_id,
780                               enable1D=enable1D, 
781                               smearer=smearer,
782                               qmin=qmin,
783                               qmax=qmax, 
784                               fid=fid,
785                               weight=weight,
786                               toggle_mode_on=toggle_mode_on,
787                               state=state,
788                               update_chisqr=update_chisqr,
789                               source=source)
790        else:     
791            ## draw model 2D with no initial data
792            self._draw_model2D(model=model,
793                                page_id=page_id,
794                                data=data,
795                                enable2D=enable2D,
796                                smearer=smearer,
797                                qmin=qmin,
798                                qmax=qmax,
799                                fid=fid,
800                                weight=weight,
801                                state=state,
802                                toggle_mode_on=toggle_mode_on,
803                                update_chisqr=update_chisqr,
804                                source=source)
805           
806    def onFit(self, uid):
807        """
808        Get series of data, model, associates parameters and range and send then
809        to  series of fit engines. Fit data and model, display result to
810        corresponding panels.
811        :param uid: id related to the panel currently calling this fit function.
812        """
813        flag = True
814        ##  count the number of fitproblem schedule to fit
815        fitproblem_count = 0
816        for value in self.page_finder.values():
817            if value.get_scheduled() == 1:
818                fitproblem_count += 1
819        self._gui_engine = self._return_engine_type()       
820        self.fitproblem_count = fitproblem_count 
821        if self._fit_engine == "park":
822            engineType = "Simultaneous Fit"
823        else:
824            engineType = "Single Fit"
825        fitter_list = []       
826        sim_fitter = None     
827        is_single_fit = True
828        batch_on = False
829        if self.sim_page is not None and self.sim_page.uid == uid:
830            #simulatanous fit only one engine need to be created
831            ## if simultaneous fit change automatically the engine to park
832            self._on_change_engine(engine='park')   
833            sim_fitter = Fit(self._fit_engine) 
834            sim_fitter.fitter_id = self.sim_page.uid
835            fitter_list.append(sim_fitter) 
836            is_single_fit = False
837            batch_on = self.sim_page.batch_on
838           
839
840        self.fitproblem_count = fitproblem_count 
841        if self._fit_engine == "park":
842            engineType = "Simultaneous Fit"
843        else:
844            engineType = "Single Fit"
845       
846        self.current_pg = None
847        list_page_id = []
848        fit_id = 0
849        batch_inputs = {}
850        batch_outputs = {}
851        for page_id, value in self.page_finder.iteritems():
852            # For simulfit (uid give with None), do for-loop
853            # if uid is specified (singlefit), do it only on the page.
854            if engineType == "Single Fit":
855                #combine more than 1 batch page on single mode
856                if self.batch_page is None or self.batch_page.uid != uid:
857                    if page_id != uid:
858                        continue
859            try:
860                if value.get_scheduled() == 1:
861                    value.nbr_residuals_computed = 0
862                    #Get list of parameters name to fit
863                    pars = []
864                    templist = []
865                    page = self.fit_panel.get_page_by_id(page_id)
866                    self.set_fit_weight(uid=page.uid, 
867                                     flag=page.get_weight_flag(),
868                                     is2d = page._is_2D())
869                    templist = page.get_param_list()
870                    flag = page._update_paramv_on_fit() 
871                    if not flag:
872                        msg = "Fitting range or parameter values are"
873                        msg += " invalid in %s"% \
874                                    page.window_caption
875                        wx.PostEvent(page.parent.parent, 
876                                     StatusEvent(status= msg, info="error",
877                                     type="stop"))
878                        return flag
879                    for element in templist:
880                        name = str(element[1])
881                        pars.append(name)
882                    fitproblem_list = value.values()
883                    for fitproblem in  fitproblem_list:
884                        if sim_fitter is None:
885                            fitter = Fit(self._fit_engine) 
886                            fitter.fitter_id = page_id
887                            self._fit_helper(fitproblem=fitproblem, 
888                                                pars=pars, 
889                                                fitter=fitter,
890                                              fit_id=fit_id, 
891                                              batch_inputs=batch_inputs,
892                                              batch_outputs=batch_outputs)
893                            fitter_list.append(fitter) 
894                        else:
895                            fitter = sim_fitter
896                            self._fit_helper(fitproblem=fitproblem, 
897                                                pars=pars, 
898                                                fitter=fitter,
899                                              fit_id=fit_id, 
900                                              batch_inputs=batch_inputs,
901                                              batch_outputs=batch_outputs)
902                        fit_id += 1
903                    list_page_id.append(page_id)
904                    current_page_id = page_id
905                    value.clear_model_param()
906            except:
907                flag = False
908                msg= "%s error: %s" % (engineType, sys.exc_value)
909                wx.PostEvent(self.parent, StatusEvent(status=msg, info="error",
910                                                      type="stop"))
911                return flag
912        ## If a thread is already started, stop it
913        #if self.calc_fit!= None and self.calc_fit.isrunning():
914        #    self.calc_fit.stop()
915        msg = "Fitting is in progress..."
916        wx.PostEvent( self.parent, StatusEvent(status=msg, type="progress" ))
917       
918        #Handler used for park engine displayed message
919        handler = ConsoleUpdate(parent=self.parent,
920                                manager=self,
921                                improvement_delta=0.1)
922        self._mac_sleep(0.2)
923        ## perform single fit
924        try:
925            page = self.fit_panel.get_page_by_id(uid)
926            batch_on = page.batch_on
927        except:
928            try:
929                #if the id cannot be found then  we deal with a self.sim_page
930                #or a self.batch_page
931                if self.sim_page is not None and uid == self.sim_page.uid:
932                    batch_on = self.sim_page.batch_on
933                if self.batch_page is not None and uid == self.batch_page.uid:
934                    batch_on = self.batch_page.batch_on
935            except:
936                 batch_on = False
937                 #raise
938       
939        # batch fit
940        if batch_on:
941            calc_fit = FitThread(handler = handler,
942                                    fn=fitter_list,
943                                    pars=pars,
944                                    batch_inputs=batch_inputs,
945                                    batch_outputs=batch_outputs,
946                                    page_id=list_page_id,
947                                    completefn=self._batch_fit_complete,
948                                    ftol=self.ftol,
949                                    reset_flag=self.batch_reset_flag)
950        else:
951            # single fit: not batch and not simul fit
952            if not is_single_fit:
953                current_page_id = self.sim_page.uid
954            ## Perform more than 1 fit at the time
955            calc_fit = FitThread(handler=handler,
956                                    fn=fitter_list,
957                                    batch_inputs=batch_inputs,
958                                    batch_outputs=batch_outputs,
959                                    page_id=list_page_id,
960                                    updatefn=handler.update_fit,
961                                    completefn=self._fit_completed,
962                                    ftol=self.ftol)
963        self.fit_thread_list[current_page_id] = calc_fit
964        calc_fit.queue()
965        msg = "Fitting is in progress..."
966        wx.PostEvent( self.parent, StatusEvent(status=msg, type="progress" ))
967       
968        self.ready_fit(calc_fit=calc_fit)
969        return flag
970   
971    def ready_fit(self, calc_fit):
972        """
973        Ready for another fit
974        """
975        if self.fitproblem_count != None and self.fitproblem_count > 1:
976            calc_fit.ready(2.5)
977        else:
978            time.sleep(0.4)
979           
980    def remove_plot(self, uid, fid=None, theory=False):
981        """
982        remove model plot when a fit page is closed
983        :param uid: the id related to the fitpage to close
984        :param fid: the id of the fitproblem(data, model, range,etc)
985        """
986        if uid not in self.page_finder.keys():
987            return
988        fitproblemList = self.page_finder[uid].get_fit_problem(fid)
989        for fitproblem in fitproblemList:
990            data = fitproblem.get_fit_data()
991            model = fitproblem.get_model()
992            plot_id = None
993            if model is not None:
994                plot_id = data.id + name
995            if theory:
996                plot_id = data.id
997            group_id = data.group_id
998            wx.PostEvent(self.parent, NewPlotEvent(id=plot_id,
999                                                       group_id=group_id,
1000                                                       action='remove'))
1001           
1002    def store_data(self, uid, data_list=None, caption=None):
1003        """
1004        Recieve a list of data and store them ans well as a caption of
1005        the fit page where they come from.
1006        :param uid: if related to a fit page
1007        :param data_list: list of data to fit
1008        :param caption: caption of the window related to these data
1009        """
1010        if data_list is None:
1011            data_list = []
1012       
1013        self.page_finder[uid].set_fit_data(data=data_list)
1014        if caption is not None:
1015            self.page_finder[uid].set_fit_tab_caption(caption=caption)
1016           
1017    def on_add_new_page(self, event=None):
1018        """
1019        ask fit panel to create a new empty page
1020        """
1021        try:
1022            page = self.fit_panel.add_empty_page()
1023            page_caption = page.window_caption
1024            # add data associated to the page created
1025            if page != None: 
1026                wx.PostEvent(self.parent, StatusEvent(status="Page Created",
1027                                               info="info"))
1028            else:
1029                msg = "Page was already Created"
1030                wx.PostEvent(self.parent, StatusEvent(status=msg,
1031                                                       info="warning"))
1032            self.set_top_panel()
1033        except:
1034            msg = "Creating Fit page: %s"%sys.exc_value
1035            wx.PostEvent(self.parent, StatusEvent(status=msg, info="error"))
1036       
1037    def add_fit_page(self, data):
1038        """
1039        given a data, ask to the fitting panel to create a new fitting page,
1040        get this page and store it into the page_finder of this plug-in
1041        :param data: is a list of data
1042        """
1043        page = self.fit_panel.set_data(data)
1044        # page could be None when loading state files
1045        if page == None:
1046            return page
1047        page_caption = page.window_caption
1048        #append Data1D to the panel containing its theory
1049        #if theory already plotted
1050        if page.uid in self.page_finder:
1051            data = page.get_data()
1052            theory_data = self.page_finder[page.uid].get_theory_data(data.id)
1053            if issubclass(data.__class__, Data2D):
1054                data.group_id = wx.NewId()
1055                if theory_data is not None:
1056                    group_id = str(page.uid) + " Model1D"
1057                    wx.PostEvent(self.parent, 
1058                             NewPlotEvent(group_id=group_id,
1059                                               action="delete"))
1060                    self.parent.update_data(prev_data=theory_data,
1061                                             new_data=data)     
1062            else:
1063                if theory_data is not None:
1064                    group_id = str(page.uid) + " Model2D"
1065                    data.group_id = theory_data.group_id
1066                    wx.PostEvent(self.parent, 
1067                             NewPlotEvent(group_id=group_id,
1068                                               action="delete"))
1069                    self.parent.update_data(prev_data=theory_data,
1070                                             new_data=data)   
1071        self.store_data(uid=page.uid, data_list=page.get_data_list(), 
1072                        caption=page.window_caption)
1073        if self.sim_page is not None and not self.batch_on:
1074            self.sim_page.draw_page()
1075        if self.batch_page is not None and self.batch_on:
1076            self.batch_page.draw_page()
1077           
1078        return page
1079           
1080    def _onEVT_SLICER_PANEL(self, event):
1081        """
1082        receive and event telling to update a panel with a name starting with
1083        event.panel_name. this method update slicer panel
1084        for a given interactor.
1085       
1086        :param event: contains type of slicer , paramaters for updating
1087            the panel and panel_name to find the slicer 's panel concerned.
1088        """
1089        for item in self.parent.panels:
1090            name = event.panel_name
1091            if self.parent.panels[item].window_caption.startswith(name):
1092                self.parent.panels[item].set_slicer(event.type, event.params)
1093               
1094        self.parent._mgr.Update()
1095   
1096    def _closed_fitpage(self, event):   
1097        """
1098        request fitpanel to close a given page when its unique data is removed
1099        from the plot. close fitpage only when the a loaded data is removed
1100        """   
1101        if event is None or event.data is None:
1102            return
1103        if hasattr(event.data,"is_data"):
1104            if not event.data.is_data or \
1105                event.data.__class__.__name__ == "Data1D":
1106                self.fit_panel.close_page_with_data(event.data) 
1107 
1108    def _reset_schedule_problem(self, value=0, uid=None):
1109        """
1110        unschedule or schedule all fitproblem to be fit
1111        """
1112        # case that uid is not specified
1113        if uid == None:
1114            for page_id in self.page_finder.keys():
1115                self.page_finder[page_id].schedule_tofit(value)
1116        # when uid is given
1117        else:
1118            if uid in self.page_finder.keys():
1119                self.page_finder[uid].schedule_tofit(value)
1120               
1121    def _fit_helper(self, fitproblem, pars, fitter, fit_id,
1122                    batch_inputs, batch_outputs):
1123        """
1124        Create and set fit engine with series of data and model
1125        :param pars: list of fittable parameters
1126        :param fitter_list: list of fit engine
1127        :param value:  structure storing data mapped to their model, range etc..
1128        """
1129        data = fitproblem.get_fit_data()
1130        model = fitproblem.get_model()
1131        smearer = fitproblem.get_smearer()
1132        qmin, qmax = fitproblem.get_range()
1133
1134        #Extra list of parameters and their constraints
1135        listOfConstraint = []
1136        param = fitproblem.get_model_param()
1137        if len(param) > 0:
1138            for item in param:
1139                ## check if constraint
1140                if item[0] != None and item[1] != None:
1141                    listOfConstraint.append((item[0],item[1]))
1142        new_model = model#deepcopy(model)
1143        fitter.set_model(new_model, fit_id, pars, data=data,
1144                         constraints=listOfConstraint)
1145        fitter.set_data(data=data, id=fit_id, smearer=smearer, qmin=qmin, 
1146                        qmax=qmax)
1147        fitter.select_problem_for_fit(id=fit_id, value=1)
1148       
1149   
1150    def _onSelect(self,event):
1151        """
1152        when Select data to fit a new page is created .Its reference is
1153        added to self.page_finder
1154        """
1155        self.panel = event.GetEventObject()
1156        Plugin.on_perspective(self, event=event)
1157        self.select_data(self.panel)
1158       
1159    def select_data(self, panel):
1160        """
1161        """
1162        self.panel = panel
1163        for plottable in self.panel.graph.plottables:
1164            if plottable.__class__.__name__ in ["Data1D", "Theory1D"]:
1165                data_id = self.panel.graph.selected_plottable
1166                if plottable == self.panel.plots[data_id]:
1167                    data = plottable
1168                    self.add_fit_page(data=[data])
1169                    return
1170            else:
1171                data = plottable
1172                self.add_fit_page(data=[data])
1173        self.set_top_panel()
1174           
1175    def update_fit(self, result=None, msg=""):
1176        """
1177        """
1178        print "update_fit result", result
1179       
1180   
1181    def _batch_fit_complete(self, result, pars, page_id, 
1182                            batch_outputs, batch_inputs, elapsed=None):
1183        """
1184        Display fit result in batch
1185        :param result: list of objects received fromt fit engines
1186        :param pars: list of  fitted parameters names
1187        :param page_id: list of page ids which called fit function
1188        :param elapsed: time spent at the fitting level
1189        """
1190        self._mac_sleep(0.2)
1191        uid = page_id[0]
1192        if uid in self.fit_thread_list.keys():
1193            del self.fit_thread_list[uid] 
1194         
1195        self._update_fit_button(page_id)
1196        t1 = time.time()
1197        str_time = time.strftime("%a, %d %b %Y %H:%M:%S ", time.localtime(t1))
1198        msg = "Fit completed on %s \n" % str_time
1199        msg += "Duration time: %s s.\n" % str(elapsed)
1200        wx.PostEvent(self.parent, StatusEvent(status=msg, info="info",
1201                                                      type="stop"))
1202       
1203        if batch_outputs is None:
1204            batch_outputs = {}
1205       
1206        # format batch_outputs
1207        batch_outputs["Chi2"] = []
1208        #Don't like these loops
1209        # Need to create dictionary of all fitted parameters
1210        # since the number of parameters can differ between each fit result
1211        for list_res in result:
1212            for res in list_res:
1213                model, data = res.inputs[0]
1214                if model is not None and hasattr(model, "model"):
1215                    model = model.model
1216                #get all fittable parameters of the current model
1217                for param in  model.getParamList():
1218                    if param  not in batch_outputs.keys():
1219                        batch_outputs[param] = []
1220                for param in model.getDispParamList():
1221                    if not model.is_fittable(param) and \
1222                        param in batch_outputs.keys():
1223                        del batch_outputs[param]
1224                # Add fitted parameters and their error
1225                for param in res.param_list:
1226                    if param not in batch_outputs.keys():
1227                        batch_outputs[param] = []
1228                    err_param = "error on %s" % str(param)
1229                    if err_param not in batch_inputs.keys():
1230                        batch_inputs[err_param] = []
1231        msg = ""
1232        for list_res in result:
1233            for res in list_res:
1234                pid = res.fitter_id
1235                model, data = res.inputs[0]
1236                correct_result = False
1237                if model is not None and hasattr(model, "model"):
1238                    model = model.model
1239                if data is not None and hasattr(data, "sans_data"):
1240                    data = data.sans_data
1241               
1242                is_data2d = issubclass(data.__class__, Data2D)
1243                #check consistency of arrays
1244                if not is_data2d:
1245                    if len(res.theory) == len(res.index[res.index]) and \
1246                        len(res.index) == len(data.y):
1247                        correct_result = True
1248                else:
1249                    copy_data = deepcopy(data)
1250                    new_theory = copy_data.data
1251                    new_theory[res.index] = res.theory
1252                    new_theory[res.index == False] = numpy.nan
1253                    correct_result = True
1254                #get all fittable parameters of the current model
1255                param_list = model.getParamList()
1256                for param in model.getDispParamList():
1257                    if not model.is_fittable(param) and \
1258                        param in param_list:
1259                        param_list.remove(param)       
1260                if not correct_result or res.fitness is None or \
1261                    not numpy.isfinite(res.fitness) or \
1262                    numpy.any(res.pvec == None) or not \
1263                    numpy.all(numpy.isfinite(res.pvec)):
1264                    data_name = str(None)
1265                    if data is not None:
1266                        data_name = str(data.name)
1267                    model_name = str(None)
1268                    if model is not None:
1269                        model_name = str(model.name)
1270                    msg += "Data %s and Model %s did not fit.\n" % (data_name, 
1271                                                                    model_name)
1272                    ERROR = numpy.NAN
1273                    cell = BatchCell()
1274                    cell.label = res.fitness
1275                    cell.value = res.fitness
1276                    batch_outputs["Chi2"].append(ERROR)
1277                    for param in param_list:
1278                        # save value of  fixed parameters
1279                        if param not in res.param_list:
1280                            batch_outputs[str(param)].append(ERROR)
1281                        else:
1282                            #save only fitted values
1283                            batch_outputs[param].append(ERROR)
1284                            batch_inputs["error on %s" % str(param)].append(ERROR)
1285                else:
1286                    # ToDo: Why sometimes res.pvec comes with numpy.float64?
1287                    # Need to fix it within ScipyEngine
1288                    if res.pvec.__class__== numpy.float64:
1289                        res.pvec = [res.pvec]
1290                       
1291                    cell = BatchCell()
1292                    cell.label = res.fitness
1293                    cell.value = res.fitness
1294                    batch_outputs["Chi2"].append(cell)
1295                    # add parameters to batch_results
1296                    for param in param_list:
1297                        # save value of  fixed parameters
1298                        if param not in res.param_list:
1299                            batch_outputs[str(param)].append(model.getParam(param))
1300                        else:
1301                            index = res.param_list.index(param)
1302                            #save only fitted values
1303                            batch_outputs[param].append(res.pvec[index])
1304                            if res.stderr is not None and \
1305                                len(res.stderr) == len(res.param_list):
1306                                item = res.stderr[index]
1307                                batch_inputs["error on %s" % param].append(item)
1308                            model.setParam(param, res.pvec[index])
1309                #fill the batch result with emtpy value if not in the current
1310                #model
1311                EMPTY = "-"
1312                for key in batch_outputs.keys():
1313                    if key not in param_list and key not in ["Chi2", "Data"]:
1314                        batch_outputs[key].append(EMPTY)
1315                for key in batch_inputs.keys():
1316                    if key not in param_list and key not in ["Chi2", "Data"]:
1317                        batch_inputs[key].append(EMPTY)
1318                               
1319                self.page_finder[pid].set_batch_result(batch_inputs=batch_inputs,
1320                                                     batch_outputs=batch_outputs) 
1321               
1322                cpage = self.fit_panel.get_page_by_id(pid)
1323                cpage._on_fit_complete()
1324                self.page_finder[pid][data.id].set_result(res)
1325                fitproblem = self.page_finder[pid][data.id]
1326                qmin, qmax = fitproblem.get_range()
1327               
1328                if correct_result:
1329                    if not is_data2d:
1330                        self._complete1D(x=data.x, y=res.theory, page_id=pid, 
1331                                     elapsed=None, 
1332                                     index=res.index, model=model,
1333                                     weight=None, fid=data.id,
1334                                     toggle_mode_on=False, state=None, 
1335                                     data=data, update_chisqr=False, 
1336                                     source='fit')
1337                    else:
1338                        self._complete2D(image=new_theory, data=data,
1339                                      model=model,
1340                                      page_id=pid,  elapsed=None, 
1341                                      index=res.index, 
1342                                      qmin=qmin,
1343                                     qmax=qmax, fid=data.id, weight=None,
1344                                      toggle_mode_on=False, state=None, 
1345                                     update_chisqr=False, 
1346                                     source='fit')
1347                self.on_set_batch_result(page_id=pid, 
1348                                         fid=data.id, 
1349                                         batch_outputs=batch_outputs, 
1350                                         batch_inputs=batch_inputs)
1351       
1352        wx.PostEvent(self.parent, StatusEvent(status=msg, error="error",
1353                                                              type="stop"))
1354        wx.CallAfter(self.parent.on_set_batch_result,batch_outputs, 
1355                                            batch_inputs,
1356                                           self.sub_menu)
1357       
1358    def on_set_batch_result(self, page_id, fid, batch_outputs, batch_inputs):
1359        """
1360        """
1361       
1362        pid =  page_id
1363        if fid not in self.page_finder[pid]:
1364            return
1365        fitproblem = self.page_finder[pid][fid]
1366        index = self.page_finder[pid].nbr_residuals_computed - 1
1367        residuals =  fitproblem.get_residuals()
1368        theory_data = fitproblem.get_theory_data()
1369        data = fitproblem.get_fit_data()
1370        model = fitproblem.get_model()
1371        #fill batch result information
1372        if "Data" not in batch_outputs.keys():
1373            batch_outputs["Data"] = []
1374        from sans.guiframe.data_processor import BatchCell
1375        cell = BatchCell()
1376        cell.label = data.name
1377        cell.value = index
1378       
1379        if theory_data != None:
1380            #Suucessful fit
1381            theory_data.id = wx.NewId()
1382            theory_data.name = model.name + "[%s]" % str(data.name)
1383            if issubclass(theory_data.__class__, Data2D):
1384                group_id = wx.NewId()
1385                theory_data.group_id = group_id
1386                if group_id not in theory_data.list_group_id:
1387                    theory_data.list_group_id.append(group_id)
1388               
1389            try:
1390                # associate residuals plot
1391                if issubclass(residuals.__class__, Data2D):
1392                    group_id = wx.NewId()
1393                    residuals.group_id = group_id
1394                    if group_id not in residuals.list_group_id:
1395                        residuals.list_group_id.append(group_id)
1396                batch_outputs["Chi2"][index].object = [residuals]
1397            except:
1398                pass
1399
1400        cell.object = [data, theory_data]
1401        batch_outputs["Data"].append(cell)
1402        for key, value in data.meta_data.iteritems():
1403            if key not in batch_inputs.keys():
1404                batch_inputs[key] = []
1405            if key.lower().strip() != "loader":
1406                batch_inputs[key].append(value)
1407        param = "temperature"
1408        if hasattr(data.sample, param):
1409            if param not in  batch_inputs.keys():
1410                 batch_inputs[param] = []
1411            batch_inputs[param].append(data.sample.temperature)
1412       
1413
1414    def _fit_completed(self, result, page_id, batch_outputs,
1415                             batch_inputs=None,
1416                              pars=None, 
1417                             elapsed=None):
1418        """
1419        Display result of the fit on related panel(s).
1420        :param result: list of object generated when fit ends
1421        :param pars: list of names of parameters fitted
1422        :param page_id: list of page ids which called fit function
1423        :param elapsed: time spent at the fitting level
1424        """
1425        t1 = time.time()
1426        str_time = time.strftime("%a, %d %b %Y %H:%M:%S ", time.localtime(t1))
1427        msg = "Fit completed on %s \n" % str_time
1428        msg += "Duration time: %s s.\n" % str(elapsed)
1429        wx.PostEvent(self.parent, StatusEvent(status=msg, info="info",
1430                                                      type="stop"))
1431        # reset fit_engine if changed by simul_fit
1432        if self._fit_engine != self._gui_engine:
1433            self._on_change_engine(self._gui_engine)
1434        self._update_fit_button(page_id)
1435        result = result[0]
1436        self.fit_thread_list = {}
1437        if page_id is None:
1438            page_id = []
1439        ## fit more than 1 model at the same time
1440        self._mac_sleep(0.2) 
1441        try:
1442            index = 0
1443            for uid in page_id:
1444                res = result[index]
1445                if res.fitness is None or \
1446                    not numpy.isfinite(res.fitness) or \
1447                    numpy.any(res.pvec == None) or \
1448                    not numpy.all(numpy.isfinite(res.pvec)):
1449                    msg = "Fitting did not converge!!!"
1450                    wx.PostEvent(self.parent, 
1451                             StatusEvent(status=msg, 
1452                                         info="warning",
1453                                         type="stop"))
1454                    self._update_fit_button(page_id)
1455                else:
1456                    #set the panel when fit result are float not list
1457                    if res.pvec.__class__== numpy.float64:
1458                        pvec = [res.pvec]
1459                    else:
1460                        pvec = res.pvec
1461                    if res.stderr.__class__== numpy.float64:
1462                        stderr = [res.stderr]
1463                    else:
1464                        stderr = res.stderr
1465                    cpage = self.fit_panel.get_page_by_id(uid)
1466                    # Make sure we got all results
1467                    #(CallAfter is important to MAC)
1468                    wx.CallAfter(cpage.onsetValues, res.fitness, res.param_list, 
1469                             pvec, stderr)
1470                    index += 1
1471                    cpage._on_fit_complete()
1472        except:
1473            msg = "Fit completed but Following"
1474            msg += " error occurred:%s" % sys.exc_value
1475            wx.PostEvent(self.parent, StatusEvent(status=msg, info="error",
1476                                                  type="stop"))
1477           
1478    def _update_fit_button(self, page_id):
1479        """
1480        Update Fit button when fit stopped
1481       
1482        : parameter page_id: fitpage where the button is
1483        """
1484        if page_id.__class__.__name__ != 'list':
1485            page_id = [page_id]
1486        for uid in page_id: 
1487            page = self.fit_panel.get_page_by_id(uid)
1488            page._on_fit_complete()
1489       
1490    def _on_show_panel(self, event):
1491        """
1492        """
1493        pass
1494   
1495    def on_reset_batch_flag(self, event):
1496        """
1497        Set batch_reset_flag
1498        """
1499        event.Skip()
1500        if self.menu1 == None:
1501            return
1502        menu_item = self.menu1.FindItemById(self.id_reset_flag)
1503        flag = menu_item.IsChecked()
1504        if not flag:
1505            menu_item.Check(False)
1506            self.batch_reset_flag = True
1507        else:
1508            menu_item.Check(True)
1509            self.batch_reset_flag = False
1510       
1511        ## post a message to status bar
1512        msg = "Set Chain Fitting: %s" % str(not self.batch_reset_flag)
1513        wx.PostEvent(self.parent, 
1514                     StatusEvent(status=msg))
1515
1516    def _onset_engine_park(self,event):
1517        """
1518        set engine to park
1519        """
1520        self._on_change_engine('park')
1521       
1522    def _onset_engine_scipy(self,event):
1523        """
1524        set engine to scipy
1525        """
1526        self._on_change_engine('scipy')
1527       
1528    def _on_slicer_event(self, event):
1529        """
1530        Receive a panel as event and send it to guiframe
1531       
1532        :param event: event containing a panel
1533       
1534        """
1535        if event.panel is not None:
1536            new_panel = event.panel
1537            self.slicer_panels.append(event.panel)
1538            # Set group ID if available
1539            event_id = self.parent.popup_panel(new_panel)
1540            new_panel.uid = event_id
1541            self.mypanels.append(new_panel) 
1542       
1543    def _onclearslicer(self, event):
1544        """
1545        Clear the boxslicer when close the panel associate with this slicer
1546        """
1547        name =event.GetPane().caption
1548   
1549        for panel in self.slicer_panels:
1550            if panel.window_caption==name:
1551               
1552                for item in self.parent.panels:
1553                    if hasattr(self.parent.panels[item], "uid"):
1554                        if self.parent.panels[item].uid ==panel.base.uid:
1555                            self.parent.panels[item].onClearSlicer(event)
1556                            self.parent._mgr.Update()
1557                            break 
1558                break
1559   
1560    def _return_engine_type(self):
1561        """
1562        return the current type of engine
1563        """
1564        return self._fit_engine
1565     
1566     
1567    def _on_change_engine(self, engine='park'):
1568        """
1569        Allow to select the type of engine to perform fit
1570       
1571        :param engine: the key work of the engine
1572       
1573        """
1574        ## saving fit engine name
1575        self._fit_engine = engine
1576        ## change menu item state
1577        if engine == "park":
1578            self.menu1.FindItemById(self.park_id).Check(True)
1579            self.menu1.FindItemById(self.scipy_id).Check(False)
1580        else:
1581            self.menu1.FindItemById(self.park_id).Check(False)
1582            self.menu1.FindItemById(self.scipy_id).Check(True)
1583        ## post a message to status bar
1584        msg = "Engine set to: %s" % self._fit_engine
1585        wx.PostEvent(self.parent, 
1586                     StatusEvent(status=msg))
1587        ## send the current engine type to fitpanel
1588        self.fit_panel._on_engine_change(name=self._fit_engine)
1589
1590       
1591    def _on_model_panel(self, evt):
1592        """
1593        react to model selection on any combo box or model menu.plot the model 
1594       
1595        :param evt: wx.combobox event
1596       
1597        """
1598        model = evt.model
1599        uid = evt.uid
1600        qmin = evt.qmin
1601        qmax = evt.qmax
1602        smearer = evt.smearer
1603        caption = evt.caption
1604        enable_smearer = evt.enable_smearer
1605        if model == None:
1606            return
1607        if uid not in self.page_finder.keys():
1608            return
1609        # save the name containing the data name with the appropriate model
1610        self.page_finder[uid].set_model(model)
1611        self.page_finder[uid].enable_smearing(enable_smearer)
1612        self.page_finder[uid].set_range(qmin=qmin, qmax=qmax)
1613        self.page_finder[uid].set_fit_tab_caption(caption=caption)
1614        if self.sim_page is not None and not self.batch_on:
1615            self.sim_page.draw_page()
1616        if self.batch_page is not None and self.batch_on:
1617            self.batch_page.draw_page()
1618       
1619    def _update1D(self, x, output):
1620        """
1621        Update the output of plotting model 1D
1622        """
1623        msg = "Plot updating ... "
1624        wx.PostEvent(self.parent, StatusEvent(status=msg,type="update"))
1625       
1626    def _complete1D(self, x, y, page_id, elapsed, index, model,
1627                    weight=None, fid=None,
1628                    toggle_mode_on=False, state=None, 
1629                    data=None, update_chisqr=True, source='model'):
1630        """
1631        Complete plotting 1D data
1632        """ 
1633        try:
1634            numpy.nan_to_num(y)
1635           
1636            new_plot = Data1D(x=x, y=y)
1637            new_plot.is_data = False
1638            new_plot.dy = numpy.zeros(len(y))
1639            new_plot.symbol = GUIFRAME_ID.CURVE_SYMBOL_NUM
1640            _yaxis, _yunit = data.get_yaxis() 
1641            _xaxis, _xunit = data.get_xaxis() 
1642            new_plot.title = data.name
1643
1644            new_plot.group_id = data.group_id#self.page_finder[page_id].get_graph_id()
1645            if new_plot.group_id == None:
1646                new_plot.group_id = data.group_id
1647            new_plot.id =  str(page_id) + "model"
1648            #if new_plot.id in self.color_dict:
1649            #    new_plot.custom_color = self.color_dict[new_plot.id]
1650            #find if this theory was already plotted and replace that plot given
1651            #the same id
1652            theory_data = self.page_finder[page_id].get_theory_data(fid=data.id)
1653           
1654            if data.is_data:
1655                data_name = str(data.name)
1656            else:
1657                data_name = str(model.__class__.__name__)
1658           
1659            new_plot.name = model.name + " ["+ data_name +"]"
1660            new_plot.xaxis(_xaxis, _xunit)
1661            new_plot.yaxis(_yaxis, _yunit)
1662            self.page_finder[page_id].set_theory_data(data=new_plot, 
1663                                                      fid=data.id)
1664            self.parent.update_theory(data_id=data.id, theory=new_plot,
1665                                       state=state)   
1666            current_pg = self.fit_panel.get_page_by_id(page_id)
1667            title = new_plot.title
1668            batch_on = self.fit_panel.get_page_by_id(page_id).batch_on
1669            if not batch_on:
1670                wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot,
1671                                            title=str(title)))
1672            else:
1673                top_data_id = self.fit_panel.get_page_by_id(page_id).data.id
1674                if data.id == top_data_id:
1675                    wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot,
1676                                            title=str(title)))   
1677            caption = current_pg.window_caption
1678            self.page_finder[page_id].set_fit_tab_caption(caption=caption)
1679           
1680            self.page_finder[page_id].set_theory_data(data=new_plot, 
1681                                                      fid=data.id)
1682            if toggle_mode_on:
1683                wx.PostEvent(self.parent, 
1684                             NewPlotEvent(group_id=str(page_id) + " Model2D",
1685                                               action="Hide"))
1686            else:
1687                if update_chisqr:
1688                    wx.PostEvent(current_pg,
1689                                 Chi2UpdateEvent(output=self._cal_chisqr(
1690                                                                data=data,
1691                                                                fid=fid,
1692                                                                weight=weight,
1693                                                            page_id=page_id,
1694                                                            index=index)))
1695                else:
1696                    self._plot_residuals(page_id=page_id, data=data, fid=fid,
1697                                          index=index, weight=weight)
1698
1699            msg = "Computation  completed!"
1700            wx.PostEvent( self.parent, StatusEvent(status=msg, type="stop" ))
1701        except:
1702            raise
1703            #msg = " Error occurred when drawing %s Model 1D: " % new_plot.name
1704            #msg += " %s"  % sys.exc_value
1705            #wx.PostEvent(self.parent, StatusEvent(status=msg, type="stop"))
1706   
1707    def _update2D(self, output,time=None):
1708        """
1709        Update the output of plotting model
1710        """
1711        wx.PostEvent(self.parent, StatusEvent(status="Plot \
1712        #updating ... ", type="update"))
1713        #self.ready_fit()
1714 
1715    def _complete2D(self, image, data, model, page_id,  elapsed, index, qmin,
1716                qmax, fid=None, weight=None, toggle_mode_on=False, state=None, 
1717                     update_chisqr=True, source='model'):
1718        """
1719        Complete get the result of modelthread and create model 2D
1720        that can be plot.
1721        """
1722        numpy.nan_to_num(image)
1723        new_plot= Data2D(image=image, err_image=data.err_data)
1724        new_plot.name = model.name
1725        new_plot.title = "Analytical model 2D "
1726        new_plot.id = str(page_id) + "model"
1727        new_plot.group_id = str(page_id) + " Model2D"
1728        new_plot.detector = data.detector
1729        new_plot.source = data.source
1730        new_plot.is_data = False 
1731        new_plot.qx_data = data.qx_data
1732        new_plot.qy_data = data.qy_data
1733        new_plot.q_data = data.q_data
1734        new_plot.mask = data.mask
1735        ## plot boundaries
1736        new_plot.ymin = data.ymin
1737        new_plot.ymax = data.ymax
1738        new_plot.xmin = data.xmin
1739        new_plot.xmax = data.xmax
1740        title = data.title
1741       
1742        new_plot.is_data = False
1743        if data.is_data:
1744            data_name = str(data.name)
1745        else:
1746            data_name = str(model.__class__.__name__)
1747
1748        if len(title) > 1:
1749            new_plot.title = "Model2D for " + data_name
1750        new_plot.name = model.name + " [" + \
1751                                    data_name + "-2D]"
1752        theory_data = deepcopy(new_plot)
1753        theory_data.name = "Unknown"
1754       
1755        self.page_finder[page_id].set_theory_data(data=theory_data, fid=data.id)
1756        self.parent.update_theory(data_id=data.id, 
1757                                       theory=new_plot,
1758                                       state=state) 
1759        current_pg = self.fit_panel.get_page_by_id(page_id)
1760        title = new_plot.title
1761        batch_on = self.fit_panel.get_page_by_id(page_id).batch_on
1762        if not source == 'fit':
1763            wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot,
1764                                               title=title))
1765        self.page_finder[page_id].set_theory_data(data=new_plot, fid=data.id)
1766        if toggle_mode_on:
1767            wx.PostEvent(self.parent, 
1768                             NewPlotEvent(group_id=str(page_id) + " Model1D",
1769                                               action="Hide"))
1770        else:
1771            # Chisqr in fitpage
1772            if update_chisqr:
1773                wx.PostEvent(current_pg,
1774                             Chi2UpdateEvent(output=self._cal_chisqr(data=data,
1775                                                                    weight=weight,
1776                                                                    fid=fid,
1777                                                         page_id=page_id,
1778                                                         index=index)))
1779            else:
1780                self._plot_residuals(page_id=page_id, data=data, fid=fid,
1781                                      index=index, weight=weight)
1782        msg = "Computation  completed!"
1783        wx.PostEvent(self.parent, StatusEvent(status=msg, type="stop"))
1784   
1785    def _draw_model2D(self, model, page_id, qmin,
1786                      qmax,
1787                      data=None, smearer=None,
1788                      description=None, enable2D=False,
1789                      state=None,
1790                      fid=None,
1791                      weight=None,
1792                      toggle_mode_on=False,
1793                       update_chisqr=True, source='model'):
1794        """
1795        draw model in 2D
1796       
1797        :param model: instance of the model to draw
1798        :param description: the description of the model
1799        :param enable2D: when True allows to draw model 2D
1800        :param qmin: the minimum value to  draw model 2D
1801        :param qmax: the maximum value to draw model 2D
1802        :param qstep: the number of division of Qx and Qy of the model to draw
1803           
1804        """
1805        if not enable2D:
1806            return None
1807        try:
1808            from model_thread import Calc2D
1809            ## If a thread is already started, stop it
1810            if (self.calc_2D is not None) and self.calc_2D.isrunning():
1811                self.calc_2D.stop()
1812            self.calc_2D = Calc2D(model=model, 
1813                                    data=data,
1814                                    page_id=page_id,
1815                                    smearer=smearer,
1816                                    qmin=qmin,
1817                                    qmax=qmax,
1818                                    weight=weight, 
1819                                    fid=fid,
1820                                    toggle_mode_on=toggle_mode_on,
1821                                    state=state,
1822                                    completefn=self._complete2D,
1823                                    update_chisqr=update_chisqr, source=source)
1824            self.calc_2D.queue()
1825
1826        except:
1827            raise
1828            #msg = " Error occurred when drawing %s Model 2D: " % model.name
1829            #msg += " %s" % sys.exc_value
1830            #wx.PostEvent(self.parent, StatusEvent(status=msg))
1831
1832    def _draw_model1D(self, model, page_id, data, 
1833                      qmin, qmax, smearer=None,
1834                state=None,
1835                weight=None,
1836                fid=None, 
1837                toggle_mode_on=False, update_chisqr=True, source='model',
1838                enable1D=True):
1839        """
1840        Draw model 1D from loaded data1D
1841       
1842        :param data: loaded data
1843        :param model: the model to plot
1844       
1845        """
1846        if not enable1D:
1847            return 
1848        try:
1849            from model_thread import Calc1D
1850            ## If a thread is already started, stop it
1851            if (self.calc_1D is not None) and self.calc_1D.isrunning():
1852                self.calc_1D.stop()
1853            self.calc_1D = Calc1D(data=data,
1854                                  model=model,
1855                                  page_id=page_id, 
1856                                  qmin=qmin,
1857                                  qmax=qmax,
1858                                  smearer=smearer,
1859                                  state=state,
1860                                  weight=weight,
1861                                  fid=fid,
1862                                  toggle_mode_on=toggle_mode_on,
1863                                  completefn=self._complete1D,
1864                                  #updatefn = self._update1D,
1865                                  update_chisqr=update_chisqr,
1866                                  source=source)
1867            self.calc_1D.queue()
1868        except:
1869            msg = " Error occurred when drawing %s Model 1D: " % model.name
1870            msg += " %s" % sys.exc_value
1871            wx.PostEvent(self.parent, StatusEvent(status=msg))
1872   
1873 
1874   
1875    def _cal_chisqr(self, page_id, data, weight, fid=None, index=None): 
1876        """
1877        Get handy Chisqr using the output from draw1D and 2D,
1878        instead of calling expansive CalcChisqr in guithread
1879        """
1880        data_copy = deepcopy(data) 
1881        # default chisqr
1882        chisqr = None
1883        #to compute chisq make sure data has valid data
1884        # return None if data == None
1885        if not check_data_validity(data_copy) or data_copy == None:
1886            return chisqr
1887
1888        # Get data: data I, theory I, and data dI in order
1889        if data_copy.__class__.__name__ == "Data2D":
1890            if index == None: 
1891                index = numpy.ones(len(data_copy.data),ntype=bool)
1892            if weight != None:
1893                data_copy.err_data = weight
1894            # get rid of zero error points
1895            index = index & (data_copy.err_data != 0) 
1896            index = index & (numpy.isfinite(data_copy.data)) 
1897            fn = data_copy.data[index] 
1898            theory_data = self.page_finder[page_id].get_theory_data(fid=data_copy.id)
1899            if theory_data== None:
1900                return chisqr
1901            gn = theory_data.data[index]
1902            en = data_copy.err_data[index]
1903        else:
1904            # 1 d theory from model_thread is only in the range of index
1905            if index == None: 
1906                index = numpy.ones(len(data_copy.y), ntype=bool)
1907            if weight != None:
1908                data_copy.dy = weight
1909            if data_copy.dy == None or data_copy.dy == []:
1910                dy = numpy.ones(len(data_copy.y))
1911            else:
1912                ## Set consitently w/AbstractFitengine:
1913                # But this should be corrected later.
1914                dy = deepcopy(data_copy.dy)
1915                dy[dy==0] = 1
1916            fn = data_copy.y[index] 
1917           
1918            theory_data = self.page_finder[page_id].get_theory_data(fid=data_copy.id)
1919            if theory_data== None:
1920                return chisqr
1921            gn = theory_data.y
1922            en = dy[index]
1923           
1924        # residual
1925        res = (fn - gn) / en
1926        residuals = res[numpy.isfinite(res)]
1927        # get chisqr only w/finite
1928        chisqr = numpy.average(residuals * residuals)
1929       
1930        self._plot_residuals(page_id=page_id, data=data_copy, 
1931                             fid=fid,
1932                             weight=weight, index=index)
1933       
1934        return chisqr
1935   
1936    def _plot_residuals(self, page_id, weight, fid=None,
1937                        data=None, index=None): 
1938        """
1939        Plot the residuals
1940       
1941        :param data: data
1942        :param index: index array (bool)
1943        : Note: this is different from the residuals in cal_chisqr()
1944        """
1945        data_copy = deepcopy(data)
1946        # Get data: data I, theory I, and data dI in order
1947        if data_copy.__class__.__name__ == "Data2D":
1948            # build residuals
1949            residuals = Data2D()
1950            #residuals.copy_from_datainfo(data)
1951            # Not for trunk the line below, instead use the line above
1952            data_copy.clone_without_data(len(data_copy.data), residuals)
1953            residuals.data = None
1954            fn = data_copy.data#[index]
1955            theory_data = self.page_finder[page_id].get_theory_data(fid=data_copy.id)
1956            gn = theory_data.data#[index]
1957            if weight == None:
1958                en = data_copy.err_data
1959            else:
1960                en = weight
1961            residuals.data = (fn - gn) / en
1962            residuals.qx_data = data_copy.qx_data#[index]
1963            residuals.qy_data = data_copy.qy_data #[index]
1964            residuals.q_data = data_copy.q_data#[index]
1965            residuals.err_data = numpy.ones(len(residuals.data))#[index]
1966            residuals.xmin = min(residuals.qx_data)
1967            residuals.xmax = max(residuals.qx_data)
1968            residuals.ymin = min(residuals.qy_data)
1969            residuals.ymax = max(residuals.qy_data)
1970            residuals.q_data = data_copy.q_data#[index]
1971            residuals.mask = data_copy.mask
1972            residuals.scale = 'linear'
1973            # check the lengths
1974            if len(residuals.data) != len(residuals.q_data):
1975                return
1976        else:
1977            # 1 d theory from model_thread is only in the range of index
1978            if data_copy.dy == None or data_copy.dy == []:
1979                dy = numpy.ones(len(data_copy.y))
1980            else:
1981                if weight == None:
1982                    dy = numpy.ones(len(data_copy.y))
1983                ## Set consitently w/AbstractFitengine:
1984                ## But this should be corrected later.
1985                else:
1986                    dy = weight#deepcopy(data_copy.dy)
1987                dy[dy==0] = 1 
1988            fn = data_copy.y[index] 
1989            theory_data = self.page_finder[page_id].get_theory_data(fid=data_copy.id)
1990            gn = theory_data.y
1991            en = dy[index]
1992            # build residuals
1993            residuals = Data1D()
1994            residuals.y = (fn - gn) / en
1995            residuals.x = data_copy.x[index]
1996            residuals.dy = numpy.ones(len(residuals.y))
1997            residuals.dx = None
1998            residuals.dxl = None
1999            residuals.dxw = None
2000            residuals.ytransform = 'y'
2001            # For latter scale changes
2002            residuals.xaxis('\\rm{Q} ', 'A^{-1}')
2003            residuals.yaxis('\\rm{Residuals} ', 'normalized')
2004        new_plot = residuals
2005        new_plot.name = "Residuals for " + str(theory_data.name.split()[0]) +"[" +  str(data.name) +"]"
2006        ## allow to highlight data when plotted
2007        new_plot.interactive = True
2008        ## when 2 data have the same id override the 1 st plotted
2009        new_plot.id = "res" + str(data_copy.id)#name + " residuals"
2010        ##group_id specify on which panel to plot this data
2011        group_id = self.page_finder[page_id].get_graph_id()
2012        if group_id == None:
2013            group_id = data.group_id
2014        new_plot.group_id ="res" + str(group_id)
2015        #new_plot.is_data = True
2016        ##post data to plot
2017        title = new_plot.name
2018        self.page_finder[page_id].set_residuals(residuals=new_plot, fid=data.id)
2019        self.parent.update_theory(data_id=data.id, theory=new_plot)
2020        batch_on = self.fit_panel.get_page_by_id(page_id).batch_on
2021        if not batch_on:
2022            wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot, title=title))
2023     
2024       
2025#def profile(fn, *args, **kw):
2026#    import cProfile, pstats, os
2027#    global call_result
2028#    def call():
2029#        global call_result
2030#        call_result = fn(*args, **kw)
2031#    cProfile.runctx('call()', dict(call=call), {}, 'profile.out')
2032#    stats = pstats.Stats('profile.out')
2033#    #stats.sort_stats('time')
2034#    stats.sort_stats('calls')
2035#    stats.print_stats()
2036#    os.unlink('profile.out')
2037#    return call_result
2038if __name__ == "__main__":
2039    i = Plugin()
2040   
2041   
2042   
2043   
Note: See TracBrowser for help on using the repository browser.