Skip to content

Commit e46f3ab

Browse files
Merge pull request #38186 from mantidproject/crosshair
added crosshair option in mantid
2 parents 843810f + 60b2e91 commit e46f3ab

File tree

4 files changed

+68
-4
lines changed

4 files changed

+68
-4
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
- A crosshair toggle option has been added in mantidplots

qt/applications/workbench/workbench/plotting/figuremanager.py

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,7 @@ def __init__(self, canvas, num):
232232
self.toolbar.sig_waterfall_conversion.connect(self.update_toolbar_waterfall_plot)
233233
self.toolbar.sig_change_line_collection_colour_triggered.connect(self.change_line_collection_colour)
234234
self.toolbar.sig_hide_plot_triggered.connect(self.hide_plot)
235+
self.toolbar.sig_crosshair_toggle_triggered.connect(self.crosshair_toggle)
235236
self.toolbar.setFloatable(False)
236237
tbs_height = self.toolbar.sizeHint().height()
237238
else:
@@ -251,9 +252,7 @@ def __init__(self, canvas, num):
251252
self.window.addDockWidget(Qt.LeftDockWidgetArea, self.fit_browser)
252253

253254
self.superplot = None
254-
255255
self.fit_browser.hide()
256-
257256
if matplotlib.is_interactive():
258257
self.window.show()
259258
canvas.draw_idle()
@@ -264,11 +263,9 @@ def notify_axes_change(fig):
264263
self.toolbar.update()
265264

266265
canvas.figure.add_axobserver(notify_axes_change)
267-
268266
# Register canvas observers
269267
self._fig_interaction = FigureInteraction(self)
270268
self._ads_observer = FigureManagerADSObserver(self)
271-
272269
self.window.raise_()
273270

274271
def full_screen_toggle(self):
@@ -603,6 +600,41 @@ def _reverse_axis_lines(ax):
603600
line.remove()
604601
ax.add_line(line)
605602

603+
def crosshair_toggle(self, on):
604+
cid = self.canvas.mpl_connect("motion_notify_event", self.crosshair)
605+
if not on:
606+
self.canvas.mpl_disconnect(cid)
607+
608+
def crosshair(self, event):
609+
axes = self.canvas.figure.gca()
610+
611+
# create a crosshair made from horizontal and verticle lines.
612+
self.horizontal_line = axes.axhline(color="r", lw=1.0, ls="-")
613+
self.vertical_line = axes.axvline(color="r", lw=1.0, ls="-")
614+
615+
def set_cross_hair_visible(visible):
616+
need_redraw = self.horizontal_line.get_visible() != visible
617+
self.horizontal_line.set_visible(visible)
618+
self.vertical_line.set_visible(visible)
619+
return need_redraw
620+
621+
# if event is out-of-bound we update
622+
if not event.inaxes:
623+
need_redraw = set_cross_hair_visible(False)
624+
if need_redraw:
625+
axes.figure.canvas.draw()
626+
627+
else:
628+
set_cross_hair_visible(True)
629+
x, y = event.xdata, event.ydata
630+
self.horizontal_line.set_ydata([y])
631+
self.vertical_line.set_xdata([x])
632+
self.canvas.draw()
633+
634+
# after update we remove
635+
self.horizontal_line.remove()
636+
self.vertical_line.remove()
637+
606638

607639
# -----------------------------------------------------------------------------
608640
# Figure control

qt/applications/workbench/workbench/plotting/test/test_toolbar.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,15 @@ def test_button_checked_for_plot_with_grid(self, mock_qappthread):
117117
# Grid button should be ON because we enabled the grid.
118118
self.assertTrue(self._is_grid_button_checked(fig))
119119

120+
@patch("workbench.plotting.figuremanager.QAppThreadCall")
121+
def test_button_checked_for_plot_with_no_crosshair(self, mock_qappthread):
122+
mock_qappthread.return_value = mock_qappthread
123+
124+
fig, axes = plt.subplots(subplot_kw={"projection": "mantid"})
125+
axes.plot([-10, 10], [1, 2])
126+
# Grid button should be OFF because we have not enabled the crosshair.
127+
self.assertFalse(self._is_crosshair_button_checked(fig))
128+
120129
@patch("workbench.plotting.figuremanager.QAppThreadCall")
121130
def test_button_checked_for_plot_with_grid_using_kwargs(self, mock_qappthread):
122131
mock_qappthread.return_value = mock_qappthread
@@ -266,6 +275,19 @@ def _is_button_enabled(cls, fig, button):
266275
fig_manager.toolbar.set_buttons_visibility(fig)
267276
return fig_manager.toolbar._actions[button].isEnabled()
268277

278+
@classmethod
279+
def _is_crosshair_button_checked(cls, fig):
280+
"""
281+
Create the figure manager and check whether its toolbar is toggled on or off for the given figure.
282+
We have to explicitly call set_button_visibility() here, which would otherwise be called within the show()
283+
function.
284+
"""
285+
canvas = MantidFigureCanvas(fig)
286+
fig_manager = FigureManagerWorkbench(canvas, 1)
287+
# This is only called when show() is called on the figure manager, so we have to manually call it here.
288+
fig_manager.toolbar.set_buttons_visibility(fig)
289+
return fig_manager.toolbar._actions["toggle_crosshair"].isChecked()
290+
269291

270292
if __name__ == "__main__":
271293
unittest.main()

qt/applications/workbench/workbench/plotting/toolbar.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ def _create_script_action(self, text, tooltip_text, mdi_icon, *args):
3434
class WorkbenchNavigationToolbar(MantidNavigationToolbar):
3535
sig_home_clicked = QtCore.Signal()
3636
sig_grid_toggle_triggered = QtCore.Signal(bool)
37+
sig_crosshair_toggle_triggered = QtCore.Signal(bool)
3738
sig_active_triggered = QtCore.Signal()
3839
sig_hold_triggered = QtCore.Signal()
3940
sig_toggle_fit_triggered = QtCore.Signal()
@@ -83,6 +84,7 @@ class WorkbenchNavigationToolbar(MantidNavigationToolbar):
8384
MantidNavigationTool("Fill Area", "Fill area under curves", "mdi.format-color-fill", "waterfall_fill_area", None),
8485
MantidStandardNavigationTools.SEPARATOR,
8586
MantidNavigationTool("Help", "Open plotting help documentation", "mdi.help", "launch_plot_help", None),
87+
MantidNavigationTool("Crosshair", "Toggle crosshair", "mdi.plus", "toggle_crosshair", False),
8688
MantidNavigationTool("Hide", "Hide the plot", "mdi.eye", "hide_plot", None),
8789
)
8890

@@ -93,6 +95,13 @@ def __init__(self, canvas, parent, coordinates=True):
9395
dpi_ratio = QtWidgets.QApplication.instance().desktop().physicalDpiX() / 100
9496
self.setIconSize(QtCore.QSize(int(24 * dpi_ratio), int(24 * dpi_ratio)))
9597

98+
def toggle_crosshair(self, enable=None):
99+
if enable is None:
100+
enable = self._actions["toggle_crosshair"].isChecked()
101+
else:
102+
self._actions["toggle_crosshair"].setChecked(enable)
103+
self.sig_crosshair_toggle_triggered.emit(enable)
104+
96105
def hide_plot(self):
97106
self.sig_hide_plot_triggered.emit()
98107

0 commit comments

Comments
 (0)