Related
I would like to define a figure and then for that specific figure do some things. Foe example: I would like to vreat a digure say:
h1 = figure('units','normalized','outerposition',[0 0 1 1]);
and then I want for h1 to do for example:
subplot(1,3,1)
plot(N_vec,1./Err(N_vec),sprintf('*%c',colconds(loop)),'LineWidth',5)
hold on
plot(N_vec,1./ErrPV(N_vec),sprintf('*%c',colconds(loop+2)),'LineWidth',5)
hold on
xlabel('Population size','fontsize',20)
ylabel('Error^-2 ','fontsize',20)
legend('OLE','PV','OLE shuffled','PV shuffled','Location','northwest')
The thing is that from loop reasons, h1 is defined far from the above lines. and is not the current figure handel. So I want the above lines to refer specifically for h1. somethong like:
subplot('h1',1,3,1)
plot('h1',N_vec,1./Err(N_vec),sprintf('*%c',colconds(loop)),'LineWidth',5)
hold on
plot('h1',N_vec,1./ErrPV(N_vec),sprintf('*%c',colconds(loop+2)),'LineWidth',5)
hold on
xlabel('h1','Population size','fontsize',20)
ylabel('h1','Error^-2 ','fontsize',20)
legend('h1','OLE','PV','OLE shuffled','PV shuffled','Location','northwest')
But matlab gives error whenever i try to add the name h1 in the specific commands for the figure...
how do I refer the figure handel when I actully want to use it?
Thanks!!
You could assign a 'Name' or 'Tag' to the h1 figure and then use that as a reference to get it before plotting.
% Create a figure with tag 'MyFig'
figure('Tag', 'MyFig');
% ... later in the code ...
% Get the figure with the Tag "MyFig"
h1 = findobj('Type', 'Figure' ,'Tag', 'MyFig')
Tag is for this purpose better than Name as the later is shown after the figure number. The Type-Figure argument could be skipped, but narrows down the objects to search.
Now you can use h1 as a regular handle.
subplot(h1,1,3,1)
plot(h1, ...)
You could also set h1 figure to the current figure
set(groot, 'CurrentFigure', h1);
% ... or for older versions
set(0, 'CurrentFigure', h1)
Then you could omit the handle in the plot commands
subplot(1,3,1)
plot(...)
I have an external function say "external_func" (seperate .m file)
Inside this function a while loop is called, and this while loop update a variabl named "update_prog"
Now I will pass this value into the GUIDE using
assignin('base', 'update_prog', update_prog); % passing to workspace
I am making this
"update_prog" as global variable and calling it into GUIDE .m file
function pb1_Callback(hObject, eventdata, handles)
global update_prog
% hObject handle to pb1 (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
% else
% set(handles.pb1,'enable','on');
% end
% update_prog first value prints, but it wont updates as the loop in external_func goes on.
drawnow;
set(handles.slider1,'Value',update_prog)
external_func;
so here in the GUIDE .m file I can get the value
"update_prog" but it wont keep up with the while loop. I used "drawnow" but its of no use.
How can I refine this value "update_prog" as the while loop in the "external_func" goes through multiple iterations. [Note: The updated values are there in the callback function of GUIDE, but unless there is a callback the callback function wont update the "update_prog"], so how can I acheive this real-time update inside a call_back function.
[Note: passing the variables through function input is not possible here in my case, so I am looking for alternatives]
Edit1: please consider this link, which has an exampleWhich may clarify you what I am trying to acheive
What I am doing here is
Passing the variable(which is being updated in the while loop of the externel function) into GUI.
I will use this variable to show the progress on the progress bar(Slider).
What is the problem?
1. The variable inside the GUI callback(Consdier I will press a push button and then it will call the function with while loop) will put the updated values into the set(handles.slider,'Value',variable)
By doing this I cant move the slider.
Why?
Callback updates the variable only when I press the push button, next all the updates to the variable will not be updated, so progress bar/slider wont move.
I wouldn't recommend to pass your variable in 3 steps with an intermediate workspace (external->base workspace->GUI). I would rather recommend to pass your variable directly (external->GUI).
Each Matlab figure offers a space to store variables (Application Data) of any type. I would suggest reading the article Share Data Among Callbacks and read the documentation for the 3 functions:
guidata
setappdata
getappdata
This way will offer you much more control over the scope of your variables and you won't need any global declaration.
Below is an example of a simple gui. The gui declare the variable in it's user space (with setappdata), then uses a timer to periodically read this variable (with getappdata).
The external function do whatever you want it to do (just a random number in the example), then to update the variable you use the same setappdata. The only thing you need for that is the handle of the main GUI figure, so in the example I give it as input of the external function.
The GUI also has two buttons to start and stop the update.
The code for the main example GUI 'theGui.m' is :
function h = theGui
%// basic GUI with 2 buttons and 1 slider
h.fig = figure('Position',[433 434 500 100],'Menubar','none','CloseRequestFcn',#my_closefcn) ;
h.sld = uicontrol('Style','Slider','Position',[20 20 460 20]) ;
h.btnStart = uicontrol('Style','pushbutton','String','Start updating','Callback',#btnStart_callback,'Position',[20 50 200 30]);
h.btnStop = uicontrol('Style','pushbutton','String','Stop updating','Callback',#btnStop_callback,'Position',[280 50 200 30],'Max',1,'Min',0);
%// Define the timer
h.t = timer ;
h.t.Period = 0.1 ; %// 0.1s refresh interval
h.t.TimerFcn = {#timer_callback,h.fig} ;
h.t.ExecutionMode = 'fixedSpacing' ;
%// initialise the variable to update in the GUI appdata
update_prog = 0 ;
setappdata( h.fig , 'update_prog' , update_prog ) ;
%// save handles
guidata( h.fig , h );
function btnStart_callback(hobj,~)
h = guidata( hobj ) ; %// retrieve handles
if strcmp('off',h.t.Running) %// Start timer (only if not already running)
start(h.t)
end
function btnStop_callback(hobj,~)
h = guidata( hobj ) ; %// retrieve handles
stop(h.t) %// Stop timer
function timer_callback(~,~,hfig)
update_prog = getappdata( hfig , 'update_prog' ) ; %// retrieve the 'update_prog' variable value
h = guidata( hfig ) ; %// retrieve handles
set(h.sld , 'Value' , update_prog) ; %// update the slider object with the retrieved value
function my_closefcn(hobj,~)
%// this function is only to clean up when the GUI will be closed.
%// It is recommended to delete the timer manually
h = guidata( hobj ) ; %// retrieve handles
stop(h.t) %// Stop timer (in case it is still running)
delete(h.t) ; %// delete the timer
delete(h.fig) ; %// destroy the figure
And the code for external_func.m
function external_func( guiMainFigureHandle )
%// This function will only generate random numbers and push them into the
%// variable 'update_prog' contained in the GUI appdata.
%// This is why this function NEEDS the handle of the gui to be able to
%// access the Application Data space of the gui.
for k = 1:100
randomValue = rand(1) ; %// generate a random value
hfig = ancestor( guiMainFigureHandle , 'figure' ) ; %// make sure the handle provided is the top level figure
setappdata( hfig , 'update_prog' , randomValue) ; %// update the variable value
pause(0.1) ;
end
Edit:
I place this in edit instead of changing the code above because I don't recommend messing with the root object if you don't need to. But in your case it can be a way round your problem.
If your external function doesn't have access to the GUI, it can always update a part of memory which is available for all the programs running in a given Matlab session, namely the root object. The handle for it is reserved and is the same for any program: 0 (although since v2014b there is another way to invoke it : groot, it is still always the same handle for all Matlab).
So in the example above, in theGui.m, use instead:
setappdata( 0 , 'update_prog' , update_prog ) ;
in the main routine, then in the subfunction function timer_callback(~,~,hfig), use:
update_prog = getappdata( 0 , 'update_prog' ) ; %// retrieve the 'update_prog' variable
And your function external_func() doesn't need any extra argument, the update only needs one line:
setappdata( 0 , 'update_prog' , update_prog) ; %// update the variable value
I "suspect" that your update_prog variable in the base workspace is not a global (you must define it to be global in every workspace that you want to use it).
Since your using globals (there are many better ways to do this - but thats not your question) - why don't you simply define the update_prog variable to be global in your external_func function (replace the assign call).
edit put a drawnow in your external_func function. That way when you click on the button it will update.
edit 3
I think I know what you want to do, try this example and see if it does what you want - updated to show how you find the slider object in your code and update inside your loop:
function mygui
% create a figure
f = figure;
% create a uicontrol slider - note that I give it a tag.
uicontrol ( 'style', 'slider', 'Position', [0 200 200 40], 'tag', 'MYSLIDER', 'backgroundcolor', 'white', 'parent', f );
% create a push button which we can press to update
uicontrol ( 'string', 'Press 2 start', 'callback', #(a,b)myLoop(), 'Position', [0 0 200 50] )
end
% This replicates your "external_func" function.
function myLoop()
% since you cant pass in any var -> you need to find the slider object
% you can do this by using findobj and search for the tag of the item
uic = findobj ( 0, 'tag', 'MYSLIDER' );
% find the figure handle (only needed for this demo)
f = ancestor ( uic, 'figure' );
% initialise the value which will be used to update the slider
count = 0;
% create your loop
while ishandle(f)
% incrememt the count variable -> this will end up on the slider value
count = count + 1e-5;
% reset count if > 1 -> so the slider cant go out of range.
if count >= 1
count = 0;
end
set ( uic, 'Value', count );
% initiate a drawnow -> this allows matlab to process GUI events
drawnow();
end
end
The downside of this is you insert a drawnow in your loop -> which could slow it down somewhat.
If this doesn't fix your problem you need to explain better what you want to do... (in my view)
I have some sliders on figure 1, and I have some images on figure 2. I want to do the callbacks for the sliders in a way that, when I change the sliders in figure 1 , the threshold changes and images update automatically in figure 2.
I'm using addlistener to send values for callback function. The problem is when you move slider the active figure is figure 1, and you want to do changes on figure 2.
adding some code for clarification:
M.rgbImage = imread('euhedral-mag-on-po-edge-pseudo-sub-ophitic-rl-fov-4-8mm.jpg');
[rows, columns, numberOfColorBands] = size(M.rgbImage);
F.f = figure; % This is the figure which has the axes to be controlled.
% Now create the other GUI
S.fh = figure('units','pixels',...
'position',[400 400 500 100],...
'menubar','none',...
'name','Image control',...
'numbertitle','off',...
'resize','off');
S.sl = uicontrol('style','slide',...
'unit','pix',...
'position',[60 10 270 20],...
'min',0,'max',255,'val',100,...
'callback',{#sl_call2,S},'deletefcn',{#delete,F.f});
....
lis = addlistener(S.sl,'Value','PostSet',#(e,h) sl_call3(S,F,M));
function sl_call3(S,F,M)
v = get(S.sl,'value');
figure(F.f), subplot(4, 4, 13);
M.redMask = (M.redPlane > v);
imshow(M.redObjectsMask, []);
set(S.ed(2),'string',v);
Create reference to both your figures:
f1=figure(1);
f2=figure(2);
And then when doing the callback pass f2 as a parameter.
In the callback, you'll have get the handle to the second figure.
There's various ways to do that.
You can specify the handle to the second figure at the time of callback-definition:
figure2 = ...;
addlistener(hSlider, ..., #(a,b) changeStuffOn(figure2));
Or during the callback:
function callbackFunction(hObject, evt)
% get the handle to the second figure, e.g. by a tag, or its name
fig2 = findobj(0, 'type', 'figure', 'tag', 'figure2'); %
% do whatever you want with fig2
end
The latter might be somewhat worse in performance, but e.g. has the benefit of working reliably even if figure2 was deleted and recreated and some point.
To avoid the change of focus you'll have to get rid of this line your callback:
figure(F.f)
This explicitly moves the focus to the second figure.
You'll have to use e.g. the imshow(axes_handle, ...) syntax, in order to show the image not in the "current axes".
Why does ishandle return 1 for double input? For example:
>> a = zeros(1, 2);
>> a(1) = line([1 2], [1 2]);
a =
175.0010 0
>> ishandle(a)
ans =
1 1
Is there a way to check if a handle is valid that will return 0 for non-handle objects?
ishandle accepts common numeric values like 0 (=desktop handle) and 1 (= first open figure by default) which are often also valid handles. However, you will still get an error if you try to set to a property that doesn't exist.
To answer your question either place your code within an exception-handling block:
try
set(a,propName,propValue);
catch
% do something useful...
end
or , if you know what type of object you're looking for, replace ishandle(a) with (for example):
ishandle(a) && strcmp(get(a,'type'),'line')
Matlab handles are in fact just double precision numbers. As you use graphics objects (figures, axes, lines etc) Matlab assigns each item a very specific double as a handle.
The ishandle function checks to see if the number passed in is serving as a handle to any object which can be represented by a handle.
To demonstrate using figures (which are always assigned integer valued doubles):
>> close all; %Close any open figures
>> ishandle(1) %Now the value 1 is not a handle
ans =
0
>> figure(1) %Open a figure, assign it the value 1
>> ishandle(1) %Now 1 i a handle
ans =
1
In your example above, the value 0 is always a handle, representing the Matlab root handle object. This is where some settings related to the command window are held, and it serves as the parent of all figures. The value 175.xxxx is the handles assigned to the line you drew using the plot command.
One useful trick is the findobj function. It finds all objects which are children of a given object, with parameters matching the input parameters. For example:
h = findobj(0,'type','figure'); Returns all figures
h = findobj(0,'type','line'); Returns all line objects in all figures
h = findobj(1,'type','line'); Returns all line objects in figure 1
h = findobj(1,'type','line','color','r'); Returns all line objects in figure 1 whose color is 'r'.
I have data from simulations in one single .dat file. Depending on certain criteria ('bu') that is contained in one column of the file (#13 here), I want to plot the data with different markers, while also defining the markersize and markerface properties.
What I have is a switch environment for the different cases - defining which markers and properties I want, and all this in a for-loop, to go through all simulation data.
I've tried the following:
for i=1:s1(1)
bu = data1(i,13);
switch bu
case 1
set(h,'kd','MarkerSize',14,'MarkerFaceColor','k');
case 2
set(h,'kd','MarkerSize',14);
case 3
set(h,'k>','MarkerSize',14,'MarkerFaceColor','k');
case 4
set(h,'ks','MarkerSize',14,'MarkerFaceColor','k');
case 5
set(h,'ks','MarkerSize',14);
case 6
set(h,'ko','markersize',14);
case 7
set(findobj(gca,'k^','MarkerSize',14,'MarkerFaceColor','k'));
end
figure(1);
h=plot(Re1(i),A1(i)); hold on
end
First I tried to use a handle 'h', but it said it was undefined, I guess since the h=plot comes later. Then I tried findobj in the last case (which is the case for the first simulation, so this gives the error in the first round), didn't work either ("Incomplete property-value pair" - not sure what it means here).
I also tried putting all these properties in a string like
str=['kd','MarkerSize',14,'MarkerFaceColor','k']
then plot with
h=plot(Re1(i),A1(i),str); hold on
but it doesn't work with/without brackets either.
Now I don't have any further ideas, thankful for any suggestions!
I think the easiest change for you is to put the plot options in a cell array in the switch block. For example:
options = {'kd', 'MarkerSize', 14, 'MarkerFaceColor', 'k'};
Later, when you plot:
plot(x, y, options{:})
Another way I've done it is to set variables and use them in the plot command:
style = 'kd';
markerSize = 14;
markerFaceColor = 'k';
plot(x, y, style, 'MarkerSize', markerSize, 'MarkerFaceColor', markerFaceColor);
There are few different ways to do that, one of them - create all plot objects before hand and then fill them with both data and formatting:
figureHandle = figure;
for i=1:s1(1)
plotHandle(i) = plot(0,0); %just creating valid handle for future here
end;
code above before your for loop with bu switch, and then in your switch
set(ph(i),'kd','MarkerSize',14,'MarkerFaceColor','k', 'Xdata', Re(1), 'Ydata', A1(i));
Approach with str would work too, except you would need two cell arrays - option nad value like that:
firstoption = 'kd';
option = {'MarkerSize','MarkerFaceColor'};
value = {14,'k'};
h=plot(Re1(i),A1(i),firstoption);
for i=1:length(option)
set(h,option{i},value{i});
end;