3

我想给我做一个简单标签的子图。不幸的是,我的行为很丑陋。考虑以下函数:

function h = set_label1(label)
tlh = get(gca, 'Title');
if strcmp(get(tlh, 'String'), '')
    title(' ');
end
ylh = get(gca, 'YLabel');
if strcmp(get(ylh, 'String'), '')
    ylabel(' ');
end

ylp = get(ylh, 'Position');
x = ylp(1);

tlp = get(tlh, 'Position');
y = tlp(2);

h = text('String', label, ...
        'HorizontalAlignment', 'right',...
        'VerticalAlignment', 'Baseline', ...
        'FontUnits', 'pixels', ...
        'FontSize', 16, ...
        'FontWeight', 'bold', ...
        'FontName', 'Arial', ...
        'Position', [x y 0]);
end

这是一个简单的测试运行:

figure;
h1 = axes('OuterPosition', [0,0,.5 1]);
set(h1,'LooseInset',get(h1,'TightInset'));
h2 = axes('OuterPosition', [.5,0,.5 1]);
set(h2,'LooseInset',get(h2,'TightInset'));

axes(h1);
plot([0 1], [4 5]);
set_label1('A');  

axes(h2);
plot([0 1], [4 5]);
set_label1('B');

我得到的图片是:

在此处输入图像描述

如果您调整图形的大小,标签将不再位于正确的位置。这很好,我预料到了(如果你知道如何把它们放回它们所属的地方并且你告诉我们那会让我很高兴)。

我面临的问题是我不想以“数据”单位指定标签的位置。相反,我想使用标准化单位。所以我使用了修改后的函数形式。现在让我们使用它:

function h = set_label2(label)
tlh = get(gca, 'Title');
if strcmp(get(tlh, 'String'), '')
    title(' ');
end
ylh = get(gca, 'YLabel');
if strcmp(get(ylh, 'String'), '')
    ylabel(' ');
end

oldUnits = replace_prop(ylh, 'Units', 'normalized');
ylp = get(ylh, 'Position');
x = ylp(1);
set(ylh, 'Units', oldUnits);

oldUnits = replace_prop(tlh, 'Units', 'normalized');
tlp = get(tlh, 'Position');
y = tlp(2);
set(ylh, 'Units', oldUnits);

h = text('String', label, ...
        'HorizontalAlignment', 'right',...
        'VerticalAlignment', 'Baseline', ...
        'FontUnits', 'pixels', ...
        'FontSize', 16, ...
        'FontWeight', 'bold', ...
        'FontName', 'Arial', ...
        'Units', 'normalized',...
        'Position', [x y 0]);
end

function oldvalue = replace_prop(handle, propName, newvalue)
oldvalue = get(handle, propName);
set(handle, propName, newvalue);
end

运行相同的测试:

figure;
h1 = axes('OuterPosition', [0,0,.5 1]);
set(h1,'LooseInset',get(h1,'TightInset'));
h2 = axes('OuterPosition', [.5,0,.5 1]);
set(h2,'LooseInset',get(h2,'TightInset'));

axes(h1);
plot([0 1], [4 5]);
set_label2('A');  

axes(h2);
plot([0 1], [4 5]);
set_label2('B');

我们得到与以前完全相同的图片。唯一的问题是,当我们现在调整它的大小时,会发生一些不好的事情:

在此处输入图像描述

标签实际上是在正确的位置。但似乎我使用的'LooseInset'and'TightInset'属性使轴的行为就像没有标签一样。有什么解决办法吗?实际上,我所做的只是在标准化单元中获取标题和 ylabel 的位置,而不是在数据单元中,这似乎把它搞砸了。

我需要以标准化单位获取它的原因是,当我们获得 3D 图时,我可以相对于标题和 zlabel 定位标签。

4

2 回答 2

2

为了后代的缘故,这是我决定使用的版本。它做了我期望它做的事情,但现在我遇到了一个我不知道如何解决的问题。好的,首先是好消息,这里是调用的函数axes_label

function c = axes_label(varargin)

if isa(varargin{1}, 'char')
    axesHandle = gca;
else
    axesHandle = get(varargin{1}{1}, 'Parent');
end

if strcmp(get(get(axesHandle, 'Title'), 'String'), '')
    title(axesHandle, ' ');
end
if strcmp(get(get(axesHandle, 'YLabel'), 'String'), '')
    ylabel(axesHandle, ' ');
end
if strcmp(get(get(axesHandle, 'ZLabel'), 'String'), '')
    zlabel(axesHandle, ' ');
end

if isa(varargin{1}, 'char')    
    label = varargin{1};
    if nargin >=2
        dx = varargin{2};
        if nargin >= 3
            dy = varargin{3};
        else
            dy = 0;
        end
    else
        dx = 3;
        dy = 3;
    end
    h = text('String', label, ...
        'HorizontalAlignment', 'left',...
        'VerticalAlignment', 'top', ...
        'FontUnits', 'pixels', ...
        'FontSize', 16, ...
        'FontWeight', 'bold', ...
        'FontName', 'Arial', ...
        'Units', 'normalized');
    el = addlistener(axesHandle, 'Position', 'PostSet', @(o, e) posChanged(o, e, h, dx, dy));
    c = {h, el};
