Matlab - 绘图相关函数中的可选句柄参数优先问题

8

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个回答

9

通常我使用这样的模式,许多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是其余的输入参数。如果不是,则ax为空,args包含所有输入参数。

希望这可以帮助您!


编辑:更多关于 axescheck 的信息,如要求所述。

首先,您可以通过键入 which axescheckedit axescheck 来查看 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)句柄和类 matlab.graphics.axis.Axes 的新版(Handle Graphics 2)句柄一起使用。

它还会检查提供的句柄是否为已删除对象的句柄,如果是则会抛出错误。

它在许多内置 MATLAB 绘图函数中被广泛使用,例如:hist.m,polar.m,surfl.m,bar3.m,comet.m,pie.m 等等。


这个答案看起来很有前途,但是如果能提供关于未记录的axescheck函数的额外信息会更好 - 简单的谷歌搜索没有找到任何结果。例如,axescheck(varargin {:})与isa(varargin {1},'matlab.graphics.axis.Axes')有什么不同? - bhillam
我总觉得只能选择一个答案很遗憾 - 我希望我能再次为你的回答点赞。 - bhillam

4
您可以编写一个函数,该函数以 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 ...

注意!你不需要执行x = varargin {1}等操作,这只是为了说明如果if评估为true,每个不同的单元素素代表什么。

您可以继续使用“名称-值对参数”。检查输入参数的类是否为char,并且它不能表示除参数名称以外的其他内容。如果是参数名称,则您知道下一个参数是参数值。


我有一种感觉这就是它的实现方式,但我希望能有更优雅的解决方案。 - bhillam
@bhillam,我不明白这有什么不优雅的?MATLAB不允许函数重载。这将需要你编写两个函数。 - patrik
如果有大量的参数组合可能性,就会出现一些代码重复,这可能会很快变得混乱。不幸的是,似乎无论使用什么技术,这都将是一个问题。我接受了这个答案,因为它解决了如何在与内置绘图函数相同的方式中包含可选参数之前的强制参数的问题,尽管Sam Roberts的答案的某些元素也很有用。 - bhillam

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接