matlab 奇怪的 xtick/ytick 标签行为
matlab's odd xtick/ytick label behavior
我偶然发现了 matlab 的 xticklabels 和 yticklabels 行为的不直观行为。我将 xticklabels 的输出存储到一个变量中,对其进行修改,然后再次应用它,并注意到标签现在已移动。这是预期的行为吗,如果是的话为什么(可选:为什么将此作为预期的行为有意义)?
想法:每一步都显示 xticks,但每第二步只显示标签。
%setup a figure to display
figure;
data=randn(1,21);
plot(-10:10,data);
xlim([-5 10]) %cut out a piece of interest from the data
xticks(-10:2:10); %adjust tick spacing to favorite
%now: keep xticks but remove every 2nd label
lbls=xticklabels;
lbls(1:2:end)={' '}; %set every 2nd label to empty space
pause(1); %take a deep breath...
xticklabels(lbls)
问题在于,虽然 xtick
函数 returns 所有现有刻度(可见和隐藏)的值,但 xticklabels
函数仅 returns可见刻度的标签。我猜这种行为是由于 MATLAB 没有为不可见的刻度分配任何标签。
因此,您的 xtick 向量是:
[-10 -8 -6 -4 -2 0 2 4 6 8 10]
而您的 xticklabels 元胞数组是:
{'-4'}, {'-2'}, {'0'}, {'2'}, {'4'}, {'6'}, {'8'}, {'10'}
并且,替换后:
{' '}, {'-2'}, {' '}, {'2'}, {' '}, {'6'}, {' '}, {'10'}
由于您的图片中唯一可见的刻度是分配给范围从-4到10的刻度,因此显示的相应标签是元胞数组中从第四个到最后一个的元素。没有分配标签的刻度(因为标签比刻度少)以空单元格为特征:
{'2'}, {' '}, {'6'}, {' '}, {'10'}, {empty}, {empty}, {empty}
解决方法:
你有多种解决方案。第一个是删除不在 x 轴范围内的刻度:
%setup a figure to display
figure;
data=randn(1,21);
plot(-10:10,data);
xlim([-5 10]) %cut out a piece of interest from the data
xticks(-10:2:10); %adjust tick spacing to favorite
% Delete external ticks
xt = xticks();
xl = xlim(); xt(xt<xl(1)) = []; xt(xt>xl(2)) = []; xticks(xt);
%now: keep xticks but remove every 2nd label
lbls=xticklabels;
lbls(1:2:end)={' '}; %set every 2nd label to empty space
pause(1); %take a deep breath...
xticklabels(lbls)
Result(1)
另一个解决方案是手动分配标签,将 xticks 返回的数字转换为字符串值:
%setup a figure to display
figure;
data=randn(1,21);
plot(-10:10,data);
xlim([-5 10]) %cut out a piece of interest from the data
xticks(-10:2:10); %adjust tick spacing to favorite
%now: keep xticks but remove every 2nd label
lbls= arrayfun(@(x) num2str(x), xticks(), 'UniformOutput', false);
lbls(1:2:end)={' '}; %set every 2nd label to empty space
pause(1); %take a deep breath...
xticklabels(lbls)
Result(2)
您会注意到两个解决方案之间的刻度不同。这是由于 even/odd 个元素在两个向量之间不同,因此,不同的元素被替换为空格。
如 中所述,问题是由于 Matlab 在读取 (labels = xticklabels
) 和指定它们 (xticklabels(labels)
) 时对刻度标签的处理方式不同。但实际行为更有趣...
读取和指定刻度标签时的行为
这些是我测试后发现的。感觉比它应该的更复杂(也许我遗漏了一些可以使描述更简单的东西?)。
如果 'XTickLabelMode'
属性 的值为 'Auto'
,刻度标签是 自动 根据当前选择的滴答声。
示例:
clf
plot(1:8)
xlim([2 7])
xticks, xticklabels.'
给予
ans =
2 3 4 5 6 7
ans =
1×6 cell array
{'2'} {'3'} {'4'} {'5'} {'6'} {'7'}
即使手动设置轴刻度,此刻度行为也是相同的:
clf
plot(1:8)
xticks(3:7)
xticks, xticklabels.'
给予
ans =
3 4 5 6 7
ans =
1×5 cell array
{'3'} {'4'} {'5'} {'6'} {'7'}
显然,行为会受到要处理的图形事件分组的影响:
clf
plot(1:8)
xlim([2 7])
drawnow % force axis creation before setting 'XTickLabelMode'
set(gca, 'XTickLabelMode', 'manual')
xticklabels.'
给出与上面一致的结果:
ans =
1×6 cell array
{'2'} {'3'} {'4'} {'5'} {'6'} {'7'}
而删除 drawnow
会产生不同的结果:
clf
plot(1:8)
xlim([2 7])
set(gca, 'XTickLabelMode', 'manual')
xticklabels.'
给予
ans =
0×0 empty char array
可能的解释是,如果没有 drawnow
,两个图形事件(轴创建和设置 属性)都是一次性处理的,这会以某种方式影响结果。
如果 'XTickLabelMode'
属性 的值为 'Manual'
,则按原样读取刻度标签 returns 标签 由用户设置 (更多信息请参见下面的 (3) 和 (4)),这可能与当前在图表上看到的标签不一致。所以现在返回的结果可能与当前轴限制不匹配。
使用 xticklabels(...)
或 set(gca, 'xticklabels', ...)
隐式 手动设置刻度标签会导致 'XTickLabelMode'
属性 具有值'Manual'
。此外,此 属性 可能 显式 设置为 'Manual'
和 set(gca, 'XTickLabelMode', 'Manual')
。
示例:
clf
plot(1:7)
xticklabels({'a' 'b' 'c'})
xlim([2 6])
get(gca, 'XTickLabelMode')
xticklabels.'
给予
ans =
'manual'
ans =
1×7 cell array
{'a'} {'b'} {'c'} {0×0 char} {0×0 char} {0×0 char} {0×0 char}
绘图显示了这些刻度标签:
当手动设置刻度标签时,它们被解释为参考当前轴刻度,无论当前轴限制,因此无论有多少轴刻度实际可见。
示例:在上图中,请注意第一个标签 ('a'
) 是如何不可见的。这是因为轴刻度是(默认情况下)[1 2 3 4 5 6 7]
:
clf
plot(1:7)
xticklabels({'a' 'b' 'c'})
xlim([2 6])
xticks
ans =
1 2 3 4 5 6 7
第一个标签指的是第一个刻度,它在 xlim
设置的轴限制之外,因此看不到。
使用xticklabels(...)
手动设置刻度标签时,如果提供的标签数量少于刻度数量,则缺少的标签最后被假定为 空字符串 .
示例:在上图中,注意'c'
以外的标签是空的。
用set(gca, 'xticklabels', ...)
手动设置刻度标签时,如果提供的标签数量小于Matlab的刻度数量在显示的图表中循环重复使用它们以匹配刻度数。
示例:
clf
plot(1:7)
xticks(1:7)
set(gca, 'xticklabels', {'a' 'b' 'c'})
xlim([2 6])
xticklabels.'
给出以下内容(另请注意,第一个标签因 (3) 而未显示):
ans =
1×3 cell array
{'a'} {'b'} {'c'}
描述的行为有意义吗?
我认为是的。乍一看可能看起来很复杂,但它是一致的。
示例(刻度标签模式的隐式更改):
>> clf
plot(1:7)
xticks(0:7)
get(gca, 'XTickLabelMode'), xticklabels.'
disp('Pausing...'), pause % press key to continue
labels = xticklabels; % read current tick labels
xticklabels(labels) % this causes 'XLabelMode' to take the value 'Manual'
get(gca, 'XTickLabelMode'), xticklabels.'
给予
ans =
'auto'
ans =
1×7 cell array
{'1'} {'2'} {'3'} {'4'} {'5'} {'6'} {'7'}
Pausing...
ans =
'manual'
ans =
1×8 cell array
{'1'} {'2'} {'3'} {'4'} {'5'} {'6'} {'7'} {0×0 char}
暂停前,刻度标签处于 'Auto'
模式,因此它们是根据当前可见的刻度自动选择的。
暂停后,代码读取轴刻度标签,写回刚刚读取的内容并再次读取;这给出了与暂停前的读数不同的结果。原因是两个读数之间对刻度标签的解释已从 (1) 更改为 (2)。但是没有歧义,因为轴的 'XTickLabelMode'
属性 已经从 'Auto'
变成了 'Manual'
来反映。
在此示例中,'XTickLabelMode'
的更改已由用户手动设置刻度标签隐式触发。如果 属性 明确更改为 'Manual'
会怎样?结果还是一致的,如下图。
示例(刻度标签模式的显式更改):
clf
plot(1:7)
xticks(0:7)
get(gca, 'XTickLabelMode'), xticklabels.'
disp('Pausing...'), pause % press key to continue
set(gca, 'XTickLabelMode', 'Manual')
get(gca, 'XTickLabelMode'), xticklabels.'
给予
ans =
'auto'
ans =
1×7 cell array
{'1'} {'2'} {'3'} {'4'} {'5'} {'6'} {'7'}
Pausing...
ans =
'manual'
ans =
1×7 cell array
{'1'} {'2'} {'3'} {'4'} {'5'} {'6'} {'7'}
暂停前的情节在 'Auto'
模式下有刻度标签,它们按预期工作。
暂停后的情节在 'Manual'
模式下有刻度标签。刻度标签与以前相同,但在这种模式下,它们适用于所有刻度,甚至是那些超出轴限制的刻度。所以有一个刻度标签比需要的少,Matlab 根据上面的(5)重用最后一个刻度的第一个标签:
之前:
之后:
因此检查 'XTickLabelMode'
属性 是 有效的 方法来确定读取的刻度标签是否应根据 (1) 或 ( 2).
我偶然发现了 matlab 的 xticklabels 和 yticklabels 行为的不直观行为。我将 xticklabels 的输出存储到一个变量中,对其进行修改,然后再次应用它,并注意到标签现在已移动。这是预期的行为吗,如果是的话为什么(可选:为什么将此作为预期的行为有意义)?
想法:每一步都显示 xticks,但每第二步只显示标签。
%setup a figure to display
figure;
data=randn(1,21);
plot(-10:10,data);
xlim([-5 10]) %cut out a piece of interest from the data
xticks(-10:2:10); %adjust tick spacing to favorite
%now: keep xticks but remove every 2nd label
lbls=xticklabels;
lbls(1:2:end)={' '}; %set every 2nd label to empty space
pause(1); %take a deep breath...
xticklabels(lbls)
问题在于,虽然 xtick
函数 returns 所有现有刻度(可见和隐藏)的值,但 xticklabels
函数仅 returns可见刻度的标签。我猜这种行为是由于 MATLAB 没有为不可见的刻度分配任何标签。
因此,您的 xtick 向量是:
[-10 -8 -6 -4 -2 0 2 4 6 8 10]
而您的 xticklabels 元胞数组是:
{'-4'}, {'-2'}, {'0'}, {'2'}, {'4'}, {'6'}, {'8'}, {'10'}
并且,替换后:
{' '}, {'-2'}, {' '}, {'2'}, {' '}, {'6'}, {' '}, {'10'}
由于您的图片中唯一可见的刻度是分配给范围从-4到10的刻度,因此显示的相应标签是元胞数组中从第四个到最后一个的元素。没有分配标签的刻度(因为标签比刻度少)以空单元格为特征:
{'2'}, {' '}, {'6'}, {' '}, {'10'}, {empty}, {empty}, {empty}
解决方法: 你有多种解决方案。第一个是删除不在 x 轴范围内的刻度:
%setup a figure to display
figure;
data=randn(1,21);
plot(-10:10,data);
xlim([-5 10]) %cut out a piece of interest from the data
xticks(-10:2:10); %adjust tick spacing to favorite
% Delete external ticks
xt = xticks();
xl = xlim(); xt(xt<xl(1)) = []; xt(xt>xl(2)) = []; xticks(xt);
%now: keep xticks but remove every 2nd label
lbls=xticklabels;
lbls(1:2:end)={' '}; %set every 2nd label to empty space
pause(1); %take a deep breath...
xticklabels(lbls)
Result(1)
另一个解决方案是手动分配标签,将 xticks 返回的数字转换为字符串值:
%setup a figure to display
figure;
data=randn(1,21);
plot(-10:10,data);
xlim([-5 10]) %cut out a piece of interest from the data
xticks(-10:2:10); %adjust tick spacing to favorite
%now: keep xticks but remove every 2nd label
lbls= arrayfun(@(x) num2str(x), xticks(), 'UniformOutput', false);
lbls(1:2:end)={' '}; %set every 2nd label to empty space
pause(1); %take a deep breath...
xticklabels(lbls)
Result(2)
您会注意到两个解决方案之间的刻度不同。这是由于 even/odd 个元素在两个向量之间不同,因此,不同的元素被替换为空格。
如 labels = xticklabels
) 和指定它们 (xticklabels(labels)
) 时对刻度标签的处理方式不同。但实际行为更有趣...
读取和指定刻度标签时的行为
这些是我测试后发现的。感觉比它应该的更复杂(也许我遗漏了一些可以使描述更简单的东西?)。
如果
'XTickLabelMode'
属性 的值为'Auto'
,刻度标签是 自动 根据当前选择的滴答声。示例:
clf plot(1:8) xlim([2 7]) xticks, xticklabels.'
给予
ans = 2 3 4 5 6 7 ans = 1×6 cell array {'2'} {'3'} {'4'} {'5'} {'6'} {'7'}
即使手动设置轴刻度,此刻度行为也是相同的:
clf plot(1:8) xticks(3:7) xticks, xticklabels.'
给予
ans = 3 4 5 6 7 ans = 1×5 cell array {'3'} {'4'} {'5'} {'6'} {'7'}
显然,行为会受到要处理的图形事件分组的影响:
clf plot(1:8) xlim([2 7]) drawnow % force axis creation before setting 'XTickLabelMode' set(gca, 'XTickLabelMode', 'manual') xticklabels.'
给出与上面一致的结果:
ans = 1×6 cell array {'2'} {'3'} {'4'} {'5'} {'6'} {'7'}
而删除
drawnow
会产生不同的结果:clf plot(1:8) xlim([2 7]) set(gca, 'XTickLabelMode', 'manual') xticklabels.'
给予
ans = 0×0 empty char array
可能的解释是,如果没有
drawnow
,两个图形事件(轴创建和设置 属性)都是一次性处理的,这会以某种方式影响结果。如果
'XTickLabelMode'
属性 的值为'Manual'
,则按原样读取刻度标签 returns 标签 由用户设置 (更多信息请参见下面的 (3) 和 (4)),这可能与当前在图表上看到的标签不一致。所以现在返回的结果可能与当前轴限制不匹配。使用
xticklabels(...)
或set(gca, 'xticklabels', ...)
隐式 手动设置刻度标签会导致'XTickLabelMode'
属性 具有值'Manual'
。此外,此 属性 可能 显式 设置为'Manual'
和set(gca, 'XTickLabelMode', 'Manual')
。示例:
clf plot(1:7) xticklabels({'a' 'b' 'c'}) xlim([2 6]) get(gca, 'XTickLabelMode') xticklabels.'
给予
ans = 'manual' ans = 1×7 cell array {'a'} {'b'} {'c'} {0×0 char} {0×0 char} {0×0 char} {0×0 char}
绘图显示了这些刻度标签:
当手动设置刻度标签时,它们被解释为参考当前轴刻度,无论当前轴限制,因此无论有多少轴刻度实际可见。
示例:在上图中,请注意第一个标签 (
'a'
) 是如何不可见的。这是因为轴刻度是(默认情况下)[1 2 3 4 5 6 7]
:clf plot(1:7) xticklabels({'a' 'b' 'c'}) xlim([2 6]) xticks ans = 1 2 3 4 5 6 7
第一个标签指的是第一个刻度,它在
xlim
设置的轴限制之外,因此看不到。使用
xticklabels(...)
手动设置刻度标签时,如果提供的标签数量少于刻度数量,则缺少的标签最后被假定为 空字符串 .示例:在上图中,注意
'c'
以外的标签是空的。用
set(gca, 'xticklabels', ...)
手动设置刻度标签时,如果提供的标签数量小于Matlab的刻度数量在显示的图表中循环重复使用它们以匹配刻度数。示例:
clf plot(1:7) xticks(1:7) set(gca, 'xticklabels', {'a' 'b' 'c'}) xlim([2 6]) xticklabels.'
给出以下内容(另请注意,第一个标签因 (3) 而未显示):
ans = 1×3 cell array {'a'} {'b'} {'c'}
描述的行为有意义吗?
我认为是的。乍一看可能看起来很复杂,但它是一致的。
示例(刻度标签模式的隐式更改):
>> clf
plot(1:7)
xticks(0:7)
get(gca, 'XTickLabelMode'), xticklabels.'
disp('Pausing...'), pause % press key to continue
labels = xticklabels; % read current tick labels
xticklabels(labels) % this causes 'XLabelMode' to take the value 'Manual'
get(gca, 'XTickLabelMode'), xticklabels.'
给予
ans =
'auto'
ans =
1×7 cell array
{'1'} {'2'} {'3'} {'4'} {'5'} {'6'} {'7'}
Pausing...
ans =
'manual'
ans =
1×8 cell array
{'1'} {'2'} {'3'} {'4'} {'5'} {'6'} {'7'} {0×0 char}
暂停前,刻度标签处于 'Auto'
模式,因此它们是根据当前可见的刻度自动选择的。
暂停后,代码读取轴刻度标签,写回刚刚读取的内容并再次读取;这给出了与暂停前的读数不同的结果。原因是两个读数之间对刻度标签的解释已从 (1) 更改为 (2)。但是没有歧义,因为轴的 'XTickLabelMode'
属性 已经从 'Auto'
变成了 'Manual'
来反映。
在此示例中,'XTickLabelMode'
的更改已由用户手动设置刻度标签隐式触发。如果 属性 明确更改为 'Manual'
会怎样?结果还是一致的,如下图。
示例(刻度标签模式的显式更改):
clf
plot(1:7)
xticks(0:7)
get(gca, 'XTickLabelMode'), xticklabels.'
disp('Pausing...'), pause % press key to continue
set(gca, 'XTickLabelMode', 'Manual')
get(gca, 'XTickLabelMode'), xticklabels.'
给予
ans =
'auto'
ans =
1×7 cell array
{'1'} {'2'} {'3'} {'4'} {'5'} {'6'} {'7'}
Pausing...
ans =
'manual'
ans =
1×7 cell array
{'1'} {'2'} {'3'} {'4'} {'5'} {'6'} {'7'}
暂停前的情节在 'Auto'
模式下有刻度标签,它们按预期工作。
暂停后的情节在 'Manual'
模式下有刻度标签。刻度标签与以前相同,但在这种模式下,它们适用于所有刻度,甚至是那些超出轴限制的刻度。所以有一个刻度标签比需要的少,Matlab 根据上面的(5)重用最后一个刻度的第一个标签:
之前:
之后:
因此检查 'XTickLabelMode'
属性 是 有效的 方法来确定读取的刻度标签是否应根据 (1) 或 ( 2).