source: sasview/sansview/perspectives/fitting/fitpanel.py @ 24adb89

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

working on batch fit

  • Property mode set to 100644
File size: 18.4 KB
RevLine 
[e2f1023]1
2import numpy
3import string 
[d89f09b]4import wx
[f22e626]5import sys
[1b1bbf9]6#from wx.lib.flatnotebook import FlatNotebook as nb
7from wx.aui import AuiNotebook as nb
[a93f525]8
[340c2b3]9from sans.guiframe.panel_base import PanelBase
[3cd5806]10from sans.guiframe.events import PanelOnFocusEvent
[6bbeacd4]11from sans.guiframe.events import StatusEvent
[66ff250]12
[cfc0913]13import basepage
[6bbeacd4]14import models
[330573d]15_BOX_WIDTH = 80
16
17
[1b1bbf9]18class FitPanel(nb, PanelBase):   
[925a30e]19
[d89f09b]20    """
[5062bbf]21    FitPanel class contains fields allowing to fit  models and  data
22   
23    :note: For Fit to be performed the user should check at least one parameter
[d89f09b]24        on fit Panel window.
25       
26    """
27    ## Internal name for the AUI manager
28    window_name = "Fit panel"
29    ## Title to appear on top of the window
30    window_caption = "Fit Panel "
[2139c3f]31    CENTER_PANE = True
[7437880]32   
[6bbeacd4]33    def __init__(self, parent, manager=None, *args, **kwargs):
[5062bbf]34        """
35        """
[1b1bbf9]36        nb.__init__(self, parent, -1,
[3244cbe1]37                    style= wx.aui.AUI_NB_WINDOWLIST_BUTTON|
38                    wx.aui.AUI_NB_DEFAULT_STYLE|
39                    wx.CLIP_CHILDREN)
[3cd5806]40        PanelBase.__init__(self, parent)
[1b1bbf9]41        #self.SetWindowStyleFlag(style=nb.FNB_FANCY_TABS)
[6bbeacd4]42        self._manager = manager
[340c2b3]43        self.parent = parent
44        self.event_owner = None
[d89f09b]45        #dictionary of miodel {model class name, model class}
[6bbeacd4]46        self.menu_mng = models.ModelManager()
[b2d9826]47        self.model_list_box = self.menu_mng.get_model_list()
[1b1bbf9]48        #pageClosedEvent = nb.EVT_FLATNOTEBOOK_PAGE_CLOSING
[f22e626]49        self.pageClosedEvent = wx.aui.EVT_AUINOTEBOOK_PAGE_CLOSE
[1b1bbf9]50       
[f22e626]51        self.Bind(self.pageClosedEvent, self.on_close_page)
[6bbeacd4]52         ## save the title of the last page tab added
[2f189dc]53        self.fit_page_name = {}
[cfc0913]54        ## list of existing fit page
[2f189dc]55        self.opened_pages = {}
[cc31608]56        #index of fit page
57        self.fit_page_index = 0
58        #index of batch page
59        self.batch_page_index = 0
[2f189dc]60        #page of simultaneous fit
[ffa69b6]61        self.sim_page = None
[66ff250]62        self.fit_engine_type = "scipy"
[cfc0913]63        ## get the state of a page
64        self.Bind(basepage.EVT_PAGE_INFO, self._onGetstate)
[330573d]65        self.Bind(basepage.EVT_PREVIOUS_STATE, self._onUndo)
[fe496eeb]66        self.Bind(basepage.EVT_NEXT_STATE, self._onRedo)
[90a7bbd]67        self.Bind(wx.aui.EVT_AUINOTEBOOK_PAGE_CHANGED, self.on_page_changing)
[f22e626]68        self.Bind(wx.aui.EVT_AUINOTEBOOK_PAGE_CLOSED, self.on_closed)
[1b1bbf9]69
[f22e626]70    def on_closed(self, event):
71        """
72        """
[394ffa7]73        if self.GetPageCount() == 0:
74            self.add_empty_page()
75            self.enable_close_button()
[f22e626]76       
[4e78f56]77    def save_project(self, doc=None):
78        """
79        return an xml node containing state of the panel
80         that guiframe can write to file
81        """
82        for uid, page in self.opened_pages.iteritems():
83            data = page.get_data()
84            # state must be cloned
85            state = page.get_state().clone()
86            if data is not None:
87                new_doc = self._manager.state_reader.write_toXML(data, state)
88                if doc != None and hasattr(doc, "firstChild"):
89                    child = new_doc.firstChild.firstChild
90                    doc.firstChild.appendChild(child) 
91                else:
92                    doc = new_doc
93        return doc   
[6bbeacd4]94   
[66ff250]95    def _on_engine_change(self, name='scipy'):
96        """
97        """
98        for panel in self.opened_pages.values():
99            self.set_engine_helper(panel=panel, name=name)
100           
101    def set_engine_helper(self, panel, name='scipy'):
102        """
103        """
104        self.fit_engine_type = name
105        if panel != self.sim_page:
106            panel._on_engine_change(name=self.fit_engine_type)
107               
[b2d9826]108    def update_model_list(self):
109        """
110        """
[9466f2d6]111        temp = self.menu_mng.update()
112        if len(temp):
113            self.model_list_box = temp
114        return temp
[b2d9826]115       
116       
[66ff250]117    def get_page_by_id(self, uid): 
[6bbeacd4]118        """
119        """
[66ff250]120        if uid not in self.opened_pages:
121            msg = "Fitpanel cannot find ID: %s in self.opened_pages" % str(uid)
[6bbeacd4]122            raise ValueError, msg
123        else:
[66ff250]124            return self.opened_pages[uid]
[31b0c47]125       
[90a7bbd]126    def on_page_changing(self, event):
[6bbeacd4]127        """
[f22e626]128        calls the function when the current event handler has exited. avoiding
129        to call panel on focus on a panel that is currently deleted
130        """
131        wx.CallAfter(self.helper_on_page_change)
132       
133       
134    def helper_on_page_change(self):
135        """
[6bbeacd4]136        """
[90a7bbd]137        pos = self.GetSelection()
138        if pos != -1:
139            selected_page = self.GetPage(pos)
140            wx.PostEvent(self.parent, PanelOnFocusEvent(panel=selected_page))
[e4c9030]141        self.enable_close_button()
[f22e626]142       
[3cd5806]143    def on_set_focus(self, event):
144        """
145        """
146        pos = self.GetSelection()
[90a7bbd]147        if pos != -1:
148            selected_page = self.GetPage(pos)
149            wx.PostEvent(self.parent, PanelOnFocusEvent(panel=selected_page))
[3cd5806]150       
[c8deee5]151    def get_data(self):
152        """
153        get the data in the current page
154        """
155        pos = self.GetSelection()
[90a7bbd]156        if pos != -1:
157            selected_page = self.GetPage(pos)
158            return selected_page.get_data()
[c8deee5]159   
[e88ebfd]160    def set_model_state(state):
161        """
162        receive a state to reset the model in the current page
163        """
164        pos = self.GetSelection()
165        if pos != -1:
166            selected_page = self.GetPage(pos)
167            selected_page.set_model_state(state)
168           
[c8deee5]169    def get_state(self):
170        """
171         return the state of the current selected page
172        """
173        pos = self.GetSelection()
[90a7bbd]174        if pos != -1:
175            selected_page = self.GetPage(pos)
176            return selected_page.get_state()
[c8deee5]177   
[f22e626]178 
[6bbeacd4]179 
[ac2dc0e]180    def close_all(self):
181        """
[8897d66]182        remove all pages, used when a svs file is opened
183        """
[90a7bbd]184       
[8897d66]185        #get number of pages
186        nop = self.GetPageCount()
187        #use while-loop, for-loop will not do the job well.
188        while (nop>0):
189            #delete the first page until no page exists
190            page = self.GetPage(0)
[90a7bbd]191            if self._manager.parent.panel_on_focus == page:
192                self._manager.parent.panel_on_focus = None
[8897d66]193            self._close_helper(selected_page=page)
194            self.DeletePage(0)
195            nop = nop - 1
[90a7bbd]196           
[ac2dc0e]197        ## save the title of the last page tab added
198        self.fit_page_name = {}
199        ## list of existing fit page
200        self.opened_pages = {} 
201         
[31b0c47]202    def set_state(self, state):
203        """
[5062bbf]204        Restore state of the panel
[31b0c47]205        """
206        page_is_opened = False
207        if state is not None:
[66ff250]208            for uid, panel in self.opened_pages.iteritems():
[31b0c47]209                #Don't return any panel is the exact same page is created
[4bee68d]210                if uid == panel.uid and panel.data == state.data:
[31b0c47]211                    # the page is still opened
212                    panel.reset_page(state=state)
[645f9b6]213                    panel.save_current_state() 
[31b0c47]214                    page_is_opened = True
215            if not page_is_opened:
[9f391af]216                panel = self._manager.add_fit_page(data=state.data)
[31b0c47]217                # add data associated to the page created
218                if panel is not None: 
[4bee68d]219                    self._manager.store_data(uid=panel.uid, 
220                                             data=state.data,
221                                             caption=panel.window_caption)
[31b0c47]222                    panel.reset_page(state=state)
[645f9b6]223                    panel.save_current_state()
[31b0c47]224                   
[90a7bbd]225    def clear_panel(self):
[9b18735]226        """
227        Clear and close all panels, used by guimanager
228        """
[90a7bbd]229       
230        #close all panels only when svs file opened
231        self.close_all()
232        self._manager.mypanels = []
233       
[9b18735]234                       
[ac2dc0e]235    def on_close_page(self, event=None):
[51d47b5]236        """
[5062bbf]237        close page and remove all references to the closed page
[51d47b5]238        """
[d361b462]239        nbr_page = self.GetPageCount()
[51d47b5]240        selected_page = self.GetPage(self.GetSelection())
[f22e626]241        if nbr_page == 1:
242            if selected_page.get_data() == None:
243                if event is not None:
244                    event.Veto()
245                return 
[2f189dc]246        self._close_helper(selected_page=selected_page)
[9853ad0]247       
[2f189dc]248    def close_page_with_data(self, deleted_data):
249        """
[5062bbf]250        close a fit page when its data is completely remove from the graph
[2f189dc]251        """
[784e2fa]252        if deleted_data is None:
253            return
[2f189dc]254        for index in range(self.GetPageCount()):
255            selected_page = self.GetPage(index) 
256            if hasattr(selected_page,"get_data"):
257                data = selected_page.get_data()
[ac2dc0e]258               
[784e2fa]259                if data is None:
260                    #the fitpanel exists and only the initial fit page is open
261                    #with no selected data
262                    return
[f22e626]263                if data.id == deleted_data.id:
[2f189dc]264                    self._close_helper(selected_page)
265                    self.DeletePage(index)
266                    break
[d89f09b]267       
268    def set_manager(self, manager):
269        """
[5062bbf]270        set panel manager
271       
272        :param manager: instance of plugin fitting
273       
[d89f09b]274        """
[c8deee5]275        self._manager = manager
[3cd5806]276        for pos in range(self.GetPageCount()):
277            page = self.GetPage(pos)
278            if page is not None:
279                page.set_manager(self._manager)
[a93f525]280
[ffa69b6]281    def set_model_list(self, dict):
[c77d859]282         """
[5062bbf]283         copy a dictionary of model into its own dictionary
284         
285         :param dict: dictionnary made of model name as key and model class
[c77d859]286             as value
287         """
288         self.model_list_box = dict
[51d47b5]289       
[c77d859]290    def get_current_page(self):
291        """
[5062bbf]292        :return: the current page selected
293       
[c77d859]294        """
[6bbeacd4]295        return self.GetPage(self.GetSelection())
[c77d859]296   
[51d47b5]297    def add_sim_page(self):
[925a30e]298        """
[5062bbf]299        Add the simultaneous fit page
[925a30e]300        """
[51d47b5]301        from simfitpage import SimultaneousFitPage
[c8deee5]302        page_finder= self._manager.get_page_finder()
[b28717b]303        self.sim_page = SimultaneousFitPage(self,page_finder=page_finder, id=-1)
[66ff250]304        self.sim_page.uid = wx.NewId()
[6bbeacd4]305        self.AddPage(self.sim_page,"Simultaneous Fit", True)
[c8deee5]306        self.sim_page.set_manager(self._manager)
[f22e626]307        self.enable_close_button()
[51d47b5]308        return self.sim_page
[d89f09b]309       
[6bbeacd4]310 
[2f189dc]311    def add_empty_page(self):
[9853ad0]312        """
[5062bbf]313        add an empty page
[9853ad0]314        """
[cc31608]315        if self.batch_on:
316            from batchfitpage import BatchFitPage
317            panel = BatchFitPage(parent=self)
318            #Increment index of batch page
319            self.batch_page_index += 1
320            index = self.batch_page_index
321        else:
322            from fitpage import FitPage
323            panel = FitPage(parent=self)
324            #Increment index of fit page
325            self.fit_page_index += 1
326            index = self.fit_page_index
[66ff250]327        panel.uid = wx.NewId()
[6bbeacd4]328        panel.populate_box(dict=self.model_list_box)
[c8deee5]329        panel.set_manager(self._manager)
[cc31608]330        caption = str(panel.window_caption) + " " + str(index)
[ae4ade7]331        self.AddPage(panel, caption, select=True)
[66ff250]332        self.opened_pages[panel.uid] = panel
333        self.set_engine_helper(panel=panel)
[f22e626]334        self.enable_close_button()
[2f189dc]335        return panel
336   
[f22e626]337    def enable_close_button(self):
338        """
339        display the close button on tab for more than 1 tabs else remove the
340        close button
341        """
342        if self.GetPageCount() <= 1:
343            style = self.GetWindowStyleFlag() 
344            if style & wx.aui.AUI_NB_CLOSE_ON_ACTIVE_TAB == wx.aui.AUI_NB_CLOSE_ON_ACTIVE_TAB:
345                style = style & ~wx.aui.AUI_NB_CLOSE_ON_ACTIVE_TAB
346                self.SetWindowStyle(style)
347        else:
348            style = self.GetWindowStyleFlag()
349            if style & wx.aui.AUI_NB_CLOSE_ON_ACTIVE_TAB != wx.aui.AUI_NB_CLOSE_ON_ACTIVE_TAB:
350                style |= wx.aui.AUI_NB_CLOSE_ON_ACTIVE_TAB
351                self.SetWindowStyle(style)
352           
[8ee56a9]353    def delete_data(self, data):
354        """
355        Delete the given data
356        """
[f22e626]357        if data.__class__.__name__ != "list":
358            raise ValueError, "Fitpanel delete_data expect list of id"
359        else:
360            n = self.GetPageCount()
361            for page in self.opened_pages.values():
362                pos = self.GetPageIndex(page)
363                temp_data = page.get_data()
364                #stop the fitting before deleting the page
365                page.is_fitting()
366                if temp_data is not None and temp_data.id in data:
367                    self.SetSelection(pos)
368                    self.on_close_page(event=None)
369                    temp = self.GetSelection()
370                    self.DeletePage(temp)
371            if self.GetPageCount()== 0:
[e4c9030]372                self._manager.on_add_new_page(event=None)
[f22e626]373       
[cc31608]374    def set_data(self, data_list):
[2f189dc]375        """
[5062bbf]376        Add a fitting page on the notebook contained by fitpanel
377       
378        :param data: data to fit
379       
380        :return panel : page just added for further used. is used by fitting module
381       
[2f189dc]382        """
[cc31608]383        if not data_list:
[2f189dc]384            return None
[cc31608]385       
386        if self.batch_on:
387            page = self.add_empty_page()
388            print  "batch on fitpanel", page.__class__.__name__, page.window_caption
389            pos = self.GetPageIndex(page)
390            page.fill_data_combobox(data_list)
391            self.opened_pages[page.uid] = page
392            return page
393        else:
394            data = None
395            data = data_list[0]
396            if data is None:
397                return None
[6bbeacd4]398        for page in self.opened_pages.values():
399            #check if the selected data existing in the fitpanel
400            pos = self.GetPageIndex(page)
401            if page.get_data() is None:
[cc31608]402                #make sure data get placed in 1D empty tab if data is 1D
403                #else data get place on 2D tab empty tab
[a5701e6]404                enable2D = page.get_view_mode()
405                if (data.__class__.__name__ == "Data2D" and enable2D)\
406                or (data.__class__.__name__ == "Data1D" and not enable2D):
[cc31608]407                    #page.set_data(data)
408                    page.fill_data_combobox(data_list)
[a5701e6]409                    self.SetPageText(pos, str(data.name))
410                    self.SetSelection(pos)
411                    return page
[cc31608]412                # Todo: Need to set different window name when has same data
413                # Todo: to catch page with same data even if it is not on the top.
414                """
415                elif page.get_data().id == data.id:
416                    msg = "Data already existing in the fitting panel"
417                    wx.PostEvent(self._manager.parent,
418                                 StatusEvent(status=msg, info='warning'))
419                    self.SetSelection(pos)
420                    return page
421                """
[6bbeacd4]422        page = self.add_empty_page()
[9f391af]423        pos = self.GetPageIndex(page)
[cc31608]424        page.fill_data_combobox(data_list)
425        #page.set_data(data)
[6bbeacd4]426        self.SetPageText(pos, str(data.name))
[66ff250]427        self.opened_pages[page.uid] = page
[ae4ade7]428       
[6bbeacd4]429        return page
430       
431    def _onGetstate(self, event):
[cfc0913]432        """
[5062bbf]433        copy the state of a page
[cfc0913]434        """
[6bbeacd4]435        page = event.page
[66ff250]436        if page.uid in self.fit_page_name:
437           self.fit_page_name[page.uid].appendItem(page.createMemento()) 
[cfc0913]438           
[4e78f56]439    def _onUndo(self, event):
[330573d]440        """
[5062bbf]441        return the previous state of a given page is available
[330573d]442        """
443        page = event.page
[66ff250]444        if page.uid in self.fit_page_name:
445            if self.fit_page_name[page.uid].getCurrentPosition()==0:
[330573d]446                state = None
447            else:
[66ff250]448                state = self.fit_page_name[page.uid].getPreviousItem()
[fe496eeb]449                page._redo.Enable(True)
[330573d]450            page.reset_page(state)
[fe496eeb]451       
[2f189dc]452    def _onRedo(self, event): 
[fe496eeb]453        """
[5062bbf]454        return the next state available
[fe496eeb]455        """       
456        page = event.page
[66ff250]457        if page.uid in self.fit_page_name:
458            length= len(self.fit_page_name[page.uid])
459            if self.fit_page_name[page.uid].getCurrentPosition()== length -1:
[fe496eeb]460                state = None
461                page._redo.Enable(False)
[3b9e023]462                page._redo.Enable(True)
[fe496eeb]463            else:
[66ff250]464                state =self.fit_page_name[page.uid].getNextItem()
[fe496eeb]465            page.reset_page(state) 
[2f189dc]466                 
467    def _close_helper(self, selected_page):
[3f1af74]468        """
[5062bbf]469        Delete the given page from the notebook
[3f1af74]470        """
[2f189dc]471        #remove hint page
[1b1bbf9]472        #if selected_page == self.hint_page:
473        #    return
[2f189dc]474        ## removing sim_page
475        if selected_page == self.sim_page :
[c8deee5]476            self._manager.sim_page=None 
[2f189dc]477            return
[cc31608]478        if selected_page.__class__.__name__ == "FitPage":
479            self.fit_page_index -= 1
480        else:
481            self.batch_page_index -= 1
[2f189dc]482        ## closing other pages
483        state = selected_page.createMemento()
484        page_name = selected_page.window_name
[c8deee5]485        page_finder = self._manager.get_page_finder() 
[2f189dc]486        fitproblem = None
487        ## removing fit page
[c6036f5]488        data = selected_page.get_data()
489        #Don' t remove plot for 2D
490        flag = True
491        if data.__class__.__name__ == 'Data2D':
492            flag = False
[2f189dc]493        if selected_page in page_finder:
494            #Delete the name of the page into the list of open page
[66ff250]495            for uid, list in self.opened_pages.iteritems():
[2f189dc]496                #Don't return any panel is the exact same page is created
[6bbeacd4]497               
[66ff250]498                if flag and selected_page.uid == uid:
499                    self._manager.remove_plot(uid, theory=False)
[2f189dc]500                    break 
501            del page_finder[selected_page]
502        ##remove the check box link to the model name of this page (selected_page)
503        try:
504            self.sim_page.draw_page()
505        except:
506            ## that page is already deleted no need to remove check box on
507            ##non existing page
508            pass
509               
510        #Delete the name of the page into the list of open page
[66ff250]511        for uid, list in self.opened_pages.iteritems():
[2f189dc]512            #Don't return any panel is the exact same page is created
[66ff250]513            if selected_page.uid == uid:
514                del self.opened_pages[selected_page.uid]
[2f189dc]515                break 
[f22e626]516     
[b787e68c]517 
Note: See TracBrowser for help on using the repository browser.