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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With