Doug's MATLAB Video Tutorials

Advanced MATLAB: Capture mouse movement 34

Posted by Doug Hull,

This week we will take a look at how you can capture the mouse movement through callbacks. As the mouse moves, we will update the xdata of a line so that you are moving the line with the mouse.
iconFiles.jpgiconPod.jpg

34 CommentsOldest to Newest

hee Doug,

this is a really nice feature… I want to use it for my GUI as well, but if I apply it on real data (obtained from a racecar) then Matlab gives the following error:

Warning: line XData length (2) and YData length (500) must be equal.

and all I did with your m-file was replacing the definition of h into:

h=plot(data(1:500,1),data(1:500,4),’ButtonDownFcn’, @startDragFcn)

and the plot disappears from the figure.
how can I apply this feature to a dataplot?

cheers Vincent

Vincent,

Assign these variables as a trouble shooting step:

x = data(1:500,1)
y = data(1:500,4)

Check to see if these are the same size.

Then try:

plot(x,y) %skip button down for now

Test that

Finally go to this command

plot(x,y,’ButtonDownFcn’, @startDragFcn)

If you take these systematic steps, I think you will find the problem.

Doug

yeah I solved that problem, the length of x was not correct. I have it working on my own data, very cool. now i want to put it in my gui, but matlab gave me the following error;

??? Input argument “handles” is undefined.

Error in ==> Data_Postprocessor_v7>startDragFcn at 658
Data=getappdata(handles.figure1,’mydata’)

??? Error while evaluating line ButtonDownFcn

I use the above code at the start in every callback function of the gui to get the data. so it works in all the callback functions but when I put it in the ButtonDown function Matlab produces the above error. is it maybe because a callback function is not the same as the ButtonDown function?

thanks Doug

Vincent

I have a similar problem as Vincent. I tried to use these functions inside my GUI, although I think these created functions can’t see the handles of the GUI.
My startDragFcn is written basically the same way as Vincent:

startDragFcn(hObject, eventdata, handles)
%Inside this function handles is not availabel and I need the axes that is stored in the handles.

When I click over the line I get ??? Input argument “handles” is undefined.

I was looking for an answer for this problem in matlab web page and I found the solution. When using the functions presented by the Doug (nice work Doug) all you have to do to use them inside your GUIs is to pass the handles of the GUI inside a cell.

When using additional arguments for the callback function, you must set the value of the property to a cell array (i.e., enclose the function handle and arguments in curly braces). For example,
You can define the callback function to accept additional input arguments by adding them to the function definition. For example,

function startDragFcn(src,eventdata,arg1)

arg1 is an additional argument. In my case I used the handles of the GUI as an additional argument:

function startDragFcn(hObject,eventdata,handles)

So, for the callback function you have to enclose the function handle and the additional arguments in curly braces. For example,

set(hLine,’ButtonDownFcn’,{@startDragFcn,handles});
set(hFigure, ‘WindowButtonUpFcn’,{@stopDragFcn,handles});

Hi!
This is really great!:] I’ve used this idea to move the data points on my plot. But here is my query:
the code works really great on Matlab 7.1, but when I run it on the older version (actually it is Matlab 6.1.0.450)
I get the following error:

********************************************************
??? Undefined function or variable ‘f’.

Error in ==> G:\MATLAB_61\MOUSE_CAPTURE\mouse_capt.m (startDragFcn)
On line 66 ==> set(f,’WindowButtonMotionFcn’,@draggingFcn)

??? Error while evaluating line ButtonDownFcn.

??? Undefined function or variable ‘f’.

Error in ==> G:\MATLAB_61\MOUSE_CAPTURE\mouse_capt.m (stopDragFcn)
On line 128 ==> set(f, ‘WindowButtonMotionFcn’,”)

??? Error while evaluating figure WindowButtonUpFcn.
********************************************************

Why is that? What to do to make it work on the older version?

Everest,

I just did a quick check. That version of MATLAB is about three years ago. There have been enough changes in function handles that I suspect that is the reason code written for the newer version of MATLAB does not work in an older version.