else
    h = varargin{1}{1};
    delete(varargin{1}{2});
    if nargin >= 2    
        if isa(varargin{2}, 'char')
            set(h, 'String', varargin{2});
            if nargin >=3
                dx = varargin{3};
                dy = varargin{4};
            else
                dx = 3;
                dy = 3;
            end
        else
            dx = varargin{2};
            dy = varargin{3};
        end
    else
       error('Needs more arguments. Type help axes_label'); 
    end
    el = addlistener(axesHandle, 'Position', 'PostSet', @(o, e) posChanged(o, e, h, dx, dy));
    c = {h, el};
end
posChanged(0, 0, h, dx, dy);
end

function posChanged(~, ~, h, dx, dy)
    axh = get(h, 'Parent');
    p = get(axh, 'Position');
    o = get(axh, 'OuterPosition');
    xp = (o(1)-p(1))/p(3);
    yp = (o(2)-p(2)+o(4))/p(4);
    set(h, 'Units', get(axh, 'Units'),'Position', [xp yp]);
    set(h, 'Units', 'pixels');
    p = get(h, 'Position');
    set(h, 'Position', [p(1)+dx, p(2)+5-dy]);
    set(h, 'Units', 'normalized');
end

好的,那么我们如何使用这个糟糕的功能呢?我这样做是为了我们可以有这些用途:

%   c = axes_label('label')
%      Places the text object with the string 'label' on the upper-left 
%      corner of the current axes and returns a cell containing the handle
%      of the text and an event listener.
%
%   c = axes_label('label', dx, dy)
%      Places the text object dx pixels from the left side of the axes
%      and dy pixels from the top. These values are set to 3 by default.
%
%   c = axes_label(c, ...)
%      Peforms the operations mentioned above on cell c containing the
%      handle of the text and the event listener.
%
%   c = axes_label(c, dx, dy)
%      Adjusts the current label to the specifed distance from the
%      upper-left corner of the current axes.

如果我们执行与之前相同的测试:

figure;
h1 = axes('OuterPosition', [0,0,.5 1]);
set(h1,'LooseInset',get(h1,'TightInset'));
h2 = axes('OuterPosition', [.5,0,.5 1]);
set(h2,'LooseInset',get(h2,'TightInset'));

axes(h1);
plot([0 1], [4 5]);
axes_label('A');  

axes(h2);
plot([0 1], [4 5]);
axes_label('B', 250, 250);

现在我们得到了我想要的。标签“A”设置在坐标区外框的左上角。并且标签 BI 明确地将其设置为距其左上角 250 像素。这是一个情节:

在此处输入图像描述

我喜欢这个函数的地方是,如果我要存储从它返回的单元格,然后我放回去,我可以改变位置。例如,如果label = axes_label('A');然后在命令提示符下我可以做label = axes_label(label, 10, 20);,我会看到我的标签移动。

我现在面临的问题与功能有关export_fig

如果我尝试使用这个:

export_fig('testing.png', '-nocrop', '-painters');

然后这是我得到的数字。

在此处输入图像描述

这就是我夸大标签 B 的原因。在我添加事件侦听器之前,export_fig 在打印我放置它们的标签时会做得很好。但不知何故,现在 export_fig 并没有像它声称的那样做。主要导出图像

在屏幕上显示的图形/轴再现

相反,如果我们删除该选项-painters,那么我们会得到:

在此处输入图像描述

由于我对听众没有经验,因此代码中可能存在错误,因此如果有人可以修复此行为和/或可以改进此代码,请随时这样做并将其作为答案分享。

于 2012-06-23T01:56:37.313 回答
1

首先,我喜欢你使用标题/y-label 将文本定位在左上角的想法,聪明:)

现在,不再使用标准化单位,而是继续使用数据单位,并为标题或 y 标签更改其位置时创建事件侦听器,并使用它们的新值重新调整创建的文本。

因此,将以下内容添加到set_label1函数的末尾:

addlistener(ylh, 'Position', 'PostSet', @(o,e) posChanged(o,e,h,1))
addlistener(tlh, 'Position', 'PostSet', @(o,e) posChanged(o,e,h,2))

这是用于这两种情况的回调函数(我们使用最后一个参数idx来控制是否设置 x 或 y 坐标):

function posChanged(src,evt,hTxt,idx)
    posLabel = evt.NewValue;          %# new position of either title/y-label
    posText = get(hTxt, 'Position');  %# current text position
    posText(idx) = posLabel(idx);     %# update x or y position (based on idx)
    set(hTxt, 'Position',posText)     %# adjust the text position
end
于 2012-06-22T21:56:58.433 回答