matlabmatlab-guidematlab-gui

How to use "ButtonDownFcn" in a populated GUI axes?


I have a very simple GUI made in guide where i have a plot function initiated by a pushbutton which plots a scatter plot in axes (called Method1axes1):

handles.plot = scatter(X,Y, 'parent', handles.Method1axes1);

Now I want the user to be able to click the axes (plot) to get en new larger figure. I tried the below code which is working if i DON'T plot in the axes first. As soon as I run the plot function the scatterplot appears in Method1axes1 but I can no longer click the figure.

% --- Executes on mouse press over axes background.
function Method1axes1_ButtonDownFcn(hObject, eventdata, handles)
figure
scatter(X,Y);

What am I doing wrong?


Solution

  • This is a kind of special case for MATLAB, and it is not extremely well documented.

    There are 2 things you need to consider:

    When you call PLOT, if the axes NextPlot property is set to 'replace' (which it is by default) most of the properties of the axes (including ButtonDownFcn) are reset to their default values.

    Change the axes NextPlot property to 'replacechildren' to avoid this, or set the ButtonDownFcn after calling PLOT, or use the low-level LINE function instead of the higher-level PLOT function.

    This is also discussed and explained here: Why does the ButtonDownFcn callback of my axes object stop working after plotting something?


    For your case, I tried set(axe_handle,'NextPlot','replacechildren') and it works ok to let the mouse click reach the ButtonDownFcn, but unfortunately it creates havoc with the axes limits and LimitModes ... so I opted for the second solution, which is to redefine the callback for ButtonDownFcn after every plot in the axes.


    So in summary, your code for the pushbutton1_Callback should be:

    function pushbutton1_Callback(hObject, eventdata, handles)
        % Whatever stuff you do before plotting
        % ...
        % Plot your data
        handles.plot = scatter(X,Y, 'parent', handles.Method1axes1);
        % Disable mouse click events for the "scatterplot" object
        set(handles.plot,'HitTest','off') ;
        % re-set the "ButtonDownFcn" callback
        set(handles.Method1axes1,'ButtonDownFcn',@(s,e) Method1axes1_ButtonDownFcn(s,e,handles) )
    

    And for your axes mouse click event, you might as well keep the handle of the new generated objects:

    function Method1axes1_ButtonDownFcn(hObject, eventdata, handles)
        handles.newfig    = figure ;
        handles.axes1copy = copyobj( handles.Method1axes1 , handles.newfig ) ;
    

    Note that instead of plotting a new set, I simply use the copyobj function, very handy when you need to reproduce a plot.


    Illustration:

    enter image description here