How to test arguments for a figure or axis object in MATLAB 2022? - matlab

A function receives a figure or axis object object as parameter.
I want to test this as shown in the FIXME line.
Which test should be used here in order to allow all valid objects for exportgraphics?
% myexportgraphics.m
function myexportgraphics(f)
arguments
f (1,1) {}; % FIXME add a test here
end
exportgraphics(f,...);
end

This full list of validation functions is documented here:
https://uk.mathworks.com/help/matlab/matlab_prog/argument-validation-functions.html
The only relevant one for checking the input type (other than ones for specific types like "double") is mustBeUnderlyingType
You can check which types are valid using underlyingType on example objects you want to accept.
underlyingType( figure() ); % 'matlab.ui.Figure'
underlyingType( axes() ); % 'matlab.graphics.axis.Axes'
So this would check for figures
function myexportgraphics(f)
arguments
f (1,1) {mustBeUnderlyingType(f,'matlab.ui.Figure')};
end
end
However, that doesn't allow multiple variable types, so per the docs you probably want to make your own validation function
function myexportgraphics(f)
arguments
f (1,1) {mustBeExportGraphicsType(f)};
end
end
function mustBeExportGraphicsType(g)
if ~ismember( class(g), {'matlab.ui.Figure','matlab.graphics.axis.Axes'} )
eidType = 'mustBeExportGraphicsType:notExportGraphicsType';
msgType = 'Input must be a figure or axes object';
throwAsCaller(MException(eidType,msgType));
end
end
These are the requirements for a custom validation function, emphasis mine:
Functions used for validation have these design elements:
Validation functions do not return outputs or modify program state. The only purpose is to check the validity of the input value.
Validation functions must accept the value being validated as an input argument. If the function accepts more than one input argument, the first input is the value to be validated.
Validation functions rely only on the inputs. No other values are available to the function.
Validation functions throw an error if the validation fails. Using throwAsCaller to throw exceptions avoids showing the validation function itself in the displayed error message.
Creating your own validation function is useful when you want to provide specific validation that is not available using the MATLAB validation functions. You can create a validation function as a local function within the function file or place it on the MATLAB path.
As an aside, you could use ishghandle within the custom validation function which returns true for figure and axes inputs. If you didn't use the arguments validation syntax, you could instead use ishghandle with the slightly older inputParser approach to input validation, or a simple assert near the start of your function, but that's probably beyond the scope of this question.

Related

Passing names of functions to another function with parameters as input in MATLAB

