My goal is to get the user's input from a uicontrol text box, do operations on the input and then display the output to another text box. MATLAB gives me the error:
Error using
UnitConverter/lbs2kg
Too many input arguments.
Error in
UnitConverter>#(varargin)app.lbs2kg(varargin{:})
(line 22)
'Callback',#app.lbs2kg,'String',app.inputMass);
Error while evaluating UIControl Callback
Here is my code:
classdef UnitConverter < handle
properties
Figure % Graphics handles
DispInputMass
DispOutputMass
inputMass %Variables/Class Properties
outputMass
end
methods
function app = UnitConverter
% This is the "constructor" for the class
% It runs when an object of this class is created
app.Figure = figure('Name','Unit Converter') ;
app.DispInputMass = uicontrol('Style','edit',...
'Callback',#app.lbs2kg,'String',app.inputMass);
app.DispOutputMass = uicontrol(app.Figure,'Style','edit','Position'...
,[168 100 47 26],'String','kg');
end
function lbs2kg(app,evt)
app.inputMass = get(app.DispInputMass,'string');
app.outputMass = app.inputMass*.453;
set(app.DispOutputMass,'string',app.outputMass);
end
end
end
The callback method actually has 3 inputs - MATLAB is throwing this error because it is trying to send three inputs to your callback which is written to only accept 2. The 3 inputs are (in order): the main object (app), the object sending the event (uicontrol) and the event (matlab.ui.eventdata.ActionData).
You can change the code to the following to get it to work:
function lbs2kg(app, obj, evt)
app.inputMass = get(app.DispInputMass,'string');
app.outputMass = app.inputMass*.453;
set(app.DispOutputMass,'string',app.outputMass);
end
Additionally you can change the first line of the function to the following:
function lbs2kg(varargin)
Breakpoint the code at the first line of the callback and investigate the contents of varargin. For more help about varargin see here (http://www.mathworks.com/help/matlab/ref/varargin.html)
Related
I have some error handling code that I want a bunch of functions to use, so in order to avoid repetition I thought I would put it in my generic class that holds utility functions FunctionContainer.
Here's a truncated version of FunctionContainer:
classdef FunctionContainer
methods (Static)
function run(func, ExpInfo, logdir, newdir, varargin)
try
func(ExpInfo, newdir, varargin)
catch ME
FunctionContainer.errproc(logdir, newdir, ME)
end
end
function errproc(logdir, newLogDir, ME)
errdir = fullfile(logdir, 'error');
movefile(newLogDir, errdir);
pathParts = strsplit(newLogDir, filesep);
logID = pathParts(end);
newLogText = fullfile(errdir, logID, 'error.txt');
fid = fopen(newLogText, 'wt');
fprintf(fid, '%s\n%s\n', ME.identifier, ME.message);
for i = 1:length(ME.stack)
fprintf(fid, '%i\t%s\n', ME.stack(i).line, ...
ME.stack(i).file);
end
fclose(fid);
rethrow(ME);
end
function newdir = prolog(logdir, id, supfiles)
id = join([id, string(clock)], '_');
newdir = fullfile(logdir, id); mkdir(newdir)
stack = dbstack('-completenames');
files = horzcat({stack.file}, supfiles);
for i = 1:numel(files)
copyfile(files{i}, newdir)
end
end
end
end
Here's the context in which I'm using it:
function realign(ExpInfo)
fc = FunctionContainer;
logdir = ExpInfo.logdir;
ws = fullfile(logdir, 'workspace.mat'); save(ws);
newdir = fc.prolog(logdir, 'realign', {ws});
fc.run(runRealign, ExpInfo, logdir, newdir);
function runRealign(ExpInfo, newdir)
% do a bunch of stuff
end
end
The relevant line in my script ks_main.m that calls realign is
realign(FullData)
I get this error:
8 fc.run(runRealign, ExpInfo, logdir, newdir);
Error using realign/runRealign
Too many output arguments.
Error in realign (line 8)
fc.run(runRealign, ExpInfo, logdir, newdir);
Error in ks_main (line 35)
realign(FullData)
I just don't understand this error in this context. None of these functions is returning anything or has any outputs. I could maybe understand if runRealign were getting too many inputs, and I tried defining runRealign like this
function runRealign(ExpInfo, newdir, varargin)
but that made no difference. Maybe this has something to do with passing a function as an argument to another function? What's the right way to do this in Matlab?
You need to put the # symbol in front of your function argument in fc.run. Always do this when passing a function handle as an argument (https://au.mathworks.com/help/matlab/matlab_prog/pass-a-function-to-another-function.html). Line 8 of realing.m should be:
fc.run(#runRealign, ExpInfo, logdir, newdir);
There are a couple of other issues. One is that you are missing an end at the end of FunctionContainer. This is probably just a typo in your question or else you would also have an error related to this.
Another small implementation detail is that you don't need to use logdir as an argument if it is going to be a field in ExpInfo anyway---you can simply access it from ExpInfo inside of FunctionContainer without having to pass it explicitly to run. Passing both ExpInfo and its field logdir to the same function is unclear and stylistically bad practice. (Which reminds me, you should provide a definition of FullData in your question as well. I had to discern that it requires this field.)
However, this is code as is is also going to cause an exception to be thrown on line 6 of FunctionContainer. The definition of runRealign only takes 2 arguments, but when you try to run it in FunctionContainer you expect 3: func(ExpInfo, newdir, varargin). If I change line 6 of FunctionContainer to:
func(ExpInfo, newdir)
it works.
To make this robust and error free you need either to parse the varargin in FunctionContainer so that it intelligently handles a variable number of arguments (https://au.mathworks.com/help/matlab/ref/varargin.html), or else guarantee that the input function handle points to one that has 2 arguments for ever and always.
I am making an app to track my finances and I am confused as how to pass a string to a callback function in a uicontrol pushbutton object.
For instance:
classdef moneyapp < handle
methods (Access = public)
function app = moneyApp
% uicontrol object example
app.NewSymbolGLMC = uicontrol(app.FigureGLMC,...
'Style','pushbutton','Position',[300 60 200 20],...
'String','New Stock',...
'Callback', {#app.newStock,'Account Name'});
end
function newStock(src,eventData,account)
% Do something with the string, 'Account Name'
end
end
end
end
I am confused as to how to get the string, 'Account Name', to the newStock function. This is an essential part to my code and I just think my syntax is not correct; more examples of the code can be provided if needed. Any help would be greatly appreciated!
Since newStock is a method of your class, the first input must be the object itself. Because of this you need four input arguments in your function definition:
the instance, the source and event data (the default inputs), and the account name.
function newStock(obj, src, eventData, account)
As a side note, the capitalization of your constructor (moneyApp) must match the capitalization of the class (moneyapp) to be treated as a constructor.
I want to find the Minimum of a function using
[x,fval] = fminsearch(#(param) esm6(param,identi),result(k,1:end-1),options)
now for each Iteration step i want some values that the function 'esm6' calculates to be saved in an Array. I tried the following:
In the first line of the function i wrote
identi.sim.i_optiIter = identi.sim.i_optiIter + 1;
to have an iteration-variable counting the iteration steps of fminsearch. And later to catch the values that I need I used
identi.sim.guete_werte.gew(identi.sim.i_optiIter,:,:) = y_sim;
identi.sim.guete_werte.ungew(identi.sim.i_optiIter,:,:) = y_sim_ungew;
and to make sure that I use the new values of the identi-struct for the next function call, I wrote this at the end of the function:
assignin('base','identi',identi);
Now unfortunatly it doesn't do what I wanted it to do. Can anyone help me with this?
EDIT:
I made another attempt on it, using an Output function. I extendend my Options like this:
options = optimset('Display','iter','MaxIter',3,'OutputFcn',#outfun);
But now the Problem is that i cannot figure out where to put this outfun. The outfun Looks like this:
function stop = outfun(x,optimvalues,state,iteration,y_sim,y_sim_ungew)
stop = false;
if state == 'iter'
guete_werte.gew(iteration,:,:) = y_sim;
guete_werte.ungew(iteration,:,:) = y_sim_ungew;
end
end
Now the Problem with it is, that i can not put it in the file, where i call the fminsearch, because that is a script. If i put the outputfunction into a separate .m-function file, it is not able to Access the variables of the esm6 function. And if I add it to the esm6-function file, matlab can't find the function and says
??? Error using ==> feval Undefined function or method 'outfun' for
input arguments of type 'struct'.
I am trying to write a minimal function that can be called with a variable number of arguments but that will not throw a wrong number of arguments error if miscalled.
Here is where I start from :
function varargout=fname(varargin)
% FNAME
% Usage: output=fname(input)
% Arguments check
if(nargin~=1 || nargout~=1)
disp('Function fname requires one input argument');
disp('and one output argument');
disp('Try `help fname`');
varargout(1:nargout)={0};
return;
end
input=varargin{1};
output=input;
varargout(1)={output};
end
However this does not work as I would like it to. Is there a way to write a function that :
never throw a "wrong number of arguments" error (so that the rest of the execution can continue)
accepts variable number of input and output arguments and checks them inside the function
(maybe more tricky) if the number of input / output arguments is not correct, does not replace the value of the provided output arguments (so that any misplaced call does not erase the previous value of the output argument)
I am open to any suggestions / other methods.
Thank you for your help.
UPDATE: thanks to #Amro for his answer, I guess what I miss here is either a call by address of reference for Matlab functions or a way to interrupt a function without returning anything and without stopping the rest of the execution.
Here is one way to implement your function:
function varargout = fname(input,varargin)
%# FNAME
%# Usage: output=fname(input)
%%# INPUT
if nargin<1
varargout(1:nargout) = {[]};
warning('Not enough input arguments.'), return
end
if ~isempty(varargin)
warning('Too many input arguments.')
end
%%# YOUR CODE: manipulate input, and compute output
output = input;
%%# OUTPUT
varargout{1} = output;
if nargout>1
warning('Too many output arguments.')
varargout(2:nargout) = {[]};
end
end
Obviously you can customize the warning messages to your liking...
Also, if you want your function to simply print the message instead of issuing warnings, replace all WARNING calls with simple DISP function calls.
Examples of function call:
fname()
fname(1)
fname(1,2)
x = fname()
x = fname(1)
x = fname(1,2)
[x,y] = fname()
[x,y] = fname(1)
[x,y] = fname(1,2)
The above calls execute as expected (showing warning messages when applicable). One caveat though, in the last three calls, if the variable y already existed in the workspace prior to the calls, it would be overwritten by the empty value y=[] in each...
If I understand your question correctly, then the answer is no. If a caller calls a function like this:
[a, b, c] = fname('foo');
then fname is required to return (at least) three outputs. There's no way to tell MATLAB that it should leave b and c alone if fname only returns one output.
I have a set of code that, depending on how the program is initiated, will either be executed locally or sent to a remote machine for execution. The ideal way I imagine this could work would look something like the following:
line_of_code = 'do_something_or_other();';
if execute_remotely
send_via_udp(line_of_code);
else
eval(line_of_code);
end
The thing is, I know that the eval() function is ridiculously inefficient. On the other hand, if I write out line_of_code in each section of the if block, that opens the door for errors. Is there any other way that I can do this more efficiently than by simply using eval()?
EDIT: After more consideration and some discussion in the comments, I have my doubts that function handles can be transmitted via UDP. I'm therefore updating my answer, instead suggesting the use of the function FUNC2STR to convert the function handle to a string for transmission, then using the function STR2FUNC to convert it back to a function handle again after transmission...
To get around using EVAL, you can use a function handle instead of storing the line of code to be executed in a string:
fcnToEvaluate = #do_something_or_other; %# Get a handle to the function
if execute_remotely
fcnString = func2str(fcnToEvaluate); %# Construct a function name string
%# from the function handle
send_via_udp(fcnString); %# Pass the function name string
else
fcnToEvaluate(); %# Evaluate the function
end
The above assumes that the function do_something_or_other already exists. You can then do something like the following on the remote system:
fcnString = receive_via_udp(); %# Get the function name string
fcnToEvaluate = str2func(fcnString); %# Construct a function handle from
%# the function name string
fcnToEvaluate(); %# Evaluate the function
As long as the code (i.e. m-file) for the function do_something_or_other exists on both the local and remote systems, I think this should work. Note that you could also use FEVAL to evaluate the function name string instead of converting it to a function handle first.
If you need to create a function on the fly, you can initialize fcnToEvaluate as an anonymous function in your code:
fcnToEvaluate = #() disp('Hello World!'); %# Create an anonymous function
And the code to send, receive, and evaluate this should be the same as above.
If you have arguments to pass to your function as well, you can place the function handle and input arguments into a cell array. For example:
fcnToEvaluate = #(x,y) x+y; %# An anonymous function to add 2 values
inArg1 = 2; %# First input argument
inArg2 = 5; %# Second input argument
cellArray = {fcnToEvaluate inArg1 inArg2}; %# Create a cell array
if execute_remotely
cellArray{1} = func2str(cellArray{1}); %# Construct a function name string
%# from the function handle
send_via_udp(cellArray); %# Pass the cell array
else
cellArray{1}(cellArray{2:end}); %# Evaluate the function with the inputs
end
In this case, the code for send_via_udp may have to break the cell array up and send each cell separately. When received, the function name string will again have to be converted back to a function handle using STR2FUNC.