Skip to content

BUG: make autoscale('tight') set margins to zero; closes #6968 #7458

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Nov 14, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
108 changes: 62 additions & 46 deletions lib/matplotlib/axes/_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -2185,6 +2185,10 @@ def autoscale(self, enable=True, axis='both', tight=None):
if axis in ['y', 'both']:
self._autoscaleYon = bool(enable)
scaley = self._autoscaleYon
if tight and scalex:
self._xmargin = 0
if tight and scaley:
self._ymargin = 0
self.autoscale_view(tight=tight, scalex=scalex, scaley=scaley)

def autoscale_view(self, tight=None, scalex=True, scaley=True):
Expand All @@ -2194,6 +2198,14 @@ def autoscale_view(self, tight=None, scalex=True, scaley=True):
setting *scaley* to *False*. The autoscaling preserves any
axis direction reversal that has already been done.

If *tight* is *False*, the axis major locator will be used
to expand the view limits if rcParams['axes.autolimit_mode']
is 'round_numbers'. Note that any margins that are in effect
will be applied first, regardless of whether *tight* is
*True* or *False*. Specifying *tight* as *True* or *False*
saves the setting as a private attribute of the Axes; specifying
it as *None* (the default) applies the previously saved value.

The data limits are not updated automatically when artist data are
changed after the artist has been added to an Axes instance. In that
case, use :meth:`matplotlib.axes.Axes.relim` prior to calling
Expand Down Expand Up @@ -2246,52 +2258,56 @@ def autoscale_view(self, tight=None, scalex=True, scaley=True):
def handle_single_axis(scale, autoscaleon, shared_axes, interval,
minpos, axis, margin, do_lower_margin,
do_upper_margin, set_bound):
if scale and autoscaleon:
shared = shared_axes.get_siblings(self)
dl = [ax.dataLim for ax in shared]
# ignore non-finite data limits if good limits exist
finite_dl = [d for d in dl if np.isfinite(d).all()]
if len(finite_dl):
dl = finite_dl

bb = mtransforms.BboxBase.union(dl)
x0, x1 = getattr(bb, interval)
locator = axis.get_major_locator()
try:
# e.g., DateLocator has its own nonsingular()
x0, x1 = locator.nonsingular(x0, x1)
except AttributeError:
# Default nonsingular for, e.g., MaxNLocator
x0, x1 = mtransforms.nonsingular(
x0, x1, increasing=False, expander=0.05)

if margin > 0 and (do_lower_margin or do_upper_margin):
if axis.get_scale() == 'linear':
delta = (x1 - x0) * margin
if do_lower_margin:
x0 -= delta
if do_upper_margin:
x1 += delta
else:
# If we have a non-linear scale, we need to
# add the margin in figure space and then
# transform back
minpos = getattr(bb, minpos)
transform = axis.get_transform()
inverse_trans = transform.inverted()
x0, x1 = axis._scale.limit_range_for_scale(
x0, x1, minpos)
x0t, x1t = transform.transform([x0, x1])
delta = (x1t - x0t) * margin
if do_lower_margin:
x0t -= delta
if do_upper_margin:
x1t += delta
x0, x1 = inverse_trans.transform([x0t, x1t])

if not _tight:
x0, x1 = locator.view_limits(x0, x1)
set_bound(x0, x1)

if not (scale and autoscaleon):
return # nothing to do...

shared = shared_axes.get_siblings(self)
dl = [ax.dataLim for ax in shared]
# ignore non-finite data limits if good limits exist
finite_dl = [d for d in dl if np.isfinite(d).all()]
if len(finite_dl):
dl = finite_dl

bb = mtransforms.BboxBase.union(dl)
x0, x1 = getattr(bb, interval)
locator = axis.get_major_locator()
try:
# e.g., DateLocator has its own nonsingular()
x0, x1 = locator.nonsingular(x0, x1)
except AttributeError:
# Default nonsingular for, e.g., MaxNLocator
x0, x1 = mtransforms.nonsingular(
x0, x1, increasing=False, expander=0.05)

if margin > 0 and (do_lower_margin or do_upper_margin):
if axis.get_scale() == 'linear':
delta = (x1 - x0) * margin
if do_lower_margin:
x0 -= delta
if do_upper_margin:
x1 += delta
else:
# If we have a non-linear scale, we need to
# add the margin in figure space and then
# transform back
minpos = getattr(bb, minpos)
transform = axis.get_transform()
inverse_trans = transform.inverted()
x0, x1 = axis._scale.limit_range_for_scale(
x0, x1, minpos)
x0t, x1t = transform.transform([x0, x1])
delta = (x1t - x0t) * margin
if do_lower_margin:
x0t -= delta
if do_upper_margin:
x1t += delta
x0, x1 = inverse_trans.transform([x0t, x1t])

if not _tight:
x0, x1 = locator.view_limits(x0, x1)
set_bound(x0, x1)
# End of definition of internal function 'handle_single_axis'.

handle_single_axis(
scalex, self._autoscaleXon, self._shared_x_axes,
Expand Down
10 changes: 10 additions & 0 deletions lib/matplotlib/tests/test_axes.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,16 @@ def test_autoscale_tiny_range():
ax[i].plot([0, 1], [1, 1 + y1])


@cleanup(style='default')
def test_autoscale_tight():
fig, ax = plt.subplots(1, 1)
ax.plot([1, 2, 3, 4])
ax.autoscale(enable=True, axis='x', tight=False)
ax.autoscale(enable=True, axis='y', tight=True)
assert_allclose(ax.get_xlim(), (-0.15, 3.15))
assert_allclose(ax.get_ylim(), (1.0, 4.0))


@image_comparison(baseline_images=['offset_points'],
remove_text=True)
def test_basic_annotate():
Expand Down