Selecting figure data interactively with rectangle or point

15 views (last 30 days)
I am trying to augment my working point selection tool with a rectangle/box selection option. The tool allows me to select points one by one, optionally adding these to a list of flagged indexes for the data. The UI works for points (ginput, button1 'UserData'=1), but when I use the box selection (drawrectangle, button0 'UserData'=1), the button0 'UserData' is never 1, so the data are not flagged.
close all
clear
fh = figure;
x1=300:10:1000;
y1(1,:) = ones(1,length(x1));
y1(2,:) = 2*y1(1,:);
y1(3,:) = 3*y1(1,:);
plot(x1,y1)
hold on
ylim([0 4])
flag = zeros(1,size(y1,1));
disp('Manual Screening')
disp('Zoom to y1 of interest and hit Box or Point select.')
disp('Accept to save and move on. Reject to ignore last.')
button0 = uicontrol(fh,'Style', 'pushbutton', 'String', 'Box select',...
'Position', [5 200 60 25], 'Callback', @buttonCallBack);
button1 = uicontrol(fh,'Style', 'pushbutton', 'String', 'Point select',...
'Position', [5 150 60 25], 'Callback', @buttonCallBack);
button2 = uicontrol('Style', 'pushbutton', 'String', 'Accept',...
'Position', [5 100 50 25], 'Callback', @buttonCallBack);
button3 = uicontrol('Style', 'pushbutton', 'String', 'Reject',...
'Position', [5 50 50 25], 'Callback', @buttonCallBack);
button4 = uicontrol('Style', 'pushbutton', 'String', 'Exit',...
'Position', [5 5 50 25], 'Callback', @buttonCallBack);
while 1
disp('Zoom to data of interest and choose selector.')
uiwait(fh)
if get(button4,'userdata') == 1
disp('Exitting')
break
end
if get(button1,'userdata') == 1
[x,y] = ginput(1);
[~,windex] = find_nearest(x,x1);
spectrumX = y1(:,windex);
[~,Rindex] = find_nearest(y,spectrumX);
plot(x1(windex),y1(Rindex,windex),'*k')
elseif get(button0,'userdata') == 1
h=drawrectangle;
pos = h.Position;
xmin = pos(1);
ymin = pos(2);
xmax = pos(1) + pos(3);
ymax = pos(2) + pos(4);
indexOfInterest = (x1 >= xmin) & (x1 <= xmax) & (y1 >= ymin) & (y1 <= ymax);
for i=1:size(y1,1)
plot(x1(1,indexOfInterest(i,:)),y1(i,indexOfInterest(i,:)),'*k')
end
end
set(button0,'userdata',0)
set(button1,'userdata',0)
set(button2,'userdata',0)
set(button3,'userdata',0)
set(button4,'userdata',0)
uiwait
if get(button0,'userdata') == 1 || get(button1,'userdata') == 1 || get(button3,'userdata') == 1
set(button0,'userdata',0)
set(button1,'userdata',0)
set(button2,'userdata',0)
set(button3,'userdata',0)
set(button4,'userdata',0)
continue
elseif get(button2,'userdata') == 1
if get(button1,'userdata') == 1
% This works
[~,windex] = find_nearest(x,x1);
spectrumX = y1(:,windex);
[~,Rindex] = find_nearest(y,spectrumX);
elseif get(button0,'userdata') == 1
% This does not work
Rindex = find(any(indexOfInterest,2));
end
plot(x1,y1(Rindex,:),'k','LineWidth',3)
flag(Rindex) = 1;
fprintf('Index of selected y1: %d\n',Rindex)
set(button0,'userdata',0)
set(button1,'userdata',0)
set(button2,'userdata',0)
set(button3,'userdata',0)
set(button4,'userdata',0)
elseif get(button4,'userdata') == 1
disp('Exitting and saving')
break
end
end
%%
function buttonCallBack(hObject,~)
set(hObject,'UserData',1)
uiresume
end
%%
function [near_scalar, index] = find_nearest(scalar,list)
diff = abs(list - scalar);
[~, index_a] = min(diff);
index = index_a(1); % Pick the first if equidistant
near_scalar = list(index);
end

Accepted Answer

Taylor
Taylor on 8 Dec 2025 at 22:38
You're running into a state management bug: you’re using the buttons’ UserData both as an event trigger (to uiresume) and as persistent state (to remember whether the last selection was point or box). You reset the UserData to 0 right after the selection step, so when you press Accept, your elseif get(button0,'userdata') == 1 never fires for the rectangle path.
I would recommend switching to App Designer to build this app. There is even a free course to get you started.

More Answers (0)

Categories

Find more on Migrate GUIDE Apps in Help Center and File Exchange

Products


Release

R2025b

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!