Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit dae0b87

Browse filesBrowse files
committed
More precise choice of axes limits.
plt.plot([-.1, .2]) used to pick (in round numbers mode) [-.1, .25] as ylims due to floating point inaccuracies; change it to pick [-.1, .2] (up to floating point inaccuracies). Support for the (unused and deprecated-in-comment) "trim" keyword argument has been dropped as the way ticks are picked has changed. Many test images have changed! Implementation notes: - A bug in numpy's implementation of divmod (numpy/numpy#6127) is worked around. - The implementation of scale_range has also been cleaned. See #5767, #5738.
1 parent 0abca30 commit dae0b87
Copy full SHA for dae0b87
Expand file treeCollapse file tree

23 files changed

+3494
-3593
lines changed
Binary file not shown.
Loading

‎lib/matplotlib/tests/baseline_images/test_axes/autoscale_tiny_range.svg

Copy file name to clipboardExpand all lines: lib/matplotlib/tests/baseline_images/test_axes/autoscale_tiny_range.svg
+194-242Lines changed: 194 additions & 242 deletions
Loading
Loading
Binary file not shown.

‎lib/matplotlib/tests/baseline_images/test_axes/errorbar_mixed.svg

Copy file name to clipboardExpand all lines: lib/matplotlib/tests/baseline_images/test_axes/errorbar_mixed.svg
+506-506Lines changed: 506 additions & 506 deletions
Loading
Binary file not shown.
Loading

‎lib/matplotlib/tests/baseline_images/test_axes/formatter_large_small.svg

Copy file name to clipboardExpand all lines: lib/matplotlib/tests/baseline_images/test_axes/formatter_large_small.svg
+107-127Lines changed: 107 additions & 127 deletions
Loading
Loading
Binary file not shown.
Loading

‎lib/matplotlib/tests/baseline_images/test_bbox_tight/bbox_inches_tight_raster.svg

Copy file name to clipboardExpand all lines: lib/matplotlib/tests/baseline_images/test_bbox_tight/bbox_inches_tight_raster.svg
+30-42Lines changed: 30 additions & 42 deletions
Loading

‎lib/matplotlib/tests/test_axes.py

Copy file name to clipboardExpand all lines: lib/matplotlib/tests/test_axes.py
+2-3Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
from matplotlib.testing.decorators import image_comparison, cleanup
2222
import matplotlib.pyplot as plt
2323
import matplotlib.markers as mmarkers
24-
from numpy.testing import assert_array_equal
24+
from numpy.testing import assert_allclose, assert_array_equal
2525
import warnings
2626
from matplotlib.cbook import IgnoredKeywordWarning
2727

@@ -3708,8 +3708,7 @@ def test_vline_limit():
37083708
ax.axvline(0.5)
37093709
ax.plot([-0.1, 0, 0.2, 0.1])
37103710
(ymin, ymax) = ax.get_ylim()
3711-
assert ymin == -0.1
3712-
assert ymax == 0.25
3711+
assert_allclose(ax.get_ylim(), (-.1, .2))
37133712

37143713

37153714
@cleanup

‎lib/matplotlib/ticker.py

Copy file name to clipboardExpand all lines: lib/matplotlib/ticker.py
+42-38Lines changed: 42 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -161,13 +161,23 @@
161161
from matplotlib import rcParams
162162
from matplotlib import cbook
163163
from matplotlib import transforms as mtransforms
164+
from matplotlib.cbook import mplDeprecation
164165

165166
import warnings
166167

167168
if six.PY3:
168169
long = int
169170

170171

