Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Passing varargs to plot() function

Tags:

plot

matlab

I am writing a wrapper for plot that automates some tasks that I find myself doing frequently.

An example code snippet might look like

function myplot(x,y,varargin)
    plot(x,y,varargin{:})
    xlabel('x axis')
    ylabel('y axis')
end

I'm using Matlab's varargin to pass additional arguments to plot. However, I find that I might want to pass my own optional arguments in varargin. For example, I might want to write something like

>> myplot(1:10, 1:10, 'r', 'LineWidth', 2, 'legend', {'Series 1'})

to have the function automatically include a legend in the plot - that is, I want to be able to mix my own keyword arguments with the ones that you can supply to plot. Short of writing a full parser for my varargs, is there a way to do this simply and reusably in Matlab?

I've tried to use the inputParser object, but that would require me to manually add every possible additional argument to plot (and a default for it) which doesn't seem ideal.

like image 211
Chris Taylor Avatar asked Dec 13 '11 09:12

Chris Taylor


People also ask

What is a varargs method in Java?

A varargs method is one that accepts a variable number of arguments. Variable-length arguments could be handled in two ways prior to JDK 5. One method employs overloaded methods (one for each), while another places the arguments in an array and then passes this array to the method. Both are potentially error-prone and necessitate more code.

How to use varargs with 3 arguments in Python?

In order to define vararg, ... (three dots) is used in the formal parameter of a method. A method that takes variable number of arguments is called a variable-arity method, or simply a varargs method. As you can clearly see, you had to overload sumNumber () method to make it work for 3 arguments.

Can a method have more than one varargs parameter?

A method can have only one varargs parameter. In the above program, the compiler gets confused if you try to invoke the test () method even though test () methods are overloaded and accepts different number of arguments. The compiler doesn’t know which method to call.

How to capture a variable number of arguments in a function?

With Python, we can use the *args or **kwargs syntax to capture a variable number of arguments in our functions. Using *args, we can process an indefinite number of arguments in a function's position.


Video Answer


2 Answers

inputParser may still be the best choice. You can construct the object for your additional arguments, and lump all the parameterName/parameterValue pairs that you want to pass to plot into Unmatched.

function myplot(x,y,varargin)

    parserObj = inputParser;
    parserObj.KeepUnmatched = true;
    parserObj.AddParamValue('legend',false); 
    %# and some more of your special arguments

    parserObj.parse(varargin);

    %# your inputs are in Results
    myArguments = parserObj.Results;

    %# plot's arguments are unmatched
    tmp = [fieldnames(parserObj.Unmatched),struct2cell(parserObj.Unmatched)];
    plotArgs = reshape(tmp',[],1)'; 


    plot(x,y,plotArgs{:})
    xlabel('x axis')
    ylabel('y axis')

    if myArguments.legend
       %# add your legend
    end
end
like image 121
Jonas Avatar answered Nov 15 '22 06:11

Jonas


To support the Linespec argument without interfering with input parser parameters that have a name of 4 characters or less (e.g., 'grid' or 'bins'), you should have a slightly more sophisticated way to check the validity of the Linespec argument than '@(x) ischar(x) && numel(x) <=4'. This check would return true also for 'grid' and 'bins', although they are no valid Linespec arguments.

The following function will return true only if a valid Linespec argument is entered:

function isls = islinespec(x)
isls    = false;

if ~ischar(x)
    return;
end

lineStyleSpecifiers     = {'--','-.','-',':'};
markerSpecifiers        = {'square','diamond','pentagram','hexagram','+','o','*','.','x','s','d','^','v','>','<','p','h'};
colorSpecifiers         = {'r','g','b','c','m','y','k','w'};

for oo=1:length(lineStyleSpecifiers)
    k = strfind(x,lineStyleSpecifiers{oo});
    if ~isempty(k)
        x(k:(k+length(lineStyleSpecifiers{oo})-1)) = [];
        break;
    end
end

for oo=1:length(markerSpecifiers)
    k = strfind(x,markerSpecifiers{oo});
    if ~isempty(k)
        x(k:(k+length(markerSpecifiers{oo})-1)) = [];
        break;
    end
end

for oo=1:length(colorSpecifiers)
    k = strfind(x,colorSpecifiers{oo});
    if ~isempty(k)
        x(k:(k+length(colorSpecifiers{oo})-1)) = [];
        break;
    end
end

if isempty(x)
    isls = true;
end

(Admittedly, the function could have been written more elegantly with regular expressions, but it does the trick.)

Example usage:

parserObj = inputParser;
parserObj.KeepUnmatched = true;
parserObj.AddParamValue('legend',false);
parserObj.AddParamValue('grid',true);
parserObj.addOptional('LineSpec','-', @(x) islinespec(x));
like image 30
Frank Drop Avatar answered Nov 15 '22 05:11

Frank Drop