Matlab plot requires the data to be of the same dimension. Meaning, you cannot plot a 1x10 vector with a 1x1x10 vector. This is sometimes necessary. For those purposes, you can use the squeeze function to get rid of the singleton dimensions.
However, this is kind of a hassle. For the plot function specifically, it would be useful to have the argument always squeezed. How would one go about creating a new function, lets call it splot which squeezes every input and passes it onto plot. Here is an attempt (that doesn't work)
function splot(varargin)
for i=1:length(varargin)
varargin{i}=squeeze(varargin{i});
end
plot(varargin)
end
plot(varargin) part fails, because that is simply not how matlab syntax works. But is there any way to achieve what I want? I guess I could write a long if elseif chain where I manually write the case with every possible number of input arguments like:
if length(varargin)==2
plot(varargin{1},varargin{2})
if length(varargin)==3
plot(varargin{1},varargin{2},varargin{3})
But this is going to be very annoying. Any better ideas.
This question is similar to Is there any mechanism to auto squeeze in Matlab / Octave , however, not similar enough, because the other question is for squeezing every vector, which is a bad idea. Here I am asking a way to squeeze only the inputs to the plot function and requiring syntax help.
CodePudding user response:
From the docs there are several ways to call plot
. Generally
Just numeric arrays, these can be on their own, or one or more pairs
plot(Y)
,plot(X,Y)
orplot(X1,Y1,...,Xn,Yn)
Numeric arrays as before, with a char array giving the line spec
plot(X,Y,LineSpec)
orplot(Y,LineSpec)
Either of the previous two, plus name-value pair options
plot(___,Name,Value)
In any of these cases, you want to squeeze the first N
inputs which are numeric, since either of the optional additions have the first non-plottable input as a char.
We can achieve that with the following code, see the comments for details:
function h = splot( varargin )
% Check if there are any optional inputs, which will either be
% LineSpec (which is a char) or name-value pairs (which the
% first of will be a char)
bNumericArg = cellfun( @isnumeric, varargin );
% By default, assume all inputs are arrays to plot
lastArrayArg = numel(varargin);
if ~all(bNumericArg)
% In this case, there are some optional inputs, get last array index
lastArrayArg = find( ~bNumericArg, 1 ) - 1;
end
% Squeeze the arrays
for ii = 1:lastArrayArg
varargin{ii} = squeeze(varargin{ii});
end
% Plot with all inputs, optional output
if nargout > 0
h = plot( varargin{:} );
else
plot( varargin{:} );
end
end
There are two possible cases I've not handled here which the plot
function can handle,
Having the first input as the target axes i.e.
plot(ax,___)
, could be achieved by altering the loop slightly to start from 1 or 2 depending if the first input is an axes objectHaving pairs of arrays each with their own line spec argument i.e.
plot(X1,Y1,LineSpec1,...,Xn,Yn,LineSpecn)
. The later pairs will be ignored. This would be trickier to handle since you'd likely have to parse all inputs and check whether a char is just a line spec or if you're messing with name-value pairs. Maybe a heuristic to do with "two arrays then a char, repeated". I've never used this syntax so omitting the over-complication for now.