Matlab includes many plotting functions which take an optional argument being the handle to the axis to plot to. There are many solutions online for adding optional arguments to user-defined functions (varargin, inputParser), however they usually require that the optional arguments come only after the mandatory arguments, whilst plotting functions in matlab typically are of the form
plot(optional, mandatory, optional)
That is, the optional arguments can come both before and after the mandatory arguments.
I would like to replicate this behaviour for a custom plot type so that it follows the same style as the built-in plot functions. The following use-cases are presented to demonstrate that checking the number of arguments alone is insufficient to accomplish the desired behaviour:
x = [1:10];
y = x.^2;
ax(1) = subplot(1, 2, 1);
ax(2) = subplot(1, 2, 2);
myplot(x, y); %Mandatory
myplot(x, y, 'r+'); %Mandatory, optional
myplot(ax(1), x, y); %Optional, mandatory
myplot(ax(2), x, y, 'r+'); %Optional, mandatory, optional
My question is, what techniques can we use to emulate this behaviour?
I usually use a pattern like this, which is also used by many of the plotting functions that are part of MATLAB:
function varargout = myplot(obj, varargin)
% Check the number of output arguments.
nargoutchk(0,1);
% Parse possible axes input.
[ax, args, ~] = axescheck(varargin{:}); %#ok<ASGLU>
% Get handle to either the requested or a new axis.
if isempty(ax)
hax = gca;
else
hax = ax;
end
% At this point, hax refers either to a specified axis, or
% to a fresh one if none was specified. args refers to the
% remainder of any arguments passed in varargin.
% Parse the rest of args
% Make the plot in hax
% Output a handle to the axes if requested.
if nargout == 1
varargout{1} = hax;
end
end
axescheck is an undocumented function. You're always taking a small risk by doing that, but it's been present and unchanged in MATLAB since forever, and it's used by many very stable plotting functions within MATLAB, so you should be OK.
What it does is to check whether the first argument is a handle to an axis. If it is, then ax is that handle, and args is the rest of the input arguments. If not, then ax is empty and args contains all of the input arguments.
Hope that helps!
Edit: More information about axescheck as requested.
Firstly, you can see the location and source code for axescheck by typing which axescheck and edit axescheck. In this way you can see exactly what it does.
The syntax is [AX, ARGS, NARGS] = AXESCHECK(ARG1, ARG2, ...).
Firstly, it checks if ARG1 is a handle to an axis. If so, it's returned as AX, the remaining arguments (ARG2, ...) are returned in ARGS, and NARGS is the value of nargin minus 1.
Secondly, it checks if any of the input arguments is a parameter-value pair with parameter Parent. If so, then all parameter-value pairs with the parameter Parent are removed from the list. The specified axis is returned in AX, the remaining arguments are returned in ARGS, and NARGS is the value of nargin minus the number of removed arguments.
If no axis is specified in either of the above ways, then AX is empty, ARGS is just the input arguments, and NARGS is the value of nargin.
axescheck works with either old-style (Handle Graphics 1) double handles, and new-style (Handle Graphics 2) handles of the class matlab.graphics.axis.Axes.
It also checks whether the supplied handle is a handle to a deleted object, throwing an error if it is.
It's quite widely used within many built-in MATLAB plotting functions - see, for example, hist.m, polar.m, surfl.m, bar3.m, comet.m, pie.m and many others.
You can write a function that takes varargin as input. Then, you check the number of arguments. If it's less than 2 (or something else, depending on your function), cast an error or warning. Then, check the class of the input parameters.
If the class of your first input is 'matlab.graphics.axis.Axes', then your function should call: plot(ax,___). If it's a double, then it must be the format plot(X,Y,LineSpec).
Something along these lines should work
function [] = myplot(varargin)
if nargin < 2
error('Minimum two input must be given'); % You probably want something other than an error. This was just an example.
elseif nargin == 2
% Code for plotting
plot(x, y)
elseif nargin == 3
if strcmp(class(varargin{1}),'matlab.graphics.axis.Axes')
ax1 = varargin{1};
x = varargin{2};
y = varargin{3};
plot(ax1, x, y)
elseif isa(varargin{2}, 'double') && isa(varargin{3}, 'double') && isa(varargin{3}, 'char')
x = varargin{1};
y = varargin{2};
LineSpec = varargin{3};
else ...
PS! You don't need to do x = varargin{1} etc., this was just to illustrate what each of the different cell elements represents if the if evaluates to true.
You can continue with "Name-Value Pair Arguments". Check if the class of the input argument is char, and that it can't represent something other than a parameter name. If it's a parameter name, then you know the next argument is a parameter value.
Related
Is it possible to get the 'nth' return value from a function without having to create dummy variables for all n-1 return values before it?
Let's say, I have the following function in MATLAB:
function [a,b,c,d] = func()
a = 1;
b = 2;
c = 3;
d = 4;
Now suppose, I'm only interested in the third return value. This can be accomplished by creating one dummy variable:
[dummy, dummy, variableThatIWillUse, dummy] = func;
clear dummy;
But I think this is kind of ugly. I would think that you might be able to do something like one of the following things, but you can't:
[_, _, variableThatIWillUse, _] = func;
[, , variableThatIWillUse, ] = func;
variableThatIWillUse = func(3);
variableThatIWillUse = func()(3);
Are there any elegant ways to do this that do work?
So far, the best solution is to simply use the variableThatIWillUse as a dummy variable. This saves me from having to create a real dummy variable that pollutes the work-space (or that I would need to clear). In short: the solution is to use the variableThatIWillUse for every return value up until the interesting one. Return values after can simply be ignored:
[variableThatIWillUse, variableThatIWillUse, variableThatIWillUse] = func;
I still think this is very ugly code.
With MATLAB Version 7.9 (R2009b) you can use a ~, e.g.,
[~, ~, variableThatIWillUse] = myFunction();
Note that the , isn't optional. Just typing [~ ~ var] will not work, and will throw an error.
See the release notes for details.
This is somewhat of a hack, but it works:
First a quick example function:
Func3 = #() deal(1,2,3);
[a,b,c]=Func3();
% yields a=1, b=2, c=3
Now the key here is that if you use a variable twice on the left-hand side of a multiple-expression assignment, an earlier assignment is clobbered by the later assignment:
[b,b,c]=Func3();
% yields b=2, c=3
[c,c,c]=Func3();
% yields c=3
(Just to check, I also verified that this technique works with [mu,mu,mu]=polyfit(x,y,n) if all you care about from polyfit is the third argument.)
There's a better approach; see ManWithSleeve's answer instead.
If you wish to use a style where a variable will be left to fall into the bit bucket, then a reasonable alternative is
[ans, ans, variableThatIWillUse] = myfun(inputs);
ans is of course the default junk variable for MATLAB, getting overwritten often in the course of a session.
While I do like the new trick that MATLAB now allows, using a ~ to designate an ignored return variable, this is a problem for backwards compatibility, in that users of older releases will be unable to use your code.
I generally avoid using new things like that until at least a few MATLAB releases have been issued to ensure there will be very few users left in the lurch. For example, even now I find people are still using an old enough MATLAB release that they cannot use anonymous functions.
Here's another option you can use. First make a cell array to capture all the outputs (you can use the NARGOUT function to determine how many outputs a given function returns):
a = cell(1,3); % For capturing 3 outputs
% OR...
a = cell(1,nargout(#func)); % For capturing all outputs from "func"
Then call the function as follows:
[a{:}] = func();
Then simply remove the element from a that you want, and overwrite a:
a = a{3}; % Get the third output
I wrote a kth out function:
function kth = kthout(k, ffnc, varargin)
% kthout: take the kth varargout from a func call %FOLDUP
%
% kth = kthout(k, ffnc, varargin)
%
% input:
% k which varargout to get
% ffnc function to call;
% varargin passed to ffnc;
% output:
% kth the kth argout;
[outargs{1:k}] = feval(ffnc, varargin{:});
kth = outargs{k};
end %function
You can then call
val_i_want = kthout(3, #myfunc, func_input_1, func_input_2);
You could also wrap up the function like:
func_i_want = #(varargin)(kthout(3, #myfunc,varargin{:})); % Assuming you want the third output.
After which you use
val_i_want = func_i_want(func_input_1, func_input_2);
Note that there is overhead associated with using anonymous functions like this, and this is not something I would do in code that would be called thousands of times.
In MATLAB 2010a, I found a neat way of doing what you are asking for.
It is simply to use the character "~" (without the quotes of course) as your dummy variable (as many as you want when returning multiple parameters). This also works for input parameters to functions if the functions are designed to handle missing data.
I don't know if this existed in previous versions, but I just came across it recently.
You can make a function (or anonymous function) that only returns selected outputs, e.g.
select = #(a,b) a(b);
Then you can call your function like this:
select(func,2);
select(func,1:3);
Or you can assign the output to a variable:
output(1,2:4) = select(func,1:3);
I don't see any reason not to use ans(n). Like this:
size(rand([5 10 20 40]));
b = ans(2);
It gives b = 10, and this way would be compatible with all MATLAB versions. Note that size() here is just used to represent any function that has multiple return variables.
Furthermore, this works to get the second output argument when you don't know how many arguments there will be! Whereas, if you do this:
[~, b] = size(a);
Then b = 8000! (You need to end with ~, to catch more arguments!)
I have a task to write a function that has an optional output argument.
Let's say I have a function y = fun(a,b). From what I understood, depending on whether the user needs the value y, it will EITHER calculate y OR draw some diagram.
So I think it means that if user calls my function like this: z = fun(1,2), then it calculates y and returns it, but if he calls it like this: fun(3,4);, then it won't return anything and draw a diagram instead.
Is there any way to check how my function has been called inside it? If yes, then how?
You can use nargout here:
function y = q61527462(a,b)
if nargout > 0
% Calculate y
y = a + b;
else
% Plot
plot(a,b)
end
end
so when you call the function as:
>> y = q61527462(1,2)
you get:
y =
3
and when you call with:
>> q61527462(1,2)
you get the plot
Have a look at nargout, that roughly translates to number of argument to output (there is also a nargin to check the number of input arguments).
However, the function will return the return-value anyway if your just check for nargin. You will also need to use varargout (variable argument output) to make your function return something only if the output will be assigned to some external variable.
So you just write in your function
function varargout = fun()
if nargout % implicit cast to a logical. It is equivalent to nargout > 0
% return output
varargout{1} = true; % note that this requires to wrap your output in a cell
else
% do plotting
end
EDIT:
It is even not necessary to use varargout. If you don't assign a value to a return-variable, it won't appear. So MATLAB can manage a not-assigned return-variable (something I was surprised to learn myself^^). This even works with multiple outputs!
I have a set of functions that takes a cell array of tables and plots data from each table as a subplot on a figure. I have been learning to use the inputParser class to handle varargin inputs, and have that here. The optional parameters are for choosing plot type (plot or bar) and for choosing the names of the variables to plot from the input tables.
In my scenario, the inputs need to be passed along about 3 functions deep, so I'm wondering about best practices for doing this. In my current setup, the outermost function (main) takes a varargin input and parses the inputs by assigning defaults and such. Then I'm wondering, when it comes time to pass these inputs to the next function, is it best to pass the parsedInputs data Results struct down the line, or is it better to have the next function also take a varargin argument and to repeat the parsing process again? I'm not sure what the best way to go about this is. My code is below. The main script for test purposes looks as follows:
% RUN TEST CASE
Tables{1} = table([1 2 3]' , [6 7 8]', 'VariableNames', {'diam', 'length'});
Tables{2} = table([1 2 6]' , [6 9 2]', 'VariableNames', {'diam', 'length'});
Tables{3} = table([3 9 11]', [7 4 1]', 'VariableNames', {'diam', 'length'});
main(Tables);
The main function takes a (required) cell array of tables (Tables) and variable argument parameters, such as 'xVariable', 'yVariable', 'plotType'.
function main(Tables, varargin)%PlotParams, DICTS)
% parse inputs
parsedInputs = parse_plot_inputs(Tables, varargin);
% create figure of subplots
figure;
make_subplots_from_tables(parsedInputs);
end
A parse_plot_inputs function takes care of the default value assignment, etc.:
function parsedInputs = parse_plot_inputs(Tables, vararginList)
% input parser function for this specific plotting case
p = inputParser;
addRequired(p, 'Tables', #iscell);
addParameter(p, 'xVariable', 'diam');
addParameter(p, 'yVariable', 'length');
addParameter(p, 'plotType', 'plot');
parse(p, Tables, vararginList{:});
parsedInputs = p;
end
make_subplots_from_tables then loops through the cell array of tables, and calls plot_special to plot each of them on its own subplot.
function make_subplots_from_tables(parsedInputs)
% unpack parsed inputs
Tables = parsedInputs.Results.Tables;
% plot each table as a subplot
numTables = length(Tables);
for i = 1:numTables
subplot(numTables, 1, i); hold on;
plot_special(Tables{i}, parsedInputs)
end
end
plot_special is the "base" function in this scenario that calls the MATLAB plot functions:
function plot_special(T, parsedInputs)
% unpack parsed inputs
xVariable = parsedInputs.Results.xVariable;
yVariable = parsedInputs.Results.yVariable;
plotType = parsedInputs.Results.plotType;
% plot single table on one plot
xVals = T.(xVariable);
yVals = T.(yVariable);
switch plotType
case 'plot'
plot(xVals, yVals, '-x');
case 'bar'
bar(xVals, yVals);
otherwise
error('invalid plot type');
end
end
I am unsure whether this is the best method for taking in arguments and for using them in subsequent functions. This method works, although I'm not sure that it's the best practice, nor the most flexible, for example, considering the scenario when I would like to use plot_special on its own, and would like to be able to pass it arguments for xVariable, yVariable, etc. if need be. Given that it is currently dependent on the parsedInputs list from the main function, that wouldn't be doable. However, I'm unsure what another way to define it would be. I considered having an if statement built in along with a varargin input argument that checks whether the varargin is an already-parsed struct, or if it's getting the variables directly and needs to call the parse_plot_inputs itself to get things working. Any advice would be great.
There is no single "best" method, it all depends on circumstances. What you are doing is fine if the functions that take an inputParser object are private sub-functions. If they are generic functions that should work independently, they should have their own argument parsing. One thing you could do, given that you want plot_special to be a stand-alone function, is as follows:
function main(Tables, varargin)
figure;
make_subplots_from_tables(Tables, varargin{:});
end
function make_subplots_from_tables(Tables, varargin)
% plot each table as a subplot
numTables = length(Tables);
for i = 1:numTables
subplot(numTables, 1, i); hold on;
plot_special(Tables{i}, varargin{:})
end
end
function plot_special(T, varargin)
% parse `varargin` to yield `xVariable`, `yVariable`, `plotType`
% plot single table on one plot
end
This way you do the parameter parsing only where necessary, although it is done once for each table plotted, rather than only once for the whole graph. This is probably a very minor issue though, since parameter parsing is not nearly as expensive as plotting.
This question already has answers here:
How to execute multiple statements in a MATLAB anonymous function?
(5 answers)
Closed 5 years ago.
So I was trying to polish my input validation in MATLAB functions and in the process I ended up creating the following function that really makes my code cleaner. I put it here in full in case someone finds it useful:
function [] = callFunctions(varargin)
%callFunctions Calls a sequence of functions on their respective arguments.
% The inputs are expected as funcHdl1, {input1}, funcHdl2, {input2}, ...
% Then callFunctions calls sequentially func1(input1); func2(input2); ...
%% === INPUT VALIDATION ===
% Check that the callFunctions has at least one argument
message = 'The number of arguments must be positive.';
assert(nargin > 0, message);
% Check that the callFunctions has an even number of arguments
message = 'The number of arguments must be even.';
assert(mod(nargin,2)==0,message);
% Name the handles
numHandles = nargin/2;
handleNames = cell(1,numHandles);
inputNames = cell(1,numHandles);
for k=1:numHandles
handleNames{k} = 'handle';
handleNames{k} = cat(2, handleNames{k}, int2str(k));
inputNames{k} = 'input';
inputNames{k} = cat(2, inputNames{k}, int2str(k));
end
% Function to check that the inputs are function handles
isValidFunctionHdl = #(x) validateattributes(x, {'function_handle'}, {});
% Create an input parser
p = inputParser;
% Add all arguments to check if they are handles. Don't check the inputs.
for k=1:numHandles
p.addOptional(handleNames{k}, 0, isValidFunctionHdl);
p.addOptional(inputNames{k}, 0);
end
% Parse the input
p.parse(varargin{:});
%% === PROGRAM ===
% Evaluate all the functions on their inputs
for k=1:numHandles
feval(varargin{2*k-1},varargin{2*k}{:});
end
end
Now the last part called %% === PROGRAM === is the important part. It just evaluates the functions func1, func2, func3, ... on their respective inputs input1, input2, input3, ..., all of which are given as inputs to callFunctions. It is called as:
callFunctions(funcHdl1, {input1}, funcHdl2, {input2}, ...)
My question is simple: is there a native MATLAB function that does what callFunctions does? I use this during input validation (in combination with assert and validateattributes). So Ì intend to use callFunctions in nearly every function I write. I'd like to use the least custom functions possible for this.
Ben
EDIT: I didn't want to go into this to keep the post short. But yes there is a context where this seems necessary for me. This is when I do input validation with the input parser. I often need to check multiple conditions, like this (completely made up example):
% Made up function to illustrate context
function [] = myFunction(input)
% Create an input parser
p = inputParser;
% Create functions to validate input. Must be a 2d logical array with at least one false value
isValidArray = #(x) validateattributes(x, {'logical'}, {'2d'});
hasAtLeastOneFalse = #(x) assert(length(find(x)) < length(x), 'Must be at least one false.');
isValidInput = #(x) callFunctions( isValidArray, {x}, hasAtLeastOneFalse, {x} );
% Add the required input
p.addRequired('input', isValidInput);
% Parse the input
p.parse(input);
end
This makes my code much cleaner because it allows me to combine multiple validateattributes and assert statements in the call to addRequired.
There is nothing like this that I know of that already exists ... and I am not sure why there would be.
Basically you are trading this:
func1(input1);
func2(input2);
For this:
callFunctions(#func1, {input1}, #func2, {input2})
All I see this doing is a bunch of input checking that callFunctions was used correctly. Assuming each individual function is written well and has it own asserts etc ... I don't get the need for this at all. Besides making it harder to read.
You could either skip it entirely or just have a simple for loop for a list of FCN handles & inputs. Each function would handle its own errors and you wouldn't be adding a bunch of code around something that seems pretty straight forward.
EDIT:
To your example usage: Why not do something like this? To me this is much "cleaner" than your example which seems to be your goal.
function [] = myFunction(input)
% Create an input parser
p = inputParser;
% Must be a 2d logical array with at least one false value
addRequired(p, 'input', #(x) validateattributes(x, {'logical'}, {'2d'}));
p.parse(input);
assert(length(find(input)) < length(input), 'Must be at least one false.')
disp('Running rest of code with good inputs!')
Which handles all your cases for bad inputs:
>> myFunction(ones(2,2,2))
Error using myFunction (line 6)
The value of 'input' is invalid. Expected input to be
one of these types:
logical
Instead its type was double.
>> myFunction(true(2,2,2))
Error using myFunction (line 6)
The value of 'input' is invalid. Expected input to be two-dimensional.
>> myFunction(true(1,2))
Error using myFunction (line 7)
Must be at least one false.
>> myFunction([true false])
Running rest of code with good inputs!
Is it possible to get the 'nth' return value from a function without having to create dummy variables for all n-1 return values before it?
Let's say, I have the following function in MATLAB:
function [a,b,c,d] = func()
a = 1;
b = 2;
c = 3;
d = 4;
Now suppose, I'm only interested in the third return value. This can be accomplished by creating one dummy variable:
[dummy, dummy, variableThatIWillUse, dummy] = func;
clear dummy;
But I think this is kind of ugly. I would think that you might be able to do something like one of the following things, but you can't:
[_, _, variableThatIWillUse, _] = func;
[, , variableThatIWillUse, ] = func;
variableThatIWillUse = func(3);
variableThatIWillUse = func()(3);
Are there any elegant ways to do this that do work?
So far, the best solution is to simply use the variableThatIWillUse as a dummy variable. This saves me from having to create a real dummy variable that pollutes the work-space (or that I would need to clear). In short: the solution is to use the variableThatIWillUse for every return value up until the interesting one. Return values after can simply be ignored:
[variableThatIWillUse, variableThatIWillUse, variableThatIWillUse] = func;
I still think this is very ugly code.
With MATLAB Version 7.9 (R2009b) you can use a ~, e.g.,
[~, ~, variableThatIWillUse] = myFunction();
Note that the , isn't optional. Just typing [~ ~ var] will not work, and will throw an error.
See the release notes for details.
This is somewhat of a hack, but it works:
First a quick example function:
Func3 = #() deal(1,2,3);
[a,b,c]=Func3();
% yields a=1, b=2, c=3
Now the key here is that if you use a variable twice on the left-hand side of a multiple-expression assignment, an earlier assignment is clobbered by the later assignment:
[b,b,c]=Func3();
% yields b=2, c=3
[c,c,c]=Func3();
% yields c=3
(Just to check, I also verified that this technique works with [mu,mu,mu]=polyfit(x,y,n) if all you care about from polyfit is the third argument.)
There's a better approach; see ManWithSleeve's answer instead.
If you wish to use a style where a variable will be left to fall into the bit bucket, then a reasonable alternative is
[ans, ans, variableThatIWillUse] = myfun(inputs);
ans is of course the default junk variable for MATLAB, getting overwritten often in the course of a session.
While I do like the new trick that MATLAB now allows, using a ~ to designate an ignored return variable, this is a problem for backwards compatibility, in that users of older releases will be unable to use your code.
I generally avoid using new things like that until at least a few MATLAB releases have been issued to ensure there will be very few users left in the lurch. For example, even now I find people are still using an old enough MATLAB release that they cannot use anonymous functions.
Here's another option you can use. First make a cell array to capture all the outputs (you can use the NARGOUT function to determine how many outputs a given function returns):
a = cell(1,3); % For capturing 3 outputs
% OR...
a = cell(1,nargout(#func)); % For capturing all outputs from "func"
Then call the function as follows:
[a{:}] = func();
Then simply remove the element from a that you want, and overwrite a:
a = a{3}; % Get the third output
I wrote a kth out function:
function kth = kthout(k, ffnc, varargin)
% kthout: take the kth varargout from a func call %FOLDUP
%
% kth = kthout(k, ffnc, varargin)
%
% input:
% k which varargout to get
% ffnc function to call;
% varargin passed to ffnc;
% output:
% kth the kth argout;
[outargs{1:k}] = feval(ffnc, varargin{:});
kth = outargs{k};
end %function
You can then call
val_i_want = kthout(3, #myfunc, func_input_1, func_input_2);
You could also wrap up the function like:
func_i_want = #(varargin)(kthout(3, #myfunc,varargin{:})); % Assuming you want the third output.
After which you use
val_i_want = func_i_want(func_input_1, func_input_2);
Note that there is overhead associated with using anonymous functions like this, and this is not something I would do in code that would be called thousands of times.
In MATLAB 2010a, I found a neat way of doing what you are asking for.
It is simply to use the character "~" (without the quotes of course) as your dummy variable (as many as you want when returning multiple parameters). This also works for input parameters to functions if the functions are designed to handle missing data.
I don't know if this existed in previous versions, but I just came across it recently.
You can make a function (or anonymous function) that only returns selected outputs, e.g.
select = #(a,b) a(b);
Then you can call your function like this:
select(func,2);
select(func,1:3);
Or you can assign the output to a variable:
output(1,2:4) = select(func,1:3);
I don't see any reason not to use ans(n). Like this:
size(rand([5 10 20 40]));
b = ans(2);
It gives b = 10, and this way would be compatible with all MATLAB versions. Note that size() here is just used to represent any function that has multiple return variables.
Furthermore, this works to get the second output argument when you don't know how many arguments there will be! Whereas, if you do this:
[~, b] = size(a);
Then b = 8000! (You need to end with ~, to catch more arguments!)