Switching values to plot using keyboard input - matlab

I have sets of data in a matrix. I want to plot on set and then use a keyboard input to move to another one. It's simply possible this way:
for t=1:N
plot(data(:,t))
pause
end
but I want to move forward and backward in time t (e.g. using arrows). OK, it could be done like this:
direction = input('Forward or backward?','s')
if direction=='forward'
plot(data(:,ii+1))
else
plot(data(:,ii-1))
end
but isn't there something more elegant? (On one click without getting the figure of the sight - it's a big full sreen figure.)

You can use mouse clicks combined with ginput. What you can do is put your code in a while loop and wait for the user to click somewhere on the screen. ginput pauses until some user input has taken place. This must be done on the figure screen though. When you're done, check to see which key was pushed then act accordingly. Left click would mean that you would plot the next set of data while right click would mean that you plot the previous set of data.
You'd call ginput this way:
[x,y,b] = ginput(1);
x and y denote the x and y coordinates of where an action occurred in the figure window and b is the button you pushed. You actually don't need the spatial coordinates and so you can ignore them when you're calling the function.
The value of 1 gets assigned a left click and the value of 3 gets assigned a right click. Also, escape (on my computer) gets assigned a value of 27. Therefore, you could have a while loop that keeps cycling and plotting things on mouse clicks until you push escape. When escape happens, quit the loop and stop asking for input.
However, if you want to use arrow keys, on my computer, the value of 28 means left arrow and the value of 29 means right arrow. I'll put comments in the code below if you desire to use arrow keys.
Do something like this:
%// Generate random data
clear all; close all;
rng(123);
data = randn(100,10);
%// Show first set of points
ii = 1;
figure;
plot(data(:,ii), 'b.');
title('Data set #1');
%// Until we decide to quit...
while true
%// Get a button from the user
[~,~,b] = ginput(1);
%// Left click
%// Use this for left arrow
%// if b == 28
if b == 1
%// Check to make sure we don't go out of bounds
if ii < size(data,2)
ii = ii + 1; %// Move to the right
end
%// Right click
%// Use this for right arrow
%// elseif b == 29
elseif b == 3
if ii > 1 %// Again check for out of bounds
ii = ii - 1; %// Move to the left
end
%// Check for escape
elseif b == 27
break;
end
%// Plot new data
plot(data(:, ii), 'b.');
title(['Data set #' num2str(ii)]);
end
Here's an animated GIF demonstrating its use:

