Ruben - here is a quick and rough way to do what I think that you want. It makes several assumptions which are hopefully valid for what you are trying to do, namely that plot (or some equivalent) function is used to plot the data on the 2D axes - so we have access to the x and y data that makes up the graphic. I've used GUIDE to mock up a GUI - it has a single axes (named axes1) and a push button (named pushbutton1). The button is used to plot some data on the axes. Its callback is
function pushbutton1_Callback(hObject, eventdata, handles)
colours = {'b','r','g','k','m','y'};
if ~isfield(handles,'plotHandles');
handles.plotHandles = [];
end
numHandles = mod(length(handles.plotHandles),6);
x = -2*pi:0.01:2*pi;
y = sin(x) + numHandles;
h = plot(handles.axes1,x,y,colours{numHandles+1});
handles.plotHandles = [handles.plotHandles ; h];
guidata(hObject,handles);
The above just plots up to six sine waves on the axes. The important part is the saving of the plot graphics handle to the handles structure. This will allow us to manipulate the data later on.
Now, in order to enable the user to move a graphic object on the axes, we are going to assign three callbacks to the GUI/figure. In the Opening function (myGuiName_OpeningFcn), add the following code
set(hObject, ...
'WindowButtonDownFcn', @mouseDownCallback, ...
'WindowButtonUpFcn', @mouseUpCallback, ...
'WindowButtonMotionFcn', @mouseMotionCallback);
hObject is our GUI/figure, and we are going to create callbacks for the (mouse) button down, up and motion events.
Each callback (within our m-file) is then defined.
The purpose of the mouseDownCallback is to check to see if the mouse down event is within axes1 (as opposed to anywhere else within the GUI). If this is true, then given the position within axes1, find (using the Euclidean distance equation) which plot graphics is closest to this position. This information is then saved for the mouse motion callback.
function mouseDownCallback(figHandle,varargin)
handles = guidata(figHandle);
currentPoint = get(figHandle, 'CurrentPoint');
x = currentPoint(1,1);
y = currentPoint(1,2);
axesPos = get(handles.axes1,'Position');
minx = axesPos(1);
miny = axesPos(2);
maxx = minx + axesPos(3);
maxy = miny + axesPos(4);
if x>=minx && x<=maxx && y>=miny && y<=maxy
if isfield(handles,'plotHandles')
currentPoint = get(handles.axes1, 'CurrentPoint');
x = currentPoint(2,1);
y = currentPoint(2,2);
minDist = Inf;
minHndl = 0;
for k=1:length(handles.plotHandles)
xData = get(handles.plotHandles(k),'XData');
yData = get(handles.plotHandles(k),'YData');
dist = min((xData-x).^2+(yData-y).^2);
if dist<minDist
minHndl = handles.plotHandles(k);
minDist = dist;
end
end
if minHndl~=0
handles.mouseIsDown = true;
handles.movingPlotHndle = minHndl;
handles.prevPoint = [x y];
guidata(figHandle,handles);
end
end
end
The purpose of the mouseUpCallback is to just reset any fields that correspond to the moving of the graphic, indicating that we are finished with the move.
function mouseUpCallback(figHandle,varargin)
handles = guidata(figHandle);
if isfield(handles,'mouseIsDown')
if handles.mouseIsDown
handles.mouseIsDown = false;
handles.movingPlotHndle = [];
handles.prevPoint = [];
guidata(figHandle,handles);
end
end
Finally, the purpose of mouseMotionCallback is to move the graphic from the previous position to the current one.
function mouseMotionCallback(figHandle,varargin)
handles = guidata(figHandle);
if isfield(handles,'mouseIsDown')
if handles.mouseIsDown
currentPoint = get(handles.axes1, 'CurrentPoint');
x = currentPoint(2,1);
y = currentPoint(2,2);
xDiff = x - handles.prevPoint(1);
yDiff = y - handles.prevPoint(2);
xData = get(handles.movingPlotHndle,'XData');
yData = get(handles.movingPlotHndle,'YData');
set(handles.movingPlotHndle,'YData',yData+yDiff,'XData',xData+xDiff);
handles.prevPoint = [x y];
guidata(figHandle,handles);
end
end
I've attached the code to this answer. Hope that it helps!
Best Answer