Skip to content

Commit

Permalink
Updating annulus slicer, batch slicing, and slicer parameters
Browse files Browse the repository at this point in the history
Changes to the annulus slicer and other slicers were merged from @rozyczko 'ESS_GUI_1381_slicer' regarding #1554 and #1381. The annulus slicer now opens and responds to changes in the SlicerParameters window. The batch slicing tab works, but the checkbox "Auto save generated 1D plots" does not save any files after clicking apply, and the fitting options dropdown is empty.
  • Loading branch information
murphyryanp committed May 28, 2020
1 parent ade9adb commit b895714
Show file tree
Hide file tree
Showing 6 changed files with 415 additions and 83 deletions.
3 changes: 2 additions & 1 deletion src/sas/qtgui/Plotting/Plotter2D.py
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,8 @@ def slicer_closed():

self.param_model = self.slicer.model()
# Pass the model to the Slicer Parameters widget
self.slicer_widget = SlicerParameters(model=self.param_model,
self.slicer_widget = SlicerParameters(self, model=self.param_model,
active_plots=self.manager.active_plots,
validate_method=self.slicer.validate)
self.slicer_widget.closeWidgetSignal.connect(slicer_closed)
# Add the plot to the workspace
Expand Down
21 changes: 18 additions & 3 deletions src/sas/qtgui/Plotting/SlicerModel.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ def __init__(self):
self._model = QtGui.QStandardItemModel()

self.update_model = True
self._model.itemChanged.connect(self.setParamsFromModel)
self._model.itemChanged.connect(self.setParamsFromModelItem)

def setModelFromParams(self):
"""
Expand All @@ -25,9 +25,24 @@ def setModelFromParams(self):
self._model.setHeaderData(0, QtCore.Qt.Horizontal, "Parameter")
self._model.setHeaderData(1, QtCore.Qt.Horizontal, "Value")

def setParamsFromModel(self, item):
def setParamsFromModel(self):
"""
Set up the params dictionary based on the model content.
Set up the params dictionary based on the current model content.
"""
params = self.getParams()
for row_index in range(self._model.rowCount()):
#index = self._model.indexFromItem(item)
#row_index = index.row()
param_name = str(self._model.item(row_index, 0).text())
params[param_name] = float(self._model.item(row_index, 1).text())

self.update_model = False
self.setParams(params)
self.update_model = True

def setParamsFromModelItem(self, item):
"""
Set up the params dictionary for the parameter in item.
"""
params = self.getParams()
index = self._model.indexFromItem(item)
Expand Down
184 changes: 154 additions & 30 deletions src/sas/qtgui/Plotting/SlicerParameters.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,22 @@
# pylint:disable=C0103,I1101
"""
Allows users to modify the box slicer parameters.
"""
import numpy
import functools

from PyQt5 import QtCore
from PyQt5 import QtGui
from PyQt5 import QtWidgets

import sas.qtgui.Utilities.GuiUtils as GuiUtils
from sas.qtgui.Plotting.PlotterData import Data1D
from sas.qtgui.Plotting.Slicers.BoxSlicer import BoxInteractorX
from sas.qtgui.Plotting.Slicers.BoxSlicer import BoxInteractorY
from sas.qtgui.Plotting.Slicers.AnnulusSlicer import AnnulusInteractor
from sas.qtgui.Plotting.Slicers.SectorSlicer import SectorInteractor

# Local UI
from sas.qtgui.UI import main_resources_rc
#from sas.qtgui.UI import main_resources_rc
from sas.qtgui.Plotting.UI.SlicerParametersUI import Ui_SlicerParametersUI

class SlicerParameters(QtWidgets.QDialog, Ui_SlicerParametersUI):
Expand All @@ -20,15 +25,29 @@ class SlicerParameters(QtWidgets.QDialog, Ui_SlicerParametersUI):
passed from a slicer instance.
"""
closeWidgetSignal = QtCore.pyqtSignal()
def __init__(self, model=None, validate_method=None):
def __init__(self, parent=None,
model=None,
active_plots=None,
validate_method=None):
super(SlicerParameters, self).__init__()

self.setupUi(self)

assert isinstance(model, QtGui.QStandardItemModel)
self.parent = parent

self.model = model
self.validate_method = validate_method
self.active_plots = active_plots

# Initially, Apply is disabled
self.cmdApply.setEnabled(False)

# Mapping combobox index -> slicer module
self.callbacks = {0: SectorInteractor,
1: AnnulusInteractor,
2: BoxInteractorX,
3: BoxInteractorY}

# Define a proxy model so cell enablement can be finegrained.
self.proxy = ProxyModel(self)
Expand All @@ -43,40 +62,145 @@ def __init__(self, model=None, validate_method=None):
# Specify the validator on the parameter value column.
self.delegate = EditDelegate(self, validate_method=self.validate_method)
self.lstParams.setItemDelegate(self.delegate)
self.delegate.refocus_signal.connect(self.onFocus)

# Display Help on clicking the button
self.buttonBox.button(QtWidgets.QDialogButtonBox.Help).clicked.connect(self.onHelp)
# define slots
self.setSlots()

# Close doesn't trigger closeEvent automatically, so force it
self.buttonBox.button(QtWidgets.QDialogButtonBox.Close).clicked.connect(functools.partial(self.closeEvent, None))
# Switch off Auto Save
self.onGeneratePlots(False)

# Set up params list
self.setParamsList()

# Set up plots list
self.setPlotsList()

def setParamsList(self):
"""
Create and initially populate the list of parameters
"""
# Disable row number display
self.lstParams.verticalHeader().setVisible(False)
self.lstParams.setAlternatingRowColors(True)
self.lstParams.setSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Expanding)
self.lstParams.setSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding,
QtWidgets.QSizePolicy.Expanding)

