Skip to content

Commit 0da1b6c

Browse files
Implement exact 3d plot limits
Fix remaining large image diffs Fix remaining large image diffs Fix the rest of the tests Fix docs error Code review updates Code review updates Fix docs error One more constant Tweaks Keep fixing CI errors Docstrings Update baseline images More test images Images Test new scaling factor Test new scaling factor Test for exact limits Cleanup Tests Update doc/users/next_whats_new/3d_axis_limits.rst Co-authored-by: Elliott Sales de Andrade <quantum.analyst@gmail.com> rebase fixes Apply suggestions from code review Co-authored-by: Oscar Gustafsson <oscar.gustafsson@gmail.com> Code review cleanup Merge conflicts and better comments Merge conflicts and better comments
1 parent a40d22b commit 0da1b6c

File tree

11 files changed

+493
-114
lines changed

11 files changed

+493
-114
lines changed

doc/api/toolkits/mplot3d/axes3d.rst

+6
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

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

+15-4
Original file line numberDiff line numberDiff line change
@@ -855,13 +855,14 @@ def _get_autoscale_on(self):
855855
def _set_autoscale_on(self, b):
856856
"""
857857
Set whether this Axis is autoscaled when drawing or by
858-
`.Axes.autoscale_view`.
858+
`.Axes.autoscale_view`. If b is None, then the value is not changed.
859859
860860
Parameters
861861
----------
862862
b : bool
863863
"""
864-
self._autoscale_on = b
864+
if b is not None:
865+
self._autoscale_on = b
865866

866867
def get_children(self):
867868
return [self.label, self.offsetText,
@@ -1244,8 +1245,7 @@ def _set_lim(self, v0, v1, *, emit=True, auto):
12441245
# Mark viewlims as no longer stale without triggering an autoscale.
12451246
for ax in self._get_shared_axes():
12461247
ax._stale_viewlims[name] = False
1247-
if auto is not None:
1248-
self._set_autoscale_on(bool(auto))
1248+
self._set_autoscale_on(auto)
12491249

12501250
if emit:
12511251
self.axes.callbacks.process(f"{name}lim_changed", self.axes)
@@ -1292,6 +1292,17 @@ def _update_ticks(self):
12921292
if view_low > view_high:
12931293
view_low, view_high = view_high, view_low
12941294

1295+
if (hasattr(self, "axes") and self.axes.name == '3d'
1296+
and mpl.rcParams['axes3d.automargin']):
1297+
# In mpl3.8, the margin was 1/48. Due to the change in automargin
1298+
# behavior in mpl3.9, we need to adjust this to compensate for a
1299+
# zoom factor of 2/48, giving us a 23/24 modifier. So the new
1300+
# margin is 0.019965277777777776 = 1/48*23/24.
1301+
margin = 0.019965277777777776
1302+
delta = view_high - view_low
1303+
view_high = view_high - delta * margin
1304+
view_low = view_low + delta * margin
1305+
12951306
interval_t = self.get_transform().transform([view_low, view_high])
12961307

12971308
ticks_to_draw = []

lib/matplotlib/mpl-data/matplotlibrc

+3-2
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

+2-1
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

+4-2
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

+1
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

+5
Original file line numberDiff line numberDiff line change
@@ -2106,6 +2106,11 @@ def _raw_ticks(self, vmin, vmax):
21062106
steps = steps[igood]
21072107

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

0 commit comments

Comments
 (0)