Вторичная ось y в 3D-графике Matlab (серфинг, сетка, 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-графиков. Есть ли работа для серфинга, сетки, surfc-графики?

Ответ 1

Не уверен, что это то, что вы ищете, но я думаю, что базовый подход к добавлению вторичных осей к 3D-графику будет таким же, как и для 2D (насколько я знаю, 2D-график в Matlab - это просто просмотр 3D-графика). сверху).

Идея состоит в том, что вы помещаете второй набор осей поверх первого, а затем настраиваете его в соответствии с вашими требованиями, например, скрывая неиспользуемые оси и делая вторичный фон прозрачным. Это объясняется в документации Matlab здесь.

Для 3D это немного сложно из-за расположения осей и меток по умолчанию, но именно там, где недокументированная метка приходит на помощь. Используя FirstCrossOverValue и SecondCrossoverValue свойства Axes ' NumericRuler объектов (XAxis, YAxis, ZAxis), мы можем позиционировать вторичную ось в нужном месте.

Основная идея проиллюстрирована на примере ниже. Это для оси 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]

Обратите внимание, что этот базовый пример ломается, когда вы начинаете вращать оси вручную или увеличивать или уменьшать масштаб. Вам нужно добавить несколько методов, которые связывают две оси вместе, чтобы позаботиться об этом.

Результат будет: Example of secondary axis in 3-D plot

Ответ 2

Как показано в ответе от Dennis, вы можете использовать некоторые недокументированные функции добавить дополнительную ось. Это имеет несколько недостатков, очевидно, что недокументированные функции имеют тенденцию к изменению без уведомления. Кроме того, добавление дополнительной оси x или y одним и тем же способом (то есть с противоположной стороны) приведет к тому, что она будет закрыта по сюжету и не будет очень полезна. Достижение эффекта, когда оси сгруппированы с одной стороны, как показывают ответы на этот вопрос, было бы более желательно в 3D. Однако это может быть несколько захламленным, и мне еще предстоит найти надежный способ сделать это, что хорошо отражается на изменениях в сюжете (т.е. Вращении, масштабировании, изменении ограничений и т.д.).

Вместо добавления другой оси осей более компактное решение, не зависящее от недокументированных функций, должно было бы контактировать с существующей осью < отметки метки и просто добавьте дополнительный набор отметьте метки в новом масштабе. Дополнительный набор меток (и оси) может быть окрашен с помощью TeX markup для их дифференциации.

Я завернул код в функцию прототипа, которая делает это. Входы представляют собой дескриптор осей, строку ('X', 'Y' или 'Z') для изменяемых осей, новый набор ограничений по оси для нового масштаба (который будет отображаться в текущих пределах), цвет новых меток (в качестве RGB triple) и строка для нового :

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)');

введите описание изображения здесь

Новые метки меток (в красном) добавляются ниже существующих меток тика, как и новая метка оси. Возможно, вы сможете создать прослушиватели для автоматического обновления новых ярлыков (например, при изменении меток), но я не разработал все детали этого еще.