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

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

Remove a bunch of pylint

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