source: sasview/src/sas/qtgui/Perspectives/Corfunc/CorfuncPerspective.py @ 6930b91

Last change on this file since 6930b91 was 6930b91, checked in by Adam Washington <adam.washington@…>, 7 years ago

Move to combobox to pick transformation model

  • Property mode set to 100644
File size: 10.9 KB
RevLine 
[a3c4217]1"""
2This module provides the intelligence behind the gui interface for Corfunc.
3"""
[be6f7af]4# pylint: disable=E1101
5
[6d96bf9]6# global
7from PyQt4 import QtCore
8from PyQt4 import QtGui
9
10# sas-global
[a3c4217]11# pylint: disable=import-error, no-name-in-module
[6d96bf9]12import sas.qtgui.Utilities.GuiUtils as GuiUtils
[b2c8aef]13from sas.sascalc.corfunc.corfunc_calculator import CorfuncCalculator
[a3c4217]14# pylint: enable=import-error, no-name-in-module
[6d96bf9]15
16# local
17from UI.CorfuncPanel import Ui_CorfuncDialog
18# from InvariantDetails import DetailsDialog
[59183b7]19from CorfuncUtils import WIDGETS as W
[6d96bf9]20
[7be7136]21from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg \
22    as FigureCanvas
[22e6043]23from matplotlib.figure import Figure
24
25
26class MyMplCanvas(FigureCanvas):
27    """Ultimately, this is a QWidget (as well as a FigureCanvasAgg, etc.)."""
[7be7136]28    def __init__(self, model, width=5, height=4, dpi=100):
[cadd595a]29        self.model = model
[22e6043]30        self.fig = Figure(figsize=(width, height), dpi=dpi)
31        self.axes = self.fig.add_subplot(111)
32
33        FigureCanvas.__init__(self, self.fig)
34
[f159d1b]35        self.data = None
36        self.extrap = None
37
[7be7136]38    def draw_q_space(self):
[be6f7af]39        """Draw the Q space data in the plot window
40
41        This draws the q space data in self.data, as well
42        as the bounds set by self.qmin, self.qmax1, and self.qmax2.
43        It will also plot the extrpolation in self.extrap, if it exists."""
44
[f159d1b]45        self.fig.clf()
46
47        self.axes = self.fig.add_subplot(111)
48        self.axes.set_xscale("log")
49        self.axes.set_yscale("log")
50
[cadd595a]51        qmin = float(self.model.item(W.W_QMIN).text())
52        qmax1 = float(self.model.item(W.W_QMAX).text())
53        qmax2 = float(self.model.item(W.W_QCUTOFF).text())
54
[f159d1b]55        if self.data:
56            self.axes.plot(self.data.x, self.data.y)
[cadd595a]57            self.axes.axvline(qmin)
58            self.axes.axvline(qmax1)
59            self.axes.axvline(qmax2)
[a3c4217]60            self.axes.set_xlim(min(self.data.x) / 2,
61                               max(self.data.x) * 1.5 - 0.5 * min(self.data.x))
[f159d1b]62        if self.extrap:
63            self.axes.plot(self.extrap.x, self.extrap.y)
64
65        self.draw()
66
[ff8cb73]67    def draw_real_space(self):
[be6f7af]68        """
69        This function draws the real space data onto the plot
70
71        The 1d correlation function in self.data, the 3d correlation function
72        in self.data3, and the interface distribution function in self.data_idf
73        are all draw in on the plot in linear cooredinates."""
[f7b73d5]74        self.fig.clf()
75
76        self.axes = self.fig.add_subplot(111)
77        self.axes.set_xscale("linear")
78        self.axes.set_yscale("linear")
79
80        if self.data:
[a3c4217]81            data1, data3, data_idf = self.data
82            self.axes.plot(data1.x, data1.y, label="1D Correlation")
83            self.axes.plot(data3.x, data3.y, label="3D Correlation")
84            self.axes.plot(data_idf.x, data_idf.y,
[7be7136]85                           label="Interface Distribution Function")
[a3c4217]86            self.axes.set_xlim(min(data1.x), max(data1.x) / 4)
[ff8cb73]87            self.axes.legend()
[f7b73d5]88
89        self.draw()
[22e6043]90
[f159d1b]91
[6d96bf9]92class CorfuncWindow(QtGui.QDialog, Ui_CorfuncDialog):
[be6f7af]93    """Displays the correlation function analysis of sas data."""
[7be7136]94    name = "Corfunc"  # For displaying in the combo box
95
[a3c4217]96# pylint: disable=unused-argument
[6d96bf9]97    def __init__(self, parent=None):
98        super(CorfuncWindow, self).__init__()
99        self.setupUi(self)
100
101        self.setWindowTitle("Corfunc Perspective")
102
[be6f7af]103        self.mapper = None
[59183b7]104        self.model = QtGui.QStandardItemModel(self)
[6d96bf9]105        self.communicate = GuiUtils.Communicate()
[b2c8aef]106        self._calculator = CorfuncCalculator()
[be6f7af]107        self._allow_close = True
[6d96bf9]108
[7be7136]109        self._canvas = MyMplCanvas(self.model)
110        self._realplot = MyMplCanvas(self.model)
[e4a3302]111        self.verticalLayout_7.insertWidget(0, self._canvas)
[f7b73d5]112        self.verticalLayout_7.insertWidget(1, self._realplot)
[22e6043]113
[59183b7]114        # Connect buttons to slots.
115        # Needs to be done early so default values propagate properly.
[7be7136]116        self.setup_slots()
[59183b7]117
118        # Set up the model.
[7be7136]119        self.setup_model()
[59183b7]120
121        # Set up the mapper
[7be7136]122        self.setup_mapper()
[59183b7]123
[7be7136]124    def setup_slots(self):
[be6f7af]125        """Connect the buttons to their appropriate slots."""
[7b536da]126        self.extrapolateBtn.clicked.connect(self.extrapolate)
[f7b73d5]127        self.transformBtn.clicked.connect(self.transform)
[59183b7]128
[be6f7af]129        self.calculateBgBtn.clicked.connect(self.calculate_background)
[b2c8aef]130
[be6f7af]131        self.model.itemChanged.connect(self.model_changed)
[b2c8aef]132
[7be7136]133    def setup_model(self):
[be6f7af]134        """Populate the model with default data."""
[59183b7]135        self.model.setItem(W.W_QMIN,
[1bb879d]136                           QtGui.QStandardItem("0.01"))
[59183b7]137        self.model.setItem(W.W_QMAX,
[1bb879d]138                           QtGui.QStandardItem("0.20"))
[59183b7]139        self.model.setItem(W.W_QCUTOFF,
[1bb879d]140                           QtGui.QStandardItem("0.22"))
[59183b7]141        self.model.setItem(W.W_BACKGROUND,
142                           QtGui.QStandardItem("0"))
143        self.model.setItem(W.W_TRANSFORM,
144                           QtGui.QStandardItem("Fourier"))
[e4a3302]145        self.model.setItem(W.W_GUINIERA,
146                           QtGui.QStandardItem("0.0"))
147        self.model.setItem(W.W_GUINIERB,
148                           QtGui.QStandardItem("0.0"))
149        self.model.setItem(W.W_PORODK,
150                           QtGui.QStandardItem("0.0"))
151        self.model.setItem(W.W_PORODSIGMA,
152                           QtGui.QStandardItem("0.0"))
[9634f86]153        self.model.setItem(W.W_CORETHICK, QtGui.QStandardItem(str(0)))
154        self.model.setItem(W.W_INTTHICK, QtGui.QStandardItem(str(0)))
155        self.model.setItem(W.W_HARDBLOCK, QtGui.QStandardItem(str(0)))
156        self.model.setItem(W.W_CRYSTAL, QtGui.QStandardItem(str(0)))
157        self.model.setItem(W.W_POLY, QtGui.QStandardItem(str(0)))
158        self.model.setItem(W.W_PERIOD, QtGui.QStandardItem(str(0)))
[59183b7]159
[be6f7af]160    def model_changed(self, _):
161        """Actions to perform when the data is updated"""
162        if not self.mapper:
163            return
[e4a3302]164        self.mapper.toFirst()
[7be7136]165        self._canvas.draw_q_space()
[f159d1b]166
[7b21c05]167    def _update_calculator(self):
168        self._calculator.lowerq = float(self.model.item(W.W_QMIN).text())
169        qmax1 = float(self.model.item(W.W_QMAX).text())
170        qmax2 = float(self.model.item(W.W_QCUTOFF).text())
171        self._calculator.upperq = (qmax1, qmax2)
[7be7136]172        self._calculator.background = \
173            float(self.model.item(W.W_BACKGROUND).text())
[b2c8aef]174
[7b536da]175    def extrapolate(self):
[be6f7af]176        """Extend the experiemntal data with guinier and porod curves."""
[cadd595a]177        self._update_calculator()
[7be7136]178        params, extrapolation, _ = self._calculator.compute_extrapolation()
[e4a3302]179
180        self.model.setItem(W.W_GUINIERA, QtGui.QStandardItem(str(params['A'])))
181        self.model.setItem(W.W_GUINIERB, QtGui.QStandardItem(str(params['B'])))
182        self.model.setItem(W.W_PORODK, QtGui.QStandardItem(str(params['K'])))
[7be7136]183        self.model.setItem(W.W_PORODSIGMA,
184                           QtGui.QStandardItem(str(params['sigma'])))
[e4a3302]185
[f159d1b]186        self._canvas.extrap = extrapolation
[7be7136]187        self._canvas.draw_q_space()
[7b536da]188
[f7b73d5]189    def transform(self):
[be6f7af]190        """Calculate the real space version of the extrapolation."""
[6930b91]191        method = str(self.model.item(W.W_TRANSFORM).text()).lower()
[f7b73d5]192
193        extrap = self._canvas.extrap
[be6f7af]194        background = float(self.model.item(W.W_BACKGROUND).text())
[7be7136]195
[be6f7af]196        def updatefn(msg):
197            """Report progress of transformation."""
198            self.communicate.statusBarUpdateSignal.emit(msg)
[f7b73d5]199
[ff8cb73]200        def completefn(transforms):
[be6f7af]201            """Extract the values from the transforms and plot"""
[a3c4217]202            self._realplot.data = transforms
[ff8cb73]203            self._realplot.draw_real_space()
[a3c4217]204            params = self._calculator.extract_parameters(transforms[0])
[ff8cb73]205            self.model.setItem(W.W_CORETHICK,
206                               QtGui.QStandardItem(str(params['d0'])))
207            self.model.setItem(W.W_INTTHICK,
208                               QtGui.QStandardItem(str(params['dtr'])))
209            self.model.setItem(W.W_HARDBLOCK,
210                               QtGui.QStandardItem(str(params['Lc'])))
211            self.model.setItem(W.W_CRYSTAL,
212                               QtGui.QStandardItem(str(params['fill'])))
213            self.model.setItem(W.W_POLY,
214                               QtGui.QStandardItem(str(params['A'])))
215            self.model.setItem(W.W_PERIOD,
216                               QtGui.QStandardItem(str(params['max'])))
[f7b73d5]217
[cadd595a]218        self._update_calculator()
[be6f7af]219        self._calculator.compute_transform(extrap, method, background,
[7be7136]220                                           completefn, updatefn)
[f7b73d5]221
[7be7136]222    def setup_mapper(self):
[be6f7af]223        """Creating mapping between model and gui elements."""
[59183b7]224        self.mapper = QtGui.QDataWidgetMapper(self)
225        self.mapper.setOrientation(QtCore.Qt.Vertical)
226        self.mapper.setModel(self.model)
227
228        self.mapper.addMapping(self.qMin, W.W_QMIN)
229        self.mapper.addMapping(self.qMax1, W.W_QMAX)
230        self.mapper.addMapping(self.qMax2, W.W_QCUTOFF)
231        self.mapper.addMapping(self.bg, W.W_BACKGROUND)
[6930b91]232        self.mapper.addMapping(self.transformCombo, W.W_TRANSFORM)
[59183b7]233
[e4a3302]234        self.mapper.addMapping(self.guinierA, W.W_GUINIERA)
235        self.mapper.addMapping(self.guinierB, W.W_GUINIERB)
236        self.mapper.addMapping(self.porodK, W.W_PORODK)
237        self.mapper.addMapping(self.porodSigma, W.W_PORODSIGMA)
238
[9634f86]239        self.mapper.addMapping(self.avgCoreThick, W.W_CORETHICK)
240        self.mapper.addMapping(self.avgIntThick, W.W_INTTHICK)
241        self.mapper.addMapping(self.avgHardBlock, W.W_HARDBLOCK)
242        self.mapper.addMapping(self.polydisp, W.W_POLY)
243        self.mapper.addMapping(self.longPeriod, W.W_PERIOD)
244        self.mapper.addMapping(self.localCrystal, W.W_CRYSTAL)
245
[59183b7]246        self.mapper.toFirst()
247
[be6f7af]248    def calculate_background(self):
249        """Find a good estimate of the background value."""
[cadd595a]250        self._update_calculator()
[be6f7af]251        background = self._calculator.compute_background()
252        temp = QtGui.QStandardItem(str(background))
[e4a3302]253        self.model.setItem(W.W_BACKGROUND, temp)
[59183b7]254
[a3c4217]255    # pylint: disable=invalid-name
256    @staticmethod
257    def allowBatch():
[6d96bf9]258        """
259        We cannot perform corfunc analysis in batch at this time.
260        """
261        return False
262
263    def setData(self, data_item, is_batch=False):
264        """
265        Obtain a QStandardItem object and dissect it to get Data1D/2D
266        Pass it over to the calculator
267        """
268        if not isinstance(data_item, list):
269            msg = "Incorrect type passed to the Corfunc Perpsective"
270            raise AttributeError(msg)
271
272        if not isinstance(data_item[0], QtGui.QStandardItem):
273            msg = "Incorrect type passed to the Corfunc Perspective"
274            raise AttributeError(msg)
275
[be6f7af]276        model_item = data_item[0]
277        data = GuiUtils.dataFromItem(model_item)
[b2c8aef]278        self._calculator.set_data(data)
[6d96bf9]279
[f159d1b]280        self._canvas.data = data
[7be7136]281        self._canvas.draw_q_space()
[22e6043]282
[6d96bf9]283        # self.model.item(WIDGETS.W_FILENAME).setData(QtCoreQVariant(self._model_item.text()))
284
285    def setClosable(self, value=True):
286        """
287        Allow outsiders close this widget
288        """
289        assert isinstance(value, bool)
290
291        self._allow_close = value
[a3c4217]292    # pylint: enable=invalid-name
Note: See TracBrowser for help on using the repository browser.