Index: src/sas/qtgui/GUITests.py
===================================================================
--- src/sas/qtgui/GUITests.py (revision 3bdbfcc5cdff8a3a11a9bb19c1cc8c3660a9c2e2)
+++ src/sas/qtgui/GUITests.py (revision 57b7ee2a03730ca7183c233fa0fcae728926ee09)
@@ -26,4 +26,5 @@
from UnitTesting import BoxSumTest
from UnitTesting import SlicerModelTest
+from UnitTesting import SlicerParametersTest
def suite():
@@ -54,4 +55,5 @@
unittest.makeSuite(BoxSumTest.BoxSumTest, 'test'),
unittest.makeSuite(SlicerModelTest.SlicerModelTest, 'test'),
+ unittest.makeSuite(SlicerParametersTest.SlicerParametersTest, 'test'),
)
return unittest.TestSuite(suites)
Index: src/sas/qtgui/Plotter2D.py
===================================================================
--- src/sas/qtgui/Plotter2D.py (revision b78996786903e718c1fb56b07723e3ceaa7d079f)
+++ src/sas/qtgui/Plotter2D.py (revision 57b7ee2a03730ca7183c233fa0fcae728926ee09)
@@ -45,4 +45,5 @@
# Reference to the current slicer
self.slicer = None
+ self.slicer_widget = None
# Create Artist and bind it
self.connect = BindArtist(self.figure)
@@ -160,6 +161,7 @@
self.actionClearSlicer = self.contextMenu.addAction("&Clear Slicer")
self.actionClearSlicer.triggered.connect(self.onClearSlicer)
- self.actionEditSlicer = self.contextMenu.addAction("&Edit Slicer Parameters")
- self.actionEditSlicer.triggered.connect(self.onEditSlicer)
+ if self.slicer.__class__.__name__ != "BoxSumCalculator":
+ self.actionEditSlicer = self.contextMenu.addAction("&Edit Slicer Parameters")
+ self.actionEditSlicer.triggered.connect(self.onEditSlicer)
self.contextMenu.addSeparator()
self.actionColorMap = self.contextMenu.addAction("&2D Color Map")
@@ -213,9 +215,17 @@
"""
assert self.slicer
+ # Only show the dialog if not currently shown
+ if self.slicer_widget:
+ return
+ def slicer_closed():
+ # Need to disconnect the signal!!
+ self.slicer_widget.close_signal.disconnect()
+ # reset slicer_widget on "Edit Slicer Parameters" window close
+ self.slicer_widget = None
self.param_model = self.slicer.model()
- # Pass the model to the Slicer Parameters widget
+ # Pass the model to the Slicer Parameters widget
self.slicer_widget = SlicerParameters(self, model=self.param_model)
- self.manager.parent.workspace().addWindow(self.slicer_widget)
+ self.slicer_widget.close_signal.connect(slicer_closed)
self.slicer_widget.show()
@@ -283,4 +293,10 @@
self.slicer.update()
+ # Reset the model on the Edit slicer parameters widget
+ self.param_model = self.slicer.model()
+ if self.slicer_widget:
+ self.slicer_widget.setModel(self.param_model)
+
+
def onSectorView(self):
"""
@@ -288,4 +304,5 @@
"""
self.setSlicer(slicer=SectorInteractor)
+
def onAnnulusView(self):
Index: src/sas/qtgui/SlicerParameters.py
===================================================================
--- src/sas/qtgui/SlicerParameters.py (revision b78996786903e718c1fb56b07723e3ceaa7d079f)
+++ src/sas/qtgui/SlicerParameters.py (revision 57b7ee2a03730ca7183c233fa0fcae728926ee09)
@@ -2,6 +2,8 @@
Allows users to modify the box slicer parameters.
"""
+import functools
from PyQt4 import QtGui
from PyQt4 import QtCore
+from PyQt4 import QtWebKit
# Local UI
@@ -13,4 +15,5 @@
passed from a slicer instance.
"""
+ close_signal = QtCore.pyqtSignal()
def __init__(self, parent=None, model=None):
super(SlicerParameters, self).__init__()
@@ -31,9 +34,48 @@
self.lstParams.model().setColumnReadOnly(0, True)
+ # Specify the validator on the parameter value column.
+ self.lstParams.setItemDelegate(ValidatedItemDelegate())
+
+ # Display Help on clicking the button
+ self.buttonBox.button(QtGui.QDialogButtonBox.Help).clicked.connect(self.onHelp)
+
+ # Close doesn't trigger closeEvent automatically, so force it
+ self.buttonBox.button(QtGui.QDialogButtonBox.Close).clicked.connect(functools.partial(self.closeEvent,None))
+
# Disable row number display
self.lstParams.verticalHeader().setVisible(False)
+ self.lstParams.setAlternatingRowColors(True)
+ self.lstParams.setSizePolicy(QtGui.QSizePolicy.MinimumExpanding, QtGui.QSizePolicy.Expanding)
- # Specify the validator on the parameter value column.
- self.lstParams.setItemDelegate(ValidatedItemDelegate())
+ # Header properties for nicer display
+ header = self.lstParams.horizontalHeader()
+ header.setResizeMode(QtGui.QHeaderView.Stretch)
+ header.setStretchLastSection(True)
+
+
+ def setModel(self, model):
+ """ Model setter """
+ self.model = model
+ self.proxy.setSourceModel(self.model)
+
+ def closeEvent(self, event):
+ """
+ Overwritten close widget method in order to send the close
+ signal to the parent.
+ """
+ self.close_signal.emit()
+ if event:
+ event.accept()
+
+ def onHelp(self):
+ """
+ Display generic data averaging help
+ """
+ location = "docs/sphinx-docs/build/html" + \
+ "/user/sasgui/guiframe/graph_help.html#d-data-averaging"
+ self._helpView = QtWebKit.QWebView()
+ self._helpView.load(QtCore.QUrl(location))
+ self._helpView.show()
+
class ProxyModel(QtGui.QIdentityProxyModel):
Index: src/sas/qtgui/UI/SlicerParametersUI.ui
===================================================================
--- src/sas/qtgui/UI/SlicerParametersUI.ui (revision 3bdbfcc5cdff8a3a11a9bb19c1cc8c3660a9c2e2)
+++ src/sas/qtgui/UI/SlicerParametersUI.ui (revision 57b7ee2a03730ca7183c233fa0fcae728926ee09)
@@ -28,18 +28,5 @@
- -
-
-
- Qt::Vertical
-
-
-
- 20
- 21
-
-
-
-
- -
+
-
@@ -47,5 +34,5 @@
- QDialogButtonBox::Ok
+ QDialogButtonBox::Close|QDialogButtonBox::Help
Index: src/sas/qtgui/run_tests.bat
===================================================================
--- src/sas/qtgui/run_tests.bat (revision 965fbd854b36d33e3c78f5ffed0a6040af2ad43e)
+++ src/sas/qtgui/run_tests.bat (revision 57b7ee2a03730ca7183c233fa0fcae728926ee09)
@@ -25,2 +25,3 @@
python -m UnitTesting.BoxSumTest
python -m UnitTesting.SlicerModelTest
+python -m UnitTesting.SlicerParametersTest
Index: src/sas/qtgui/run_tests.sh
===================================================================
--- src/sas/qtgui/run_tests.sh (revision 3bdbfcc5cdff8a3a11a9bb19c1cc8c3660a9c2e2)
+++ src/sas/qtgui/run_tests.sh (revision 57b7ee2a03730ca7183c233fa0fcae728926ee09)
@@ -24,2 +24,3 @@
python -m UnitTesting.BoxSumTest
python -m UnitTesting.SlicerModelTest
+python -m UnitTesting.SlicerParametersTest
Index: src/sas/sasgui/guiframe/local_perspectives/plotting/SectorSlicer.py
===================================================================
--- src/sas/sasgui/guiframe/local_perspectives/plotting/SectorSlicer.py (revision 3bdbfcc5cdff8a3a11a9bb19c1cc8c3660a9c2e2)
+++ src/sas/sasgui/guiframe/local_perspectives/plotting/SectorSlicer.py (revision 57b7ee2a03730ca7183c233fa0fcae728926ee09)
@@ -2,5 +2,5 @@
Sector interactor
"""
-import math
+import numpy
from PyQt4 import QtGui
from PyQt4 import QtCore
@@ -11,4 +11,5 @@
from sas.qtgui.SlicerModel import SlicerModel
+MIN_PHI = 0.05
class SectorInteractor(_BaseInteractor, SlicerModel):
@@ -28,15 +29,15 @@
# Compute qmax limit to reset the graph
- x = math.pow(max(self.base.data.xmax,
- math.fabs(self.base.data.xmin)), 2)
- y = math.pow(max(self.base.data.ymax,
- math.fabs(self.base.data.ymin)), 2)
- self.qmax = math.sqrt(x + y)
+ x = numpy.power(max(self.base.data.xmax,
+ numpy.fabs(self.base.data.xmin)), 2)
+ y = numpy.power(max(self.base.data.ymax,
+ numpy.fabs(self.base.data.ymin)), 2)
+ self.qmax = numpy.sqrt(x + y)
# Number of points on the plot
self.nbins = 20
# Angle of the middle line
- self.theta2 = math.pi / 3
+ self.theta2 = numpy.pi / 3
# Absolute value of the Angle between the middle line and any side line
- self.phi = math.pi / 12
+ self.phi = numpy.pi / 12
# Middle line
self.main_line = LineInteractor(self, self.axes, color='blue',
@@ -135,6 +136,6 @@
nbins = 20
sect = SectorQ(r_min=0.0, r_max=radius,
- phi_min=phimin + math.pi,
- phi_max=phimax + math.pi, nbins=nbins)
+ phi_min=phimin + numpy.pi,
+ phi_max=phimax + numpy.pi, nbins=nbins)
sector = sect(self.base.data)
@@ -209,10 +210,10 @@
# Always make sure that the left and the right line are at phi
# angle of the middle line
- if math.fabs(self.left_line.phi) != math.fabs(self.right_line.phi):
+ if numpy.fabs(self.left_line.phi) != numpy.fabs(self.right_line.phi):
msg = "Phi left and phi right are different"
msg += " %f, %f" % (self.left_line.phi, self.right_line.phi)
raise ValueError, msg
- params["Phi [deg]"] = self.main_line.theta * 180 / math.pi
- params["Delta_Phi [deg]"] = math.fabs(self.left_line.phi * 180 / math.pi)
+ params["Phi [deg]"] = self.main_line.theta * 180 / numpy.pi
+ params["Delta_Phi [deg]"] = numpy.fabs(self.left_line.phi * 180 / numpy.pi)
params["nbins"] = self.nbins
return params
@@ -226,6 +227,12 @@
values the user assigned to the slicer.
"""
- main = params["Phi [deg]"] * math.pi / 180
- phi = math.fabs(params["Delta_Phi [deg]"] * math.pi / 180)
+ main = params["Phi [deg]"] * numpy.pi / 180
+ phi = numpy.fabs(params["Delta_Phi [deg]"] * numpy.pi / 180)
+
+ # phi should not be too close.
+ if numpy.fabs(phi) < MIN_PHI:
+ phi = MIN_PHI
+ params["Delta_Phi [deg]"] = MIN_PHI
+
self.nbins = int(params["nbins"])
self.main_line.theta = main
@@ -241,4 +248,5 @@
def draw(self):
"""
+ Redraw canvas
"""
self.base.draw()
@@ -254,5 +262,5 @@
"""
def __init__(self, base, axes, color='black', zorder=5, r=1.0,
- phi=math.pi / 4, theta2=math.pi / 3):
+ phi=numpy.pi / 4, theta2=numpy.pi / 3):
"""
"""
@@ -272,8 +280,8 @@
self.phi = phi
# End points polar coordinates
- x1 = self.radius * math.cos(self.theta)
- y1 = self.radius * math.sin(self.theta)
- x2 = -1 * self.radius * math.cos(self.theta)
- y2 = -1 * self.radius * math.sin(self.theta)
+ x1 = self.radius * numpy.cos(self.theta)
+ y1 = self.radius * numpy.sin(self.theta)
+ x2 = -1 * self.radius * numpy.cos(self.theta)
+ y2 = -1 * self.radius * numpy.sin(self.theta)
# Defining a new marker
self.inner_marker = self.axes.plot([x1 / 2.5], [y1 / 2.5], linestyle='',
@@ -331,8 +339,8 @@
delta = 0
if right:
- self.phi = -1 * math.fabs(self.phi)
+ self.phi = -1 * numpy.fabs(self.phi)
#delta=-delta
else:
- self.phi = math.fabs(self.phi)
+ self.phi = numpy.fabs(self.phi)
if side:
self.theta = mline.theta + self.phi
@@ -347,8 +355,8 @@
else:
theta3 = self.theta2 + delta
- x1 = self.radius * math.cos(theta3)
- y1 = self.radius * math.sin(theta3)
- x2 = -1 * self.radius * math.cos(theta3)
- y2 = -1 * self.radius * math.sin(theta3)
+ x1 = self.radius * numpy.cos(theta3)
+ y1 = self.radius * numpy.sin(theta3)
+ x2 = -1 * self.radius * numpy.cos(theta3)
+ y2 = -1 * self.radius * numpy.sin(theta3)
self.inner_marker.set(xdata=[x1 / 2.5], ydata=[y1 / 2.5])
self.line.set(xdata=[x1, x2], ydata=[y1, y2])
@@ -377,5 +385,5 @@
Process move to a new position, making sure that the move is allowed.
"""
- self.theta = math.atan2(y, x)
+ self.theta = numpy.arctan2(y, x)
self.has_move = True
if not self.left_moving:
@@ -388,17 +396,17 @@
return
elif self.theta2 < 0 and self.theta > 0 and \
- (self.theta2 + 2 * math.pi - self.theta) >= math.pi / 2:
+ (self.theta2 + 2 * numpy.pi - self.theta) >= numpy.pi / 2:
self.restore()
return
elif self.theta2 < 0 and self.theta < 0 and \
- (self.theta2 - self.theta) >= math.pi / 2:
- self.restore()
- return
- elif self.theta2 > 0 and (self.theta2 - self.theta >= math.pi / 2 or \
- (self.theta2 - self.theta >= math.pi / 2)):
+ (self.theta2 - self.theta) >= numpy.pi / 2:
+ self.restore()
+ return
+ elif self.theta2 > 0 and (self.theta2 - self.theta >= numpy.pi / 2 or \
+ (self.theta2 - self.theta >= numpy.pi / 2)):
self.restore()
return
else:
- if self.theta < 0 and (self.theta + math.pi * 2 - self.theta2) <= 0:
+ if self.theta < 0 and (self.theta + numpy.pi * 2 - self.theta2) <= 0:
self.restore()
return
@@ -409,13 +417,13 @@
self.restore()
return
- elif self.theta - self.theta2 >= math.pi / 2 or \
- ((self.theta + math.pi * 2 - self.theta2) >= math.pi / 2 and \
+ elif self.theta - self.theta2 >= numpy.pi / 2 or \
+ ((self.theta + numpy.pi * 2 - self.theta2) >= numpy.pi / 2 and \
self.theta < 0 and self.theta2 > 0):
self.restore()
return
- self.phi = math.fabs(self.theta2 - self.theta)
- if self.phi > math.pi:
- self.phi = 2 * math.pi - math.fabs(self.theta2 - self.theta)
+ self.phi = numpy.fabs(self.theta2 - self.theta)
+ if self.phi > numpy.pi:
+ self.phi = 2 * numpy.pi - numpy.fabs(self.theta2 - self.theta)
self.base.base.update()
@@ -446,5 +454,5 @@
"""
def __init__(self, base, axes, color='black',
- zorder=5, r=1.0, theta=math.pi / 4):
+ zorder=5, r=1.0, theta=numpy.pi / 4):
"""
"""
@@ -458,8 +466,8 @@
self.scale = 10.0
# Inner circle
- x1 = self.radius * math.cos(self.theta)
- y1 = self.radius * math.sin(self.theta)
- x2 = -1 * self.radius * math.cos(self.theta)
- y2 = -1 * self.radius * math.sin(self.theta)
+ x1 = self.radius * numpy.cos(self.theta)
+ y1 = self.radius * numpy.sin(self.theta)
+ x2 = -1 * self.radius * numpy.cos(self.theta)
+ y2 = -1 * self.radius * numpy.sin(self.theta)
# Inner circle marker
self.inner_marker = self.axes.plot([x1 / 2.5], [y1 / 2.5], linestyle='',
@@ -502,8 +510,8 @@
if theta != None:
self.theta = theta
- x1 = self.radius * math.cos(self.theta)
- y1 = self.radius * math.sin(self.theta)
- x2 = -1 * self.radius * math.cos(self.theta)
- y2 = -1 * self.radius * math.sin(self.theta)
+ x1 = self.radius * numpy.cos(self.theta)
+ y1 = self.radius * numpy.sin(self.theta)
+ x2 = -1 * self.radius * numpy.cos(self.theta)
+ y2 = -1 * self.radius * numpy.sin(self.theta)
self.inner_marker.set(xdata=[x1 / 2.5], ydata=[y1 / 2.5])
@@ -533,5 +541,5 @@
Process move to a new position, making sure that the move is allowed.
"""
- self.theta = math.atan2(y, x)
+ self.theta = numpy.arctan2(y, x)
self.has_move = True
self.base.base.update()