diff --git a/Code/Mantid/Framework/MDAlgorithms/CMakeLists.txt b/Code/Mantid/Framework/MDAlgorithms/CMakeLists.txt
index b64ab8c3316d23e7cfa74ce1d5cf4b99708c84c9..12b1561a2dda2012e92d813f457e3f6b0520eb21 100644
--- a/Code/Mantid/Framework/MDAlgorithms/CMakeLists.txt
+++ b/Code/Mantid/Framework/MDAlgorithms/CMakeLists.txt
@@ -109,6 +109,7 @@ set ( SRC_FILES
 	src/SmoothMD.cpp
 	src/ThresholdMD.cpp
 	src/TransformMD.cpp
+	src/TransposeMD.cpp
 	src/UnaryOperationMD.cpp
 	src/UnitsConversionHelper.cpp
 	src/UserFunctionMD.cpp
@@ -227,6 +228,7 @@ set ( INC_FILES
 	inc/MantidMDAlgorithms/SmoothMD.h
 	inc/MantidMDAlgorithms/ThresholdMD.h
 	inc/MantidMDAlgorithms/TransformMD.h
+	inc/MantidMDAlgorithms/TransposeMD.h
 	inc/MantidMDAlgorithms/UnaryOperationMD.h
 	inc/MantidMDAlgorithms/UnitsConversionHelper.h
 	inc/MantidMDAlgorithms/Vector3DParameter.h
@@ -334,6 +336,7 @@ set ( TEST_FILES
 	TobyFitResolutionModelTest.h
 	TobyFitYVectorTest.h
 	TransformMDTest.h
+	TransposeMDTest.h
 	UnaryOperationMDTest.h
 	UnitsConversionHelperTest.h
 	WeightedMeanMDTest.h
diff --git a/Code/Mantid/Framework/MDAlgorithms/inc/MantidMDAlgorithms/TransposeMD.h b/Code/Mantid/Framework/MDAlgorithms/inc/MantidMDAlgorithms/TransposeMD.h
new file mode 100644
index 0000000000000000000000000000000000000000..a218102a80ebe1bf030fb1eed9e769258355213a
--- /dev/null
+++ b/Code/Mantid/Framework/MDAlgorithms/inc/MantidMDAlgorithms/TransposeMD.h
@@ -0,0 +1,50 @@
+#ifndef MANTID_MDALGORITHMS_TRANSPOSEMD_H_
+#define MANTID_MDALGORITHMS_TRANSPOSEMD_H_
+
+#include "MantidMDAlgorithms/DllConfig.h"
+#include "MantidAPI/Algorithm.h"
+namespace Mantid {
+namespace MDAlgorithms {
+
+/** TransposeMD : Transpose an MDWorkspace. Allows dimensions to be collapsed down.
+
+  Copyright © 2015 ISIS Rutherford Appleton Laboratory, NScD Oak Ridge
+  National Laboratory & European Spallation Source
+
+  This file is part of Mantid.
+
+  Mantid is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 3 of the License, or
+  (at your option) any later version.
+
+  Mantid is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+  File change history is stored at: <https://github.com/mantidproject/mantid>
+  Code Documentation is available at: <http://doxygen.mantidproject.org>
+*/
+class MANTID_MDALGORITHMS_DLL TransposeMD : public API::Algorithm {
+public:
+  TransposeMD();
+  virtual ~TransposeMD();
+
+  virtual const std::string name() const;
+  virtual int version() const;
+  virtual const std::string category() const;
+  virtual const std::string summary() const;
+
+private:
+  void init();
+  void exec();
+};
+
+} // namespace MDAlgorithms
+} // namespace Mantid
+
+#endif /* MANTID_MDALGORITHMS_TRANSPOSEMD_H_ */
diff --git a/Code/Mantid/Framework/MDAlgorithms/src/TransposeMD.cpp b/Code/Mantid/Framework/MDAlgorithms/src/TransposeMD.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..55c9619e4fdf79d8ca11fea6e521563f12eb93f3
--- /dev/null
+++ b/Code/Mantid/Framework/MDAlgorithms/src/TransposeMD.cpp
@@ -0,0 +1,148 @@
+#include "MantidMDAlgorithms/TransposeMD.h"
+#include "MantidKernel/ArrayProperty.h"
+#include "MantidKernel/ArrayBoundedValidator.h"
+#include "MantidAPI/IMDHistoWorkspace.h"
+#include "MantidAPI/IMDIterator.h"
+#include "MantidDataObjects/CoordTransformAligned.h"
+#include "MantidDataObjects/MDHistoWorkspace.h"
+#include "MantidGeometry/MDGeometry/IMDDimension.h"
+#include "MantidGeometry/MDGeometry/MDHistoDimension.h"
+
+#include <vector>
+#include <algorithm>
+#include <numeric>
+#include <boost/shared_ptr.hpp>
+#include <boost/make_shared.hpp>
+
+namespace Mantid {
+namespace MDAlgorithms {
+
+using namespace Mantid::Kernel;
+using namespace Mantid::API;
+using namespace Mantid::DataObjects;
+
+// Register the algorithm into the AlgorithmFactory
+DECLARE_ALGORITHM(TransposeMD)
+
+//----------------------------------------------------------------------------------------------
+/** Constructor
+ */
+TransposeMD::TransposeMD() {}
+
+//----------------------------------------------------------------------------------------------
+/** Destructor
+ */
+TransposeMD::~TransposeMD() {}
+
+//----------------------------------------------------------------------------------------------
+
+/// Algorithms name for identification. @see Algorithm::name
+const std::string TransposeMD::name() const { return "TransposeMD"; }
+
+/// Algorithm's version for identification. @see Algorithm::version
+int TransposeMD::version() const { return 1; }
+
+/// Algorithm's category for identification. @see Algorithm::category
+const std::string TransposeMD::category() const { return "MDAlgorithms"; }
+
+/// Algorithm's summary for use in the GUI and help. @see Algorithm::summary
+const std::string TransposeMD::summary() const {
+  return "Transpose the dimensions of a MDWorkspace to create a new output "
+         "MDWorkspace";
+}
+
+//----------------------------------------------------------------------------------------------
+/** Initialize the algorithm's properties.
+ */
+void TransposeMD::init() {
+  declareProperty(new WorkspaceProperty<IMDHistoWorkspace>("InputWorkspace", "",
+                                                           Direction::Input),
+                  "An input workspace.");
+
+  auto axisValidator = boost::make_shared<ArrayBoundedValidator<int>>();
+  axisValidator->clearUpper();
+  axisValidator->setLower(0);
+
+  declareProperty(new ArrayProperty<int>("Axes", std::vector<int>(0),
+                                         axisValidator, Direction::Input),
+                  "Permutes the axes according to the indexes given. Zero "
+                  "based indexing. Defaults to no transpose.");
+
+  declareProperty(new WorkspaceProperty<IMDHistoWorkspace>(
+                      "OutputWorkspace", "", Direction::Output),
+                  "An output workspace.");
+}
+
+//----------------------------------------------------------------------------------------------
+/** Execute the algorithm.
+ */
+void TransposeMD::exec() {
+  IMDHistoWorkspace_sptr inWSProp = getProperty("InputWorkspace");
+  auto inWS = boost::dynamic_pointer_cast<MDHistoWorkspace>(inWSProp);
+  if (!inWS) {
+    throw std::invalid_argument(
+        "Expect the InputWorkspace to be a MDHistoWorkspace");
+  }
+
+  size_t nDimsInput = inWS->getNumDims();
+  size_t nDimsOutput = inWS->getNumDims(); // The assumed default.
+  std::vector<int> axesInts = this->getProperty("Axes");
+  std::vector<size_t> axes(axesInts.begin(), axesInts.end());
+  Property *axesProperty = this->getProperty("Axes");
+  if (!axesProperty->isDefault()) {
+    if (axes.size() > nDimsInput) {
+      throw std::invalid_argument(
+          "More axis specified than dimensions are avaiable in the input");
+    }
+    auto it = std::max_element(axes.begin(), axes.end());
+    if (*it > nDimsInput) {
+      throw std::invalid_argument("One of the axis indexes specified indexes a "
+                                  "dimension outside the real dimension range");
+    }
+    nDimsOutput = axes.size();
+  } else {
+    axes = std::vector<size_t>(nDimsOutput);
+    std::iota(axes.begin(), axes.end(), 0);
+  }
+
+
+  std::vector<coord_t> origin;
+  std::vector<Geometry::IMDDimension_sptr> targetGeometry;
+  for (size_t i = 0; i < nDimsOutput; ++i) {
+    // Clone the dimension corresponding to the axis requested.
+    auto cloneDim = Geometry::IMDDimension_sptr(
+        new Geometry::MDHistoDimension(inWS->getDimension(axes[i]).get()));
+    targetGeometry.push_back(cloneDim);
+    // Set the same origin as we have on the input workspace
+    origin.push_back(coord_t(cloneDim->getMinimum()));
+  }
+
+  // Make the output workspace in the right shape.
+  auto outWS = MDHistoWorkspace_sptr(new MDHistoWorkspace(targetGeometry));
+
+  // Configure the coordinate transform.
+  std::vector<coord_t> scaling(nDimsOutput, 1); // No scaling
+  CoordTransformAligned coordTransform(nDimsInput, nDimsOutput, axes, origin,
+                                       scaling);
+
+  IMDIterator * inIterator = inWS->createIterator();
+  do{
+      auto center = inIterator->getCenter();
+      const coord_t* incoords = center.getBareArray();
+      std::vector<coord_t> outcoords(nDimsOutput);
+      coordTransform.apply(incoords, &outcoords[0]);
+
+      size_t index = outWS->getLinearIndexAtCoord(&outcoords[0]);
+      outWS->setSignalAt(index, inIterator->getSignal());
+      outWS->setErrorSquaredAt(index, inIterator->getError()*inIterator->getError());
+      // TODO more otherwise
+
+  }while(inIterator->next());
+
+
+  this->setProperty("OutputWorkspace",
+                    outWS);
+}
+
+} // namespace MDAlgorithms
+} // namespace Mantid
diff --git a/Code/Mantid/Framework/MDAlgorithms/test/TransposeMDTest.h b/Code/Mantid/Framework/MDAlgorithms/test/TransposeMDTest.h
new file mode 100644
index 0000000000000000000000000000000000000000..7f008da51b4f51b3858582cfa4ee112e58e9b633
--- /dev/null
+++ b/Code/Mantid/Framework/MDAlgorithms/test/TransposeMDTest.h
@@ -0,0 +1,174 @@
+#ifndef MANTID_MDALGORITHMS_TRANSPOSEMDTEST_H_
+#define MANTID_MDALGORITHMS_TRANSPOSEMDTEST_H_
+
+#include <cxxtest/TestSuite.h>
+#include <vector>
+
+#include "MantidMDAlgorithms/TransposeMD.h"
+#include "MantidTestHelpers/MDEventsTestHelper.h"
+#include "MantidGeometry/MDGeometry/MDTypes.h"
+
+using Mantid::MDAlgorithms::TransposeMD;
+using namespace Mantid::DataObjects;
+using namespace Mantid::API;
+
+class TransposeMDTest : public CxxTest::TestSuite {
+public:
+  // This pair of boilerplate methods prevent the suite being created statically
+  // This means the constructor isn't called when running other tests
+  static TransposeMDTest *createSuite() { return new TransposeMDTest(); }
+  static void destroySuite(TransposeMDTest *suite) { delete suite; }
+
+  void test_Init() {
+    TransposeMD alg;
+    TS_ASSERT_THROWS_NOTHING(alg.initialize())
+    TS_ASSERT(alg.isInitialized())
+  }
+
+  void test_valid_axes_lower_limit_throws() {
+    TransposeMD transposeMD;
+    transposeMD.initialize();
+    std::vector<int> axes;
+    axes.push_back(1); // should be fine.
+    TS_ASSERT_THROWS_NOTHING(transposeMD.setProperty("Axes", axes));
+    axes.push_back(-1); // Not a valid axis
+    TS_ASSERT_THROWS(transposeMD.setProperty("Axes", axes),
+                     std::invalid_argument &);
+  }
+
+  void test_too_many_dimension_indexes_throws() {
+    auto inputWS = MDEventsTestHelper::makeFakeMDHistoWorkspace(
+        1 /*signal*/, 2 /*numDims*/, 3 /*numBins in each dimension*/);
+
+    TransposeMD transposeMD;
+    transposeMD.setChild(true);
+    transposeMD.initialize();
+    transposeMD.setPropertyValue("OutputWorkspace", "dummy");
+    transposeMD.setProperty(
+        "Axes",
+        std::vector<int>(4, 1)); // 4-axis entries, but only 3 dimensions
+    transposeMD.setProperty("InputWorkspace", inputWS);
+    TS_ASSERT_THROWS(transposeMD.execute(), std::invalid_argument &);
+  }
+
+  void test_indexes_that_dont_exist_throws() {
+    auto inputWS = MDEventsTestHelper::makeFakeMDHistoWorkspace(
+        1 /*signal*/, 2 /*numDims*/, 3 /*numBins in each dimension*/);
+
+    TransposeMD transposeMD;
+    transposeMD.setChild(true);
+    transposeMD.initialize();
+    transposeMD.setPropertyValue("OutputWorkspace", "dummy");
+    transposeMD.setProperty("Axes",
+                            std::vector<int>(1, 3)); // Invalid index of 3!
+    transposeMD.setProperty("InputWorkspace", inputWS);
+    TSM_ASSERT_THROWS(
+        "Axis values can only be 0-2 for this ws. 3 is not valid.",
+        transposeMD.execute(), std::invalid_argument &);
+  }
+
+  void test_no_transpose() {
+    auto inputWS = MDEventsTestHelper::makeFakeMDHistoWorkspace(
+        1 /*signal*/, 2 /*numDims*/, 3 /*numBins in each dimension*/);
+
+    // Set some values. If transposed then these should end up elsewhere.
+    inputWS->setSignalAt(0, 2);
+    inputWS->setSignalAt(1, 2);
+
+    TransposeMD transposeMD;
+    transposeMD.setChild(true);
+    transposeMD.initialize();
+    transposeMD.setPropertyValue("OutputWorkspace", "dummy");
+    transposeMD.setProperty("InputWorkspace", inputWS);
+    transposeMD.execute();
+    IMDHistoWorkspace_sptr outputWS =
+        transposeMD.getProperty("OutputWorkspace");
+
+    // Lets check that the workspaces are essentially the same.
+    TS_ASSERT_EQUALS(inputWS->getNumDims(), outputWS->getNumDims());
+    TS_ASSERT_EQUALS(inputWS->getDimension(0)->getName(),
+                     outputWS->getDimension(0)->getName());
+    TS_ASSERT_EQUALS(inputWS->getDimension(1)->getName(),
+                     outputWS->getDimension(1)->getName());
+
+    // Data should be the same too.
+    TS_ASSERT_EQUALS(inputWS->getSignalAt(0), outputWS->getSignalAt(0));
+    TS_ASSERT_EQUALS(inputWS->getSignalAt(1), outputWS->getSignalAt(1));
+    TS_ASSERT_EQUALS(inputWS->getSignalAt(2), outputWS->getSignalAt(2));
+  }
+
+  void test_transpose_all() {
+    auto inputWS = MDEventsTestHelper::makeFakeMDHistoWorkspace(
+        1 /*signal*/, 2 /*numDims*/, 3 /*numBins in each dimension*/);
+
+    // Set some values. If transposed then these should end up elsewhere.
+    inputWS->setSignalAt(0, 2);
+    inputWS->setSignalAt(1, 2);
+
+    TransposeMD transposeMD;
+    transposeMD.setChild(true);
+    transposeMD.initialize();
+    transposeMD.setPropertyValue("OutputWorkspace", "dummy");
+    transposeMD.setProperty("InputWorkspace", inputWS);
+    std::vector<int> axes;
+    axes.push_back(1);
+    axes.push_back(0);
+    transposeMD.setProperty("Axes", axes);
+    transposeMD.execute();
+    IMDHistoWorkspace_sptr outputWS =
+        transposeMD.getProperty("OutputWorkspace");
+
+    // Lets check the output workspace
+    TS_ASSERT_EQUALS(inputWS->getNumDims(), outputWS->getNumDims());
+    TS_ASSERT_EQUALS(inputWS->getDimension(0)->getName(),
+                     outputWS->getDimension(axes[0])->getName());
+    TS_ASSERT_EQUALS(inputWS->getDimension(1)->getName(),
+                     outputWS->getDimension(axes[1])->getName());
+
+    // Data should be transposed.
+    TS_ASSERT_EQUALS(inputWS->getSignalAt(0), outputWS->getSignalAt(0));
+    TS_ASSERT_EQUALS(inputWS->getSignalAt(1), outputWS->getSignalAt(1 * 3));
+    TS_ASSERT_EQUALS(inputWS->getSignalAt(2), outputWS->getSignalAt(2));
+  }
+
+  void test_collapse() {
+
+    size_t nbins[3] = {3, 3, 1}; // last dimension integrated out
+    Mantid::coord_t min[3] = {0, 0, 0};
+    Mantid::coord_t max[3] = {10, 10, 5};
+    auto inputWS = MDEventsTestHelper::makeFakeMDHistoWorkspaceGeneral(3 /*ndims*/, 1 /*signal*/,
+                                                   1 /*errorSquared*/,
+                                                   nbins /*numBins*/, min, max);
+    // Set some values. If transposed then these should end up elsewhere.
+    inputWS->setSignalAt(0, 2);
+    inputWS->setSignalAt(1, 2);
+
+    TransposeMD transposeMD;
+    transposeMD.setChild(true);
+    transposeMD.initialize();
+    transposeMD.setPropertyValue("OutputWorkspace", "dummy");
+    transposeMD.setProperty("InputWorkspace", inputWS);
+    std::vector<int> axes;
+    axes.push_back(0);
+    axes.push_back(1);
+    transposeMD.setProperty("Axes", axes); // 0 and 1, but 2 not specified!
+    transposeMD.execute();
+    IMDHistoWorkspace_sptr outputWS =
+        transposeMD.getProperty("OutputWorkspace");
+
+    // Lets check that output workspace
+    TS_ASSERT_EQUALS(inputWS->getNumDims(), outputWS->getNumDims() + 1);
+    TS_ASSERT_EQUALS(inputWS->getDimension(0)->getName(),
+                     outputWS->getDimension(axes[0])->getName());
+    TS_ASSERT_EQUALS(inputWS->getDimension(1)->getName(),
+                     outputWS->getDimension(axes[1])->getName());
+
+    // Otherwise the data should be the same. We simply clipped off the
+    // integrated dimension.
+    TS_ASSERT_EQUALS(inputWS->getSignalAt(0), outputWS->getSignalAt(0));
+    TS_ASSERT_EQUALS(inputWS->getSignalAt(1), outputWS->getSignalAt(1));
+    TS_ASSERT_EQUALS(inputWS->getSignalAt(2), outputWS->getSignalAt(2));
+  }
+};
+
+#endif /* MANTID_MDALGORITHMS_TRANSPOSEMDTEST_H_ */