Problem of using "assignin" during figure callbacks

Hi every member,
Overall, I want to get a output from a figure callback after the figure closed. I am doing it by using "assignin". But during I used it, I found a curious problem. Even by assignin('caller'), which is suppose to be a function workspase, the argument always be sent to the base workspace. I have no idea why it happens in this way. Following is my code to illustrate my problem in details. The variable "rx" and "imgx" is a contrast to show my problem.
>> make_img % this is the input command in matlab command line
% this function is to make a "img" variable and calling "test" function
function make_img
radius=100;
c0=[radius+1,radius+1];
[X,Y] = ndgrid(1:2*radius+1) ;
img = zeros(2*radius+1);
img(sqrt((X-c0(1)).^2 + (Y-c0(2)).^2) <= radius) = 1;
test(img) % call "test"
end
% this is the called function
% it suppose to give the "caller" two variable, rx and imgx, not to the base
function test(img)
r=20;
assignin('caller','rx',r)
h=imshow(img);
fig = gcf;
fig.UserData.img=img;
fig.WindowKeyPressFcn=@key;
function key(fig,~)
img=fig.UserData.img;
a=fig.CurrentCharacter;
if isequal(a,'q')
assignin('caller','imgx',img);
delete(fig)
return
end
end
end
The output in base workspace is suppose to be none. But the "imgx" exist and "rx" not. It seems the caller of the callback is always the base workspace? I am confused about it. If it is so, how could I get a output after the figure deleted in the subfunction workspace?
Thank you.

7 Comments

Messing around with variables in other workspaces, e.g. making them magically appear or changing their values, is an unreliable way to write code. It also give scode that is slow, complex, obfuscated, liable to bugs, and (as you are finding out now) hard to debug:
The simple solution that all experienced MATLAB users recommend is to pass data properly between workspaces, e.g. using input/output functions, nested functions, guidata, etc.:
I completely agree withe the previous comment. Why can't the "called function" be:
% this is the called function
% it suppose to give the "caller" two variable, rx and imgx, not to the base
[rx, imgx] = function test(img)
imgx = [];
rx=20;
h=imshow(img);
fig = gcf;
fig.UserData.img=img;
fig.WindowKeyPressFcn=@key;
function key(fig,~)
img=fig.UserData.img;
a=fig.CurrentCharacter;
if isequal(a,'q')
imgx = img;
delete(fig)
return
end
end
end
At first, thank you for your comment. I had tried to do it in your suggested way.
function [rx, imgx] = test1(img)
imgx = [];
rx=20;
h=imshow(img);
fig = gcf;
fig.UserData.img=img;
fig.WindowKeyPressFcn=@key;
function key(fig,~)
img=fig.UserData.img;
a=fig.CurrentCharacter;
if isequal(a,'q')
imgx = img;
delete(fig)
return
end
end
end
The command main script is:
radius=100;
c0=[radius+1,radius+1];
[X,Y] = ndgrid(1:2*radius+1) ;
img = zeros(2*radius+1);
img(sqrt((X-c0(1)).^2 + (Y-c0(2)).^2) <= radius) = 1;
[r0,img0]=test1(img);
The return value of "img0" is "[]", and "r0" is exactly 20. It seems useless to get the value of img in this way, cause it is in a callback.
Thank you for your illustration of scripting rules. I don't like to use "assignin" function, cause it is partial illegal. But in this case, I don't have a better way to complete it. The "guidata" or "fig.userdata" is a good way to share data among callbacks. But as the figure object deleted, the shared data is deleted, neither. I can't make the data as a proper output of the function ( "test" function as above). If I do it in the input/output way, as my reply to @Joel Handy above part, it gives the initial value,"[]". If there is some other ways, I won't choose to modify the variable in workspace.
" I can't make the data as a proper output of the function..."
I have written many GUIs and have never needed to use assignin to return data. I find that nested functions are simple and intuitive, you just need to add waitfor to your code:
function out = test(...)
out = [];
fgh = figure(...);
...
function mycallback(...)
out = 'hello world';
end
...
waitfor(fgh) % return only when figure is closed.
end
Thank you for your greart advise! This is exactly what I need, the "waitfor" function. I have never used it before. A really neat way instead of "assignin". It is a pity could not accept your comment as an answer. : )
"It is a pity could not accept your comment as an answer"
You can now :)
I am glad that it helped!

Sign in to comment.

 Accepted Answer

You just need to add waitfor to your code:
function out = test(...)
out = [];
fgh = figure(...);
...
function mycallback(...)
out = 'hello world';
end
...
waitfor(fgh) % return only when figure is closed.
end

More Answers (1)

Exactly: Callbacks are called from the base workspace.
"how could I get a output after the figure deleted in the subfunction workspace?"
It depends on where you want which output. You can simply write in a message in the command window from inside the key() function. But if you want to create a variable in the base workspace, the program design is inefficient. Using the base workspace as a collector of variables is not smart. Better create a GUI and keep it open as long as the processing is going on. Then store the variables inside the GUI, e.g. using guidata. This allows you e.g. to run multiple instances of the code without collisions by a polluted base workspace.

1 Comment

At first, thank you for your reply. You seems to clarify the impossibility of storing a variable as a output. However, I could not always keep the gui opening. I need to save some data after I close it. If I close the gui, the "guidata" disappear, right? Do you mean there is no way to output the data from gui?
"You can simply write in a message in the command window from inside the key() function." Does it mean I can use "disp" or other display function to give a note?

Sign in to comment.

Categories

Find more on Creating, Deleting, and Querying Graphics Objects in Help Center and File Exchange

Products

Release

R2019a

Tags

Asked:

on 4 Jun 2019

Commented:

on 5 Jun 2019

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!