diff --git a/Framework/PythonInterface/plugins/algorithms/SortXAxis.py b/Framework/PythonInterface/plugins/algorithms/SortXAxis.py index ee803cb59e1246ccd5785d922c4efe1626ebf173..d7d20db04962973b56378fc41a837e66f764103b 100644 --- a/Framework/PythonInterface/plugins/algorithms/SortXAxis.py +++ b/Framework/PythonInterface/plugins/algorithms/SortXAxis.py @@ -1,8 +1,8 @@ #pylint: disable=no-init,invalid-name from __future__ import (absolute_import, division, print_function) -from mantid.api import * -from mantid.kernel import * +from mantid.api import AlgorithmFactory, MatrixWorkspaceProperty, PythonAlgorithm +from mantid.kernel import Direction, StringListValidator import numpy as np @@ -22,6 +22,11 @@ class SortXAxis(PythonAlgorithm): doc="Input workspace") self.declareProperty(MatrixWorkspaceProperty("OutputWorkspace", defaultValue="", direction=Direction.Output), doc="Sorted Output Workspace") + self.declareProperty("Ordering", + defaultValue="Ascending", + validator=StringListValidator(["Ascending", "Descending"]), + direction=Direction.Input, + doc="Ascending or descending sorting") def PyExec(self): input_ws = self.getProperty('InputWorkspace').value @@ -40,9 +45,14 @@ class SortXAxis(PythonAlgorithm): y_data = input_ws.readY(i) e_data = input_ws.readE(i) - indexes = x_data.argsort() + indexes = x_data.argsort() + + if self.getPropertyValue("Ordering") == "Descending": + self.log().information("Sort descending") + indexes = indexes[::-1] x_ordered = x_data[indexes] + if input_ws.isHistogramData(): max_index = np.argmax(indexes) indexes = np.delete(indexes, max_index) @@ -54,7 +64,12 @@ class SortXAxis(PythonAlgorithm): output_ws.setY(i, y_ordered) output_ws.setE(i, e_ordered) + if input_ws.hasDx(i): + dx = input_ws.readDx(i) + dx_ordered = dx[indexes] + output_ws.setDx(i, dx_ordered) + self.setProperty('OutputWorkspace', output_ws) -AlgorithmFactory.subscribe(SortXAxis()) +AlgorithmFactory.subscribe(SortXAxis) diff --git a/Framework/PythonInterface/test/python/plugins/algorithms/SortXAxisTest.py b/Framework/PythonInterface/test/python/plugins/algorithms/SortXAxisTest.py index 211ba767192a7a7e8d38e4611af7d7b84ccf2736..9b43e770f953ed20e7eaef4600dd635f58969ac8 100644 --- a/Framework/PythonInterface/test/python/plugins/algorithms/SortXAxisTest.py +++ b/Framework/PythonInterface/test/python/plugins/algorithms/SortXAxisTest.py @@ -1,16 +1,16 @@ from __future__ import (absolute_import, division, print_function) import unittest -from mantid.kernel import * -from mantid.api import * -from mantid.simpleapi import * +from mantid.simpleapi import AlgorithmManager, CreateWorkspace, DeleteWorkspace, SortXAxis + class SortXAxisTest(unittest.TestCase): + def test_x_ascending(self): - dataX = [1, 2, 3] # In ascending order, so y and e will need to be reversed. - dataY = [1, 2, 3] - dataE = [1, 2, 3] + dataX = [1., 2., 3.] # In ascending order, so y and e will need to be reversed. + dataY = [1., 2., 3.] + dataE = [1., 2., 3.] unsortedws = CreateWorkspace(DataX=dataX,DataY=dataY,DataE=dataE,UnitX='TOF',Distribution=True) # Run the algorithm sortedws = SortXAxis(InputWorkspace=unsortedws) @@ -24,11 +24,10 @@ class SortXAxisTest(unittest.TestCase): DeleteWorkspace(unsortedws) DeleteWorkspace(sortedws) - def test_x_descending(self): - dataX = [3, 2, 1] # In descending order, so y and e will need to be reversed. - dataY = [1, 2, 3] - dataE = [1, 2, 3] + dataX = [3., 2., 1.] # In descending order, so y and e will need to be reversed. + dataY = [1., 2., 3.] + dataE = [1., 2., 3.] unsortedws = CreateWorkspace(DataX=dataX,DataY=dataY,DataE=dataE,UnitX='TOF',Distribution=True) # Run the algorithm sortedws = SortXAxis(InputWorkspace=unsortedws) @@ -45,9 +44,9 @@ class SortXAxisTest(unittest.TestCase): DeleteWorkspace(sortedws) def test_on_multiple_spectrum(self): - dataX = [3, 2, 1, 3, 2, 1] # In descending order, so y and e will need to be reversed. - dataY = [1, 2, 3, 1, 2, 3] - dataE = [1, 2, 3, 1, 2, 3] + dataX = [3., 2., 1., 3., 2., 1.] # In descending order, so y and e will need to be reversed. + dataY = [1., 2., 3., 1., 2., 3.] + dataE = [1., 2., 3., 1., 2., 3.] unsortedws = CreateWorkspace(DataX=dataX,DataY=dataY,DataE=dataE,UnitX='TOF',Distribution=True, NSpec=2) dataY.reverse() dataE.reverse() @@ -70,11 +69,10 @@ class SortXAxisTest(unittest.TestCase): DeleteWorkspace(unsortedws) DeleteWorkspace(sortedws) - def test_sorts_x_histogram_ascending(self): - dataX = [1, 2, 3, 4] - dataY = [1, 2, 3] - dataE = [1, 2, 3] + dataX = [1., 2., 3., 4.] + dataY = [1., 2., 3.] + dataE = [1., 2., 3.] unsortedws = CreateWorkspace(DataX=dataX,DataY=dataY,DataE=dataE,UnitX='TOF',Distribution=False) # Run the algorithm sortedws = SortXAxis(InputWorkspace=unsortedws) @@ -90,9 +88,9 @@ class SortXAxisTest(unittest.TestCase): DeleteWorkspace(sortedws) def test_sorts_x_histogram_descending(self): - dataX = [4, 3, 2, 1] - dataY = [1, 2, 3] - dataE = [1, 2, 3] + dataX = [4., 3., 2., 1.] + dataY = [1., 2., 3.] + dataE = [1., 2., 3.] unsortedws = CreateWorkspace(DataX=dataX,DataY=dataY,DataE=dataE,UnitX='TOF',Distribution=False) # Run the algorithm sortedws = SortXAxis(InputWorkspace=unsortedws) @@ -113,9 +111,9 @@ class SortXAxisTest(unittest.TestCase): # Create unsorted workspace parent = AlgorithmManager.createUnmanaged('Load') create_ws_alg = parent.createChildAlgorithm("CreateWorkspace") - dataX = [4, 3, 2, 1] - dataY = [1, 2, 3] - dataE = [1, 2, 3] + dataX = [4., 3., 2., 1.] + dataY = [1., 2., 3.] + dataE = [1., 2., 3.] create_ws_alg.setProperty("DataX", dataX) create_ws_alg.setProperty("DataY", dataY) create_ws_alg.setProperty("DataE", dataE) @@ -137,5 +135,49 @@ class SortXAxisTest(unittest.TestCase): self.assertEqual(dataY, sortedY.tolist()) self.assertEqual(dataE, sortedE.tolist()) + def test_dx_multiple_spectrum(self): + dataX = [3, 2, 1, 3, 2, 1] # In descending order, so y and e will need to be reversed. + dataY = [1, 2, 3, 1, 2, 3] + dx = [1, 2, 3, 1, 2, 3] + unsortedws = CreateWorkspace(DataX=dataX, DataY=dataY, Dx=dx, UnitX='TOF', Distribution=True, NSpec=2) + dx.reverse() + # Run the algorithm + sortedws = SortXAxis(InputWorkspace=unsortedws) + # Check the resulting data values for 1st spectrum. + sortedDx = sortedws.readDx(0) + self.assertEqual(dx[0:3], sortedDx.tolist()) + # Check the resulting data values for 2nd spectrum. + sortedDx = sortedws.readDx(1) + self.assertEqual(dx[3:], sortedDx.tolist()) + DeleteWorkspace(unsortedws) + DeleteWorkspace(sortedws) + + def test_dx_histogram_ascending(self): + dataX = [1., 2., 3., 4.] + dataY = [1., 2., 3.] + dx = [1., 2., 3.] + unsortedws = CreateWorkspace(DataX=dataX, DataY=dataY, Dx=dx, UnitX='TOF', Distribution=False) + # Run the algorithm + sortedws = SortXAxis(InputWorkspace=unsortedws) + sortedDx = sortedws.readDx(0) + # Check the resulting data values. Sorting operation should have resulted in no changes + self.assertEqual(dx, sortedDx.tolist()) + DeleteWorkspace(unsortedws) + DeleteWorkspace(sortedws) + + def test_sort_descending(self): + dataX = [1., 2., 3., 4.] + dataY = [1., 2., 3.] + unsortedws = CreateWorkspace(DataX=dataX, DataY=dataY, UnitX='TOF', Distribution=False) + # Run the algorithm + sortedws = SortXAxis(InputWorkspace=unsortedws, Ordering="Descending") + sortedX = sortedws.readX(0) + sortedY = sortedws.readY(0) + # Check the resulting data values. Sorting operation should have resulted in no changes + self.assertEqual([4., 3., 2., 1.], sortedX.tolist()) + self.assertEqual([3., 2., 1.], sortedY.tolist()) + DeleteWorkspace(unsortedws) + DeleteWorkspace(sortedws) + if __name__ == '__main__': - unittest.main() \ No newline at end of file + unittest.main() diff --git a/docs/source/algorithms/SortXAxis-v1.rst b/docs/source/algorithms/SortXAxis-v1.rst index 7b14bd708d4c134a878730a0d16c99aef8ae72cd..a02d7ec28ed0c9a808d5e71f7c3f514d3f9a4df1 100644 --- a/docs/source/algorithms/SortXAxis-v1.rst +++ b/docs/source/algorithms/SortXAxis-v1.rst @@ -10,14 +10,12 @@ Description ----------- Clones the input :ref:`Matrix Workspaces <MatrixWorkspace>` and orders the -x-axis in an ascending fashion. Ensures that the y-axis and error data -is sorted in a consistent way with the x-axis. All x-values of the input -workspace MUST be in either a descending or ascending fashion before -passing to this algorithm. +x-axis in an ascending or descending fashion. Ensures that the y-axis and error data as well as optional Dx data +are sorted in a consistent way with the x-axis. This algorithm is for use with small workspaces loaded. It is particularly suitable for reformatting workspaces loaded via -:ref:`LoadAscii <algm-LoadAscii>`. Input workspaces must be a distribution. +:ref:`LoadAscii <algm-LoadAscii>`. Input workspaces must be point data. .. categories:: diff --git a/docs/source/release/v3.13.0/framework.rst b/docs/source/release/v3.13.0/framework.rst index 33076b1f065d313975c698f4ee31b774131e202e..476a2fb1aa9025c7322e2509f1b02899beb1ddbc 100644 --- a/docs/source/release/v3.13.0/framework.rst +++ b/docs/source/release/v3.13.0/framework.rst @@ -20,6 +20,7 @@ Algorithms - :ref:`ConvertToPointData <algm-ConvertToPointData>` and :ref:`ConvertToHistogram <algm-ConvertToHistogram>` now propagate the Dx errors to the output. - The algorithm :ref:`CreateWorkspace <algm-CreateWorkspace>` can now optionally receive the Dx errors. +- The algorithm :ref:`SortXAxis <algm-SortXAxis>` has a new input option that allows ascending (default) and descending sorting. Furthermore, Dx values will be considered if present. The documentation needed to be corrected. :ref:`Release 3.13.0 <v3.13.0>`