# Show mouse position in another subplot

137 views (last 30 days)
Stefan Lang on 2 Oct 2020
Commented: Ameer Hamza on 5 Oct 2020
I have a plot with two subplots, one frontal xray and one sagital xray, both with the same height, taken at the some moment. Hence y position in subplot 1 equals y position subplot 2.
I have to mark some points in subplot 1, but while moving my mouse in subplot 1, i want to show a (also moving) horizontal line in sublot 2, indicating the y value of the current mouse position from subplot 1. How can i make this?

Ameer Hamza on 2 Oct 2020
You can use WindowButtonMotionFcn callback if figure. Run the following example
f = figure();
ax_up = subplot(2, 1, 1);
hold(ax_up);
ax_up.YLim = [0 2];
ax_down = subplot(2, 1, 2);
hold(ax_down);
ax_down.YLim = [0 2];
l = yline(0, 'r');
f.WindowButtonMotionFcn = @(fig, eve) btnCb(fig, eve, ax_up, l);
function btnCb(~, ~, ax_up, l_h)
y = ax_up.CurrentPoint(1, 2);
if (ax_up.YLim(1) < y) && (y < ax_up.YLim(2))
l_h.Value = y;
end
end
Ameer Hamza on 5 Oct 2020
Following shows the line on both axes
f = figure();
ax_up = subplot(2, 1, 1);
hold(ax_up);
ax_up.YLim = [0 2];
l1 = plot([0 1], [0 0], 'r');
ax_down = subplot(2, 1, 2);
hold(ax_down);
ax_down.YLim = [0 2];
l2 = plot([0 1], [0 0], 'r');
f.WindowButtonMotionFcn = @(fig, eve) btnCb(fig, eve, ax_up, l1, l2);
function btnCb(~, ~, ax_up, l1, l2)
y = ax_up.CurrentPoint(1, 2);
if (ax_up.YLim(1) < y) && (y < ax_up.YLim(2))
l1.YData = [y y];
l2.YData = [y y];
end
end

Adam Danz on 2 Oct 2020
Edited: Adam Danz on 2 Oct 2020
Here's a full demo that tracks mouse movement in axis #1 and replicates it in axis #2. The windowbuttondownfcn function updates the position of xline and yline objects in both axes.
You can easily remove one of the reference lines or the line labels if they are not desired.
A right and left mouse click on axis #1 will turn the tracking off/on.
Key components:
1. linkaxes(ax,'xy') - ensures the axis limits remain the same between axes (use 'y' to link y-axis only).
2. hlink = linkprop() - used to yoke the x and y lines between the axes so when the position of those lines changes in axis #1, the lines in ax #2 follows. The hlink objects must be stored in axis #1 as the inline comments indicate. % Create two axes
clf()
ax(1) = subplot(1,2,1);
title('Track mouse movement')
grid on
ax(2) = subplot(1,2,2);
grid on
% Set up crosshairs on each axis at the edges
gobj(1,1) = xline(ax(1),min(xlim(ax(1))), 'k-');
gobj(1,2) = yline(ax(1),min(ylim(ax(1))), 'k-');
gobj(2,1) = xline(ax(2),min(xlim(ax(2))), 'k-');
gobj(2,2) = yline(ax(2),min(ylim(ax(2))), 'k-');
% Assign windowbuttonmotion fcn on axis #1
set(ax(1).Parent,'windowbuttonmotionfcn', {@mouseMove, ax, gobj});
% Assign mouse button functions to start/stop tracking
WindowButtonMotionFcnInput = {@mouseMove, ax, gobj};
set(ax(1).Parent,'windowbuttondownfcn', {@startStopMouseMove, WindowButtonMotionFcnInput})
function mouseMove(~, ~, ax, gobj)
% Responds to mouse movement in axis #1
% ax is a vector of subplot handles; ax(1) tracks mouse movement, ax(2) follows.
% gobj(1,1) is xline in ax 1
% gobj(1,2) is yline in ax 1
% Get mouse coordinate
C = ax(1).CurrentPoint;
x = C(1,1);
y = C(1,2);
% If mouse isn't on axis #1, do nothing.
if x < ax(1).XLim(1) || x > ax(1).XLim(2) || y < ax(1).YLim(1) || y > ax(1).YLim(2)
return
end
% Update crosshairs (cross hairs in ax 2 are yoked).
gobj(1,1).Value = x;
gobj(1,1).Label = x;
gobj(1,2).Value = y;
gobj(1,2).Label = y;
end
function startStopMouseMove(hobj,~,WindowButtonMotionFcnInput)
% Turns mouse tracking off (right mouse button) and on (left mouse button)
buttonID = hobj.SelectionType;
switch buttonID
case 'normal' %left mouse button
% Start interactivity
set(hobj,'windowbuttonmotionfcn', WindowButtonMotionFcnInput);
case 'alt' % right mouse button
% Stop interactivity
set(hobj,'windowbuttonmotionfcn', []);
end
end

Mario Malic on 2 Oct 2020
Edited: Mario Malic on 2 Oct 2020
Here's something to get you started, this code does the following:
These two callbacks obtains the X and Y coordinates, twice - When the mouse button is pressed, and when the mouse button is released. You can create a helper function and call it within the callback to update the current values of X and Y.
properties (Access = public)
X_Start = [];
Y_Start = [];
X_End = [];
Y_End = [];
end
% Callback function: UIFigure, UIFigure
function UIFigureWindowButtonDown(app, event)
ax = app.UIFigure.CurrentAxes; % Gets the data from clicked axes
Start_Points = ax.CurrentPoint;
app.X_Start = Start_Points(1,1);
app.Y_Start = Start_Points(1,2);
HelperFun(app)
end
% Window button up function: UIFigure
function UIFigureWindowButtonUp(app, event)
ax = app.UIFigure.CurrentAxes; % Gets the data from clicked axes
End_Points = ax.CurrentPoint;
app.X_End = End_Points(1,1);
app.Y_End = End_Points(1,2);
% command to plot on right
end
function HelperFun(app)
% Check if key is pressed
while(Key_Pressed)
% get x and y values
% update the plot however you want to
end
end
Edit: WindowButtonMotionFcn callback seems like the way to go