This demo shows you how to use either the left and right arrows of the keyboard to switch data set or even the mouse wheel.
It uses the KeyPressFcn and/or WindowScrollWheelFcn event of the figure.
function h = change_dataset_demo
%// sample data
nDataset = 8 ;
x = linspace(0,2*pi,50).' ; %'// ignore this comment
data = sin( x*(1:nDataset) ) ;
index.max = nDataset ;
index.current = 1 ;
%// Plot the first one
h.fig = figure ;
h.plot = plot( data(:,index.current) ) ;
%// store data in figure appdata
setappdata( h.fig , 'data', data )
setappdata( h.fig , 'index', index )
%// set the figure event callbacks
set(h.fig, 'KeyPressFcn', #KeyPressFcn_callback ) ; %// Set figure KeyPressFcn function
set(h.fig, 'WindowScrollWheelFcn',#mouseWheelCallback) %// Set figure Mouse wheel function
guidata( h.fig , h )
function mouseWheelCallback(hobj,evt)
update_display( hobj , evt.VerticalScrollCount )
function KeyPressFcn_callback(hobj,evt)
if ~isempty( evt.Modifier ) ; return ; end % Bail out if there is a modifier
switch evt.Key
case 'rightarrow'
increment = +1 ;
case 'leftarrow'
increment = -1 ;
otherwise
% do nothing
return ;
end
update_display( hobj , increment )
function update_display( hobj , increment )
h = guidata( hobj ) ;
index = getappdata( h.fig , 'index' ) ;
data = getappdata( h.fig , 'data' ) ;
newindex = index.current + increment ;
%// roll over if we go out of bound
if newindex > index.max
newindex = 1 ;
elseif newindex < 1
newindex = index.max ;
end
set( h.plot , 'YData' , data(:,newindex) ) ;
index.current = newindex ;
setappdata( h.fig , 'index', index )
This will roll over when the end of the data set is reached.
done a little gif too but it's a lot less impressive because it does not show the keyboard/mouse action, only the graph updates :

Related

Real-time update of values inside a call_back function[the values are from external function(of another .m file)]

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)

Scatter persists after setting X & YData to fewer points

EDIT: See end of post for code to automatically reproduce the issue without the mouse/keyboard input and for pictures describing the issue.
Please let me know if any of the following explanation or code requires further clarification.
I'm allowing a user to click on an axis and scatter points appear where they click. Left clicking results in larger scatter markers, and right clicking results in smaller scatter markers. Pressing enter adds a new set (represented by scatter markers switching between yellow and red). Pressing backspace should delete the most recent marker, and consecutively delete markers back through the set and into previous sets if continued to be pressed.
This works fine if I use only one size marker, however, if I allow the size to be determined by the left/right click, then upon clicking backspace to delete previous points, it will correctly delete the points until you arrive at the first point (the earliest point, not the first you try to delete) which had a size change. The still appear on the figure as if they were a separate scatter plot, even though they are one scatter plot, and the data the plot is set from has been deleted (and the scatter data set to that deleted data set).
Here is my example code:
function CodeToReplicateIssue()
a = get(0,'ScreenSize');
set(0,'DefaultFigurePosition',[a(3)*.3,a(4)*.1,a(3)*.4,a(4)*.8]);
mainFig = figure;
set(mainFig, 'WindowButtonDownFcn', #mouseDown);
set(mainFig,'WindowKeyPressFcn', #keyPress);
pfTitle = 'Next Set: Enter Delete Previous Point: Backspace';
colormap('gray');
imagesc(zeros(512,512));
set(gca,'XTick',[]);
set(gca,'YTick',[]);
axis image;
title(pfTitle)
hold on;
cStrs2 = {'r','y'};
pfTracks = {[]};
pfTracksRef = {[]};
pfTrackI = 1;
pfScatters{1} = scatter([],[],5,cStrs2{2});
function mouseDown(source,callbackData)
%display('mouseDown');
pos = get (gca, 'CurrentPoint');
pos = pos(1,1:2);
pfTracksRef{pfTrackI}(end+1) = ~strcmp(get(source,'SelectionType'),'alt');
pfTracks{pfTrackI}(end+1,1:2) = pos;
if(numel(pfScatters)<pfTrackI)
pfScatters{pfTrackI} = scatter(pos(1),pos(2),getSizes(pfTrackI),cStrs2{mod(pfTrackI,2)+1});
else
set(pfScatters{pfTrackI},{'XData','YData','SizeData'},{pfTracks{pfTrackI}(:,1),pfTracks{pfTrackI}(:,2),getSizes(pfTrackI)});
end
end
function keyPress(source,eventdata)
%display(eventdata.Key);
if(strcmp(eventdata.Key,'return'))
if(isempty(pfTracks{pfTrackI}))
%do nothing
else
refreshScatter('pfScatters');
pfTrackI = pfTrackI+1;
pfTracks{pfTrackI} = [];
pfTracksRef{pfTrackI} = [];
end
elseif(strcmp(eventdata.Key,'backspace'))
if(isempty(pfTracks{pfTrackI}) && numel(pfTracks)>1)
pfTracks(pfTrackI) = [];
pfTracksRef(pfTrackI) = [];
if(numel(pfScatters) >= pfTrackI)
pfScatters(pfTrackI:end) = [];
end
pfTrackI = pfTrackI -1;
end
if(numel(pfTracks{pfTrackI}))
pfTracks{pfTrackI}(end,:) = [];
pfTracksRef{pfTrackI}(end) = [];
end
refreshScatter('pfScatters');
end
end
function refreshScatter(strOption)
if(nargin<1)
strOption = '';
end
if(any(strcmp(strOption,{'','pfScatters'})))
for n = 1:numel(pfScatters)
if(numel(pfTracks{n})>0)
set(pfScatters{n},{'XData','YData','SizeData','MarkerEdgeColor'},{pfTracks{n}(:,1),pfTracks{n}(:,2),getSizes(n),cStrs2{mod(n,2)+1}});
else
set(pfScatters{n},{'XData','YData'},{[],[]});
end
end
end
end
function scatterSize = getSizes(indx)
scatterSize = 9*(pfTracksRef{indx}(:)+1)-6;
end
end
Line 32:
pfTracksRef{pfTrackI}(end+1) = ~strcmp(get(source,'SelectionType'),'alt');
This is where the left or right mouse button is recorded, later used in getSizes(), with the output used for calls to scatter (or when setting the scatter series SizeData).
I can't figure out why the points created before a size change persist after deleteing the associated data and setting the scatter values to that data. It seems like the first time a size is changed a new scatter series is created.
Any light that could be shed on this issue would be appreciated, and any fixes would be doubly appreciated.
Thanks.
EDIT: One way to see what I'm talking about is to do the following:
Left click several times (lets say 5), spaced out so you can see them all.
Push Enter
Left click 5 more times, again spaced out, note they are in red (this is a desired functionality for my final product).
Press backspace until all the points are no longer visible. This is the correct funcitonality.
Incorrect:
Left click 1 time, right click 4 times.
Press enter
Left click 1 time, right click 4 times.
Backspace repeatedly (10 times). Note that the first 2 points (1 large and 1 small) from both the red and the yellow persist, even though you have clicked backspace enough times to delete everything, which is what happened when there was no size change.
EDIT: I've added code below that replicates the issue I am seeing using some loops and doing away with requiring mouse and keyboard input.
function ReplicateIssueWithLoops()
mainFig = figure;
imshow(zeros(512,512));
hold on;
axis image;
for hh = 1:2
%two runs, the first works fine, the second fails to remove scatter
%points from the figure.
cStrs = {'r','y'};
tracks = {[]};
tracksSizeRef = {[]};
trackI = 1;
scatters{1} = scatter([],[],5,cStrs{2});
for ii = 1:2
%simulates 2 sets
for jj = 1:5
%simulates 5 left clicks each
tracks{ii}(end+1,:) = [256,(ii*6+jj)*20];
if(hh ==1) %Simulates all left clicks
tracksSizeRef{ii}(end+1) = 12;
else %Simulates 1 left click and 4 right clicks
tracksSizeRef{ii}(end+1) = ((jj==1)+1)*9-6;
end
if(numel(scatters)<ii)
scatters{ii} = scatter(tracks{ii}(:,1),tracks{ii}(:,2),tracksSizeRef{ii},cStrs{mod(ii,2)+1});
else
set(scatters{ii},{'XData','YData','SizeData'},{tracks{ii}(:,1),tracks{ii}(:,2),tracksSizeRef{ii}});
end
pause(0.25);
end
tracks{ii+1}=[];
tracksSizeRef{ii+1} = [];
end
trackI = ii;
for kk = 1:10
%simulates 10 backspaces
if(isempty(tracks{trackI}) && numel(tracks)>1)
tracks(trackI) = [];
tracksSizeRef(trackI) = [];
if(numel(scatters) >= trackI)
scatters(trackI:end) = [];
end
trackI = trackI -1;
end
if(numel(tracks{trackI}))
tracks{trackI}(end,:) = [];
tracksSizeRef{trackI}(end) = [];
end
refreshScatters();
pause(0.25);
end
end
function refreshScatters()
for n = 1:numel(scatters)
if(numel(tracks{n})>0)
set(scatters{n},{'XData','YData','SizeData','MarkerEdgeColor'},{tracks{n}(:,1),tracks{n}(:,2),tracksSizeRef{n},cStrs{mod(n,2)+1}});
else
set(scatters{n},{'XData','YData'},{[],[]});
end
end
end
end
Below are pictures demonstrating how the issue looks on my end. In left to right order the pictures show 1) at the end of the first 10 points, 2) after deleting the first 10 points , 3) after the second ten points (the set with size difference), 4) after deleting the second 10 points (4 remain, the two from each set when the size was first changed).

