I'm creating a set of axes in a figure and assigning a callback for its 'ButtonDownFcn'
property like so:
HRaxes = axes('Parent', Figure, 'Position', [.05 .60 .9 .35],...
'XLimMode', 'manual', 'ButtonDownFcn', @HR_ButtonDown);
Where the callback function is defined as such:
function HR_ButtonDown(hObject, eventData)
%# Do some stuff here when the axes is clicked on...
end
The callback works fine until I plot something on the axes like so:
plot(HRaxes, data.HR_X, data.HR_Y, 'b');
After which the callback doesn't trigger anymore when I click on the axes. What's going wrong and how can I fix it?
The main problem here is that the function PLOT is a high-level plotting function, meaning that it adds objects to the plot and will modify existing plot settings. If you look at the 'NextPlot'
property for axes objects, you will see that it has three settings that determine how high-level plotting functions can affect the axes object:
add
— Use the existing axes to draw graphics objects.
replace
— Reset all axes properties except Position
to their defaults and delete all axes children before displaying graphics (equivalent to cla reset
).
replacechildren
— Remove all child objects, but do not reset axes properties (equivalent to cla
).
Since 'replace'
is the default setting, the handle you set for the 'ButtonDownFcn'
callback gets reset to nothing when you call PLOT, thus turning off the button-click behavior. There are two ways you can avoid this:
Setting the 'NextPlot'
property of the axes to either 'add'
(to add to the existing plot objects) or 'replacechildren'
(to replace the existing plot objects but keep the current axes property settings) before you make your call to PLOT.
HRaxes = axes('Parent', Figure, 'Position', [.05 .60 .9 .35],...
'XLimMode', 'manual', 'ButtonDownFcn', @HR_ButtonDown,...
'NextPlot', 'add');
plot(HRaxes, data.HR_X, data.HR_Y, 'b');
Using a lower-level plotting routine (such as LINE) that doesn't modify existing plot properties:
HRaxes = axes('Parent', Figure, 'Position', [.05 .60 .9 .35],...
'XLimMode', 'manual', 'ButtonDownFcn', @HR_ButtonDown);
line(data.HR_X, data.HR_Y, 'Parent', HRaxes, 'Color', 'b');
@David Snyder, observe that an image
object can have a ButtonDownFcn
callback property as well. Then in your callback you can have access to the corresponding axes
property throught Parent
property or ancestor
function. For instance, say you want to use in your ButtonDownFcn callback the position of the pixel and the button you clicked with.
When you plot the image, use
imh = image(some_image);
set(imh,'ButtonDownFcn',@position_and_button);
where you defined your callback somewhere else
function position_and_button(hObject,eventdata)
Position = get( ancestor(hObject,'axes'), 'CurrentPoint' );
Button = get( ancestor(hObject,'figure'), 'SelectionType' );
%# do stuff with Position and Button