source: sasview/src/sas/qtgui/Perspectives/Fitting/FittingPerspective.py @ ee18d33

ESS_GUIESS_GUI_DocsESS_GUI_batch_fittingESS_GUI_bumps_abstractionESS_GUI_iss1116ESS_GUI_iss879ESS_GUI_iss959ESS_GUI_openclESS_GUI_orderingESS_GUI_sync_sascalc
Last change on this file since ee18d33 was ee18d33, checked in by Piotr Rozyczko <rozyczko@…>, 7 years ago

Initial setup for batch fitting. SASVIEW-615

  • Property mode set to 100644
File size: 5.5 KB
Line 
1import numpy
2
3from PyQt4 import QtCore
4from PyQt4 import QtGui
5
6from bumps import options
7from bumps import fitters
8
9import sas.qtgui.Utilities.ObjectLibrary as ObjectLibrary
10
11from sas.qtgui.Perspectives.Fitting.FittingWidget import FittingWidget
12from sas.qtgui.Perspectives.Fitting.FittingOptions import FittingOptions
13from sas.qtgui.Perspectives.Fitting import ModelUtilities
14
15class FittingWindow(QtGui.QTabWidget):
16    """
17    """
18    name = "Fitting" # For displaying in the combo box in DataExplorer
19    def __init__(self, parent=None, data=None):
20        super(FittingWindow, self).__init__()
21
22        self.parent = parent
23        self._data = data
24
25        # List of active fits
26        self.tabs = []
27
28        # Max index for adding new, non-clashing tab names
29        self.maxIndex = 0
30
31        # Index of the current tab
32        self.currentTab = 0
33
34        # The current optimizer
35        self.optimizer = 'Levenberg-Marquardt'
36
37        # The tabs need to be closeable
38        self.setTabsClosable(True)
39
40        self.communicate = self.parent.communicator()
41
42        # Initialize the first tab
43        self.addFit(None)
44
45        # Deal with signals
46        self.tabCloseRequested.connect(self.tabCloses)
47
48        # Perspective window not allowed to close by default
49        self._allow_close = False
50
51        # Fit options - uniform for all tabs
52        self.fit_options = options.FIT_CONFIG
53        self.fit_options_widget = FittingOptions(self, config=self.fit_options)
54        self.fit_options.selected_id = fitters.LevenbergMarquardtFit.id
55
56        # Listen to GUI Manager signal updating fit options
57        self.fit_options_widget.fit_option_changed.connect(self.onFittingOptionsChange)
58
59        self.menu_manager = ModelUtilities.ModelManager()
60        # TODO: reuse these in FittingWidget properly
61        self.model_list_box = self.menu_manager.get_model_list()
62        self.model_dictionary = self.menu_manager.get_model_dictionary()
63
64        #self.setWindowTitle('Fit panel - Active Fitting Optimizer: %s' % self.optimizer)
65        self.updateWindowTitle()
66
67    def updateWindowTitle(self):
68        """
69        Update the window title with the current optimizer name
70        """
71        self.optimizer = self.fit_options.selected_name
72        self.setWindowTitle('Fit panel - Active Fitting Optimizer: %s' % self.optimizer)
73
74
75    def setClosable(self, value=True):
76        """
77        Allow outsiders close this widget
78        """
79        assert isinstance(value, bool)
80
81        self._allow_close = value
82
83    def closeEvent(self, event):
84        """
85        Overwrite QDialog close method to allow for custom widget close
86        """
87        # Invoke fit page events
88        for tab in self.tabs:
89            tab.close()
90        if self._allow_close:
91            # reset the closability flag
92            self.setClosable(value=False)
93            event.accept()
94        else:
95            # Maybe we should just minimize
96            self.setWindowState(QtCore.Qt.WindowMinimized)
97            event.ignore()
98
99    def addFit(self, data, is_batch=False):
100        """
101        Add a new tab for passed data
102        """
103        tab     = FittingWidget(parent=self.parent, data=data, tab_id=self.maxIndex+1)
104        tab.is_batch_fitting = is_batch
105        # Add this tab to the object library so it can be retrieved by scripting/jupyter
106        ObjectLibrary.addObject(self.tabName(), tab)
107        self.tabs.append(tab)
108        self.maxIndex += 1
109        self.addTab(tab, self.tabName())
110
111    def tabName(self):
112        """
113        Get the new tab name, based on the number of fitting tabs so far
114        """
115        page_name = "FitPage" + str(self.maxIndex)
116        return page_name
117
118    def tabCloses(self, index):
119        """
120        Update local bookkeeping on tab close
121        """
122        assert len(self.tabs) >= index
123        # don't remove the last tab
124        if len(self.tabs) <= 1:
125            return
126        ObjectLibrary.deleteObjectByRef(self.tabs[index])
127        del self.tabs[index]
128        self.removeTab(index)
129
130    def allowBatch(self):
131        """
132        Tell the caller that we accept multiple data instances
133        """
134        return True
135
136    def setData(self, data_item=None, is_batch=False):
137        """
138        Assign new dataset to the fitting instance
139        Obtain a QStandardItem object and dissect it to get Data1D/2D
140        Pass it over to the calculator
141        """
142        assert data_item is not None
143
144        if not isinstance(data_item, list):
145            msg = "Incorrect type passed to the Fitting Perspective"
146            raise AttributeError, msg
147
148        if not isinstance(data_item[0], QtGui.QStandardItem):
149            msg = "Incorrect type passed to the Fitting Perspective"
150            raise AttributeError, msg
151
152        items = [data_item] if is_batch else data_item
153
154        for data in items:
155            # Find the first unassigned tab.
156            # If none, open a new tab.
157            available_tabs = list(map(lambda tab: tab.acceptsData(), self.tabs))
158
159            if numpy.any(available_tabs):
160                self.tabs[available_tabs.index(True)].data = data
161            else:
162                self.addFit(data, is_batch=is_batch)
163
164    def onFittingOptionsChange(self, fit_engine):
165        """
166        React to the fitting algorithm change by modifying window title
167        """
168        fitter = [f.id for f in options.FITTERS if f.name == str(fit_engine)][0]
169        # set the optimizer
170        self.fit_options.selected_id = str(fitter)
171        # Update the title
172        self.updateWindowTitle()
173
174        pass
Note: See TracBrowser for help on using the repository browser.