Matlab loop until keystroke - matlab

I have a loop in which I keep entering points into figure using ginput. I would like the loop to run until user presses a key, Heres what I have:
function enter_points()
f = figure();
axis([-1 1 -1 1]);
coorX = [];
coorY = [];
while 1
[x, y] = ginput(1);
coorX = [coorX x];
coorY = [coorY y];
waitforbuttonpress;
key = get(f,'CurrentCharacter');
if (key == 'e')
display('End of cycle.')
break;
else
display('Enter next point')
end
end
coor = [transpose(coorX) transpose(coorY)];
display(size(coor));
display(coor);
end
The problem with this code is, that I haveto press a key to continue entering points. Another problem is, that Matlab sometimes freezes when running this code (Im not sure it the code is the reason or something else is). And how to detect pressing "enter" instead of "e"? Thanks for any help

Why don't you use the builtin:
[X,Y] = ginput gathers an unlimited number of points until the return
key is pressed.

AFAIK, the general way to handle your problem in OOP and Event Oriented Programming is to generate a listener to a given event, in your case a keypress-like event. When defining the listener, one usually passes a callback function to be called(-back) when the event is generated.
One may define listeners e.g. in matlab GUIs (reference). Nonetheless, I am not sure one can do that when the event is generated at the console level.

bdecaf already gave you the simplest answer, but you could also try these couple of changes:
1) Change this:
[x, y] = ginput(1);
to this:
[x, y, key] = ginput(1);
ginput also returns the key you press and even which mouse button (1:LB, 2:RB or 3:MB).
2) Delete these lines:
waitforbuttonpress;
key = get(f,'CurrentCharacter');
With these changes your routine should work as intended. No pause between points, and exit when pressing [e].

Related

Refresh positions of all draw points after deleting or moving - Matlab App designer

