How to preserve the 3d plot box, when changing patch visibility.

I have a 3d plot with a collection of patches. If I set a subset of patches Visible attributes to 'off', the plot box is recomputed. How can I capture and preserve all aspects of the plot box so that the visible patches don't jump around as other patches become visible or invisible.

 Réponse acceptée

Here's something a little fancier, and maybe more robust. It captures (and reasserts) all relevant properties of the plot perspective, including camera angles and such:
figure;
ax = gca;
% drop some data between 1 and 5 in all 3 dimensions
for x = 1:4:5
for y = 1:4:5
line([x,x],[y,y],[1,5]);
end
end
axis equal;
view(ax,[1,1,1]);
fpose=figPose(ax);
figPose(ax, fpose)
ax.XLimMode %Verify manual mode
ans = 'manual'
ax.YLimMode
ans = 'manual'
ax.ZLimMode
ans = 'manual'
function varargout = figPose(varargin)
%figPose Record or assert a 3-D camera/figure pose
%
%Record pose
%
% S = figPose();
% S = figPose(ax);
%
%Apply pose
%
% figPose(S)
% figPose(ax,S)
%
%The pose includes:
% • Camera geometry
% • Projection mode
% • Axis limits / aspect ratios
% • Figure size
%--------------------------------------------
% Resolve axis handle
%--------------------------------------------
if nargin == 0
hAx = gca;
varargin = {};
else
if isgraphics(varargin{1},'axes')
hAx = varargin{1};
varargin = varargin(2:end);
else
hAx = gca;
end
end
assert(isvalid(hAx),'Axis invalid')
hFig = ancestor(hAx,'figure');
assertPose = ~isempty(varargin) && isstruct(varargin{1});
%--------------------------------------------
% Properties to clone
%--------------------------------------------
camProps = { ...
'CameraPosition',...
'CameraTarget',...
'CameraUpVector',...
'CameraViewAngle',...
'Projection'};
axisProps = { ...
'XLim','YLim','ZLim',...
'DataAspectRatio',...
'PlotBoxAspectRatio'};
%--------------------------------------------
% Apply pose
%--------------------------------------------
if assertPose
S = varargin{1};
% Lock camera modes
set(hAx,...
'CameraPositionMode','manual',...
'CameraTargetMode','manual',...
'CameraUpVectorMode','manual',...
'CameraViewAngleMode','manual');
% Restore camera
set(hAx,camProps,S.cam);
% Restore axis geometry if present
if isfield(S,'axis')
set(hAx,axisProps,S.axis);
end
% Restore figure size
if isfield(S,'figpos')
set(hFig,'Position',S.figpos);
end
%--------------------------------------------
% Capture pose
%--------------------------------------------
else
S.cam = get(hAx,camProps);
S.axis = get(hAx,axisProps);
S.figpos = hFig.Position;
varargout = {S};
end
end

Plus de réponses (3)

Matt J
Matt J le 11 Mar 2026 à 2:53
Modifié(e) : Matt J le 11 Mar 2026 à 23:32
Using axis() twice, we can both capture and reassert the axis limits,
axis(axis)
This also then converts all X,Y,ZLimModes to 'manual' so automatic changes will not happen.

4 commentaires