Doug

Thanks Doug!

The problem is solved now.. Actually I’ve used UserData property to gave the name to my ‘figure’,axis’ and ‘line’ so I could call them in the external function (draggingFcn etc.)
However, it was not so obvious at the beginning.

Everest

Hello Doug!

Many thanks for your excellent videos, it sure makes it easier for newbies like me to get into Matlab. However, I have a question, or actually a couple of questions…

My goal is to make a surface object and be able to change the surface Zdata by clicking and dragging. I have been looking through the documentation, the net and all books I could find, but I haven’t been able to find anything that explains how to do that, except from this tutorial. Sure the documentation contains some hints, but I need more than that…

So far, I’ve found some examples that comes close on the File Exchange, namely ‘gnurbs’ by Daniel Claxton and ‘moveplot’ by by Brandon Kuczenski/Alex Woo.

One thing I don’t understand is how to translate the axes ‘CurrentPoint’ property to determine which point of the surface is being clicked on.

Also, by looking at the above two examples, I’ve noticed that they copy the data to be manipulated to the axes ‘userdata’ property. Is this necessary, or is there any way to ‘set’ individual points of the surface objects Zdata property directly?

I understand you might not be able to give me a full answer, but maybe you know where I can learn some more about this?

Thanks again and keep up the good work!

Ö.H.

Great Work Doug! Thanks!

I have one question about that..

I want to do samething but not only one graph but also two or three subplots. I mean: i have 2-3 graphs in one figure, and i want to apply samethings to my whole graphs.

Here is the screenshot.

http://img21.imageshack.us/i/adszpu.jpg/

It seems work but i can adjust only one line. Another one didn’t move.

If i understand correctly i can expand this up to 10 graphs.

I am working on it but unfortunately i couldn’t handle with it.

If you could help me, i would be appreciated…

Thanks Again!

@Fatih,

Good problem. You will just have to make sure that when you set the XData on the original line, you also set it on all the additional lines. You would want to put the callbacks on all the lines so that any of them can move.

Doug

Hi Doug,

I’m learning how to create GUIs in Matlab and your GUI tutorials have really helped me. I would like to implement the above function for capturing mouse movement into a GUI, but I’m having lots of problems. At the moment I can’t even get the xdata line to appear. Please could you suggest how to go about implementing your code below into GUI form? Any hints would be very,very much appreciated!

************************************************************
function main
axes = handles.axes1
ah = axes(‘xlim’,[0 1],’ylim’,[0 1])
h = hLine([0.5 0.5], [0 1],…
‘color’, ‘red’,…
‘linewidth’, 3,…
‘ButtonDownFcn’, @startDragFcn)

set(f, ‘WindowButtonUpFcn’, @stopDragFcn)

function startDragFcn(varargin)
set(f, ‘WindowButtonMotionFcn’,@dragginFcn)

function dragginFcn(varargin)
pt = get(aH, ‘CurrentPoint’)
set(h, ‘xData’, pt(1)*[1 1])

function stopDragFcn(varargin)
set(f, ‘WindowButtonMotionFcn’,”)
************************************************************

Many thanks

Lucy

@lucy,

With just this snippet, I can not really tell anything.

My guess is that the handles of the various objects you are using in the callbacks are going out of scope. This is very common for people doing GUIs. Go take a look at my second GUI video (next to oldest in the TOPIC GUI to right).

That might help, though it is not specific to this at all.

Doug

Hi Dough

I’m trying to get the new x position once you move the line
I now can display the new XData using

x=get(h,’XData’)

but on the workspace there is no variables x, i try to read
x by using

xtest=get(gca,’XData’)
but it give error

?? Error using ==> get
There is no ‘XData’ property in the ‘axes’ class.

any suggestion, thx in advance

@kushairy,

in the first bit of code, you have the handle h in scope. In the second the handle h does not exist. You can probably get to that handle if you pass it out as an output of the main function.

Doug

Hi Doug.

I am implementing a gui which tries to move different lines in a plot.

Therefore, I have a plot with different lines (the number is depending on preivous things, so we don’t know it), and I need to move up and down these lines with the mouse.