Set data tips programmatically?

I need to be able to set data tips programmatically from a list of array of x axis values. For example, I create a figure and plot my data.
figure;plot(t1,[filter(b,a,Gyro(:,2)),filter(b,a,Gyro(:,4))])
I have a set of timestamp values from t1 variable (time) (e.g. [0.450, 0.854, 1.2343....]) where I want to place data tips to mark certain events in my data. Without having to place them every time manual by clicking and saving data trip... How can I pass them as array and do this programmatically through matlab script?
You can add matlab datatip programatically and customize them to an extent.
The function below shows how to add a few datatip, position them and customize their display:
The code for this demo (save that in a file demo_datatip.m and run it to obtain the above figure) :
function h = demo_datatip
%// basic sample curve
npts = 600 ;
x = linspace(0,4*pi,npts) ;
y = sin(x) ;
%// plot
h.fig = figure ;
h.ax = axes ;
h.plot = plot(x,y) ;
%// simulate some event times
time_events = x([25 265 442]) ; %// events type 1 at index 25, 265 and 422
%// define the target line for the new datatip
hTarget = handle(h.plot);
%// Add the datatip array
h.dtip = add_datatips( time_events , hTarget ) ;
function hdtip = add_datatips( evt_times , hTarget )
%// retrieve the datacursor manager
cursorMode = datacursormode(gcf);
set(cursorMode, 'UpdateFcn',#customDatatipFunction, 'NewDataCursorOnClick',false);
xdata = get(hTarget,'XData') ;
ydata = get(hTarget,'YData') ;
%// add the datatip for each event
for idt = 1:numel(evt_times)
hdtip(idt) = cursorMode.createDatatip(hTarget) ;
set(hdtip(idt), 'MarkerSize',5, 'MarkerFaceColor','none', ...
'MarkerEdgeColor','r', 'Marker','o', 'HitTest','off');
%// move it into the right place
idx = find( xdata == evt_times(idt) ) ;%// find the index of the corresponding time
pos = [xdata(idx) , ydata(idx) ,1 ];
update(hdtip(idt), pos);
end
function output_txt = customDatatipFunction(~,evt)
pos = get(evt,'Position');
idx = get(evt,'DataIndex');
output_txt = { ...
'*** !! Event !! ***' , ...
['at Time : ' num2str(pos(1),4)] ...
['Value: ' , num2str(pos(2),8)] ...
['Data index: ',num2str(idx)] ...
};
If you need to delete a data tip, you can simply call delete(datatip_handle) on it's handle (or even an array of handles to delete them in group).
Here is a small example that might be what you are looking for:
time = 0:0.5:10;
values = rand(1,length(time));
datatip_index = [3 6]; % an 'event' occurs on the 3rd and 6th datapoint
datatip_text = {'event1', 'event2'};
figure;
plot(time,values)
hold on
text(time(datatip_index), values(datatip_index), datatip_text)

For Loop and indexing

Following is my code :
function marks(my_numbers)
handle = zeros(5,1)
x = 10 ;
y = 10:20:100 ;
for i = 1
for j = 1:5 ;
handle(j,i) = rectangle('position',[x(i),y(j),20 10],'facecolor','r')
end
end
end
now lets say input argument my_numbers = 2
so i have written the code :
set(handle(j(my_numbers),1),'facecolor','g')
With this command, rectangle with lower left corner at (30,10) should have turned green. But MATLAB gives an error of index exceeds matrix dimensions
This is more an illustrated comment than an answer, but as #hagubear mentioned your i index is pointless so you could remove it altogether.
Using set(handle(my_numbers,1),'facecolor','g') will remove the error, because you were trying to access handles(j(2),1) and that was not possible because j is a scalar.
Anyhow using this line after your plot works fine:
set(handle(my_numbers,1),'facecolor','g')
According to your comment below, here is a way to call the function multiple times and add green rectangles as you go along. There are 2 files for the purpose of demonstration, the function per se and a script to call the function multiple times and generate an animated gif:
1) The function:
function marks(my_numbers)
%// Get green and red rectangles to access their properties.
GreenRect = findobj('Type','rectangle','FaceColor','g');
RedRect = findobj('Type','rectangle');
%// If 1st call to the function, create your plot
if isempty(RedRect)
handle = zeros(5,1);
x = 10 ;
y = 10:20:100 ;
for j = 1:5 ;
handle(j) = rectangle('position',[x,y(j),20 10],'facecolor','r');
end
set(handle(my_numbers,1),'facecolor','g')
%// If not 1st call, fetch existing green rectangles and color them green. Then color the appropriate rectangle given by my_numbers.
else
RedRect = flipud(RedRect); %// Flip them to maintain correct order
if numel(GreenRect) > 0
hold on
for k = numel(GreenRect)
set(GreenRect(k),'facecolor','g')
set(RedRect(my_numbers,1),'facecolor','g')
end
end
end
2) The script:
clear
clc
%// Shuffle order for appearance of green rectangles.
iter = randperm(5);
filename = 'MyGifFile.gif';
for k = iter
marks(k)
pause(1)
frame = getframe(1);
im = frame2im(frame);
[imind,cm] = rgb2ind(im,256);
if k == iter(1)
imwrite(imind,cm,filename,'gif', 'Loopcount',inf);
else
imwrite(imind,cm,filename,'gif','WriteMode','append');
end
end
Here is the animated gif of the output:

