From b96f7d8374043f9b5e66d2f16d6af8ece7fe0d64 Mon Sep 17 00:00:00 2001 From: Martyn Gigg Date: Wed, 23 Apr 2014 12:43:16 +0100 Subject: [PATCH] Implement a Python plot2D command for colourfill-type plots This avoids having to create a matrix first. Refs #9319 --- Code/Mantid/MantidPlot/CMakeLists.txt | 3 +- Code/Mantid/MantidPlot/mantidplot.py | 44 ++++++++++- .../Mantid/MantidPlot/src/Mantid/MantidUI.cpp | 26 +++++-- Code/Mantid/MantidPlot/src/Mantid/MantidUI.h | 3 +- Code/Mantid/MantidPlot/src/qti.sip | 4 +- .../MantidPlot/test/MantidPlot2DPlotTest.py | 73 +++++++++++++++++++ 6 files changed, 141 insertions(+), 12 deletions(-) create mode 100644 Code/Mantid/MantidPlot/test/MantidPlot2DPlotTest.py diff --git a/Code/Mantid/MantidPlot/CMakeLists.txt b/Code/Mantid/MantidPlot/CMakeLists.txt index c7b226b5a9f2..1b7229ffe5dd 100644 --- a/Code/Mantid/MantidPlot/CMakeLists.txt +++ b/Code/Mantid/MantidPlot/CMakeLists.txt @@ -916,7 +916,8 @@ set ( MANTIDPLOT_TEST_PY_FILES MantidPlotInstrumentViewTest.py MantidPlotSliceViewerTest.py MantidPlot1DPlotTest.py - MantidPlotProxiesTest.py + MantidPlot2DPlotTest.py + MantidPlotProxiesTest.py MantidPlotPythonImportTest.py MantidPlotFoldersTest.py ) diff --git a/Code/Mantid/MantidPlot/mantidplot.py b/Code/Mantid/MantidPlot/mantidplot.py index 3f94b59e9ef5..012c62c8465b 100644 --- a/Code/Mantid/MantidPlot/mantidplot.py +++ b/Code/Mantid/MantidPlot/mantidplot.py @@ -186,7 +186,7 @@ def plot(source, *args, **kwargs): else: return plotSpectrum(source, *args, **kwargs) -#----------------------------------------------------------------------------- +#---------------------------------------------------------------------------------------------------- def plotSpectrum(source, indices, error_bars = False, type = -1, window = None, clearWindow = False): """Open a 1D Plot of a spectrum in a workspace. @@ -213,18 +213,56 @@ def plotSpectrum(source, indices, error_bars = False, type = -1, window = None, if window != None: window = window._getHeldObject() - graph = proxies.Graph(threadsafe_call(_qti.app.mantidUI.plotSpectraList, workspace_names, index_list, error_bars, type, window, clearWindow)) + graph = proxies.Graph(threadsafe_call(_qti.app.mantidUI.plotSpectraList, + workspace_names, index_list, error_bars, + type, window, clearWindow)) if graph._getHeldObject() == None: raise RuntimeError("Cannot create graph, see log for details.") else: return graph +#---------------------------------------------------------------------------------------------------- +def plot2D(source, style = -1, window = None): + """Open a 2D plot of the given workspace(s) + + Produces a 2D histogram for each of the given workspaces + + Args: + source: workspace or name of a workspace + style: Indicates the type of plot required. Default=ColorMap + window: window used for plotting. If None a new one will be created + Returns: + If a single workspace is specified then the handle is returned, otherwise a list + of handles for each new window is returned + """ + names = getWorkspaceNames(source) + if len(names) == 0: + raise ValueError("No workspace names given to plot") + + # Unwrap the window object, if any specified + if window != None: + window = window._getHeldObject() + + handles = [] + cfunc = _qti.app.mantidUI.drawSingleColorFillPlot + for name in names: + g = proxies.Graph(threadsafe_call(cfunc, name, style, window)) + if g: + handles.append(g) + else: + raise RuntimeError("Cannot create graph from workspace '%s'" % name) + + if len(handles) == 1: return handles[0] + else: return handles + +#---------------------------------------------------------------------------------------------------- + # IPython couldn't correctly display complex enum value in doc pop-up, so we extract integer value # of enum manually. DEFAULT_MD_NORMALIZATION = int(mantid.api.MDNormalization.VolumeNormalization) def plotMD(source, plot_axis=-2, normalization = DEFAULT_MD_NORMALIZATION, error_bars = False, window = None, - clearWindow = False): + clearWindow = False): """Open a 1D plot of a MDWorkspace. Args: diff --git a/Code/Mantid/MantidPlot/src/Mantid/MantidUI.cpp b/Code/Mantid/MantidPlot/src/Mantid/MantidUI.cpp index 20cd50813f97..b9c9fa7edc34 100644 --- a/Code/Mantid/MantidPlot/src/Mantid/MantidUI.cpp +++ b/Code/Mantid/MantidPlot/src/Mantid/MantidUI.cpp @@ -3189,17 +3189,31 @@ void MantidUI::drawColorFillPlots(const QStringList & wsNames, Graph::CurveType * Draw a single ColorFill plot for the named workspace * @param wsName :: The name of the workspace which provides data for the plot * @param curveType :: The type of curve +* @param window :: An optional pointer to a plot window. If not NULL the window is cleared +* and reused * @returns A pointer to the created plot */ -MultiLayer* MantidUI::drawSingleColorFillPlot(const QString & wsName, Graph::CurveType curveType) +MultiLayer* MantidUI::drawSingleColorFillPlot(const QString & wsName, Graph::CurveType curveType, + MultiLayer* window) { auto workspace = boost::dynamic_pointer_cast(getWorkspace(wsName)); if(!workspace) return NULL; QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); - auto * ml = appWindow()->multilayerPlot(appWindow()->generateUniqueName( wsName + "-")); - ml->setCloseOnEmpty(true); - Graph *plot = ml->activeGraph(); + if(window == NULL) + { + window = appWindow()->multilayerPlot(appWindow()->generateUniqueName( wsName + "-")); + window->setCloseOnEmpty(true); + } + else + { + // start fresh layer + window->setWindowTitle(appWindow()->generateUniqueName( wsName + "-")); + window->setLayersNumber(0); + window->addLayer(); + } + + Graph *plot = window->activeGraph(); appWindow()->setPreferences(plot); plot->setTitle(wsName); @@ -3228,14 +3242,14 @@ MultiLayer* MantidUI::drawSingleColorFillPlot(const QString & wsName, Graph::Cur plot->plotSpectrogram(spgrm, curveType); connect(spgrm, SIGNAL(removeMe(Spectrogram*)), plot, SLOT(removeSpectrogram(Spectrogram*))); - connect(plot, SIGNAL(curveRemoved()), ml, + connect(plot, SIGNAL(curveRemoved()), window, SLOT(maybeNeedToClose()), Qt::QueuedConnection); appWindow()->setSpectrogramTickStyle(plot); plot->setAutoScale(); QApplication::restoreOverrideCursor(); - return ml; + return window; } /** Create a 1d graph form specified spectra in a MatrixWorkspace diff --git a/Code/Mantid/MantidPlot/src/Mantid/MantidUI.h b/Code/Mantid/MantidPlot/src/Mantid/MantidUI.h index f6a8b744d933..4d1625832172 100644 --- a/Code/Mantid/MantidPlot/src/Mantid/MantidUI.h +++ b/Code/Mantid/MantidPlot/src/Mantid/MantidUI.h @@ -209,7 +209,8 @@ class MantidUI:public QObject /// Draw a color fill plot for each of the listed workspaces void drawColorFillPlots(const QStringList & wsNames, Graph::CurveType curveType = Graph::ColorMap); /// Draw a color fill plot for the named workspace - MultiLayer* drawSingleColorFillPlot(const QString & wsName, Graph::CurveType curveType = Graph::ColorMap); + MultiLayer* drawSingleColorFillPlot(const QString & wsName, Graph::CurveType curveType = Graph::ColorMap, + MultiLayer* window = NULL); // Create a 1d graph form specified spectra in a MatrixWorkspace MultiLayer* plotSpectraRange(const QString& wsName, int i0, int i1, bool errs=true, bool distr=false); diff --git a/Code/Mantid/MantidPlot/src/qti.sip b/Code/Mantid/MantidPlot/src/qti.sip index fbbfac66fe87..26c58a21eb23 100644 --- a/Code/Mantid/MantidPlot/src/qti.sip +++ b/Code/Mantid/MantidPlot/src/qti.sip @@ -1610,11 +1610,13 @@ public: MultiLayer* plotBin(const QString&,const QList&,bool = false,Graph::CurveType style = Graph::Unspecified, MultiLayer* window = NULL, bool clearWindow = false); + MultiLayer* drawSingleColorFillPlot(const QString & name, Graph::CurveType style = Graph::ColorMap, + MultiLayer* window = NULL); + MultiLayer* plotMDList(const QList& wsNames, const int plotAxis, const Mantid::API::MDNormalization normalization, const bool showErrors, MultiLayer* window = NULL, bool clearWindow = false); - MultiLayer* mergePlots(MultiLayer*, MultiLayer*); void convertToWaterfall(MultiLayer*); diff --git a/Code/Mantid/MantidPlot/test/MantidPlot2DPlotTest.py b/Code/Mantid/MantidPlot/test/MantidPlot2DPlotTest.py new file mode 100644 index 000000000000..d1ba2981e8bf --- /dev/null +++ b/Code/Mantid/MantidPlot/test/MantidPlot2DPlotTest.py @@ -0,0 +1,73 @@ +""" +Test of basic 2D plotting methods in MantidPlot +""" +import mantidplottests +from mantidplottests import * +import time +import numpy as np +from PyQt4 import QtGui, QtCore + +# =============== Create a fake workspace to plot ======================= +X1 = np.linspace(0,10, 100) +Y1 = 1000*(np.sin(X1)**2) + X1*10 +X1 = np.append(X1, 10.1) + +X2 = np.linspace(2,12, 100) +Y2 = 500*(np.cos(X2/2.)**2) + 20 +X2 = np.append(X2, 12.10) + +X = np.append(X1, X2) +Y = np.append(Y1, Y2) +E = np.sqrt(Y) + +CreateWorkspace(OutputWorkspace="fake", DataX=list(X), DataY=list(Y), DataE=list(E), NSpec=2, + UnitX="TOF", YUnitLabel="Counts", WorkspaceTitle="Faked data Workspace") + +class MantidPlot2DPlotTest(unittest.TestCase): + + def setUp(self): + self.g = None + + def tearDown(self): + """Clean up by closing the created window """ + windows = self.g + if type(self.g) != list: + windows = [self.g] + + for window in windows: + window.confirmClose(False) + window.close() + QtCore.QCoreApplication.processEvents() + + def test_plot2D_using_string_name(self): + self.g = plot2D("fake") + self.assertTrue(isinstance(self.g, proxies.Graph)) + + def test_plot2D_using_workspace_handle(self): + ws = mtd["fake"] + self.g = plot2D(ws) + self.assertTrue(isinstance(self.g, proxies.Graph)) + + def test_plot2D_multiple_workspaces(self): + CreateWorkspace(OutputWorkspace="fake2", DataX=list(X), DataY=list(Y), DataE=list(E), NSpec=2, + UnitX="TOF", YUnitLabel="Counts", WorkspaceTitle="Faked data Workspace") + plots = plot2D(["fake", "fake2"]) + self.g = plots + + self.assertTrue(isinstance(plots, list)) + self.assertEquals(2, len(plots)) + self.assertTrue(isinstance(plots[0], proxies.Graph)) + self.assertTrue(isinstance(plots[1], proxies.Graph)) + + DeleteWorkspace("fake2") + plots.pop() + + def test_plot2D_given_window_reuses_given_window(self): + win1 = plot2D("fake") + self.g = plot2D("fake", window=win1) + + open_wins = app.windows() + self.assertEquals(1, len(open_wins)) + +# Run the unit tests +mantidplottests.runTests(MantidPlot2DPlotTest)