source: sasview/src/sas/qtgui/Perspectives/Inversion/DMaxExplorerWidget.py @ 5d14851a

ESS_GUIESS_GUI_bumps_abstractionESS_GUI_iss1116ESS_GUI_opencl
Last change on this file since 5d14851a was 9f2f713, checked in by wojciech, 6 years ago

Dmax explorer plot switches between different plots

  • Property mode set to 100644
File size: 6.6 KB
RevLine 
[fa81e94]1# -*- coding: utf-8 -*-
2"""
3Dialog panel to explore the P(r) inversion results for a range
4of D_max value. User picks a number of points and a range of
5distances, then can toggle between inversion outputs and see
6their distribution as a function of D_max.
7"""
8
9# global
10import logging
11import numpy as np
12from PyQt5 import QtCore
13from PyQt5 import QtGui
14from PyQt5 import QtWidgets
15
16# sas-global
17from sas.qtgui.Plotting.PlotterData import Data1D
18from sas.qtgui.Plotting.Plotter import PlotterWidget
19import sas.qtgui.Utilities.GuiUtils as GuiUtils
20
21# local
[6a3e1fe]22from .UI.DMaxExplorer import Ui_DmaxExplorer
[fa81e94]23
24logger = logging.getLogger(__name__)
25
[d4881f6a]26from sas.qtgui.Utilities.GuiUtils import enum
[fa81e94]27
[8f83719f]28W = enum( 'NPTS',      #0
29          'DMIN',      #1
30          'DMAX',      #2
31          'VARIABLE',  #3
[fa81e94]32)
33
34class DmaxWindow(QtWidgets.QDialog, Ui_DmaxExplorer):
35    # The controller which is responsible for managing signal slots connections
36    # for the gui and providing an interface to the data model.
37    name = "Dmax Explorer"  # For displaying in the combo box
38
39    def __init__(self, pr_state, nfunc, parent=None):
40        super(DmaxWindow, self).__init__()
41        self.setupUi(self)
[ae34d30]42        self.parent = parent
[fa81e94]43
[e908916]44        self.setWindowTitle("Dmax Explorer")
[fa81e94]45
46        self.pr_state = pr_state
47        self.nfunc = nfunc
48        self.communicator = GuiUtils.Communicate()
49
50        self.plot = PlotterWidget(self, self)
[6da860a]51        self.hasPlot = False
[fa81e94]52        self.verticalLayout.insertWidget(0, self.plot)
53
54        # Let's choose the Standard Item Model.
55        self.model = QtGui.QStandardItemModel(self)
[6da860a]56        self.mapper = QtWidgets.QDataWidgetMapper(self)
[fa81e94]57
[8f83719f]58        # Add validators on line edits
59        self.setupValidators()
60
[6da860a]61        # Connect buttons to slots.
62        # Needs to be done early so default values propagate properly.
[fa81e94]63        self.setupSlots()
64
65        # Set up the model.
66        self.setupModel()
67
68        # # Set up the mapper
69        self.setupMapper()
70
[8f83719f]71    def setupValidators(self):
72        """Add validators on relevant line edits"""
73        self.Npts.setValidator(QtGui.QIntValidator())
74        self.minDist.setValidator(GuiUtils.DoubleValidator())
75        self.maxDist.setValidator(GuiUtils.DoubleValidator())
76
[fa81e94]77    def setupSlots(self):
78        self.closeButton.clicked.connect(self.close)
79        self.model.itemChanged.connect(self.modelChanged)
[8f83719f]80        self.dependentVariable.currentIndexChanged.connect(lambda:self.modelChanged(None))
[fa81e94]81
82    def setupModel(self):
[b0ba43e]83        self.model.blockSignals(True)
[fa81e94]84        self.model.setItem(W.NPTS, QtGui.QStandardItem(str(self.nfunc)))
[b0ba43e]85        self.model.blockSignals(False)
86        self.model.blockSignals(True)
[8f83719f]87        self.model.setItem(W.DMIN, QtGui.QStandardItem("{:.1f}".format(0.9*self.pr_state.d_max)))
[b0ba43e]88        self.model.blockSignals(False)
89        self.model.blockSignals(True)
[8f83719f]90        self.model.setItem(W.DMAX, QtGui.QStandardItem("{:.1f}".format(1.1*self.pr_state.d_max)))
[b0ba43e]91        self.model.blockSignals(False)
92        self.model.blockSignals(True)
[6a3e1fe]93        self.model.setItem(W.VARIABLE, QtGui.QStandardItem( "χ²/dof"))
[b0ba43e]94        self.model.blockSignals(False)
[fa81e94]95
96    def setupMapper(self):
97        self.mapper.setOrientation(QtCore.Qt.Vertical)
98        self.mapper.setModel(self.model)
99
100        self.mapper.addMapping(self.Npts, W.NPTS)
101        self.mapper.addMapping(self.minDist, W.DMIN)
102        self.mapper.addMapping(self.maxDist, W.DMAX)
103        self.mapper.addMapping(self.dependentVariable, W.VARIABLE)
104
105        self.mapper.toFirst()
106
107    def modelChanged(self, item):
108        if not self.mapper:
109            return
110
111        iq0 = []
112        rg = []
113        pos = []
114        pos_err = []
115        osc = []
116        bck = []
117        chi2 = []
[e908916]118        plotable_xs = [] #Introducing this to make sure size of x and y for plotting is the same.8
[6da860a]119        try:
120            dmin = float(self.model.item(W.DMIN).text())
121            dmax = float(self.model.item(W.DMAX).text())
122            npts = float(self.model.item(W.NPTS).text())
123            xs = np.linspace(dmin, dmax, npts)
124        except ValueError as e:
125            msg = ("An input value is not correctly formatted. Please check {}"
126                   .format(e.message))
127            logger.error(msg)
[fa81e94]128
129        original = self.pr_state.d_max
[e908916]130
[fa81e94]131        for x in xs:
132            self.pr_state.d_max = x
133            try:
134                out, cov = self.pr_state.invert(self.pr_state.nfunc)
135
136                iq0.append(self.pr_state.iq0(out))
137                rg.append(self.pr_state.rg(out))
138                pos.append(self.pr_state.get_positive(out))
139                pos_err.append(self.pr_state.get_pos_err(out, cov))
140                osc.append(self.pr_state.oscillations(out))
141                bck.append(self.pr_state.background)
142                chi2.append(self.pr_state.chi2)
[e908916]143                plotable_xs.append(x)
[8f83719f]144            except Exception as ex:
[fa81e94]145                # This inversion failed, skip this D_max value
146                msg = "ExploreDialog: inversion failed "
[8f83719f]147                msg += "for D_max=%s\n%s" % (str(x), ex)
[6a3e1fe]148                logger.error(msg)
[fa81e94]149
150        #Return the invertor to its original state
151        self.pr_state.d_max = original
[6a3e1fe]152        try:
153            self.pr_state.invert(self.nfunc)
154        except RuntimeError as ex:
155            msg = "ExploreDialog: inversion failed "
[8f83719f]156            msg += "for D_max=%s\n%s" % (str(x), ex)
[6a3e1fe]157            logger.error(msg)
[fa81e94]158
[9f2f713]159        plotter = self.dependentVariable.currentText()
[8f83719f]160        x_label = "D_{max}"
161        x_unit = "A"
[fa81e94]162        if plotter == "χ²/dof":
163            ys = chi2
[72ecbdf2]164            y_label = "\\chi^2/dof"
[8f83719f]165            y_unit = "a.u."
[fa81e94]166        elif plotter == "I(Q=0)":
167            ys = iq0
[8f83719f]168            y_label = "I(q=0)"
[72ecbdf2]169            y_unit = "\\AA^{-1}"
[fa81e94]170        elif plotter == "Rg":
171            ys = rg
[8f83719f]172            y_label = "R_g"
[72ecbdf2]173            y_unit = "\\AA"
[fa81e94]174        elif plotter == "Oscillation parameter":
175            ys = osc
[8f83719f]176            y_label = "Osc"
177            y_unit = "a.u."
[fa81e94]178        elif plotter == "Background":
179            ys = bck
[8f83719f]180            y_label = "Bckg"
[72ecbdf2]181            y_unit = "\\AA^{-1}"
[fa81e94]182        elif plotter == "Positive Fraction":
183            ys = pos
[8f83719f]184            y_label = "P^+"
185            y_unit = "a.u."
[fa81e94]186        else:
187            ys = pos_err
[72ecbdf2]188            y_label = "P^{+}_{1\\sigma}"
[8f83719f]189            y_unit = "a.u."
[fa81e94]190
[e908916]191        data = Data1D(plotable_xs, ys)
[fa81e94]192        if self.hasPlot:
[9f2f713]193            self.plot.removePlot(data.name)
[fa81e94]194        self.hasPlot = True
[8f83719f]195        data.title = plotter
196        data._xaxis= x_label
197        data._xunit = x_unit
198        data._yaxis = y_label
199        data._yunit = y_unit
[fa81e94]200        self.plot.plot(data=data, marker="-")
[ae34d30]201
202    def closeEvent(self, event):
203        """Override close event"""
204        self.parent.dmaxWindow = None
205        event.accept()
Note: See TracBrowser for help on using the repository browser.