Skip to content

Commit fe42617

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 ea8cf0d commit fe42617

File tree

11 files changed

+488
-98
lines changed

11 files changed

+488
-98
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
@@ -854,13 +854,14 @@ def _get_autoscale_on(self):
854854
def _set_autoscale_on(self, b):
855855
"""
856856
Set whether this Axis is autoscaled when drawing or by
857-
`.Axes.autoscale_view`.
857+
`.Axes.autoscale_view`. If b is None, then the value is not changed.
858858
859859
Parameters
860860
----------
861861
b : bool
862862
"""
863-
self._autoscale_on = b
863+
if b is not None:
864+
self._autoscale_on = b
864865

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

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

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

12961307
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
@@ -1081,8 +1081,10 @@ def _convert_validator_spec(key, conv):
10811081
"axes.ymargin": _validate_greaterthan_minushalf, # margin added to yaxis
10821082
"axes.zmargin": _validate_greaterthan_minushalf, # margin added to zaxis
10831083

1084-
"polaraxes.grid": validate_bool, # display polar grid or not
1085-
"axes3d.grid": validate_bool, # display 3d grid
1084+
"polaraxes.grid": validate_bool, # display polar grid or not
1085+
"axes3d.grid": validate_bool, # display 3d grid
1086+
"axes3d.automargin": validate_bool, # automatically add margin when
1087+
# manually setting 3D axis limits
10861088

10871089
"axes3d.xaxis.panecolor": validate_color, # 3d background pane
10881090
"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)