I'm trying to replace the pointer on a chart plot with a full crosshair (that is, a set of 2 perpendicular lines that stretch to the edges of the plot vertically and horizontally and follow the mouse cursor). Years ago, I was able to accomplish this with this line of code:
set(gcf,'Pointer','fullcross')
However, when I try to run this line now, I get the following message:
Warning: Full crosshair pointer is no longer supported. A crosshair pointer will be used instead.
I would really like to find an alternative way to implement this functionality, but have been unable to thus far. I have come across the following function: MYGINPUT, but it does not seem to accomplish what I'm looking for. Does anyone have any suggestions?
You can actually do this by adding a 'WindowButtonMotionFcn'
to your figure (assuming nothing else is using it) that will display crosshair lines in your axes when your mouse is over it. Here's a function that creates such functionality for all axes in a figure:
function full_crosshair(hFigure)
% Find axes children:
hAxes = findall(hFigure, 'Type', 'axes');
% Get all axes limits:
xLimits = get(hAxes, 'XLim');
xLimits = vertcat(xLimits{:});
yLimits = get(hAxes, 'YLim');
yLimits = vertcat(yLimits{:});
% Create lines (not displayed yet due to NaNs) and listeners:
for iAxes = 1:numel(hAxes)
hHoriz(iAxes) = line(xLimits(iAxes, :), nan(1, 2), 'Parent', hAxes(iAxes));
hVert(iAxes) = line(nan(1, 2), yLimits(iAxes, :), 'Parent', hAxes(iAxes));
listenObj(iAxes) = addlistener(hAxes(iAxes), {'XLim', 'YLim'}, ...
'PostSet', @(~, ~) update_limits(iAxes));
end
% Set callback on the axes parent to the nested function below:
set(hFigure, 'WindowButtonMotionFcn', @show_lines);
function update_limits(axesIndex)
xLimits(axesIndex, :) = get(hAxes(axesIndex), 'XLim');
yLimits(axesIndex, :) = get(hAxes(axesIndex), 'YLim');
set(hHoriz(axesIndex), 'XData', xLimits(axesIndex, :));
set(hVert(axesIndex), 'YData', yLimits(axesIndex, :));
end
function show_lines(~, ~)
% Get current cursor positions in axes:
cursorPos = get(hAxes, 'CurrentPoint');
cursorPos = vertcat(cursorPos{:});
cursorPos = cursorPos(1:2:end, 1:2);
% Determine if the cursor is within an axes:
inAxes = (cursorPos(:, 1) >= xLimits(:, 1)) & ...
(cursorPos(:, 1) <= xLimits(:, 2)) & ...
(cursorPos(:, 2) >= yLimits(:, 1)) & ...
(cursorPos(:, 2) <= yLimits(:, 2));
% Update lines and cursor:
if any(inAxes) % Cursor within an axes
set(hFigure, 'Pointer', 'custom', 'PointerShapeCData', nan(16));
set(hHoriz(inAxes), {'YData'}, num2cell(cursorPos(inAxes, 2)*[1 1], 2));
set(hVert(inAxes), {'XData'}, num2cell(cursorPos(inAxes, 1)*[1 1], 2));
set(hHoriz(~inAxes), 'YData', nan(1, 2));
set(hVert(~inAxes), 'XData', nan(1, 2));
else % Cursor outside axes
set(hFigure, 'Pointer', 'arrow');
set(hHoriz, 'YData', nan(1, 2));
set(hVert, 'XData', nan(1, 2));
end
end
end
If you do the following:
full_crosshair(gcf);
Then as you move the cursor over each axes in your figure the cursor will disappear and you will see two lines appear and track the mouse position. If any of the axes limits change, then the event listeners in the above code will detect and account for it. If axes are added to or removed from the figure, you will need to call full_crosshair
again to update 'WindowButtonMotionFcn'
accordingly.
Finally, you can turn it off by just clearing 'WindowButtonMotionFcn'
:
set(gcf, 'WindowButtonMotionFcn', []);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With