【问题标题】:Subplot label in matlab figuresmatlab图中的子图标签
【发布时间】:2012-06-24 07:34:43
【问题描述】:

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

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''TightInset' 属性使轴的行为就像没有标签一样。 有什么解决办法吗?实际上,我所做的只是在标准化单元中获取标题和 ylabel 的位置,而不是在数据单元中,这似乎搞砸了。

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

【问题讨论】:

  • 即使我们在测试代码中删除关于更改LooseInset 的代码,我们仍然会得到与set_label2 相同的行为。
  • 顺便说一下,LooseInsetundocumented 属性

标签: matlab plot label matlab-figure subplot


【解决方案1】:

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

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

所以在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

【讨论】:

  • 感谢您向我展示如何添加监听器。最后,我决定使用标准化单位使其工作。但是这次我得到了轴的“位置”和“外部位置”。使用此信息,我可以指定标签相对于左上角的位置。这样它也可以在 3D 中工作。
  • @jmlopez:为了后代,你也应该考虑发布你的新代码。
  • 会的,我只是想解决我在事件监听器方面遇到的一个问题。
  • 问题...您正在向ylhtlh 添加一个事件侦听器。有没有办法在给定ylh 广告tlh 时引用此事件侦听器。请注意,我们没有存储它,但我希望以后能够获得这样的监听器,以便我可以删除它。
  • @jmlopez:是的,只需存储返回值:lh = addlistener(..);,然后在您想删除它时调用delete(lh)
【解决方案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”设置在坐标区外框的左上角。并且标签 B 我明确地将其设置为距其左上角 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,那么我们会得到:

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

【讨论】:

    猜你喜欢
    • 2016-09-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-24
    相关资源
    最近更新 更多