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

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

Move more data into the model

  • Property mode set to 100644
File size: 9.3 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.hilbertBtn.clicked.connect(self.action)
123        self.fourierBtn.clicked.connect(self.action)
124
125        self.model.itemChanged.connect(self.modelChanged)
126
127    def setupModel(self):
128        self.model.setItem(W.W_QMIN,
129                           QtGui.QStandardItem("0"))
130        self.model.setItem(W.W_QMAX,
131                           QtGui.QStandardItem("0"))
132        self.model.setItem(W.W_QCUTOFF,
133                           QtGui.QStandardItem("0"))
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
147    def modelChanged(self, item):
148        if item.row() == W.W_QMIN:
149            value = float(self.model.item(W.W_QMIN).text())
150            self._calculator.lowerq = value
151            self._canvas.qmin = value
152        elif item.row() == W.W_QMAX:
153            value = float(self.model.item(W.W_QMAX).text())
154            self._calculator.upperq = (value, self._calculator.upperq[1])
155            self._canvas.qmax1 = value
156        elif item.row() == W.W_QCUTOFF:
157            value = float(self.model.item(W.W_QCUTOFF).text())
158            self._calculator.upperq = (self._calculator.upperq[0], value)
159            self._canvas.qmax2 = value
160        elif item.row() == W.W_BACKGROUND:
161            value = float(self.model.item(W.W_BACKGROUND).text())
162            self._calculator.background = value
163        else:
164            print("{} Changed".format(item))
165
166        self.mapper.toFirst()
167        self._canvas.drawQSpace()
168
169
170    def extrapolate(self):
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, QtGui.QStandardItem(str(params['sigma'])))
177
178        self._canvas.extrap = extrapolation
179        self._canvas.drawQSpace()
180
181
182    def transform(self):
183        if self.fourierBtn.isChecked():
184            method = "fourier"
185        elif self.hilbertBtn.isChecked():
186            method = "hilbert"
187
188        extrap = self._canvas.extrap
189        bg = self._calculator.background
190        def updatefn(*args, **kwargs):
191            pass
192
193        def completefn(transform):
194            self._realplot.data = transform
195            self._realplot.drawRealSpace()
196            params = self._calculator.extract_parameters(transform)
197            self.avgCoreThick.setValue(params["d0"])
198            self.avgHardBlock.setValue(params["Lc"])
199            self.avgIntThick.setValue(params["dtr"])
200            self.localCrystal.setValue(params["fill"])
201            self.polydisp.setValue(params["A"])
202            self.longPeriod.setValue(params["max"])
203
204        self._calculator.compute_transform(extrap, method, bg, completefn, updatefn)
205
206
207    def setupMapper(self):
208        self.mapper = QtGui.QDataWidgetMapper(self)
209        self.mapper.setOrientation(QtCore.Qt.Vertical)
210        self.mapper.setModel(self.model)
211
212        self.mapper.addMapping(self.qMin, W.W_QMIN)
213        self.mapper.addMapping(self.qMax1, W.W_QMAX)
214        self.mapper.addMapping(self.qMax2, W.W_QCUTOFF)
215        self.mapper.addMapping(self.bg, W.W_BACKGROUND)
216
217        self.mapper.addMapping(self.guinierA, W.W_GUINIERA)
218        self.mapper.addMapping(self.guinierB, W.W_GUINIERB)
219        self.mapper.addMapping(self.porodK, W.W_PORODK)
220        self.mapper.addMapping(self.porodSigma, W.W_PORODSIGMA)
221
222        self.mapper.toFirst()
223
224    def calculateBackground(self):
225        bg = self._calculator.compute_background()
226        temp = QtGui.QStandardItem(str(bg))
227        self.model.setItem(W.W_BACKGROUND, temp)
228
229    def action(self):
230        print("Called an action!")
231        print(self.model)
232        print(self.mapper)
233
234    def allowBatch(self):
235        """
236        We cannot perform corfunc analysis in batch at this time.
237        """
238        return False
239
240    def setData(self, data_item, is_batch=False):
241        """
242        Obtain a QStandardItem object and dissect it to get Data1D/2D
243        Pass it over to the calculator
244        """
245        if not isinstance(data_item, list):
246            msg = "Incorrect type passed to the Corfunc Perpsective"
247            raise AttributeError(msg)
248
249        if not isinstance(data_item[0], QtGui.QStandardItem):
250            msg = "Incorrect type passed to the Corfunc Perspective"
251            raise AttributeError(msg)
252
253        self._model_item = data_item[0]
254        data = GuiUtils.dataFromItem(self._model_item)
255        self._calculator.lowerq = 1e-3
256        self._calculator.upperq = (2e-1, 3e-1)
257        self._calculator.set_data(data)
258
259        self._canvas.data = data
260        self._canvas.drawQSpace()
261
262        # self.model.item(WIDGETS.W_FILENAME).setData(QtCoreQVariant(self._model_item.text()))
263
264    def setClosable(self, value=True):
265        """
266        Allow outsiders close this widget
267        """
268        assert isinstance(value, bool)
269
270        self._allow_close = value
271
272
273if __name__ == "__main__":
274    app = QtGui.QApplication([])
275    import qt4reactor
276    # qt4reactor.install()
277    # DO NOT move the following import to the top!
278    # (unless you know what you're doing)
279    from twisted.internet import reactor
280    dlg = CorfuncWindow(reactor)
281    print(dlg)
282    dlg.show()
283    # print(reactor)
284    # reactor.run()
285    sys.exit(app.exec_())
Note: See TracBrowser for help on using the repository browser.