# Header properties for nicer display
header = self.lstParams.horizontalHeader()
header.setSectionResizeMode(QtWidgets.QHeaderView.Stretch)
header.setStretchLastSection(True)

def setPlotsList(self):
"""
Create and initially populate the list of plots
"""
# Fill out list of plots
for item in self.active_plots.keys():
if isinstance(self.active_plots[item].data[0], Data1D):
continue
checked = QtCore.Qt.Unchecked
if self.parent.data[0].name == item:
checked = QtCore.Qt.Checked
chkboxItem = QtWidgets.QListWidgetItem(str(item))
chkboxItem.setFlags(QtCore.Qt.ItemIsUserCheckable | QtCore.Qt.ItemIsEnabled)
chkboxItem.setCheckState(checked)
self.lstPlots.addItem(chkboxItem)

def setSlots(self):
"""
define slots for signals from various sources
"""
self.delegate.refocus_signal.connect(self.onFocus)
self.cbSave1DPlots.toggled.connect(self.onGeneratePlots)
# Display Help on clicking the button
self.cmdHelp.clicked.connect(self.onHelp)

# Close doesn't trigger closeEvent automatically, so force it
self.cmdClose.clicked.connect(functools.partial(self.closeEvent, None))

# Apply slicer to selected plots
self.cmdApply.clicked.connect(self.onApply)

# Initialize slicer combobox to the current slicer
current_slicer = type(self.parent.slicer)
for index in self.callbacks:
if self.callbacks[index] == current_slicer:
self.cbSlicer.setCurrentIndex(index)
break
# change the slicer type
self.cbSlicer.currentIndexChanged.connect(self.onSlicerChanged)

# selecting/deselecting items in lstPlots enables `Apply`
self.lstPlots.itemChanged.connect(lambda: self.cmdApply.setEnabled(True))

def onFocus(self, row, column):
""" Set the focus on the cell (row, column) """
selection_model = self.lstParams.selectionModel()
selection_model.select(self.model.index(row, column), QtGui.QItemSelectionModel.Select)
self.lstParams.setSelectionModel(selection_model)
self.lstParams.setCurrentIndex(self.model.index(row, column))

def onSlicerChanged(self, index):
""" change the parameters based on the slicer chosen """
if index < len(self.callbacks):
slicer = self.callbacks[index]
self.parent.setSlicer(slicer=slicer)

def onGeneratePlots(self, isChecked):
"""
Respond to choice of auto saving plots
"""
self.enableFileControls(isChecked)
self.isSave = isChecked

def enableFileControls(self, enabled):
"""
Sets enablement of file related UI elements
"""
self.txtLocation.setEnabled(enabled)
self.cmdFiles.setEnabled(enabled)
self.cbFitOptions.setEnabled(enabled)

