diff --git a/Framework/PythonInterface/mantid/plots/mantidaxes.py b/Framework/PythonInterface/mantid/plots/mantidaxes.py index 6091bf75dd0b..a5132939c9fc 100644 --- a/Framework/PythonInterface/mantid/plots/mantidaxes.py +++ b/Framework/PythonInterface/mantid/plots/mantidaxes.py @@ -1325,7 +1325,7 @@ def _remove_matching_curve_from_creation_args(self, workspace_name, workspace_in :returns: None """ for index, creation_arg in enumerate(self.creation_args): # type: int, dict - if workspace_name == creation_arg["workspaces"]: + if "workspaces" in creation_arg and workspace_name == creation_arg["workspaces"]: if creation_arg.get("wkspIndex", -1) == workspace_index or creation_arg.get("specNum", -1) == spec_num: del self.creation_args[index] return diff --git a/qt/applications/workbench/workbench/plotting/figureinteraction.py b/qt/applications/workbench/workbench/plotting/figureinteraction.py index ae66d535a17b..1d4c8c79a265 100644 --- a/qt/applications/workbench/workbench/plotting/figureinteraction.py +++ b/qt/applications/workbench/workbench/plotting/figureinteraction.py @@ -874,8 +874,7 @@ def _change_plot_normalization(self, ax): for arg_set in ax.creation_args: if arg_set["function"] == "contour": continue - - if arg_set["workspaces"] in ax.tracked_workspaces: + if "workspaces" in arg_set and arg_set["workspaces"] in ax.tracked_workspaces: workspace = ads.retrieve(arg_set["workspaces"]) arg_set["distribution"] = is_normalized if "specNum" not in arg_set: diff --git a/qt/applications/workbench/workbench/plotting/figuremanager.py b/qt/applications/workbench/workbench/plotting/figuremanager.py index fb5d882417b2..5e255eca2314 100644 --- a/qt/applications/workbench/workbench/plotting/figuremanager.py +++ b/qt/applications/workbench/workbench/plotting/figuremanager.py @@ -605,39 +605,49 @@ def _reverse_axis_lines(ax): ax.add_line(line) def crosshair_toggle(self, on): - cid = self.canvas.mpl_connect("motion_notify_event", self.crosshair) - if not on: - self.canvas.mpl_disconnect(cid) - - def crosshair(self, event): - axes = self.canvas.figure.gca() - - # create a crosshair made from horizontal and verticle lines. - self.horizontal_line = axes.axhline(color="r", lw=1.0, ls="-") - self.vertical_line = axes.axvline(color="r", lw=1.0, ls="-") + if on: + # Create crosshair lines for each axes (except colorbars) + self._crosshair_lines = {} + for ax in self._axes_that_are_not_colour_bars(): + ax.set_autoscalex_on(False) + ax.set_autoscaley_on(False) + hline = ax.axhline(color="r", lw=1.0, ls="-", visible=False) + vline = ax.axvline(color="r", lw=1.0, ls="-", visible=False) + self._crosshair_lines[ax] = (hline, vline) + + self._crosshair_cid = self.canvas.mpl_connect("motion_notify_event", self.crosshair) + else: + if hasattr(self, "_crosshair_cid"): + self.canvas.mpl_disconnect(self._crosshair_cid) + del self._crosshair_cid - def set_cross_hair_visible(visible): - need_redraw = self.horizontal_line.get_visible() != visible - self.horizontal_line.set_visible(visible) - self.vertical_line.set_visible(visible) - return need_redraw + if hasattr(self, "_crosshair_lines"): + # Remove the crosshair lines + for hline, vline in self._crosshair_lines.values(): + hline.remove() + vline.remove() + del self._crosshair_lines - # if event is out-of-bound we update - if not event.inaxes: - need_redraw = set_cross_hair_visible(False) - if need_redraw: - axes.figure.canvas.draw() + self.canvas.draw_idle() + def crosshair(self, event): + if event.inaxes and event.xdata is not None and event.ydata is not None: + x = event.xdata + y = event.ydata + + # Update all crosshairs to same (x, y) + for ax, (hline, vline) in self._crosshair_lines.items(): + hline.set_ydata([y]) + vline.set_xdata([x]) + hline.set_visible(True) + vline.set_visible(True) else: - set_cross_hair_visible(True) - x, y = event.xdata, event.ydata - self.horizontal_line.set_ydata([y]) - self.vertical_line.set_xdata([x]) - self.canvas.draw() + # Hide all crosshairs when mouse is out of axes + for hline, vline in self._crosshair_lines.values(): + hline.set_visible(False) + vline.set_visible(False) - # after update we remove - self.horizontal_line.remove() - self.vertical_line.remove() + self.canvas.draw_idle() # ----------------------------------------------------------------------------- diff --git a/qt/applications/workbench/workbench/plotting/test/test_toolbar.py b/qt/applications/workbench/workbench/plotting/test/test_toolbar.py index fb506216bfb1..eb63b79819e3 100644 --- a/qt/applications/workbench/workbench/plotting/test/test_toolbar.py +++ b/qt/applications/workbench/workbench/plotting/test/test_toolbar.py @@ -132,14 +132,14 @@ def test_button_checked_for_plot_with_no_crosshair(self, mock_qappthread): self.assertTrue(self._is_crosshair_button_visible(fig)) @patch("workbench.plotting.figuremanager.QAppThreadCall") - def test_button_hiden_for_tiled_plots(self, mock_qappthread): + def test_button_for_tiled_plots(self, mock_qappthread): mock_qappthread.return_value = mock_qappthread fig, axes = plt.subplots(2) axes[0].plot([-10, 10], [1, 2]) axes[1].plot([3, 2, 1], [1, 2, 3]) # crosshair button should be hidden because this is a tiled plot - self.assertFalse(self._is_crosshair_button_visible(fig)) + self.assertTrue(self._is_crosshair_button_visible(fig)) self.assertFalse(self._is_crosshair_button_checked(fig)) @patch("workbench.plotting.figuremanager.QAppThreadCall") diff --git a/qt/applications/workbench/workbench/plotting/toolbar.py b/qt/applications/workbench/workbench/plotting/toolbar.py index f4ed4d1ad367..96a2fbaf023e 100644 --- a/qt/applications/workbench/workbench/plotting/toolbar.py +++ b/qt/applications/workbench/workbench/plotting/toolbar.py @@ -85,7 +85,7 @@ class WorkbenchNavigationToolbar(MantidNavigationToolbar): MantidNavigationTool("Fill Area", "Fill area under curves", "mdi.format-color-fill", "waterfall_fill_area", None), MantidStandardNavigationTools.SEPARATOR, MantidNavigationTool("Help", "Open plotting help documentation", "mdi.help", "launch_plot_help", None), - MantidNavigationTool("Crosshair", "Toggle crosshair", "mdi.plus", "toggle_crosshair", False), + MantidNavigationTool("Crosshair", "Toggle crosshair", "mdi.target", "toggle_crosshair", False), MantidNavigationTool("Hide", "Hide the plot", "mdi.eye", "hide_plot", None), ) @@ -234,10 +234,8 @@ def set_buttons_visibility(self, fig): self.set_fit_enabled(False) self.set_superplot_enabled(False) - # disable crosshair in tiled plots, 3D plots but keep it enabled in color contour plot - if (len(fig.get_axes()) > 1 and figure_type(fig) not in [FigureType.Contour]) or ( - figure_type(fig) in [FigureType.Surface, FigureType.Wireframe, FigureType.Mesh] - ): + # disable crosshair in 3D plots + if figure_type(fig) in [FigureType.Surface, FigureType.Wireframe, FigureType.Mesh]: self.set_crosshair_enabled(False) for ax in fig.get_axes():