Problem Statement: I am trying to write MATLAB code for a main caller function (like run_experiment below) to specify which computations I want to execute where computations are made sequentially using other MATLAB functions. Those other functions are to be evaluated based on parameters passed with the main caller function. The said functions used in computations are to be specified with name of the scripts they are written in.
Example Desired Code Behavior: For example, a command like the following should run the preprocess_data, initialise_model and train_model scripts.
>> run_experiment('dataset_1_options', '|preprocess_data|initialise_model|train_model|');
And this command should run only the train_model script but also evaluates its performance:
>> run_experiment('dataset_1_options', '|train_model|evaluate_model|');
In the above examples "|" is used as a delimiter to specify separate function names to be evaluated. Those functions use the options specified with dataset_1_options. Please do not focus on how to separate that part of the input into meaningful function names; I know how to do it with strsplit.
Constraints and Specifications: The function names to be passed as input to the main caller function are NOT anonymous functions. The purpose is to be able to pass such multiple function names as input AND to evaluate them with the options like the above example. They return output to be evaluated in other parts of the research code (i.e. passing data matrices to other functions within the research code as results of the computations carried out within them.)
Question: Given the desired behavior and constraints mentioned above, can anybody help in how to pass the separate function names from another caller function along with options/parameter to those functions? How should the main caller function evaluate the function names passed in as input with the options specified during the call?
Thank you in advance.
You can pass functions to functions in matlab. You just need to use the # sign when you pass it. In your case it would be run_experiment('dataset_1_options', #train_model) inside a script. You could keep your options in a cell array or something. The run_experiment function would just be a regular function,
function [output] = run_experiment(options, train_model, ...);
train_model(options{1}, ...)
.
.
.
end
What you need to do this is create a cell array with your function names and another array with the corresponding options as below
% Function name array
fn_array = {#fn_1, #fn_2, ...};
% Option array
option_array = {{fn1_opt1, fn2opt2, ...}; {fn2_opt1, fn2_opt2, ...};, ...};
These two need to be passed to your run_experiment function which will evaluate them as below
function run_experiment(fn_array, option_array)
num_fn = length(fn_array); %Finds number of functions to evaluate
for ii = 1:num_fn %Evaluates each function
fn_array{ii}(option_array{ii}{:});
end

Creating a function handle to an overloaded `end` function

MATLAB allows overloading various operators for custom classes. One of the unlisted overloadable operators is end, as can be learned from \matlab\lang\end.m:
% END(A,K,N) is called for indexing expressions involving the object A
% when END is part of the K-th index out of N indices. For example,
% the expression A(end-1,:) calls A's END method with END(A,1,2).
An example of such a method is table.end (paste in the MATLAB command line and press "Open Selection" to go to its definition; it is defined in ...\matlab\datatypes\#tabular\end.m).
Unlike a normal method, one cannot simply write hEnd = #end, because this gives the error:
>> hEnd = #end;
hEnd = #end;
↑
Error: Illegal use of reserved keyword "end".
On the other hand, writing e = str2func('end'); works, but it links to the default end function (even when temporarily switching to the folder where the desired end.m is found).
Failed attempts include str2func('table>end');, str2func('table\end');, str2func('table.end'); and #(a,b,c)table.end(a,b,c);.
My question: How do I create a handle to the end function of a specific class?
Overloading — If the function you specify overloads a function in a class that is not a fundamental MATLAB class, the function is not associated with the function handle at the time it is constructed. Instead, MATLAB considers the input arguments and determines which implementation to call at the time of evaluation.
Function handles store their absolute path, so when you have a valid handle, you can invoke the function from any location. You do not have to specify the path to the function when creating the handle, only the function name.
so if your 'end' function is in matlab path , matlab consider it as a candidate for evaluation depending on the inputs,in your case if input object is of 'table' class type the feval(str2func('end'),i,j) evaluate the end function which is defined in the folder #table/end.m

passing anonymous functions through inputParser (matlab)

I'm trying to use Matlab's inputParser for the first time, and I have to say I'm finding it a bit confusing. I am unable to successfully provide an anonymous function as an optional parameter.
This is the function I am passing arguments to
function myfun(str,bounds,varargin)
p = inputParser;
p.FunctionName = mfilename;
p.addRequired('str',#isstr);
p.addRequired('bounds',#isvector);
p.addOptional('str_latex','',#isstr);
p.addOptional('seed',[], #(x) isa(x,'function_handle'))
p.parse(str,bounds,varargin{:});
p.Results
% do something here
end
And I am calling it like this...
myfun('str', 'epsilon',...
'str_latex', '\epsilon',...
'bounds', [0 1],...
'seed', #() betarnd(2,2))
But I get an error:
Error using my fun
The value of 'seed' is invalid. It must satisfy the function: #(x)isa(x,'function_handle').
I suspect a simple error, but I cannot figure it out.
Name-value pairs are declared using the addParameter method (R2013b+, addParamValue prior to that). addRequired and addOptional do not have name-value pairs associated with them, simply identifying/documenting argname inputs for internal use and association with the parsed struct. It appears you want to use all addParamter-s in this use case.
The main idea behind the three input types is
Required: the very first arguments with explicit, documented inputnames that absolutely need to be supplied by the user for the function to perform properly.
Optional: arguments that typically follow Required arguments with explicit, documented inputnames that are often input by the user for customized behavior.
Name-Value: arguments that typically follow Optional arguments with a name specifying the value to be set are often input by the user for customized behavior but not so often as to be given an upfront, explicit parameter like Optional arguments.
In my experience, Required arguments are almost always obvious, for good, well-defined functions, while Optional and Name-Value is more experience-, complexity-, and aesthetics-based. A simple example would be linspace: the start and end of the interval are absolutely needed for the function to work, but not necessarily the number of points which can be left to 100 by default, but giving it an explicit name-value pair is a little overkill. A more complex example would be the plot function: at a minimum y data is needed, then x,y pairs of data, then x,y,linSpec sets of data, and then a whole list of specific name-value pairs for pinpoint customization that users can use if they so choose.
With your input parser as written, the call sequence should be:
myfun('epsilon',[0,1],'\epsilon',#() betarnd(2,2));
Since no name-value pairs were declared, none exist, but the Optional arguments still have a positional order associated with them. You can re-write your parser as:
function myfun(varargin)
p = inputParser;
p.FunctionName = mfilename;
p.addParameter('str',[],#isstr);
p.addParameter('bounds',[],#isvector);
p.addParameter('str_latex','',#isstr);
p.addParameter('seed',[], #(x) isa(x,'function_handle'))
p.parse(str, bounds, varargin{:});
p.Results
% do something here
end
For something like the generic input sequence you may have been expecting. Notice that I used []-s to fail the simple validations without a good error message; you should add a good error message indicating that those name-value pairs are required for proper functionality, or do as you were doing and have explicit, upfront Required inputs with addRequired but without the name-value semantics.

input parser and function handle

I am using the Matlab input parser and want to parse a function handle using this code:
p = inputParser;
p.addOptional('progresscallback', 0, #(x) isa(x,'function_handle') );
p.parse(varargin{:});
This works well for a given function handle, but fails for no handle with
Argument 'progresscallback' failed validation #(x)isa(x,'function_handle').
Now I wonder how to contruct the testing function or the default value to make it work.
If you just want to accept either empty or function handle inputs, you can modify the testing function like this:
#(x) isempty(x) || isa(x,'function_handle')
The short-circuit OR (||) won't evaluate the second half of the test if the first one is already true. BTW, you may also want to set your default value to [].

matlab function with argument not required

I create a function
function y = getValue(modelName, param, option)
open_system(modelName);
runModel(option);
y = getActiveFun(param);
end
I would like when calling this function to have the choice to pass or not argument option
from some other files I call the function with all arguments and sometimes I would like to call it without passing option argument ?
I would like to call : getValue(modelName, param) from other files
How could I do that ?
The simplest way to do this is to use the nargin variable:
function y = getValue(modelName,param,option)
open_system(modelName);
if (nargin < 3)
# No option passed, do something like
runModel('defaultOption')
else
# Option passed
runModel(option);
end
y = getActiveFun(param);
end
nargin is just the number of input arguments that were actually submitted. Thus, nargin == 3 indicates that the option parameter has been set, nargin < 3 that it has not been set.
Thus, you could now always call your function like
result = getValue('myModel', myParameter)
or with all parameters
result = getValue('myModel', myParameter, someOption)
While solutions with nargin are already given and more or less a standard usage within most MATLAB codebases, I think there is a nicer alternative that is more readable.
With nargin in big functions, you have to remember what argument 3 was exactly. Especially if you have more optional arguments, it becomes cumbersome to keep track or to allow that some optional arguments are passed, while others are not.
The first and easier solution is my personal alternative to nargin, and that is using the exist function:
function [output] = getValue(modelName,param,option, otherOption)
if ~exist('option', 'var') || isempty(option)
option = 'defaultValueForOption';
end
if ~exist('otherOption', 'var') || isempty(otherOption)
otherOption = 'defaultValueForOption';
end
% perform other actions
The advantage is that now all input-related code is at the beginning and it is more verbose as to what should be happening. You won't clutter your other code with that logic. And you can also supplement those if statements with validation of the input and fall back onto the default when an invalid option is given.
The other possibility is standard in later versions of MATLAB: the inputParser class. With this class, you can define even more complicated scenarios of optional parameters and even key-value pairs.
Below is a self-descriptive example I have kept to avoid needing the documentation every time.
%% Usage Example input Parser
%
function output = FuncName(rParam1, rParam2, oParam1, oParam2, varargin)
p = inputParser();
defaultValue = 0;
validatorFunc = #(x)(true); % validator function should return true when x is valid
%% Input Format definition
p.addRequired('rParam1', validatorFunc);
p.addRequired('rParam2', validatorFunc);
p.addOptional('oParam1', defaultValue, validatorFunc);
p.addOptional('oParam2', defaultValue, validatorFunc);
p.addParamValue('kvParam1', defaultValue, validatorFunc);
p.addParamValue('kvParam2', defaultValue, validatorFunc);
p.addParamValue('kvParam3', defaultValue, validatorFunc);
p.addParamValue('kvParam4', defaultValue, validatorFunc)
%% Optional Settings
% expand supplied struct to ParamValue pairs (or other arguments)
p.StructExpand = true; % default: false
%% Parse
p.parse(rParam1, rParam2, oParam1, oParam2, varargin{:})
%% Retrieve results
values = p.Results(); % structure with all values
defaultedArgs = p.UsingDefaults; % cell array of all parameter names using defaults
end
This approach is even more verbose and personally, I don't quite like the fact that one has to redefine for every input whether it is required or optional and that it requires quite a lot of boilerplate code. But at least, it is a solution that is a standard solution and without a doubt to be preferred for larger functions.
Both approaches do suffer from a drawback compared to the nargin way of checking: they are both slower. So if you use these in functions that get called a lot (or only perform a very quick calculaion), it might be more worthwhile to use nargin instead.
For completeness, lets see the basics (see documentation here).
In a function if an argument is not used, it is only a "programming warning", nothing more. So the problem is that you use a parameter that may or may not be provided.
So this is handled using
nargin % the number of parameters provided in current call
nargin(function_name) % the number of parameters the declaration has
So based on these you may program some conditions and include there the code that uses the non-standard input parameters.
For more complex cases varargin is most proper that handles variable length parameter list where the ordering may not be defined. But this is too much for this question
Look at the following link:
http://www.mathworks.com/matlabcentral/newsreader/view_thread/65943
they have several suggestions