How can I change pushbutton visibility in MATLAB?

I am trying to create a simple game.
What it should do: Create 2 pushbuttons and when user clicks each button it should disappear.
What it actually does: When I click the first button it disappears. But when I click the 2nd one nothing happens.
clear all, clc, close all
fh = figure;
n = 2;
x = ceil(rand(10)*2);
y = ceil(rand(10)*2);
bgh = uibuttongroup('Parent',fh,'Title',...
'Button Game','Position',[.1 .2 .8 .6]);
for i = 1:n
rbh1 = uicontrol(bgh,'Style','Pushbutton','String','Red',...
'Units','normalized','Position',[rand(1) rand(1) x(1,i) y(1,i)]);
set(rbh1,'CallBack','set(rbh1,''visible'',''off'')')
end
axt = axes('Parent',bgh,'Units','normalized');
axis([0.5 1 0.5 1])
axis square
axis off
How can I fix this?
The problem is that you're setting the callback for one handle only. Change the loop bit of your code to the following and it will work. Since this seems like a learning exercise, I'll leave it to you to explore it and figure out why making this change helps.
for i = 1:n
rbh(i) = uicontrol(bgh,'Style','Pushbutton','String','Red',...
'Units','normalized','Position',[rand(1) rand(1) x(1,i) y(1,i)]);
set(rbh(i),'CallBack',['set(rbh( ' num2str(i) '),''visible'',''off'')'])
end