Matt J
Matt J le 12 Mar 2026 à 19:47
Modifié(e) : Matt J le 12 Mar 2026 à 19:50
Borrowing your example,
figure;
ax = gca;
% drop some data between 1 and 5 in all 3 dimensions
for x = 1:4:5
for y = 1:4:5
line([x,x],[y,y],[1,5]);
end
end
axis equal;
view(ax,[1,1,1]);
originalLimits = axis %Check the current axis limits
originalLimits = 1×6
0.4628 5.5372 1.0000 5.0000 0.5000 5.5000
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
axis(axis) %assert the limits and change to manual limit mode
isequal(originalLimits,axis) %recheck axis limits -- they're unchanged
ans = logical
1
ax.XLimMode %Verify manual mode
ans = 'manual'
ax.YLimMode
ans = 'manual'
ax.ZLimMode
ans = 'manual'
John
John le 13 Mar 2026 à 1:17
Yes, that's working for me.
(But on code hygeine grounds, I hate it. What does axis(axis) do? In other languages, it might look like a copy constructor. Or maybe the Y combinator, invoking a function on itself. In matlab, it's some magic incantation whose semantics are completely independent of the rest of the language. Bleh.)
"What does axis(axis) do?"
It's the same as
lim = axis();
axis(lim)
but without assigning to the variable lim.
Both of those usages are documented.
In matlab, it's some magic incantation whose semantics are completely independent of the rest of the language.
There must be dozens of other graphics commands that behave the same way:
xlim(xlim) %reasserts x-limits
ylim(ylim) %reasserts y-limits
zlim(zlim) %reasserts z-limits
campos(campos)
camva(camva)
camup(camup)
view(view)
figure(figure(n))

Connectez-vous pour commenter.

Voss
Voss le 11 Mar 2026 à 14:40
Modifié(e) : Voss le 11 Mar 2026 à 14:44
You don't need to capture anything.
To preserve the axes limits as they are, set the axes XLimMode, YLimMode, and ZLimMode to 'manual'. Obviously you would do that at a point in the code where the axes limits are what you want them to be, e.g., after all patches are initialized.
Other axes properties besides the limits affect the plot box, so you may want to set some other properties' modes to 'manual' as well in order to disable all undesired automatic changes to the plot box, e.g., PlotBoxAspectRatioMode, CameraViewAngleMode, etc. Look through the axes properties to see what you have control over:

5 commentaires

It seems I do need to capture previous values because setting the ?LimMode's causes the limits to change.
See below how the ZLim values change when the YLimMode is set.
>> [ax.XLim, ax.YLim, ax.ZLim]
ans =
-0.1561 6.1561 1.0000 5.0000 0.5000 5.5000
>> ax.XLimMode = 'manual';
>> ax.YLimMode = 'manual';
>> [ax.XLim, ax.YLim, ax.ZLim]
ans =
-0.1561 6.1561 1.0000 5.0000 1.0000 5.0000
Voss
Voss le 12 Mar 2026 à 0:11
Interesting
It's definitely an Xbug (i.e. unexpected behavior). Whether it's a bug depends on whether all the auto-scaling behavior has a comprehensive description somewhere in the documentation. This code demonstrates the (X)bug.
figure;
ax = gca;
% drop some data between 1 and 5 in all 3 dimensions
for x = 1:4:5
for y = 1:4:5
line([x,x],[y,y],[1,5]);
end
end
axis equal;
view(ax,[1,1,1]);
[ax.XLim, ax.YLim, ax.ZLim]
ans = 1×6
0.4628 5.5372 1.0000 5.0000 0.5000 5.5000
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
ax.XLimMode = 'manual';
ax.YLimMode = 'manual';
[ax.XLim, ax.YLim, ax.ZLim]
ans = 1×6
0.4628 5.5372 1.0000 5.0000 1.0000 5.0000
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
ax.ZLimMode = 'manual';
Voss
Voss le 13 Mar 2026 à 1:52
Modifié(e) : Voss le 13 Mar 2026 à 2:00
If you set the modes all at once, i.e.,
set(ax,'XLimMode','manual','YLimMode','manual','ZLimMode','manual')
Then the limits don't change.

Connectez-vous pour commenter.

Nick
Nick le 18 Mar 2026 à 11:21
Modifié(e) : Matt J le 18 Mar 2026 à 12:08
you may change patch color to fully transparent instead, e.g.
patch_handle.FaceAlpha = 0;
% or make use of the function
alpha(patch_handle, 'clear');
% prepend with "hold on;" if necessary

1 commentaire

John
John le 18 Mar 2026 à 22:01
That's an interesting suggestion. One difference (between setting alpha and setting object visibility) might be in the behavior of tooltips. I haven't done much with tooltips yet, but plan to.

Connectez-vous pour commenter.

Catégories

En savoir plus sur Discrete Data Plots dans Centre d'aide et File Exchange

Produits

Version

R2025b

Question posée :

le 11 Mar 2026 à 2:38

Commenté :

le 18 Mar 2026 à 22:01

Community Treasure Hunt

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

Start Hunting!

Translated by