source: sasview/src/sas/qtgui/Perspectives/PrInversion/PrInversionPerspective.py @ bde1a6b

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 bde1a6b was bde1a6b, checked in by krzywon, 6 years ago

Data loading into p(r) properly and estimates running.

  • Property mode set to 100644
File size: 11.7 KB
Line 
1import numpy as np
2
3from PyQt4 import QtGui, QtCore, QtWebKit
4
5# sas-global
6import sas.qtgui.Utilities.GuiUtils as GuiUtils
7
8# pr inversion gui elements
9from PrInversionUtils import WIDGETS
10import UI.TabbedPrInversionUI
11from UI.TabbedPrInversionUI import Ui_PrInversion
12
13# pr inversion calculation elements
14from sas.sascalc.pr.invertor import Invertor
15from sas.sasgui.perspectives.pr import pr_thread as pr_thread
16
17
18class PrInversionWindow(QtGui.QTabWidget, Ui_PrInversion):
19    """
20    The main window for the P(r) Inversion perspective.
21    """
22
23    name = "PrInversion"
24
25    def __init__(self, parent=None, data=None):
26        super(PrInversionWindow, self).__init__()
27        self.setupUi(self)
28
29        self.setWindowTitle("P(r) Inversion Perspective")
30
31        self._manager = parent
32        self._model_item = QtGui.QStandardItem()
33        self._helpView = QtWebKit.QWebView()
34
35        self.communicate = GuiUtils.Communicate()
36
37        # The window should not close
38        self._allow_close = False
39
40        # is there data
41        self._has_data = False
42
43        # Current data object in view
44        self._data_index = 0
45        # list mapping data to p(r) calculation
46        self._data_list = []
47        if not isinstance(data, list):
48            data = [data]
49        for datum in data:
50            self._data_list.append({datum : None})
51
52        # p(r) calculator
53        self._calculator = Invertor()
54
55        self.model = QtGui.QStandardItemModel(self)
56        self.mapper = QtGui.QDataWidgetMapper(self)
57        # Link user interactions with methods
58        self.setupLinks()
59        # Set values
60        self.setupModel()
61        # Set up the Widget Map
62        self.setupMapper()
63
64    ######################################################################
65    # Base Perspective Class Definitions
66
67    def allowBatch(self):
68        return False
69
70    def setClosable(self, value=True):
71        """
72        Allow outsiders close this widget
73        """
74        assert isinstance(value, bool)
75        self._allow_close = value
76
77    def closeEvent(self, event):
78        """
79        Overwrite QDialog close method to allow for custom widget close
80        """
81        if self._allow_close:
82            # reset the closability flag
83            self.setClosable(value=False)
84            event.accept()
85        else:
86            event.ignore()
87            # Maybe we should just minimize
88            self.setWindowState(QtCore.Qt.WindowMinimized)
89
90    ######################################################################
91    # Initialization routines
92
93    def setupLinks(self):
94        """Connect the use controls to their appropriate methods"""
95        self.enableButtons()
96        self.checkBgdClicked(False)
97        # TODO: enable the drop down box once batch is working
98        self.dataList.setEnabled(False)
99        # TODO: enable displayChange once batch is working
100        # self.dataList.currentIndexChanged.connect(self.displayChange)
101        self.calculateButton.clicked.connect(self._calculation)
102        self.statusButton.clicked.connect(self.status)
103        self.helpButton.clicked.connect(self.help)
104        self.estimateBgd.toggled.connect(self.toggleBgd)
105        self.manualBgd.toggled.connect(self.toggleBgd)
106        self.explorerButton.clicked.connect(self.openExplorerWindow)
107        self.model.itemChanged.connect(self.model_changed)
108
109    def setupMapper(self):
110        # Set up the mapper.
111        self.mapper.setOrientation(QtCore.Qt.Vertical)
112        self.mapper.setModel(self.model)
113
114        # Filename
115        self.mapper.addMapping(self.dataList, WIDGETS.W_FILENAME)
116        # Background
117        self.mapper.addMapping(self.backgroundInput, WIDGETS.W_BACKGROUND_INPUT)
118        self.mapper.addMapping(self.estimateBgd, WIDGETS.W_ESTIMATE)
119        self.mapper.addMapping(self.manualBgd, WIDGETS.W_MANUAL_INPUT)
120
121        # Qmin/Qmax
122        self.mapper.addMapping(self.minQInput, WIDGETS.W_QMIN)
123        self.mapper.addMapping(self.maxQInput, WIDGETS.W_QMAX)
124
125        # Slit Parameter items
126        self.mapper.addMapping(self.slitWidthInput, WIDGETS.W_SLIT_WIDTH)
127        self.mapper.addMapping(self.slitHeightInput, WIDGETS.W_SLIT_HEIGHT)
128
129        # Parameter Items
130        self.mapper.addMapping(self.regularizationConstantInput,
131                               WIDGETS.W_REGULARIZATION)
132        self.mapper.addMapping(self.regConstantSuggestionButton,
133                               WIDGETS.W_REGULARIZATION_SUGGEST)
134        self.mapper.addMapping(self.explorerButton, WIDGETS.W_EXPLORE)
135        self.mapper.addMapping(self.maxDistanceInput, WIDGETS.W_MAX_DIST)
136        self.mapper.addMapping(self.noOfTermsInput, WIDGETS.W_NO_TERMS)
137        self.mapper.addMapping(self.noOfTermsSuggestionButton,
138                               WIDGETS.W_NO_TERMS_SUGGEST)
139
140        # Output
141        self.mapper.addMapping(self.rgValue, WIDGETS.W_RG)
142        self.mapper.addMapping(self.iQ0Value, WIDGETS.W_I_ZERO)
143        self.mapper.addMapping(self.backgroundValue, WIDGETS.W_BACKGROUND_OUTPUT)
144        self.mapper.addMapping(self.computationTimeValue, WIDGETS.W_COMP_TIME)
145        self.mapper.addMapping(self.chiDofValue, WIDGETS.W_CHI_SQUARED)
146        self.mapper.addMapping(self.oscillationValue, WIDGETS.W_OSCILLATION)
147        self.mapper.addMapping(self.posFractionValue, WIDGETS.W_POS_FRACTION)
148        self.mapper.addMapping(self.sigmaPosFractionValue,
149                               WIDGETS.W_SIGMA_POS_FRACTION)
150
151        # Main Buttons
152        self.mapper.addMapping(self.calculateButton, WIDGETS.W_CALCULATE)
153        self.mapper.addMapping(self.statusButton, WIDGETS.W_STATUS)
154        self.mapper.addMapping(self.helpButton, WIDGETS.W_HELP)
155
156        self.mapper.toFirst()
157
158    def setupModel(self):
159        """
160        Update boxes with initial values
161        """
162        item = QtGui.QStandardItem("")
163        self.model.setItem(WIDGETS.W_FILENAME, item)
164        item = QtGui.QStandardItem('0.0')
165        self.model.setItem(WIDGETS.W_BACKGROUND_INPUT, item)
166        item = QtGui.QStandardItem("")
167        self.model.setItem(WIDGETS.W_QMIN, item)
168        item = QtGui.QStandardItem("")
169        self.model.setItem(WIDGETS.W_QMAX, item)
170        item = QtGui.QStandardItem("")
171        self.model.setItem(WIDGETS.W_SLIT_WIDTH, item)
172        item = QtGui.QStandardItem("")
173        self.model.setItem(WIDGETS.W_SLIT_HEIGHT, item)
174        item = QtGui.QStandardItem("10")
175        self.model.setItem(WIDGETS.W_NO_TERMS, item)
176        item = QtGui.QStandardItem("0.0001")
177        self.model.setItem(WIDGETS.W_REGULARIZATION, item)
178        item = QtGui.QStandardItem("140.0")
179        self.model.setItem(WIDGETS.W_MAX_DIST, item)
180        item = QtGui.QStandardItem("")
181        self.model.setItem(WIDGETS.W_RG, item)
182        item = QtGui.QStandardItem("")
183        self.model.setItem(WIDGETS.W_I_ZERO, item)
184        item = QtGui.QStandardItem("")
185        self.model.setItem(WIDGETS.W_BACKGROUND_OUTPUT, item)
186        item = QtGui.QStandardItem("")
187        self.model.setItem(WIDGETS.W_COMP_TIME, item)
188        item = QtGui.QStandardItem("")
189        self.model.setItem(WIDGETS.W_CHI_SQUARED, item)
190        item = QtGui.QStandardItem("")
191        self.model.setItem(WIDGETS.W_OSCILLATION, item)
192        item = QtGui.QStandardItem("")
193        self.model.setItem(WIDGETS.W_POS_FRACTION, item)
194        item = QtGui.QStandardItem("")
195        self.model.setItem(WIDGETS.W_SIGMA_POS_FRACTION, item)
196
197    ######################################################################
198    # Methods for updating GUI
199
200    def enableButtons(self):
201        """
202        Enable buttons when data is present, else disable them
203        """
204        if self._has_data:
205            self.statusButton.setEnabled(True)
206            self.explorerButton.setEnabled(True)
207            self.calculateButton.setEnabled(True)
208        else:
209            self.calculateButton.setEnabled(False)
210            self.explorerButton.setEnabled(False)
211            self.statusButton.setEnabled(False)
212
213    def populateDataComboBox(self, filename):
214        """
215        Append a new file name to the data combobox
216        :param data: Data1D object
217        """
218        qt_item = QtCore.QString.fromUtf8(filename)
219        self.dataList.addItem(qt_item)
220
221    ######################################################################
222    # GUI Actions
223
224    def _calculation(self):
225        """
226        Calculate the P(r) for every data set in the data list
227        """
228        # TODO: Run the calculations
229        pass
230
231    def model_changed(self):
232        """Update the values when user makes changes"""
233        if not self.mapper:
234            return
235        self.mapper.toFirst()
236        # TODO: Update plots, etc.
237
238    def status(self):
239        """
240        Show the status of the calculations
241        """
242        # TODO: Status - is this even needed/wanted?
243        pass
244
245    def help(self):
246        """
247        Open the P(r) Inversion help browser
248        """
249        tree_location = (GuiUtils.HELP_DIRECTORY_LOCATION +
250                         "user/sasgui/perspectives/pr/pr_help.html")
251
252        # Actual file anchor will depend on the combo box index
253        # Note that we can be clusmy here, since bad current_fitter_id
254        # will just make the page displayed from the top
255        self._helpView.load(QtCore.QUrl(tree_location))
256        self._helpView.show()
257
258    def checkBgdClicked(self, boolean=None):
259        if boolean or self.manualBgd.isChecked():
260            self.manualBgd.setChecked(True)
261            self.toggleBgd(self.manualBgd)
262        else:
263            self.estimateBgd.setChecked(True)
264            self.toggleBgd(self.estimateBgd)
265
266    def toggleBgd(self, item=None):
267        """
268        Toggle the background between manual and estimated
269        :param item: gui item that was triggered
270        """
271        if not item:
272            self.checkBgdClicked()
273        elif isinstance(item, QtGui.QRadioButton):
274            if item is self.estimateBgd:
275                self.backgroundInput.setEnabled(False)
276            else:
277                self.backgroundInput.setEnabled(True)
278
279    def openExplorerWindow(self):
280        """
281        Open the Explorer window to see correlations between params and results
282        """
283        # TODO: This depends on SVCC-45
284        pass
285
286    ######################################################################
287    # Response Actions
288
289    def setData(self, data_item=None, is_batch=False):
290        """
291        Assign new data set or sets to the P(r) perspective
292        Obtain a QStandardItem object and dissect it to get Data1D/2D
293        Pass it over to the calculator
294        """
295        assert data_item is not None
296
297        if not isinstance(data_item, list):
298            msg = "Incorrect type passed to the P(r) Perspective"
299            raise AttributeError, msg
300
301        if not isinstance(data_item[0], QtGui.QStandardItem):
302            msg = "Incorrect type passed to the P(r) Perspective"
303            raise AttributeError, msg
304
305        for data in data_item:
306            data_object = GuiUtils.dataFromItem(data)
307            self._data_list.append({data_object: None})
308            self._has_data = True
309            self.enableButtons()
310            self.populateDataComboBox(data_object.filename)
311            self.model.setItem(WIDGETS.W_QMIN,
312                               QtGui.QStandardItem(str(data_object.x.min())))
313            self.model.setItem(WIDGETS.W_QMAX,
314                               QtGui.QStandardItem(str(data_object.x.max())))
315
316            # TODO: Get value estimates
317            no_terms, alpha, _ = self._calculator.estimate_numterms(
318                self._calculator)
319            self.noOfTermsSuggestionButton.setText(
320                QtCore.QString(str(no_terms)))
321            self.noOfTermsSuggestionButton.setEnabled(True)
322            self.regConstantSuggestionButton.setText(QtCore.QString(str(alpha)))
323            self.regConstantSuggestionButton.setEnabled(True)
324
325            # TODO: Only load in the 1st data until batch mode is working
326            break
Note: See TracBrowser for help on using the repository browser.