matlab 3D 绘图中的次要 y 轴(surf、mesh、surfc)

Secondary y-axis in matlab 3D plot (surf, mesh, surfc)

我正在尝试将具有不同单位的辅助 y 轴添加到 3D 图。

[m2_array, ~ , ~] = F_readBin('amb.bin');
amb = m2_array(:,:,lat);

surfc(light,'LineWidth',0.001); 
ylim([1 24]); xlim([1 size(light,2)]); title(['@ ',num2str(lat),'°N']);
xticks([0:50:size(m2_array,2)]);
labels=cellstr(num2str((day_start:50:day_end)')); xticklabels(labels);
xlabel('Season days'); ylabel('Daytime{[hours]}');zlabel('surface light 
[\mumol m^2 s^-^1]')
colormap winter;

但是,我可以找到所有解决方案,例如yyaxis 似乎只适用于 2D 图。 是否有针对 surf、mesh、surfc 图的解决方法?

不确定这是否是您要查找的内容,但我想将次轴添加到 3D 图的基本方法与 2D 相同(据我所知,matlab 中的 2D 图只是从上面看的 3D 图)。

我们的想法是将第二组轴放在第一组轴之上,然后调整它以满足您的要求,例如通过隐藏未使用的轴并使辅助背景透明。这在 Matlab 文档 here.

中有解释

对于 3D,由于默认的轴和标签位置,这有点棘手,但这正是 undocumentedmatlab 可以解决的问题。使用 Axes' NumericRuler 对象(XAxisYAxisZAxis)的 FirstCrossOverValueSecondCrossoverValue 属性,我们可以将辅助轴定位在所需位置。

下面的例子说明了基本思想。这是针对 z 轴的,但同样的方法可用于 y 或 x。

clear; close all; clc

% Dummy data from matlab example
[X,Y,Z] = peaks(25);

% Primary axes with some arbitrary viewpoint and labels
hs = surf(X,Y,Z); % Get surface object
ha = hs.Parent; % Get parent Axes
ha.View = [25, 40]; % Set arbitrary view point
xlabel 'xa';
ylabel 'ya';
zlabel 'za';
grid on

% Secondary axes on top of primary, using same view point
hb = axes('view',ha.View);
hb.ZLim = [0 7]; % Arbitrary axis limits
zlabel 'zb'; 

% Hide secondary background and x and y rulers
hb.Color = 'none'; % Transparent background
hb.XAxis.Visible = 'off';
hb.YAxis.Visible = 'off';

% Move z-ruler to opposite corner (from undocumentedmatlab)
hb.ZAxis.FirstCrossoverValue = 1; % x-location of z-ruler [normalized]
hb.ZAxis.SecondCrossoverValue = 1; % y-location of z-ruler [normalized]

请注意,当您开始手动旋转轴或放大或缩小时,此基本示例将失效。您需要添加一些方法 link 将两个轴放在一起才能解决这个问题。

结果将是:

如图, you could make use of some undocumented features to add an extra axis. This has a few drawbacks, the obvious being that undocumented features have a tendency to change without notice. Additionally, adding an extra x or y axis in the same fashion (i.e. on the opposite side) would cause it to be occluded by the plot and not be very useful. Achieving an effect where the axes are stacked up on one side, as the answers to this question所示,最好是3D的。然而,这可能有点混乱,我还没有找到一种可靠的方法来做到这一点,以适应情节的变化(即旋转、缩放、改变限制等)。

不添加另一条轴线,不依赖于未记录的功能的更紧凑的解决方案是搭载现有轴 tick marks and simply add an additional set of tick labels at a new scale. The additional set of tick (and axis) labels can be colored using TeX markup 以区分它们。

我将一些代码包装到执行此操作的原型函数中。输入是坐标轴句柄、用于要修改的坐标轴的字符串('X''Y''Z')、新比例的一组新坐标轴限制(将被映射到当前限制),新标签的颜色(作为 RGB triple), and a string for the new axis label:

function add_scale(hAxes, axisStr, newLimits, newColor, newLabel)

  % Get axis ruler to modify:
  axisStr = upper(axisStr);
  hRuler = get(hAxes, [axisStr 'Axis']);

  % Create TeX color modification strings:
  labelColor = ['\color[rgb]{' sprintf('%f ', hRuler.Label.Color) '}'];
  tickColor = ['\color[rgb]{' sprintf('%f ', hRuler.Color) '}'];
  newColor = ['\color[rgb]{' sprintf('%f ', newColor) '}'];

  % Compute tick values for new axis scale:
  tickValues = hRuler.TickValues;
  limits = hRuler.Limits;
  newValues = newLimits(1)+...
              diff(newLimits).*(tickValues-limits(1))./diff(limits);

  % Create new tick labels:
  formatString = ['\' tickColor hRuler.TickLabelFormat '\newline\' ...
                  newColor hRuler.TickLabelFormat '\n'];
  newTicks = strsplit(sprintf(formatString, [tickValues; newValues]), '\n');

  % Update tick and axis labels:
  hRuler.Label.String = {[labelColor hRuler.Label.String]; ...
                         [newColor newLabel]};
  hRuler.TickLabels = newTicks(1:(end-1));

end

这是一个例子:

[X, Y, Z] = peaks(25);
hSurf = surfc(Z);
hAxes = gca;
ylabel('Distance (inches)');
add_scale(hAxes, 'Y', hAxes.YLim.*2.54, [1 0 0], 'Distance (cm)');

新刻度标签(红色)添加在现有刻度标签下方,新轴标签也是如此。可以创建 listeners 来自动更新新标签(例如当刻度线更改时),但我还没有弄清楚这方面的所有细节。