def onApply(self):
"""
Apply current slicer to selected plots
"""
for row in range(self.lstPlots.count()):
item = self.lstPlots.item(row)
isChecked = item.checkState() == QtCore.Qt.Checked
# Only checked items
if not isChecked:
continue
plot = item.text()
# don't assign to itself
if plot == self.parent.data[0].name:
continue
# a plot might have been deleted
if plot not in self.active_plots:
continue
# get the plotter2D instance
plotter = self.active_plots[plot]
# Assign model to slicer
index = self.cbSlicer.currentIndex()
slicer = self.callbacks[index]
plotter.setSlicer(slicer=slicer)
# override slicer model
plotter.slicer._model = self.model
# force conversion model->parameters in slicer
plotter.slicer.setParamsFromModel()
pass

def setModel(self, model):
""" Model setter """
self.model = model
self.proxy.setSourceModel(self.model)

def keyPressEvent(self, event):
key = event.key()

if key == QtCore.Qt.Key_Escape:
"""
Added Esc key shortcut
"""
key = event.key()
if key == QtCore.Qt.Key_Escape:
self.closeWidgetSignal.emit()

def closeEvent(self, event):
Expand Down Expand Up @@ -126,18 +250,18 @@ class PositiveDoubleEditor(QtWidgets.QLineEdit):
editingFinished = QtCore.Signal()

def __init__(self, parent=None):
# Initialize the editor object
super(PositiveDoubleEditor, self).__init__(parent)
self.setAutoFillBackground(True)
validator = GuiUtils.DoubleValidator()
# Don't use the scientific notation, cause 'e'.
validator.setNotation(GuiUtils.DoubleValidator.StandardNotation)
# Initialize the editor object
super(PositiveDoubleEditor, self).__init__(parent)
self.setAutoFillBackground(True)
validator = GuiUtils.DoubleValidator()
# Don't use the scientific notation, cause 'e'.
validator.setNotation(GuiUtils.DoubleValidator.StandardNotation)

self.setValidator(validator)
self.setValidator(validator)

def focusOutEvent(self, event):
# Once focus is lost, tell the delegate we're done editing
self.editingFinished.emit()
# Once focus is lost, tell the delegate we're done editing
self.editingFinished.emit()


class EditDelegate(QtWidgets.QStyledItemDelegate):
Expand All @@ -154,12 +278,12 @@ def createEditor(self, parent, option, index):
return 0

result = index.column()
if result==1:
self.editor = PositiveDoubleEditor(parent)
self.index = index
return self.editor
else:
return QtWidgets.QStyledItemDelegate.createEditor(self, parent, option, index)
if result == 1:
self.editor = PositiveDoubleEditor(parent)
self.index = index
return self.editor

return QtWidgets.QStyledItemDelegate.createEditor(self, parent, option, index)

def setModelData(self, editor, model, index):
"""
Expand All @@ -169,13 +293,13 @@ def setModelData(self, editor, model, index):

# Find out the changed parameter name and proposed value
new_value = GuiUtils.toDouble(self.editor.text())
param_name = model.sourceModel().item(index.row(),0).text()
param_name = model.sourceModel().item(index.row(), 0).text()

validated = True
if self.validate_method:
# Validate the proposed value in the slicer
value_accepted = self.validate_method(param_name, new_value)

if value_accepted:
# Update the model only if value accepted
return super(EditDelegate, self).setModelData(editor, model, index)
return super(EditDelegate, self).setModelData(editor, model, index)
return None
4 changes: 2 additions & 2 deletions src/sas/qtgui/Plotting/Slicers/AnnulusSlicer.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ def __init__(self, base, axes, item=None, color='black', zorder=3):
# Number of points on the plot
self.nbins = 36
# Cursor position of Rings (Left(-1) or Right(1))
self.xmaxd = self.xmax
self.xmind = self.xmin
self.xmaxd = self.data.xmax
self.xmind = self.data.xmin

if (self.xmaxd + self.xmind) > 0:
self.sign = 1
Expand Down
6 changes: 6 additions & 0 deletions src/sas/qtgui/Plotting/Slicers/BoxSlicer.py
Original file line number Diff line number Diff line change
Expand Up @@ -397,6 +397,12 @@ def __init__(self, base, axes, color='black', zorder=5, x=0.5, y=0.5):
self.connect_markers([self.right_line, self.inner_marker])
self.update()

def validate(self, param_name, param_value):
"""
Validate input from user
"""
return True

def set_layer(self, n):
"""
Allow adding plot to the same panel
Expand Down
Loading

0 comments on commit b895714

Please sign in to comment.