My code makes a plot and then makes a prompt asking the user if he wants to make another plot with different parameters. The problem is, while questdlg.m is open, the user cannot look at details on the plot.
Here's the code :
while strcmp(Cont,'Yes') == 1
%Some code modifying 'data'
plot(1:X,data);
Cont = questdlg('Would you like to plot another pixel?','','Yes','No','Yes');
close all;
end
I've tried a few things. I tried to create another function called normalquestdlg.m, and I copy pasted the questdlg.m code into it, modifying line 401.
set(QuestFig,'WindowStyle','modal','Visible','on');
to
set(QuestFig,'Visible','on');
I tried different location for the normalquestdlg.m function. Putting it in my default Matlab folder for homemade functions gave me the following error :
Undefined function 'dialogCellstrHelper' for input arguments of type 'char'.
Error in **normalquestdlg** (line 74)
Question = dialogCellstrHelper(Question);
Error in **Plot** (line 40)
Cont = normalquestdlg('Would you like to plot another pixel?','','Yes','No','Yes');
And putting it in the same folder as questdlg.m (C:\Program Files\MATLAB\R2014a\toolbox\matlab\uitools) gave me the following error :
Undefined function 'normalquestdlg' for input arguments of type 'char'.
Error in **Plot** (line 40)
Cont = normalquestdlg('Would you like to plot another pixel?','','Yes','No','Yes');
I even tried to put it as the first path to look for :
p = path
path('C:\Program Files\MATLAB\R2014a\toolbox\matlab\uitools', p)
Cont = normalquestdlg('Would you like to plot another pixel?','','Yes','No','Yes');
path(p)
Needless to say, this didn't change a thing.
Anyone has any tips for me?
No easy solutions were to be found. The easiest thing I could find was to download MFquestdlg.m (http://www.mathworks.com/matlabcentral/fileexchange/31044-specifying-questdlg-position/content/MFquestdlg.m) and modify line 384 of it this way :
set(QuestFig, 'WindowStyle', 'modal', 'Visible', 'on');
to
set(QuestFig, 'Visible', 'on');
since 'normal' is the default WindowStyle.
I prefered to do this than to modify basic Matlab functions. This could be enhanced even more (if someone had the need to do so) by adding an input in the function specifying the WindowStyle (either 'normal', 'modal' or 'docked'), and it would be quite easy, adding too a little fail-proof like line in this style :
if nargin < 8
WinStyle = '%enter default mode'
end
if nargin == 8
if strcmp(WinStyle,'normal') == 1 | strcmp(WinStyle, 'modal') == 1 | strcmp(WinStyle, 'docked') == 1
else
error('MATLAB:questdlg:IncorrectInput', 'The WindowStyle input parameter was incorrectly written')
end
end
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.
function [ muln, varargout ] = my_mul( varargin )
%MY_MUL This function is used to multiply numbers.
% My_mul function multiplies array of entered numbers, and outputs single
% solution.
% For example: my_mul(12, 2, 3, 5) gives ans = 360
if nargout >=1
disp('Error, wrong number of output arguments');
varargout{1} = 0;
return
end
if nargin <= 1
disp('Error, small number of input argumnets');
return
else
muln = 1;
for i = 1:nargin
muln = muln*varargin{i};
end
end
end
Hi, everyone, I'm just doing my assignment for uni and have a qiuck question.
How can I make this function to give an error if it is called with more than one output.(It meant to give only one) Thanks!
In your function definition, you have defined your function to allow for an unlimited number of outputs. The keyword varargout is a place-holder for a variable number of outputs.
As you have stated in your question, you only want one possible output which in your case looks to be muln. So if you simply remove varargout from your function definition, MATLAB should automatically throw an error if too many outputs are requested
function muln = my_mul(varargin)
If you ever do need to use varargout but want to place constraints on how many outputs are provided for any given scenario, you can check the number of output arguments that were requested using nargout and then throw an error with the error function.
if nargout > 4
error('my_mul:TooManyOutputs', 'Too many outputs requested');
end
My opinion is that if a return value is expected the function needs to throw. Otherwise the caller (function calling this function) will expect everything to be ok. Note that disp('Error') gives information to the developer, but it does not give the program any indication on what happens. More importantly, the information does not give any indication of where the error occurs. This can force the developer to do heavy debugging just to find the error, which is completely unnecessary.
The use of variable output arguments should only be used in case a different number of output arguments should be expected. An example is some customized plot function
function varargout = myplot(varargin)
filename = '';
idx = find(strcmp(varargin,'filename'));
if (~isempty(idx) && length(varargin)<idx+1 && ~ischar(varargin{idx+1}))
error('filename property must be followed by a directory');
elseif(~isempty(idx))
filename = varargin{idx+1};
varargin([idx,idx+1]) = [];
end
h = plot(varargin{:});
varagout{1} = h;
if (~isempty(idx))
save(filename, h);
end
varagout{2} = filename;
This function works as plot except it saves the figure to file in case a filename is specified. In case the developer needs the handle it will be returned and in case the developer wants the save directory it can be returned as well. None of these arguments are necessary though. The developer may want to use this function as a standard plot function and this means that the user may want to call myplot as myplot(x,y);which does not return a value. Further note that even if 'filename' is not specified, the function can still return 2 outputs. The second output may be an empty array of char, but two outputs for the caller will never cause a crash.
Also, note that no further error handling is required. The only unchecked crashes are in plot and save. How this is handled may be different for different users and this means that it only is reasonable to let the user catch the error and handle it (as he would have done if save or plot would have thrown).
Apart from this you may also want to have a check so that the number of output variables are within the correct range (in this case 0,1 or 2 outputs).
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'm completely new to matlab and this is my first question.
I found a program like this
x = inputdlg('foo');
x = str2num(x{1})
and trying to make some gui from it, put this line to callback function of push button:
x=get(handles.edit1, 'String')
x=str2num(x{1})
and it works, but not after i add this the same thing with different variable
y=get(handles.edit2, 'String')
y=str2num(y{1})
command window said
Cell contents reference from a non-cell array object.
Error in regresilinear>pushbutton1_Callback (line 128)
x=str2num(x{1})
Error in gui_mainfcn (line 96)
feval(varargin{:});
Error in regresilinear (line 42)
gui_mainfcn(gui_State, varargin{:});
Error in
#(hObject,eventdata)regresilinear('pushbutton1_Callback',hObject,eventdata,guidata(hObject))
Error while evaluating uicontrol Callback
I found out that the output from command window is different when it's running and not with the same input.
When it got errors:
x =
0 1 2 3
when not (the first time)
x =
'0 1 2 3'
It doesn't give any error if i delete the str2num line.
I hope somebody can help fix the problem.
Start with a clear workspace and
x=get(handles.edit1, 'String');
x=str2num(x);
or better:
x=str2num(get(handles.edit1, 'String'));
{} are used for accessing the elements of a cell array. You are probably trying to use it on a string and that is why you are getting that error.
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.