172+
# Work around numpy/numpy#6127.
173+
def _divmod(x, y):
174+
if isinstance(x, np.generic):
175+
x = x.item()
176+
if isinstance(y, np.generic):
177+
y = y.item()
178+
return six.moves.builtins.divmod(x, y)
179+
180+
171181
def _mathdefault(s):
172182
"""
173183
For backward compatibility, in classic mode we display
@@ -1218,7 +1228,7 @@ def view_limits(self, vmin, vmax):
12181228
vmax += 1
12191229

12201230
if rcParams['axes.autolimit_mode'] == 'round_numbers':
1221-
exponent, remainder = divmod(math.log10(vmax - vmin), 1)
1231+
exponent, remainder = _divmod(math.log10(vmax - vmin), 1)
12221232
if remainder < 0.5:
12231233
exponent -= 1
12241234
scale = 10 ** (-exponent)
@@ -1244,30 +1254,30 @@ def __init__(self, base):
12441254

12451255
def lt(self, x):
12461256
'return the largest multiple of base < x'
1247-
d, m = divmod(x, self._base)
1257+
d, m = _divmod(x, self._base)
12481258
if closeto(m, 0) and not closeto(m / self._base, 1):
12491259
return (d - 1) * self._base
12501260
return d * self._base
12511261

12521262
def le(self, x):
12531263
'return the largest multiple of base <= x'
1254-
d, m = divmod(x, self._base)
1264+
d, m = _divmod(x, self._base)
12551265
if closeto(m / self._base, 1): # was closeto(m, self._base)
12561266
#looks like floating point error
12571267
return (d + 1) * self._base
12581268
return d * self._base
12591269

12601270
def gt(self, x):
12611271
'return the smallest multiple of base > x'
1262-
d, m = divmod(x, self._base)
1272+
d, m = _divmod(x, self._base)
12631273
if closeto(m / self._base, 1):
12641274
#looks like floating point error
12651275
return (d + 2) * self._base
12661276
return (d + 1) * self._base
12671277

12681278
def ge(self, x):
12691279
'return the smallest multiple of base >= x'
1270-
d, m = divmod(x, self._base)
1280+
d, m = _divmod(x, self._base)
12711281
if closeto(m, 0) and not closeto(m / self._base, 1):
12721282
return d * self._base
12731283
return (d + 1) * self._base
@@ -1323,23 +1333,13 @@ def view_limits(self, dmin, dmax):
13231333

13241334

13251335
def scale_range(vmin, vmax, n=1, threshold=100):
1326-
dv = abs(vmax - vmin)
1327-
if dv == 0: # maxabsv == 0 is a special case of this.
1328-
return 1.0, 0.0
1329-
# Note: this should never occur because
1330-
# vmin, vmax should have been checked by nonsingular(),
1331-
# and spread apart if necessary.
1332-
meanv = 0.5 * (vmax + vmin)
1336+
dv = abs(vmax - vmin) # > 0 as nonsingular is called before.
1337+
meanv = (vmax + vmin) / 2
13331338
if abs(meanv) / dv < threshold:
13341339
offset = 0
1335-
elif meanv > 0:
1336-
ex = divmod(math.log10(meanv), 1)[0]
1337-
offset = 10 ** ex
13381340
else:
1339-
ex = divmod(math.log10(-meanv), 1)[0]
1340-
offset = -10 ** ex
1341-
ex = divmod(math.log10(dv / n), 1)[0]
1342-
scale = 10 ** ex
1341+
offset = math.copysign(10 ** (math.log10(abs(meanv)) // 1), meanv)
1342+
scale = 10 ** (math.log10(dv / n) // 1)
13431343
return scale, offset
13441344

13451345

@@ -1349,7 +1349,6 @@ class MaxNLocator(Locator):
13491349
"""
13501350
default_params = dict(nbins=10,
13511351
steps=None,
1352-
trim=True,
13531352
integer=False,
13541353
symmetric=False,
13551354
prune=None)
@@ -1385,9 +1384,6 @@ def __init__(self, *args, **kwargs):
13851384
will be removed. If prune==None, no ticks will be removed.
13861385
13871386
"""
1388-
# I left "trim" out; it defaults to True, and it is not
1389-
# clear that there is any use case for False, so we may
1390-
# want to remove that kwarg. EF 2010/04/18
13911387
if args:
13921388
kwargs['nbins'] = args[0]
13931389
if len(args) > 1:
@@ -1403,7 +1399,8 @@ def set_params(self, **kwargs):
14031399
if self._nbins != 'auto':
14041400
self._nbins = int(self._nbins)
14051401
if 'trim' in kwargs:
1406-
self._trim = kwargs['trim']
1402+
warnings.warn("The 'trim' keyword has no effect since version 2.0.",
1403+
mplDeprecation)
14071404
if 'integer' in kwargs:
14081405
self._integer = kwargs['integer']
14091406
if 'symmetric' in kwargs:
@@ -1426,9 +1423,9 @@ def set_params(self, **kwargs):
14261423
if 'integer' in kwargs:
14271424
self._integer = kwargs['integer']
14281425
if self._integer:
1429-
self._steps = [n for n in self._steps if divmod(n, 1)[1] < 0.001]
1426+
self._steps = [n for n in self._steps if _divmod(n, 1)[1] < 0.001]
14301427

1431-
def bin_boundaries(self, vmin, vmax):
1428+
def _raw_ticks(self, vmin, vmax):
14321429
nbins = self._nbins
14331430
if nbins == 'auto':
14341431
nbins = self.axis.get_tick_space()
@@ -1446,23 +1443,30 @@ def bin_boundaries(self, vmin, vmax):
14461443
if step < scaled_raw_step:
14471444
continue
14481445
step *= scale
1449-
best_vmin = step * divmod(vmin, step)[0]
1446+
best_vmin = vmin // step * step
14501447
best_vmax = best_vmin + step * nbins
1451-
if (best_vmax >= vmax):
1448+
if best_vmax >= vmax:
14521449
break
1453-
if self._trim:
1454-
extra_bins = int(divmod((best_vmax - vmax), step)[0])
1455-
nbins -= extra_bins
1456-
return (np.arange(nbins + 1) * step + best_vmin + offset)
1450+
1451+
# More than nbins may be required, e.g. vmin, vmax = -4.1, 4.1 gives
1452+
# nbins=9 but 10 bins are actually required after rounding. So we just
1453+
# create the bins that span the range we need instead.
1454+
low = round(Base(step).le(vmin - best_vmin) / step)
1455+
high = round(Base(step).ge(vmax - best_vmin) / step)
1456+
return np.arange(low, high + 1) * step + best_vmin + offset
1457+
1458+
@cbook.deprecated("2.0")
1459+
def bin_boundaries(self, vmin, vmax):
1460+
return self._raw_ticks(vmin, vmax)
14571461

14581462
def __call__(self):
14591463
vmin, vmax = self.axis.get_view_interval()
14601464
return self.tick_values(vmin, vmax)
14611465

14621466
def tick_values(self, vmin, vmax):
1463-
vmin, vmax = mtransforms.nonsingular(vmin, vmax, expander=1e-13,
1464-
tiny=1e-14)
1465-
locs = self.bin_boundaries(vmin, vmax)
1467+
vmin, vmax = mtransforms.nonsingular(
1468+
vmin, vmax, expander=1e-13, tiny=1e-14)
1469+
locs = self._raw_ticks(vmin, vmax)
14661470
prune = self._prune
14671471
if prune == 'lower':
14681472
locs = locs[1:]
@@ -1479,11 +1483,11 @@ def view_limits(self, dmin, dmax):
14791483
dmin = -maxabs
14801484
dmax = maxabs
14811485

1482-
dmin, dmax = mtransforms.nonsingular(dmin, dmax, expander=1e-12,
1483-
tiny=1.e-13)
1486+
dmin, dmax = mtransforms.nonsingular(
1487+
dmin, dmax, expander=1e-12, tiny=1e-13)
14841488

14851489
if rcParams['axes.autolimit_mode'] == 'round_numbers':
1486-
return np.take(self.bin_boundaries(dmin, dmax), [0, -1])
1490+
return self._raw_ticks(dmin, dmax)[[0, -1]]
14871491
else:
14881492
return dmin, dmax
14891493

Binary file not shown.
Loading

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.