Source code for sas.qtgui.Perspectives.Inversion.DMaxExplorerWidget

# -*- coding: utf-8 -*-
"""
Dialog panel to explore the P(r) inversion results for a range
of D_max value. User picks a number of points and a range of
distances, then can toggle between inversion outputs and see
their distribution as a function of D_max.
"""

# global
import logging
import numpy as np
from PyQt5 import QtCore
from PyQt5 import QtGui
from PyQt5 import QtWidgets

# sas-global
from sas.qtgui.Plotting.PlotterData import Data1D
from sas.qtgui.Plotting.Plotter import PlotterWidget
import sas.qtgui.Utilities.GuiUtils as GuiUtils

# local
from .UI.DMaxExplorer import Ui_DmaxExplorer

logger = logging.getLogger(__name__)

from sas.qtgui.Utilities.GuiUtils import enum

W = enum( 'NPTS',      #0
          'DMIN',      #1
          'DMAX',      #2
          'VARIABLE',  #3
)

[docs]class DmaxWindow(QtWidgets.QDialog, Ui_DmaxExplorer): # The controller which is responsible for managing signal slots connections # for the gui and providing an interface to the data model. name = "Dmax Explorer" # For displaying in the combo box def __init__(self, pr_state, nfunc, parent=None): super(DmaxWindow, self).__init__() self.setupUi(self) self.parent = parent self.setWindowTitle("Dmax Explorer") self.pr_state = pr_state self.nfunc = nfunc self.communicator = GuiUtils.Communicate() self.plot = PlotterWidget(self, self) self.hasPlot = False self.plot.showLegend = False self.verticalLayout.insertWidget(0, self.plot) # Let's choose the Standard Item Model. self.model = QtGui.QStandardItemModel(self) self.mapper = QtWidgets.QDataWidgetMapper(self) # Add validators on line edits self.setupValidators() # Connect buttons to slots. # Needs to be done early so default values propagate properly. self.setupSlots() # Set up the model. self.setupModel() # # Set up the mapper self.setupMapper()
[docs] def setupValidators(self): """Add validators on relevant line edits""" self.Npts.setValidator(QtGui.QIntValidator()) self.minDist.setValidator(GuiUtils.DoubleValidator()) self.maxDist.setValidator(GuiUtils.DoubleValidator())
[docs] def setupSlots(self): self.closeButton.clicked.connect(self.close) self.model.itemChanged.connect(self.modelChanged) self.dependentVariable.currentIndexChanged.connect(lambda:self.modelChanged(None))
[docs] def setupModel(self): self.model.blockSignals(True) self.model.setItem(W.NPTS, QtGui.QStandardItem(str(self.nfunc))) self.model.blockSignals(False) self.model.blockSignals(True) self.model.setItem(W.DMIN, QtGui.QStandardItem("{:.1f}".format(0.9*self.pr_state.d_max))) self.model.blockSignals(False) self.model.blockSignals(True) self.model.setItem(W.DMAX, QtGui.QStandardItem("{:.1f}".format(1.1*self.pr_state.d_max))) self.model.blockSignals(False) self.model.blockSignals(True) self.model.setItem(W.VARIABLE, QtGui.QStandardItem( "χ²/dof")) self.model.blockSignals(False)
[docs] def setupMapper(self): self.mapper.setOrientation(QtCore.Qt.Vertical) self.mapper.setModel(self.model) self.mapper.addMapping(self.Npts, W.NPTS) self.mapper.addMapping(self.minDist, W.DMIN) self.mapper.addMapping(self.maxDist, W.DMAX) self.mapper.addMapping(self.dependentVariable, W.VARIABLE) self.mapper.toFirst()
[docs] def modelChanged(self, item): if not self.mapper: return iq0 = [] rg = [] pos = [] pos_err = [] osc = [] bck = [] chi2 = [] plotable_xs = [] #Introducing this to make sure size of x and y for plotting is the same.8 try: dmin = float(self.model.item(W.DMIN).text()) dmax = float(self.model.item(W.DMAX).text()) npts = int(self.model.item(W.NPTS).text()) xs = np.linspace(dmin, dmax, npts) except ValueError as e: msg = ("An input value is not correctly formatted. Please check {}" .format(e.message)) logger.error(msg) original = self.pr_state.d_max for x in xs: self.pr_state.d_max = x try: out, cov = self.pr_state.invert(self.pr_state.nfunc) iq0.append(self.pr_state.iq0(out)) rg.append(self.pr_state.rg(out)) pos.append(self.pr_state.get_positive(out)) pos_err.append(self.pr_state.get_pos_err(out, cov)) osc.append(self.pr_state.oscillations(out)) bck.append(self.pr_state.background) chi2.append(self.pr_state.chi2) plotable_xs.append(x) except Exception as ex: # This inversion failed, skip this D_max value msg = "ExploreDialog: inversion failed " msg += "for D_max=%s\n%s" % (str(x), ex) logger.error(msg) #Return the invertor to its original state self.pr_state.d_max = original try: self.pr_state.invert(self.nfunc) except RuntimeError as ex: msg = "ExploreDialog: inversion failed " msg += "for D_max=%s\n%s" % (str(x), ex) logger.error(msg) plotter = self.dependentVariable.currentText() x_label = "D_{max}" x_unit = "A" if plotter == "χ²/dof": ys = chi2 y_label = "\\chi^2/dof" y_unit = "a.u." elif plotter == "I(Q=0)": ys = iq0 y_label = "I(q=0)" y_unit = "cm^{-1}" elif plotter == "Rg": ys = rg y_label = "R_g" y_unit = "\\AA" elif plotter == "Oscillation parameter": ys = osc y_label = "Osc" y_unit = "a.u." elif plotter == "Background": ys = bck y_label = "Bckg" y_unit = "cm^{-1}" elif plotter == "Positive Fraction": ys = pos y_label = "P^+" y_unit = "a.u." else: ys = pos_err y_label = "P^{+}_{1\\sigma}" y_unit = "a.u." data = Data1D(plotable_xs, ys) if self.hasPlot: self.plot.removePlot(data.name) self.hasPlot = True data.title = plotter data._xaxis= x_label data._xunit = x_unit data._yaxis = y_label data._yunit = y_unit self.plot.plot(data=data, marker="-")
[docs] def closeEvent(self, event): """Override close event""" self.parent.dmaxWindow = None event.accept()