Matlab-необязательный аргумент дескриптора сначала для функций типа plot

Matlab включает в себя множество функций построения, которые принимают необязательный аргумент, являющийся дескриптором оси для построения. Существует много решений для добавления необязательных аргументов в пользовательские функции (varargin, inputParser), однако они обычно требуют, чтобы необязательные аргументы приходили только после обязательных аргументов, в то время как функции построения в matlab обычно имеют форму

plot(optional, mandatory, optional)

то есть, необязательные аргументы могут прийти как до, так и после обязательные аргументы.

Я хотел бы повторить это поведение для пользовательского типа графика, чтобы он следовал тому же стилю, что и встроенные функции графика. Представлены следующие варианты использования, демонстрирующие, что одной проверки количества аргументов недостаточно для достижения желаемого поведения:

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

мой вопрос в том, какие методы мы можем использовать для эмуляции этого поведения?

2 ответов


вы можете написать функцию, которая принимает varargin в качестве входных данных. Затем вы проверяете количество аргументов. Если это меньше, чем 2 (или что-то еще, в зависимости от вашей функции), вызовите ошибку или предупреждение. Затем проверьте class входных параметров.

если class ваш первый вход 'matlab.graphics.axis.Axes', тогда ваша функция должна вызвать: plot(ax,___). Если это double, то это должен быть формат plot(X,Y,LineSpec).

что-то в этом роде должно работа

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! Вам не нужно делать x = varargin{1} etc., это было просто, чтобы проиллюстрировать, что каждый из различных элементов ячейки представляет, если if оценивает в true.

вы можете продолжить с "аргументами пары имя-значение". Проверьте, является ли класс входного аргумента char, и что он не может представлять что-то, кроме имени параметра. Если это имя параметра, то вы знаете, что следующий аргумент является значением параметра.


я обычно использую такой шаблон, который также используется многими функциями построения графиков, которые являются частью 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 является недокументированной функцией. Вы всегда идете на небольшой риск, делая это, но он присутствует и неизменен в MATLAB с тех пор навсегда, и он используется многими очень стабильными функциями построения графиков в MATLAB, поэтому вы должны быть в порядке.

он проверяет, является ли первый аргумент дескриптором оси. Если это, тогда ax это ручка, и args - Это остальные входные аргументы. Если нет, то ... --2--> пусто и args содержит все входные аргументы.

надеюсь, что это поможет!


Edit: дополнительная информация о axescheck как просили.

во-первых, вы можете увидеть расположение и исходный код axescheck введя which axescheck и edit axescheck. Таким образом, вы можете точно видеть, что он делает.

синтаксис [AX, ARGS, NARGS] = AXESCHECK(ARG1, ARG2, ...).

во-первых, он проверяет, если ARG1 является ручкой оси. Если это так, он возвращается как AX, остальные аргументы (ARG2, ...) возвращены в ARGS и NARGS значение nargin минус 1.

во-вторых, он проверяет, если любой из входных аргументов параметр-значение параметра Parent. Если да, то все пары параметр-значение с параметром Parent удаляются из списка. Указанная ось возвращается в AX, в остальные аргументы возвращаются в ARGS и NARGS значение nargin минус количество удаленных аргументов.

если ось не указана ни в одном из вышеуказанных способов, то AX пустой ARGS - это только входные аргументы, а NARGS значение nargin.

axescheck работает как со старыми (Handle Graphics 1) двойными ручками, так и с новыми (Handle Graphics 2) ручками класса matlab.graphics.axis.Axes.

он также проверяет является ли предоставленный дескриптор дескриптором удаленного объекта, вызывая ошибку, если это так.

он довольно широко используется во многих встроенных функциях построения графиков MATLAB-см., например,hist.m, polar.m, surfl.m, bar3.m, comet.m, pie.m и многие другие.