问题
I am using patch
in order to draw inside an ellipse into a figure I have created in gui environment.
Normally, I get figures' points (coordinates) by clicking (using callback functions). It works properly when the point I want to grab is not inside an ellipse that I have previously plotted (applying patch
).
What should I do after applying patch
in order to be able to get a point that is inside some ellipse after I have drawn it? Thanks a lot!
回答1:
Here's a way to solve your problem:
First we draw a point followed by a patch that "covers" it. In this example the patch is transparent, and still the point behind it cannot be selected.
(this part of the code is taken from MATLAB's example for patch)
close all force; clear variables; clc;
h = plot(3,6,'o')
hold on;
xdata = [2 2 0 2 5;
2 8 2 4 5;
8 8 2 4 8];
ydata = [4 4 4 2 0;
8 4 6 2 2;
4 0 4 0 0];
cdata = [15 0 4 6 10;
1 2 5 7 9;
2 3 0 8 3];
p = patch(xdata,ydata,cdata,'Marker','o',...
'FaceColor','flat')
If you run this code, you should get an output along the lines of:
h =
174.0110
p =
175.0105
Which shows the handles assigned to each child of the axes.
To get some more insight, you add this additional code:
axes_children = get(gca,'Children')
disp(['Type of "point" plot: ' get(h,'type')]);
disp(['Type of "patch" plot: ' get(p,'type')]);
The output of which is:
axes_children =
175.0105
174.0110
Type of "point" plot: line
Type of "patch" plot: patch
Notice the order of the elements: 175.0105 (i.e. the patch
) is higher in the list - this is very important, because you cannot select an object that is obscured by another object.
In case you have multiple points\patches you can simply reposition the patch
es below the point
s using something like this:
for ind1=1:length(axes_children)
if strcmp(get(axes_children(ind1),'type'),'patch')
uistack(axes_children(ind1),'bottom');
end
end
This will make the point(s) selectable and also preserve the order of the patches in case they overlap each other.
Edit
Here's an extended example of the some mouse tracking code that I have compiled for your problem using idea from UndocumentedMatlab. It may give you some more ideas...
function init()
close all force; clear variables; clc;
%// Initialize the figure with a listener:
h = figure('WindowButtonMotionFcn',@windowMotion);
%// Add a "static" text label:
col = get(h,'color');
uicontrol('Style','text', 'Pos',[0,0,300,30],'Tag','lbl',...
'Background',col, 'HorizontalAlignment','left');
axes('units','pix'); hold all;
for i=1:3
X = 5*rand(100,1);
plot(X,rand*X + rand(100,1),'.');
end
xdata = [2 2 0 2 5;
2 8 2 4 5;
8 8 2 4 8]/2;
ydata = [4 4 4 2 0;
8 4 6 2 2;
4 0 4 0 0]/2;
cdata = [5 0 4 6 10;
1 2 5 7 9;
2 3 0 8 3];
patch(xdata,ydata,cdata,'Marker','o',...
'FaceColor','interp');
drawnow;
datacursormode on;
end
function windowMotion(hObject,eventData,varargin)
persistent inCallback;
%// If you want to do something complex inside the callback, the
%// inCallback lines makes sure that only 1 instance of the callback is
%// being executed at a time.
if ~isempty(inCallback), return; end
inCallback = true;
lbl = findobj('Tag','lbl');
try
currPos = get(gcf,'CurrentPoint');
ax_pos = get(gca,'Position');
%// Test if the mouse pointer is inside the axes:
if (currPos(1)>ax_pos(1) && currPos(1)<ax_pos(1)+ax_pos(3)) && ...
(currPos(2)>ax_pos(2) && currPos(2)<ax_pos(2)+ax_pos(4))
%// Find all possible
possible_points_obj = findobj(gca,'Type','line');
%// SOME LOGIC TO FIND THE CORRECT points_obj
%// In this example it will look only in the last-plotted group of
%// points - RED. This can be extended to loop over all "line"
%// objects and select the closest point of all.
correct_points_obj = possible_points_obj(1);
X=get(correct_points_obj,'XData')'; ...'
Y=get(correct_points_obj,'YData')'; ...'
XScale=diff(get(gca,'XLim'));
YScale=diff(get(gca,'YLim'));
currPosinAx = (currPos - ax_pos(1:2))./ax_pos(3:4).*[XScale YScale];
r=(((X-currPosinAx(1))./XScale).^2+((Y-currPosinAx(2))./YScale).^2);
[~,i]=min(r);
%// Here you put whatever you want to do with the point you found
set(lbl,'String',{['The closest point to the pointer is at: ('...
num2str(X(i)) ',' num2str(Y(i)) '),'];
['and belongs to handle: ' num2str(correct_points_obj)]});
else
set(lbl,'String','Mouse is outside axes');
end
catch
% error trapping here
end
drawnow;
inCallback = [];
end % myCallbackFcn1
来源:https://stackoverflow.com/questions/25229506/how-to-get-point-of-a-figure-using-callbacks-in-gui-when-the-point-is-inside-a