Skip to content

Commit 8f3e9e6

Browse files
authored
Merge pull request matplotlib#25272 from scottshambaugh/3d_exact_limits
Do not add padding to 3D axis limits when limits are manually set
2 parents cd86571 + 0da1b6c commit 8f3e9e6

File tree

11 files changed

+493
-114
lines changed

11 files changed

+493
-114
lines changed

doc/api/toolkits/mplot3d/axes3d.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,12 +92,18 @@ Axis limits and direction
9292

9393
get_zaxis
9494
get_xlim
95+
set_xlim
9596
get_ylim
97+
set_ylim
9698
get_zlim
9799
set_zlim
98100
get_w_lims
99101
invert_zaxis
100102
zaxis_inverted
103+
get_xbound
104+
set_xbound
105+
get_ybound
106+
set_ybound
101107
get_zbound
102108
set_zbound
103109

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
Setting 3D axis limits now set the limits exactly
2+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3+
4+
Previously, setting the limits of a 3D axis would always add a small margin to
5+
the limits. Limits are now set exactly by default. The newly introduced rcparam
6+
``axes3d.automargin`` can be used to revert to the old behavior where margin is
7+
automatically added.
8+
9+
.. plot::
10+
:include-source: true
11+
:alt: Example of the new behavior of 3D axis limits, and how setting the rcparam reverts to the old behavior.
12+
13+
import matplotlib.pyplot as plt
14+
fig, axs = plt.subplots(1, 2, subplot_kw={'projection': '3d'})
15+
plt.rcParams['axes3d.automargin'] = False # the default in 3.9.0
16+
axs[0].set(xlim=(0, 1), ylim=(0, 1), zlim=(0, 1), title='New Behavior')
17+
plt.rcParams['axes3d.automargin'] = True
18+
axs[1].set(xlim=(0, 1), ylim=(0, 1), zlim=(0, 1), title='Old Behavior')

lib/matplotlib/axis.py

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -840,13 +840,14 @@ def _get_autoscale_on(self):
840840
def _set_autoscale_on(self, b):
841841
"""
842842
Set whether this Axis is autoscaled when drawing or by
843-
`.Axes.autoscale_view`.
843+
`.Axes.autoscale_view`. If b is None, then the value is not changed.
844844
845845
Parameters
846846
----------
847847
b : bool
848848
"""
849-
self._autoscale_on = b
849+
if b is not None:
850+
self._autoscale_on = b
850851

851852
def get_children(self):
852853
return [self.label, self.offsetText,
@@ -1229,8 +1230,7 @@ def _set_lim(self, v0, v1, *, emit=True, auto):
12291230
# Mark viewlims as no longer stale without triggering an autoscale.
12301231
for ax in self._get_shared_axes():
12311232
ax._stale_viewlims[name] = False
1232-
if auto is not None:
1233-
self._set_autoscale_on(bool(auto))
1233+
self._set_autoscale_on(auto)
12341234

12351235
if emit:
12361236
self.axes.callbacks.process(f"{name}lim_changed", self.axes)
@@ -1277,6 +1277,17 @@ def _update_ticks(self):
12771277
if view_low > view_high:
12781278
view_low, view_high = view_high, view_low
12791279

1280+
if (hasattr(self, "axes") and self.axes.name == '3d'
1281+
and mpl.rcParams['axes3d.automargin']):
1282+
# In mpl3.8, the margin was 1/48. Due to the change in automargin
1283+
# behavior in mpl3.9, we need to adjust this to compensate for a
1284+
# zoom factor of 2/48, giving us a 23/24 modifier. So the new
1285+
# margin is 0.019965277777777776 = 1/48*23/24.
1286+
margin = 0.019965277777777776
1287+
delta = view_high - view_low
1288+
view_high = view_high - delta * margin
1289+
view_low = view_low + delta * margin
1290+
12801291
interval_t = self.get_transform().transform([view_low, view_high])
12811292

12821293
ticks_to_draw = []

lib/matplotlib/mpl-data/matplotlibrc

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -425,8 +425,9 @@
425425
#axes.autolimit_mode: data # If "data", use axes.xmargin and axes.ymargin as is.
426426
# If "round_numbers", after application of margins, axis
427427
# limits are further expanded to the nearest "round" number.
428-
#polaraxes.grid: True # display grid on polar axes
429-
#axes3d.grid: True # display grid on 3D axes
428+
#polaraxes.grid: True # display grid on polar axes
429+
#axes3d.grid: True # display grid on 3D axes
430+
#axes3d.automargin: False # automatically add margin when manually setting 3D axis limits
430431

431432
#axes3d.xaxis.panecolor: (0.95, 0.95, 0.95, 0.5) # background pane on 3D axes
432433
#axes3d.yaxis.panecolor: (0.90, 0.90, 0.90, 0.5) # background pane on 3D axes

lib/matplotlib/mpl-data/stylelib/classic.mplstyle

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,8 @@ axes.spines.left : True
223223
axes.spines.right : True
224224
axes.spines.top : True
225225
polaraxes.grid : True # display grid on polar axes
226-
axes3d.grid : True # display grid on 3d axes
226+
axes3d.grid : True # display grid on 3D axes
227+
axes3d.automargin : False # automatically add margin when manually setting 3D axis limits
227228

228229
date.autoformatter.year : %Y
229230
date.autoformatter.month : %b %Y

lib/matplotlib/rcsetup.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1094,8 +1094,10 @@ def _convert_validator_spec(key, conv):
10941094
"axes.ymargin": _validate_greaterthan_minushalf, # margin added to yaxis
10951095
"axes.zmargin": _validate_greaterthan_minushalf, # margin added to zaxis
10961096

1097-
"polaraxes.grid": validate_bool, # display polar grid or not
1098-
"axes3d.grid": validate_bool, # display 3d grid
1097+
"polaraxes.grid": validate_bool, # display polar grid or not
1098+
"axes3d.grid": validate_bool, # display 3d grid
1099+
"axes3d.automargin": validate_bool, # automatically add margin when
1100+
# manually setting 3D axis limits
10991101

11001102
"axes3d.xaxis.panecolor": validate_color, # 3d background pane
11011103
"axes3d.yaxis.panecolor": validate_color, # 3d background pane

lib/matplotlib/tests/test_collections.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,7 @@ def test_EllipseCollection():
401401
@image_comparison(['polycollection_close.png'], remove_text=True, style='mpl20')
402402
def test_polycollection_close():
403403
from mpl_toolkits.mplot3d import Axes3D # type: ignore
404+
plt.rcParams['axes3d.automargin'] = True
404405

405406
vertsQuad = [
406407
[[0., 0.], [0., 1.], [1., 1.], [1., 0.]],

lib/matplotlib/ticker.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2102,6 +2102,11 @@ def _raw_ticks(self, vmin, vmax):
21022102
steps = steps[igood]
21032103

21042104
raw_step = ((_vmax - _vmin) / nbins)
2105+
if hasattr(self.axis, "axes") and self.axis.axes.name == '3d':
2106+
# Due to the change in automargin behavior in mpl3.9, we need to
2107+
# adjust the raw step to match the mpl3.8 appearance. The zoom
2108+
# factor of 2/48, gives us the 23/24 modifier.
2109+
raw_step = raw_step * 23/24
21052110
large_steps = steps >= raw_step
21062111
if mpl.rcParams['axes.autolimit_mode'] == 'round_numbers':
21072112
# Classic round_numbers mode may require a larger step.

0 commit comments

Comments
 (0)