Discover MakerZone

MATLAB and Simulink resources for Arduino, LEGO, and Raspberry Pi

Learn more

Discover what MATLAB® can do for your career.

Opportunities for recent engineering grads.

Apply Today

Ginput in a GUI

Asked by Mel on 16 May 2011

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.

http://www.mathworks.com/matlabcentral/fileexchange/39799

Mel

Tags

Products

No products are associated with this question.

6 Answers

Answer by 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

Mel on 16 May 2011

Thanks for the code. How exactly would I call this function within my GUI .m file?

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.

Matt Tearle
Answer by 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

1 Comment

Matt Tearle on 18 May 2011

No, sorry. Not sure what changed.

Mike Loucks
Answer by 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

Yes. I set 'Pointer' to 'crosshair' which is just the local crosshair. Set it to 'fullcrosshair' to fully mimic ginput. I probably should have done that initially. Don't know why I didn't -- personal preference, I guess.

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
Answer by 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.

Mike Loucks
Answer by 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

Divakar Roy

Contact us