I've been playing around for several hours trying to get the x and y labels in a 3D plot to align properly. The following code creates an isometric view, for which the axis angles should be 30° (which is correctly computed).
figure;
axh = axes;
Z = peaks(20);
surf(Z)
xlabel('x-axis');
ylabel('y-axis');
azimuth = -45;
elevation = 35.264;
% Isometric view, c. f. https://en.wikipedia.org/wiki/Isometric_projection
view(axh,azimuth,elevation);
camproj % returns 'orthographic'
unitx = [1;0;0];
unity = [0;1;0];
unitz = [0;0;1];
projectedunitx = rotx(elevation) * rotz(-azimuth) * unitx;
projectedunity = rotx(elevation) * rotz(-azimuth) * unity;
xlabelangle = atan2d(projectedunitx(3),projectedunitx(1)) %#ok
ylabelangle = -(180 - atan2d(projectedunity(3),projectedunity(1))) %#ok
xlabelhandle = axh.XLabel;
ylabelhandle = axh.YLabel;
xlabelhandle.Rotation = xlabelangle;
ylabelhandle.Rotation = ylabelangle;
xlimits = xlim(axh);
ylimits = ylim(axh);
zlimits = zlim(axh);
xmean = mean(xlimits);
ymean = mean(ylimits);
xbottom = xlimits(1);
ybottom = ylimits(1);
zbottom = zlimits(1);
xlabelhandle.Position = [xmean ybottom zbottom];
ylabelhandle.Position = [xbottom ymean zbottom];
Yet in the plot the labels don't align exactly parallel to the axes:
The error is relatively small, but I'd like to have an exact solution. It appears Matlab doesn't exactly adhere to the rules of orthographic projection because in a truly isometric view (which is orthographic), the axes angles are 30°. Is there some way to get the alignment (mathematically) right? (I'm aware of this FEX function https://mathworks.com/matlabcentral/fileexchange/49542-phymhan-matlab-axis-label-alignment but it doesn't seem to work in R2020b.)

 채택된 답변

Dave B
Dave B 2022년 4월 1일

3 개 추천

The differrence between your labels and the axes is because MATLAB stretches an axes to fill the space of its container - if you made your figure wider the angles would become flatter. To get the exact angle, axis equal should do the trick:
figure;
axh = axes;
Z = peaks(20);
surf(Z)
xlabel('x-axis');
ylabel('y-axis');
azimuth = -45;
elevation = 35.264;
% Isometric view, c. f. https://en.wikipedia.org/wiki/Isometric_projection
view(axh,azimuth,elevation);
camproj % returns 'orthographic'
ans = 'orthographic'
unitx = [1;0;0];
unity = [0;1;0];
unitz = [0;0;1];
projectedunitx = rotx(elevation) * rotz(-azimuth) * unitx;
projectedunity = rotx(elevation) * rotz(-azimuth) * unity;
xlabelangle = atan2d(projectedunitx(3),projectedunitx(1)) %#ok
xlabelangle = 29.9998
ylabelangle = -(180 - atan2d(projectedunity(3),projectedunity(1))) %#ok
ylabelangle = -29.9998
xlabelhandle = axh.XLabel;
ylabelhandle = axh.YLabel;
xlabelhandle.Rotation = xlabelangle;
ylabelhandle.Rotation = ylabelangle;
xlimits = xlim(axh);
ylimits = ylim(axh);
zlimits = zlim(axh);
xmean = mean(xlimits);
ymean = mean(ylimits);
xbottom = xlimits(1);
ybottom = ylimits(1);
zbottom = zlimits(1);
xlabelhandle.Position = [xmean ybottom zbottom];
ylabelhandle.Position = [xbottom ymean zbottom];
axis equal

댓글 수: 6

broken_arrow
broken_arrow 2022년 4월 1일
편집: broken_arrow 2022년 4월 1일
Ah ok. Sadly axis equal isn't always an option. Is there a way to account for stretching? By the way (since you are from "HQ"), it would be great to have a native functionality to automatically align labels in 3D plots (and keep them that way when rotating, zooming etc). Currently, the labels tend to "hang around loosely" especially when the text gets longer.
Dave B
Dave B 2022년 4월 4일
It looked like the FEX submission you mentioned takes a shot at computing the values for abitrary aspect ratios but it doesn't work. I'm guessing this could be done with some trig, but I don't see an easy bit of math to do it. I agree this would be a nice feature to be built directly into axes...I think it's been discussed but I'm not sure where it sits in the priority stack, I'll happily add a +1 that we should work on it!
broken_arrow
broken_arrow 2022년 4월 7일
Ok, great. Thanks.
broken_arrow
broken_arrow 2022년 4월 7일
The main problem when trying to correct the "stretch error" is the "stretching algorithm" which fits the plot to the axes is unknown to the user. Given the "initial plot size" before stretching and the respective "scaling factors" for length and width, the axis angle changes could be easily calculated.
Dyuman Joshi
Dyuman Joshi 2023년 9월 9일
This answer was flagged by @Giovanni de amici with the comment -
"this answer uses functions [ rotx(variable) and rotz(variable) ] which are not defined as part of the answer (or of the question) and are not in the Matlab distribution. That makes the answer rather useless, does it not? "
@Giovanni de amici, The functions rotx and rotz are a part of the Phased Array System Toolbox. You will need the aforementioned toolbox to access the functions.
Both the questioner and the answerer were aware of this fact.
So, No, the answer is not useless. And there is a reason the questioner accepted this answer, because the answer worked.
Dave B
Dave B 2023년 9월 10일
@Giovanni de amici - I used rotx and rotz because they were included in the code snippet in the question. But these are quite simple one liners...if you don't have access to the toolbox mentioned above you'll find they're trivial to implement (and the documentation page for rotx has a clear description of what the matrices look like, although you can find these elsewhere of course).
I think, for instance, you could implement your own version rotx as:
function T = myrotx(ang)
T = [1 0 0; ...
0 cosd(ang) -sind(ang); ...
0 sind(ang) cosd(ang)];
end

댓글을 달려면 로그인하십시오.

추가 답변 (0개)

카테고리

도움말 센터File Exchange에서 Graphics Performance에 대해 자세히 알아보기

제품

릴리스

R2020b

질문:

2022년 4월 1일

댓글:

2023년 9월 10일

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by