The problem is that if a use a common startDragFcn, when I am inside this function I don’t know which line I have to move.

If I had a static number of lines I would implement a different startDragFcn for each line.

Is there a way to know which line I selected, using these approach. I’ve expected that some attribute of the line changes when I selected using ButtonDownFcn, then I would have just to identified this attribute to know which line I have to move.

Is there any idea.

thanks

Óscar

@Oscar,

GCO or GCBO whould help you know which line was clicked. I think it *might* also be in hObject (which is automatically passed into the callback)

Doug

Thanks, it works perfect. I’m always wondering what for is this hObject, and finally I found the answer.

Óscar

My initial use of the information from this video was a simple “click and display current position” feature in my GUI. Below is the code for clicking on the axes and displaying the location of that click in a text box.

When I start up the GUI, it works great. BUT after I’ve drawn something on the axis (using a plot() function) nothing happens; it’s almost like axes1_ButtonDownFcn is disabled. What’s going on?

% --- Executes on mouse press over axes background.
function axes1_ButtonDownFcn(hObject, eventdata, handles)
% hObject    handle to axes1 (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
pt = get(hObject, 'currentPoint');
AStr = strcat('x = ',num2str(pt(1,1)),'  and  y = ',num2str(pt(1,2)));
set(handles.text5,'String',AStr);

@Dwight,

A high level function like plot often changes a lot of values in the underlying axes when it is run. Check the axes after plot to make sure all the callbacks, properties and such you are expecting are still there.

This is done because in the general case, it is what you usually want. For higher level Handle Graphics manipulation like this, you need to watch these convenience functions carefully.

Doug

Hi Doug,

Thanks for sharing this with us. It is extremely helpful.

How would make this example work if you have a random amount of lines? i.e. you didnt know how many lines were going to be in the figure everytime you ran the script.

How would the dragginFcn know the handle of the particular line you were dragging?

It’s probably easy to do but I thought I would ask you.

Thanks

@George,

Each line can have its own callback function. hObject is always the calling object, so things stay clear in the callbacks.

Doug

Hi Doug

How can I create two independent lines. (with this properties)
I create a GUI, which has to know this option on a axes, where I have already plotted something else before.
How can I implement it to work well.
Thank you for your answers in advance.

Aron

@Aron,

You can set whatever callbacks you want on a line, even if there are different callbacks on different lines in the same axes. They are independent.

You can use hold on, line (the primitive command), or plot(x,y,x2,y2). These would all work.

hi,
i got the new positions by setting:
y = get(h, ‘Xdata’)

in draggingFcn function

I want to store all these values in a matrix and not able to do that.

Hi Doug,

Nice demo, thanks! The code has been removed from the file exchange though – is there any chance you could upload this?

Cheers.

This is the code for this example with one tweak added. I use gco so the code can be shared between multiple objects.

function lines

f = figure;
a = axes(‘xlim’,[0 1],’ylim’,[0 1]);
h1 = line(rand*[1 1], [0 1],…
‘color’, ‘red’,…
‘linewidth’, 3,…
‘ButtonDownFcn’, @startDragFcn);

h2 = line(rand*[1 1], [0 1],…
‘color’, ‘green’,…
‘linewidth’, 3,…
‘ButtonDownFcn’, @startDragFcn);

h3 = line(rand*[1 1], [0 1],…
‘color’, ‘blue’,…
‘linewidth’, 3,…
‘ButtonDownFcn’, @startDragFcn);

set(f, ‘WindowButtonUpFcn’, @stopDragFcn)

function startDragFcn(varargin)
set(f, ‘WindowButtonMotionFcn’,@dragginFcn)
end

function dragginFcn(varargin)
pt = get(a, ‘CurrentPoint’);
set(gco, ‘xData’, pt(1)*[1 1])
end

function stopDragFcn(varargin)
set(f, ‘WindowButtonMotionFcn’,”)
end

end

Add A Comment

What is 4 + 7?

Preview: hide

These postings are the author's and don't necessarily represent the opinions of MathWorks.