Ginput in a GUI
20 views (last 30 days)
Show older comments
Hi, How can I restrict the selection of ginput to the figure in the GUI (rather than the entire GUI). Also as an aside, how can I store that information and export it into excel all within the GUI .m file.
2 Comments
B_Richardson
on 6 Jul 2011
Hello, did you ever solve your problem? I am attempting to accomplish somewhat the same thing?
Pedro Teodoro
on 12 Jan 2013
Try this,
This function works as ginput but it is adapted to be used in GUIs. It restrict the selection of ginput in the specified axes.
Answers (6)
Matt Tearle
on 16 May 2011
Can't find the answer where I shared this before, so I'll just copy-n-paste. This is code that works around the limitations of ginput. The magic occurs in the functions changepointer and getpoints. This isn't the most efficient way to do this (most of the calculations in changepointer should be done in the parent function), but it should give an idea of how to mimic ginput.
function getgraphinput
hf = figure;
ha = axes('position',[0.1 0.3 0.8 0.6]);
x = linspace(0,1);
hp = plot(x,sin(5*pi*x));
set(hp,'hittest','off')
hstart = uicontrol('style','pushbutton','string','Start',...
'units','normalized','position',[0.2 0.1 0.2 0.1],...
'callback',@startgin);
hstop = uicontrol('style','pushbutton','string','Done',...
'units','normalized','position',[0.6 0.1 0.2 0.1],...
'callback',@stopgin,'enable','off');
function startgin(hObj,handles,eventdat)
set(hObj,'Enable','off')
set(hstop,'enable','on')
set(hf,'WindowButtonMotionFcn',@changepointer)
set(ha,'ButtonDownFcn',@getpoints)
end
function stopgin(hObj,handles)
set(hObj,'Enable','off')
set(hstart,'enable','on')
set(hf,'Pointer','arrow')
set(hf,'WindowButtonMotionFcn',[])
set(ha,'ButtonDownFcn',[])
xy = getappdata(hf,'xypoints');
line(xy(:,1),xy(:,2))
end
function changepointer(hObj,handles)
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);
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(hObj,~,~)
cp = get(hObj,'CurrentPoint');
line(cp(1,1),cp(1,2),'linestyle','none','marker','o','color','r')
xy = getappdata(hf,'xypoints');
xy = [xy;cp(1,1:2)];
setappdata(hf,'xypoints',xy);
end
end
EDIT TO ADD
Sorry to make this balloon, but this might be preferable... here's a function that can stand alone in place of ginput. It mostly mimics ginput except that (1) the first input should be the handle to an axes object, and (2) if a number of points isn't specified, it defaults to 1.
function varargout = ginput_ax(ha,n)
if nargin<2
n=1;
end
k = 0;
xy = zeros(n,2);
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
if 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(hObj,~,~)
cp = get(hObj,'CurrentPoint');
k = k+1;
xy(k,:) = cp(1,1:2);
if k==n
set(hf,'Pointer','arrow')
set(hf,'WindowButtonMotionFcn',[])
set(ha,'ButtonDownFcn',[])
end
end
end
3 Comments
Matt Tearle
on 16 May 2011
Copy changepointer and getpoints as nested functions, just as I have here, and set the 'WindowButtonMotionFcn' property of your figure and the 'ButtonDownFcn' property of your axes, like I did inside startgin.
Matt Tearle
on 16 May 2011
See above edit. You can copy/paste this into a separate file, then call it just like you'd call ginput.
Mike Loucks
on 18 May 2011
Matt, Thanks for this, it helped me a lot. I am not getting the croshairs to show up though. You mention setting windowbuttonmotionfcn of the figure, but I'm not sure what to set it to. It looks like maybe you set that in the code, but I'm not seeing the crosshairs.
I've had a heck of a time with ginput. It works fine in my older matlab code, but I'm running a version of that code now in Matlab Engine (being called from an external program) and I can't get ginput to ever act on the axes in the figure I want (there is only one figure, and only one axes). This is consistent with other matlab functions I'm using (contour, and associated graphing utilities). Previously, I could use the "axes" call once and all my contour calls went to the right place. Now, every single call that plots must have a direct reference to the axes or they will create another figure and graph there (useless). ginput doesn't take a direct reference, (and any attempt to direct focus for it fails), so the only thing I have that works is your stuff here.
Do you have any understanding of why this might be?
Thanks,
Mike
Mike Loucks
on 18 May 2011
Update, the cross-hairs do show up, but only over a very small portion at the top of my figure.
3 Comments
Matt Tearle
on 18 May 2011
Er, wait, maybe I misunderstood. Do you mean the cursor turns into a crosshair only over a small portion of the figure window? That's weird. Could be a bug in my code. Do you have subplots, perhaps? It should turn into crosshairs anyone inside the axes, and be a regular pointer anywhere else in the figure window.
If you move the figure window after calling ginput_ax, that would probably mess it up.
Keerthi Kumar
on 5 Jun 2013
As Mike mentioned there was a problem with the cross hair. The problem was when you read out the position of the GUI figure window, the unit was not in pixel and pixels are used later to identify the axes region. I solved the problem by changing the unit to pixels before reading the position values.
oldUnits = get(hf,{'units'});
set(hf,{'units'},{'pixels'});
fglim = get(hf,'Position');
set(hf,{'units'},oldUnits);
Mike Loucks
on 18 May 2011
I have a figure with a graph area that covers only about 50% of the figure (the rest are buttons and text fields for output). The cross-hair only exists over a very small portion of my figure, and only when I place it in a particular place on one of my monitors! It's quite weird, I almost didn't see it. I did move the figure window though.
Should I do anything to the figure definition itself, or should the code change the crosshairs properly?
1 Comment
Mike Loucks
on 18 May 2011
I changed your "changepointer" function so that the if statement always sets the pointer to fullcrosshair, and now it seems to work. It's not confined to the axes (but neither was the original function). Of course that was the original purpose of this post, but my issue was slight different, in that I couldn't get ginput to work at all.
Divakar Roy
on 13 Nov 2012
I have just uploaded to file-exchange, codes that are supposed to solve the original problem of restricting the selection of ginput to the figure in the GUI. Here's the link - http://www.mathworks.com/matlabcentral/fileexchange/38997 . Would appreciate to know if the codes are any help to people still interested in the problem.
0 Comments
See Also
Categories
Find more on Graphics Object Properties in Help Center and File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!