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

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

Move more data into the model

  • Property mode set to 100644
File size: 10.0 KB
Line 
1# global
2import sys
3from PyQt4 import QtCore
4from PyQt4 import QtGui
5from PyQt4 import QtWebKit
6
7from twisted.internet import threads
8from twisted.internet import reactor
9
10# sas-global
11from sas.qtgui.Plotting.PlotterData import Data1D
12import sas.qtgui.Utilities.GuiUtils as GuiUtils
13from sas.sascalc.corfunc.corfunc_calculator import CorfuncCalculator
14
15# local
16from UI.CorfuncPanel import Ui_CorfuncDialog
17# from InvariantDetails import DetailsDialog
18from CorfuncUtils import WIDGETS as W
19
20from matplotlib.backends import qt_compat
21from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
22from matplotlib.figure import Figure
23
24
25class MyMplCanvas(FigureCanvas):
26    """Ultimately, this is a QWidget (as well as a FigureCanvasAgg, etc.)."""
27    def __init__(self, parent=None, width=5, height=4, dpi=100):
28        self.fig = Figure(figsize=(width, height), dpi=dpi)
29        self.axes = self.fig.add_subplot(111)
30
31        FigureCanvas.__init__(self, self.fig)
32        # self.reparent(parent, QPoint(0, 0))
33
34        # FigureCanvas.setSizePolicy(self,
35        #                            QSizePolicy.Expanding,
36        #                            QSizePolicy.Expanding)
37        # FigureCanvas.updateGeometry(self)
38
39        self.data = None
40        self.qmin = None
41        self.qmax1 = None
42        self.qmax2 = None
43        self.extrap = None
44
45    def drawQSpace(self):
46        self.fig.clf()
47
48        self.axes = self.fig.add_subplot(111)
49        self.axes.set_xscale("log")
50        self.axes.set_yscale("log")
51
52        if self.data:
53            self.axes.plot(self.data.x, self.data.y)
54        if self.qmin:
55            self.axes.axvline(self.qmin)
56        if self.qmax1:
57            self.axes.axvline(self.qmax1)
58        if self.qmax2:
59            self.axes.axvline(self.qmax2)
60        if self.extrap:
61            self.axes.plot(self.extrap.x, self.extrap.y)
62
63        self.draw()
64
65    def drawRealSpace(self):
66        self.fig.clf()
67
68        self.axes = self.fig.add_subplot(111)
69        self.axes.set_xscale("linear")
70        self.axes.set_yscale("linear")
71
72        if self.data:
73            self.axes.plot(self.data.x, self.data.y)
74
75        self.draw()
76
77
78    # def sizeHint(self):
79    #     w, h = self.get_width_height()
80    #     return QSize(w, h)
81
82    # def minimumSizeHint(self):
83    #     return QSize(10, 10)
84
85
86class CorfuncWindow(QtGui.QDialog, Ui_CorfuncDialog):
87    # The controller which is responsible for managing signal slots connections
88    # for the gui and providing an interface to the data model.
89    name = "Corfunc" # For displaying in the combo box
90    #def __init__(self, manager=None, parent=None):
91    def __init__(self, parent=None):
92        super(CorfuncWindow, self).__init__()
93        self.setupUi(self)
94
95        self.setWindowTitle("Corfunc Perspective")
96
97        self.model = QtGui.QStandardItemModel(self)
98        self.communicate = GuiUtils.Communicate()
99        self._calculator = CorfuncCalculator()
100
101        self._canvas = MyMplCanvas(self)
102        self._realplot = MyMplCanvas(self)
103        self.verticalLayout_7.insertWidget(0, self._canvas)
104        self.verticalLayout_7.insertWidget(1, self._realplot)
105
106        # Connect buttons to slots.
107        # Needs to be done early so default values propagate properly.
108        self.setupSlots()
109
110        # Set up the model.
111        self.setupModel()
112
113        # Set up the mapper
114        self.setupMapper()
115
116    def setupSlots(self):
117        self.extrapolateBtn.clicked.connect(self.extrapolate)
118        self.transformBtn.clicked.connect(self.transform)
119
120        self.calculateBgBtn.clicked.connect(self.calculateBackground)
121
122        self.model.itemChanged.connect(self.modelChanged)
123
124    def setupModel(self):
125        self.model.setItem(W.W_QMIN,
126                           QtGui.QStandardItem("0.01"))
127        self.model.setItem(W.W_QMAX,
128                           QtGui.QStandardItem("0.20"))
129        self.model.setItem(W.W_QCUTOFF,
130                           QtGui.QStandardItem("0.22"))
131        self.model.setItem(W.W_BACKGROUND,
132                           QtGui.QStandardItem("0"))
133        self.model.setItem(W.W_TRANSFORM,
134                           QtGui.QStandardItem("Fourier"))
135        self.model.setItem(W.W_GUINIERA,
136                           QtGui.QStandardItem("0.0"))
137        self.model.setItem(W.W_GUINIERB,
138                           QtGui.QStandardItem("0.0"))
139        self.model.setItem(W.W_PORODK,
140                           QtGui.QStandardItem("0.0"))
141        self.model.setItem(W.W_PORODSIGMA,
142                           QtGui.QStandardItem("0.0"))
143        self.model.setItem(W.W_CORETHICK, QtGui.QStandardItem(str(0)))
144        self.model.setItem(W.W_INTTHICK, QtGui.QStandardItem(str(0)))
145        self.model.setItem(W.W_HARDBLOCK, QtGui.QStandardItem(str(0)))
146        self.model.setItem(W.W_CRYSTAL, QtGui.QStandardItem(str(0)))
147        self.model.setItem(W.W_POLY, QtGui.QStandardItem(str(0)))
148        self.model.setItem(W.W_PERIOD, QtGui.QStandardItem(str(0)))
149
150    def modelChanged(self, item):
151        if item.row() == W.W_QMIN:
152            value = float(self.model.item(W.W_QMIN).text())
153            self._canvas.qmin = value
154        elif item.row() == W.W_QMAX or item.row() == W.W_QCUTOFF:
155            a = float(self.model.item(W.W_QMAX).text())
156            b = float(self.model.item(W.W_QCUTOFF).text())
157            self._canvas.qmax1 = a
158            self._canvas.qmax2 = b
159        else:
160            print("{} Changed".format(item))
161
162        self._update_calculator()
163        self.mapper.toFirst()
164        self._canvas.drawQSpace()
165
166    def _update_calculator(self):
167        self._calculator.lowerq = float(self.model.item(W.W_QMIN).text())
168        qmax1 = float(self.model.item(W.W_QMAX).text())
169        qmax2 = float(self.model.item(W.W_QCUTOFF).text())
170        self._calculator.upperq = (qmax1, qmax2)
171        self._calculator.background = float(self.model.item(W.W_BACKGROUND).text())
172
173    def extrapolate(self):
174        params, extrapolation = self._calculator.compute_extrapolation()
175
176        self.model.setItem(W.W_GUINIERA, QtGui.QStandardItem(str(params['A'])))
177        self.model.setItem(W.W_GUINIERB, QtGui.QStandardItem(str(params['B'])))
178        self.model.setItem(W.W_PORODK, QtGui.QStandardItem(str(params['K'])))
179        self.model.setItem(W.W_PORODSIGMA, QtGui.QStandardItem(str(params['sigma'])))
180
181        self._canvas.extrap = extrapolation
182        self._canvas.drawQSpace()
183
184
185    def transform(self):
186        if self.fourierBtn.isChecked():
187            method = "fourier"
188        elif self.hilbertBtn.isChecked():
189            method = "hilbert"
190
191        extrap = self._canvas.extrap
192        bg = float(self.model.item(W.W_BACKGROUND).text())
193        def updatefn(*args, **kwargs):
194            pass
195
196        def completefn(transform):
197            self._realplot.data = transform
198            self._realplot.drawRealSpace()
199            params = self._calculator.extract_parameters(transform)
200            self.model.setItem(W.W_CORETHICK, QtGui.QStandardItem(str(params['d0'])))
201            self.model.setItem(W.W_INTTHICK, QtGui.QStandardItem(str(params['dtr'])))
202            self.model.setItem(W.W_HARDBLOCK, QtGui.QStandardItem(str(params['Lc'])))
203            self.model.setItem(W.W_CRYSTAL, QtGui.QStandardItem(str(params['fill'])))
204            self.model.setItem(W.W_POLY, QtGui.QStandardItem(str(params['A'])))
205            self.model.setItem(W.W_PERIOD, QtGui.QStandardItem(str(params['max'])))
206
207        self._calculator.compute_transform(extrap, method, bg, completefn, updatefn)
208
209
210    def setupMapper(self):
211        self.mapper = QtGui.QDataWidgetMapper(self)
212        self.mapper.setOrientation(QtCore.Qt.Vertical)
213        self.mapper.setModel(self.model)
214
215        self.mapper.addMapping(self.qMin, W.W_QMIN)
216        self.mapper.addMapping(self.qMax1, W.W_QMAX)
217        self.mapper.addMapping(self.qMax2, W.W_QCUTOFF)
218        self.mapper.addMapping(self.bg, W.W_BACKGROUND)
219
220        self.mapper.addMapping(self.guinierA, W.W_GUINIERA)
221        self.mapper.addMapping(self.guinierB, W.W_GUINIERB)
222        self.mapper.addMapping(self.porodK, W.W_PORODK)
223        self.mapper.addMapping(self.porodSigma, W.W_PORODSIGMA)
224
225        self.mapper.addMapping(self.avgCoreThick, W.W_CORETHICK)
226        self.mapper.addMapping(self.avgIntThick, W.W_INTTHICK)
227        self.mapper.addMapping(self.avgHardBlock, W.W_HARDBLOCK)
228        self.mapper.addMapping(self.polydisp, W.W_POLY)
229        self.mapper.addMapping(self.longPeriod, W.W_PERIOD)
230        self.mapper.addMapping(self.localCrystal, W.W_CRYSTAL)
231
232        self.mapper.toFirst()
233
234    def calculateBackground(self):
235        bg = self._calculator.compute_background()
236        temp = QtGui.QStandardItem(str(bg))
237        self.model.setItem(W.W_BACKGROUND, temp)
238
239    def allowBatch(self):
240        """
241        We cannot perform corfunc analysis in batch at this time.
242        """
243        return False
244
245    def setData(self, data_item, is_batch=False):
246        """
247        Obtain a QStandardItem object and dissect it to get Data1D/2D
248        Pass it over to the calculator
249        """
250        if not isinstance(data_item, list):
251            msg = "Incorrect type passed to the Corfunc Perpsective"
252            raise AttributeError(msg)
253
254        if not isinstance(data_item[0], QtGui.QStandardItem):
255            msg = "Incorrect type passed to the Corfunc Perspective"
256            raise AttributeError(msg)
257
258        self._model_item = data_item[0]
259        data = GuiUtils.dataFromItem(self._model_item)
260        self._calculator.set_data(data)
261
262        self._canvas.data = data
263        self._canvas.drawQSpace()
264
265        # self.model.item(WIDGETS.W_FILENAME).setData(QtCoreQVariant(self._model_item.text()))
266
267    def setClosable(self, value=True):
268        """
269        Allow outsiders close this widget
270        """
271        assert isinstance(value, bool)
272
273        self._allow_close = value
274
275
276if __name__ == "__main__":
277    app = QtGui.QApplication([])
278    import qt4reactor
279    # qt4reactor.install()
280    # DO NOT move the following import to the top!
281    # (unless you know what you're doing)
282    from twisted.internet import reactor
283    dlg = CorfuncWindow(reactor)
284    print(dlg)
285    dlg.show()
286    # print(reactor)
287    # reactor.run()
288    sys.exit(app.exec_())
Note: See TracBrowser for help on using the repository browser.