I did an app designer GUI with two buttons and axes. The first one (LoadimageButton) is loading the pappers image and I can mark points until I press escape. The second button is printing out the point coordinates (PositionButton).
I have noticed that after pressing the two buttons I can move points in the axes and change their positions or delete them. The issue is that when I press the delete (in the context menu) I get this error after pressing the PositionButton:
Error using images.roi.Point/get
Invalid or deleted object.
Error in tempDrwPnt1/PositionButtonPushed (line 61)
positions = cell2mat(get(app.pointhandles, 'position'))
Error while evaluating Button PrivateButtonPushedFcn.
How can I refresh the app.pointhandles after deleting a point?
Code:
function LoadimageButtonPushed(app, event)
imshow('peppers.png','Parent',app.ImageAxes);
userStopped = false;
app.pointhandles = gobjects();
while ~userStopped
roi = drawpoint(app.ImageAxes);
if ~isvalid(roi) || isempty(roi.Position)
% End the loop
userStopped = true;
else
% store point object handle
app.pointhandles(end+1) = roi;
end
end
addlistener(roi,'MovingROI',#allevents);
addlistener(roi,'ROIMoved',#allevents);
app.pointhandles(1) = [];
function allevents(src,evt)
evname = evt.EventName;
switch(evname)
case{'MovingROI'}
disp(['ROI moving previous position: ' mat2str(evt.PreviousPosition)]);
disp(['ROI moving current position: ' mat2str(evt.CurrentPosition)]);
case{'ROIMoved'}
disp(['ROI moved previous position: ' mat2str(evt.PreviousPosition)]);
disp(['ROI moved current position: ' mat2str(evt.CurrentPosition)]);
end
end
end
% Button pushed function: PositionButton
function PositionButtonPushed(app, event)
positions = cell2mat(get(app.pointhandles, 'position'))
end
You could add a check within the PositionButtonPushed function for whether or not each pointhandles element is valid, report on it if so or remove it if not
Something like
function PositionButtonPushed(app, event)
nPts = numel(app.pointhandles);
positions = NaN(nPts,2); % array to hold positions
for iPt = nPts:-1:1 % loop backwards so we can remove elements without issue
if isvalid( app.pointhandles(iPt) )
positions(iPt,:) = get(app.pointhandles(iPt),'position');
else
% No longer valid (been deleted), remove the reference
app.pointhandles(iPt) = [];
% Also remove from the positions output
positions(iPt,:) = [];
end
end
end
I haven't got a compatible MATLAB version available right now to test this, but I am assuming the in-built function isvalid works for Point objects, otherwise you will have to add your own validity check. Alternatively you could try to get the position, and do the deletion (handled by else above) within a catch, but I usually recommend against try/catch if you can check for a specific (known) issue instead.
I've often used something similar (e.g. for axes), but bundled the cleanup functionality for invalid handles into its own function. In this case it would have let you add a single function call before getting the positions of the remaining valid points.
I've also made this more condensed by using arrayfun, but under the hood it's the same approach as the above loop:
function PositionButtonPushed(app, event )
app.checkHandleValidity(); % cleanup handles just in case
positions = cell2mat(get(app.pointhandles, 'position'));
end
function checkHandleValidity( app )
bValid = arrayfun( #isvalid, app.pointhandles ); % Check validity
app.pointhandles( ~bValid ) = []; % Remove invalid elements
end

How to make gracefull by-user termination in Matlab?

I am doing bayessian hyperparameter search in Matlab. The process is infinite by nature, so I am showing the plot and have limits by number of iterations and time. Nevertheless, very often I see that the plot will not improve anymore and want to terminate the process. If I terminate script by force it will stop in random place and won't finish gracefully. I would like it to save best found combination so far.
Can I make a button or something, which could flag process to terminate gracefully and perform final operations?
Here is a simple example of how you could achieve this, from a figure with uicontrol helpers.
function pushbuttonPlot
f = figure;
ax = axes;
L = 160*membrane(1,100);
s = surface(L);
s.EdgeColor = 'none';
view(3)
ax.XLim = [1 201];
ax.YLim = [1 201];
ax.ZLim = [-53.4 160];
c = uicontrol;
c.String = 'Clean Up';
c.Callback = #cleanUpandExit;
function cleanUpandExit(src,event)
disp('Cleanup and exit');
% Save data and exit
close(f);
end
end

Matlab GUI. Set pushbutton handles in another .m file

I have a big Matlab code and now I am trying to connect it to GUI. I have created a function
function z = interface_master(handles)
which first gets initial parameters from GUI text edit box and then runs a number of .m files using these parameters, for example
n = get(handles.n_value,'String');
n = str2num(n);
assign('base','n',n)
run('code_1')
run('code_2')
...
Within this 'codes' I create and save a number of figures. I would like now for the User to be able to display a figure of his choice within GUI. Lets say I will have 3 different push buttons (Push1, Push2, Push3) and User after pressing Push1 will get Figure_A displayed. Then after pressing Push2, he will get Figure_B replacing Figure_A, and so on. Can I somehow make it work just setting handles in my function interface_master?
I don't want to overcrowd my interface.m file and so far I managed to do everything else (reading values, displaying messages) in this additional interface_master file, by just connecting both through interface_master(handles) in the interface callback functions. But now I am stuck with these push buttons.
I would really appreciate some help here. I have never done any GUI before.
I have created a very much simplified version of what I am doing. In general code_1 and code_2 are much much bigger and the interface will be displaying more messages, while code_1 and code_2 save around 20 different figures. But what I am struggling with can be demonstrated by a simple code calculating polynomials.
%% code_1.m
x = linspace(-1,1) ;
y = x.^n ;
%% code_2.m
f = figure('visible','off');
plot(x,y);
set(f,'Visible','on')
saveas(f,'power_plot_1','fig')
delete(f)
g = figure('visible','off');
plot(x,x.^(n+1));
set(f,'Visible','on')
saveas(g,'power_plot_2','fig')
delete(g)
%%% master.m
function z = master(handles)
n = get(handles.n_value,'String')
n = str2num(n) ;
assignin('base','n',n)
if (n < 1)
message = ('small n') ;
elseif (n>10)
message = ('large n') ;
else
message=('hello world') ;
run('code_1')
run('code_2')
end
set(handles.text1,'String',message)
and here is the interface:
https://lh3.googleusercontent.com/-5zoGVwgJhoM/V1qdiyd667I/AAAAAAAACQ0/oaTQHYn13gIuLoSb42Q7N66AV102e-VjQCCo/s912/inter.png

Matlab gui with pause function

I am using the GUIDE for matlab gui.
The gui built in order to communicate with keithley current measurement device through GPIB.
When using a toggle button for Current measurement while loop, i am using a pause() function inside the while loop for each iteration and a ytranspose on the y array reading results.
function Measure_Callback(hObject, eventdata, handles)
global GPIB1
global filename
global timeStep
disp('Measurement in progress \n stopwatch starts!');
tic
x=0;
n=0;
while get(hObject,'Value')
fprintf(GPIB1, 'printnumber(smua.measure.i(smua.nvbuffer1))');
fprintf(GPIB1, 'printbuffer(1,1,nvbuffer1)');
A = fscanf(GPIB1);
if length(A)<20
x = x+1;
n = n+1;
t(n) = toc ;
y(x) = str2double(A);
plot(t,y,'-bo',...
'LineWidth',2,...
'MarkerEdgeColor','k',...
'MarkerFaceColor',[.49 1 .63],...
'MarkerSize',10);
grid on
hold on
end
title('Current vs Time','FontSize', 15)
xlabel('Time [s]','FontSize', 15)
ylabel('Current [A]','FontSize', 15)
a = timeStep;
pause(a)
end
disp('Measurement terminated');
disp('Elapsed time: ');
elapsedtime = toc;
elapsedtime_string = num2str(elapsedtime);
disp(elapsedtime_string);
ytrans = transpose(y);
csvwrite(filename,ytrans);
fprintf(GPIB1, 'smua.source.output = smua.OUTPUT_OFF');
For the pause function i'm geting error:
?? Error using ==> pause Error while evaluating uicontrol Callback
For the transpose(y) function i'm also getting a error:
its undefined y.
Cant understand why are those errors and could use some help.
Thank you!
First off, as people say, post the errors and the code. Do you know if length(A) is smaller than 20 in the first time you run the loop? Because if not, A is not defined and you can't transpose something that is not there. Initialize A before the loop to something and see if the error persists (or print out length(A) to make sure the loop gets entered the first run).
As for the pause error, make sure pause is an int or double, not a string. If you get your global timeStep from the GUI field, it is probably a string and you need to covert it to double first.

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