Question

Follow-up question from Matlab: Get coordinates of clicks in figure BUT keep button-callbacks.

Great code.

The function provided only outputs the 'button' of the last click. Is there a way to modify the code to output the specific mouse button clicked for every point selected?

Also, is there a way to have, say, a third input that can be used to specify that there are an unknown number of points to be chosen, and continue to select points until something like 'c' or 'return' is entered with the keyboard?

Was it helpful?

Solution

Regarding your second requirement, when a user presses a key, the control moves from the figure window to the command window, unless you are using waitforbuttonpress , which would unnecessarily complicate things. So an alternative solution could be suggested to use double clicks to signal the end of inputting coordinates. This is done in the modified version of the linked stackoverflow code shown next.

Code

function varargout = ginput_ax_mod2(ha,n)
if nargin<2
    n=1;
end
k = 0;
button = 0;

%%// Tolerance so that in the inifnity case, this could act as
%%// the thresholding distance below which the
%%// input extracting operation must be terminated
TOL = 0.01;

%%// Placeholders for X-Y and button type could be stored 
button1 = [];
xy = [];

hf = get(ha,'parent');
figure(hf);
set(hf,'WindowButtonMotionFcn',@changepointer)
set(ha,'ButtonDownFcn',@getpoints)
hp = get(ha,'children');
ht = get(hp,'hittest');
set(hp,'hittest','off')
axlim = get(ha,'Position');
fglim = get(hf,'Position');
x1 = axlim(1)*fglim(3) + fglim(1);
x2 = (axlim(1)+axlim(3))*fglim(3) + fglim(1);
y1 = axlim(2)*fglim(4) + fglim(2);
y2 = (axlim(2)+axlim(4))*fglim(4) + fglim(2);
waitfor(hf,'WindowButtonMotionFcn',[])
if iscell(ht)
    for jj=1:length(ht)
        set(hp(jj),'hittest',ht{jj})
    end
else
    set(hp,'hittest',ht)
end
selType = get(hf,'SelectionType');

% Mouse-Button recognition...
if(strcmp(button, 'normal'))
    button = 1; % left
elseif(strcmp(button, 'extend'))
    button = 2; % right
elseif(strcmp(button, 'alt'))
    button = 3; % middle
else
    button = 4; % double click any mousebutton
end

if nargout==3
    varargout{1} = xy(:,1);
    varargout{2} = xy(:,2);
    varargout{3} = button1(:,1);
elseif nargout==2
    varargout{1} = xy(:,1);
    varargout{2} = xy(:,2);
else
    varargout{1} = xy;
end
    function changepointer(~,~)
        pntr = get(0,'PointerLocation');
        if pntr(1)>x1 && pntr(1)<x2 && pntr(2)>y1 && pntr(2)<y2
            set(hf,'Pointer','crosshair')
        else
            set(hf,'Pointer','arrow')
        end
    end
    function getpoints(src,evnt)
        cp = get(src,'CurrentPoint');
        button = get(hf, 'SelectionType');
        k = k+1;

        if k==1
            xy = [xy ;cp(1,1:2)];
            button1 = [button1; {button}];
        end

        if k>=2
            if pdist2(cp(1,1:2),xy(k-1,:))<TOL && isinf(n)
                k = n;
            else
                xy = [xy ;cp(1,1:2)];
                button1 = [button1; {button}];
            end
        end
        if k==n
            set(hf,'Pointer','arrow')
            set(hf,'WindowButtonMotionFcn',[])
            set(ha,'ButtonDownFcn',[])
            return;
        end
    end
end

Sample runs

Run 1: Infinite points case

[x_coords,y_coords,button_types] = ginput_ax_mod2(gca, Inf)

Run 2: 10 points case

[x_coords,y_coords,button_types] = ginput_ax_mod2(gca, 10)

Sample output with infinite case but double clicks after third click -

x_coords =  
    2.0472
    4.3076
    5.9873

y_coords =
   24.4152
   25.2924
   26.7544

button_types = 
    'normal'
    'alt'
    'normal'
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top