Skip to content

Surface Plotting from Multiple Single-Spectrum Workspaces #38599

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 21 commits into from
Jan 27, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/source/release/v6.12.0/Workbench/New_features/38171.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
- Enabled surface and contour plotting in the `Plot Advanced` dialog when multiple single-spectrum workspaces are selected.
- Fixed a bug where selecting multiple workspaces in the ADS and plotting a wireframe would only result in one of the workspaces being plotted.
55 changes: 44 additions & 11 deletions qt/python/mantidqt/mantidqt/dialogs/spectraselectordialog.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,11 +100,35 @@ def __init__(self, workspaces, parent=None, show_colorfill_btn=False, overplot=F
self._on_specnums_changed()
self._on_wkspindices_changed()

# Check if workspace only has a single spectra, if true set it as first valid spectrum number
def update_spectrum_number_text(self):
if self.selection and (
(self.selection.wksp_indices and len(self.selection.wksp_indices) > 0)
or (self.selection.spectra and len(self.selection.spectra) > 0)
):
return

if not self._ui.specNums.text():
for ws in self._workspaces:
if ws.getNumberHistograms() == 1:
spectrum_number = ws.getSpectrum(0).getSpectrumNo()
self._ui.specNums.setText(str(spectrum_number))
self._parse_spec_nums()
break

def on_ok_clicked(self):
self.update_spectrum_number_text()

if self.selection is None:
QMessageBox.warning(self, "Invalid Input", "Please enter a valid workspace index or spectrum number.")
return

if self._check_number_of_plots(self.selection):
self.accept()

def on_plot_all_clicked(self):
self.update_spectrum_number_text()

selection = SpectraSelection(self._workspaces)
selection.spectra = self._plottable_spectra
selection.plot_type = self._ui.plotType.currentIndex()
Expand Down Expand Up @@ -252,21 +276,29 @@ def _on_specnums_changed(self):
ui.wkspIndices.clear()
ui.wkspIndicesValid.hide()

self._parse_spec_nums()
ui.specNumsValid.setVisible(not self._is_input_valid())
if self._is_input_valid() or ui.specNums.text() == "":
ui.specNumsValid.setVisible(False)
ui.specNumsValid.setToolTip("")
elif ui.plotType.currentText() == SURFACE or ui.plotType.currentText() == CONTOUR:
try:
self._parse_spec_nums()
except Exception as e:
logger.error(f"Error parsing spectrum numbers: {e}")
ui.specNumsValid.setToolTip("Invalid spectrum number input.")
ui.specNumsValid.setVisible(True)
ui.specNumsValid.setToolTip("Enter one spectrum number in " + ui.specNums.placeholderText())
ui.buttonBox.button(QDialogButtonBox.Ok).setEnabled(False)

spectrum_numbers = [ws.getSpectrumNumbers() for ws in self._workspaces]
unique_spectra = {tuple(numbers) for numbers in spectrum_numbers}

if len(unique_spectra) > 1:
ui.specNums.setEnabled(False)
ui.specNumsValid.setToolTip("Spectrum numbers differ across workspaces. Use 'Plot All' or workspace indices instead.")
else:
ui.specNumsValid.setVisible(True)
ui.specNumsValid.setToolTip("Not in " + ui.specNums.placeholderText())
ui.specNums.setEnabled(True)
ui.specNumsValid.setToolTip("")

ui.specNumsValid.setVisible(not self._is_input_valid())
ui.buttonBox.button(QDialogButtonBox.Ok).setEnabled(self._is_input_valid())

if self._advanced:
ui.advanced_options_widget._validate_custom_logs(self._ui.advanced_options_widget.ui.custom_log_line_edit.text())
ui.advanced_options_widget._validate_custom_logs(ui.advanced_options_widget.ui.custom_log_line_edit.text())

def _on_plot_type_changed(self, new_index):
if self._overplot:
Expand All @@ -290,7 +322,8 @@ def _on_plot_type_changed(self, new_index):
if self._ui.advanced_options_widget.ui.plot_axis_label_line_edit.text() == WORKSPACE_NAME:
self._ui.advanced_options_widget.ui.plot_axis_label_line_edit.setText(WORKSPACE_REFERENCE_NUMBER)

self._ui.buttonBox.button(QDialogButtonBox.YesToAll).setEnabled(False)
self._ui.buttonBox.button(QDialogButtonBox.YesToAll).setEnabled(True)

else:
self._ui.advanced_options_widget.ui.error_bars_check_box.setEnabled(True)
self._ui.advanced_options_widget.ui.plot_axis_label_line_edit.setEnabled(False)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -281,17 +281,17 @@ def test_ok_button_disabled_when_custom_log_values_contains_decreasing_values(se
ssd._ui.advanced_options_widget.ui.custom_log_line_edit.setText("2,1,3")
self.assertFalse(ssd._ui.buttonBox.button(QDialogButtonBox.Ok).isEnabled())

def test_plot_all_button_disabled_when_plot_type_is_surface(self):
def test_plot_all_button_enabled_when_plot_type_is_surface(self):
workspaces = [self._single_spec_ws] * 3
ssd = SpectraSelectionDialog(workspaces, advanced=True)
ssd._ui.plotType.setCurrentIndex(3)
self.assertFalse(ssd._ui.buttonBox.button(QDialogButtonBox.YesToAll).isEnabled())
self.assertTrue(ssd._ui.buttonBox.button(QDialogButtonBox.YesToAll).isEnabled())

def test_plot_all_button_disabled_when_plot_type_is_contour(self):
def test_plot_all_button_enabled_when_plot_type_is_contour(self):
workspaces = [self._single_spec_ws] * 3
ssd = SpectraSelectionDialog(workspaces, advanced=True)
ssd._ui.plotType.setCurrentIndex(4)
self.assertFalse(ssd._ui.buttonBox.button(QDialogButtonBox.YesToAll).isEnabled())
self.assertTrue(ssd._ui.buttonBox.button(QDialogButtonBox.YesToAll).isEnabled())

def test_ok_button_disabled_when_plot_type_is_surface_and_more_than_one_spectrum_number_entered(self):
workspaces = [self._multi_spec_ws] * 3
Expand Down
36 changes: 25 additions & 11 deletions qt/python/mantidqt/mantidqt/plotting/functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@

from mantid.kernel import Logger, ConfigService
from mantid.plots.datafunctions import add_colorbar_label
from mantid.plots.utility import get_single_workspace_log_value
from mantid.plots.utility import get_single_workspace_log_value, legend_set_draggable
from mantidqt.plotting.figuretype import figure_type, FigureType
from mantidqt.dialogs.spectraselectorutils import get_spectra_selection
from mantid.api import IMDHistoWorkspace
Expand Down Expand Up @@ -365,18 +365,32 @@ def plot_surface(workspaces, fig=None):
@manage_workspace_names
def plot_wireframe(workspaces, fig=None):
import matplotlib.pyplot as plt
from matplotlib import colormaps

for ws in workspaces:
if fig:
fig.clf()
ax = fig.add_subplot(111, projection="mantid3d")
else:
fig, ax = plt.subplots(subplot_kw={"projection": "mantid3d"})
cmap = colormaps["tab10"]
colors = [cmap(i / max(1, len(workspaces) - 1)) for i in range(len(workspaces))]

fig.set_layout_engine(layout="tight")
ax.plot_wireframe(ws)
ax.set_title(ws.name())
fig.show()
if fig:
fig.clf()
ax = fig.add_subplot(111, projection="mantid3d")
else:
fig, ax = plt.subplots(subplot_kw={"projection": "mantid3d"})

for i, ws in enumerate(workspaces):
try:
ax.plot_wireframe(ws, color=colors[i], label=ws.name())
except Exception as e:
LOGGER.error(f"Failed to plot workspace {ws.name()}: {e}")

if len(workspaces) > 1:
legend = ax.legend(loc="upper right", title="Workspaces")
legend_set_draggable(legend, True)

workspace_names = ", ".join(ws.name() for ws in workspaces)
ax.set_title(f"Wireframe Plot: {workspace_names}")

fig.set_layout_engine(layout="tight")
fig.show()

return fig

Expand Down
Loading