Home > Blockchain >  Matlab "auto-squeeze" plot
Matlab "auto-squeeze" plot

Time:12-10

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) or plot(X1,Y1,...,Xn,Yn)

  • Numeric arrays as before, with a char array giving the line spec

    plot(X,Y,LineSpec) or plot(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 object

  • Having 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.

  • Related