Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit ed8e70e

Browse files
authored
Merge pull request #13409 from anntzer/nonsingular
Add nonsingular to the locator base class, and use it in set_*lim too.
2 parents df9e346 + e44c8cc commit ed8e70e

File tree

6 files changed

+48
-61
lines changed

6 files changed

+48
-61
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
Changes in handling of degenerate bounds passed to `set_xlim`
2+
`````````````````````````````````````````````````````````````
3+
4+
When bounds passed to `set_xlim` (`set_xlim`, etc.) are degenerate (i.e. the
5+
lower and upper value are equal), the method used to "expand" the bounds now
6+
matches the expansion behavior of autoscaling when the plot contains a single
7+
x-value, and should in particular produce nicer limits for non-linear scales.

lib/matplotlib/axes/_base.py

Lines changed: 13 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2423,13 +2423,7 @@ def handle_single_axis(scale, autoscaleon, shared_axes, interval,
24232423
bb = mtransforms.BboxBase.union(dl)
24242424
x0, x1 = getattr(bb, interval)
24252425
locator = axis.get_major_locator()
2426-
try:
2427-
# e.g., DateLocator has its own nonsingular()
2428-
x0, x1 = locator.nonsingular(x0, x1)
2429-
except AttributeError:
2430-
# Default nonsingular for, e.g., MaxNLocator
2431-
x0, x1 = mtransforms.nonsingular(
2432-
x0, x1, increasing=False, expander=0.05)
2426+
x0, x1 = locator.nonsingular(x0, x1)
24332427

24342428
# Add the margin in figure space and then transform back, to handle
24352429
# non-linear scales.
@@ -2443,7 +2437,7 @@ def handle_single_axis(scale, autoscaleon, shared_axes, interval,
24432437
x0, x1 = axis._scale.limit_range_for_scale(x0, x1, minpos)
24442438
x0t, x1t = transform.transform([x0, x1])
24452439

2446-
if (np.isfinite(x1t) and np.isfinite(x0t)):
2440+
if np.isfinite(x1t) and np.isfinite(x0t):
24472441
delta = (x1t - x0t) * margin
24482442
else:
24492443
# If at least one bound isn't finite, set margin to zero
@@ -3216,13 +3210,6 @@ def set_xlim(self, left=None, right=None, emit=True, auto=False,
32163210
if right is None:
32173211
right = old_right
32183212

3219-
if left == right:
3220-
cbook._warn_external(
3221-
('Attempting to set identical left==right results\n'
3222-
'in singular transformations; automatically expanding.\n'
3223-
'left=%s, right=%s') % (left, right))
3224-
left, right = mtransforms.nonsingular(left, right, increasing=False)
3225-
32263213
if self.get_xscale() == 'log':
32273214
if left <= 0:
32283215
cbook._warn_external(
@@ -3236,7 +3223,11 @@ def set_xlim(self, left=None, right=None, emit=True, auto=False,
32363223
'log-scaled axis.\n'
32373224
'Invalid limit will be ignored.')
32383225
right = old_right
3239-
3226+
if left == right:
3227+
cbook._warn_external(
3228+
f"Attempting to set identical left == right == {left} results "
3229+
f"in singular transformations; automatically expanding.")
3230+
left, right = self.xaxis.get_major_locator().nonsingular(left, right)
32403231
left, right = self.xaxis.limit_range_for_scale(left, right)
32413232

32423233
self.viewLim.intervalx = (left, right)
@@ -3603,14 +3594,6 @@ def set_ylim(self, bottom=None, top=None, emit=True, auto=False,
36033594
if top is None:
36043595
top = old_top
36053596

3606-
if bottom == top:
3607-
cbook._warn_external(
3608-
('Attempting to set identical bottom==top results\n'
3609-
'in singular transformations; automatically expanding.\n'
3610-
'bottom=%s, top=%s') % (bottom, top))
3611-
3612-
bottom, top = mtransforms.nonsingular(bottom, top, increasing=False)
3613-
36143597
if self.get_yscale() == 'log':
36153598
if bottom <= 0:
36163599
cbook._warn_external(
@@ -3624,6 +3607,12 @@ def set_ylim(self, bottom=None, top=None, emit=True, auto=False,
36243607
'log-scaled axis.\n'
36253608
'Invalid limit will be ignored.')
36263609
top = old_top
3610+
if bottom == top:
3611+
cbook._warn_external(
3612+
f"Attempting to set identical bottom == top == {bottom} "
3613+
f"results in singular transformations; automatically "
3614+
f"expanding.")
3615+
bottom, top = self.yaxis.get_major_locator().nonsingular(bottom, top)
36273616
bottom, top = self.yaxis.limit_range_for_scale(bottom, top)
36283617

36293618
self.viewLim.intervaly = (bottom, top)

lib/matplotlib/tests/test_dates.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,8 @@ def test_too_many_date_ticks():
156156
with pytest.warns(UserWarning) as rec:
157157
ax.set_xlim((t0, tf), auto=True)
158158
assert len(rec) == 1
159-
assert 'Attempting to set identical left==right' in str(rec[0].message)
159+
assert \
160+
'Attempting to set identical left == right' in str(rec[0].message)
160161
ax.plot([], [])
161162
ax.xaxis.set_major_locator(mdates.DayLocator())
162163
with pytest.raises(RuntimeError):

lib/matplotlib/tests/test_ticker.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -302,7 +302,7 @@ class TestScalarFormatter(object):
302302
(1233999, 1234001, 1234000),
303303
(-1234001, -1233999, -1234000),
304304
(1, 1, 1),
305-
(123, 123, 120),
305+
(123, 123, 0),
306306
# Test cases courtesy of @WeatherGod
307307
(.4538, .4578, .45),
308308
(3789.12, 3783.1, 3780),

lib/matplotlib/ticker.py

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1411,9 +1411,9 @@ class Locator(TickHelper):
14111411
"""
14121412
Determine the tick locations;
14131413
1414-
Note, you should not use the same locator between different
1415-
:class:`~matplotlib.axis.Axis` because the locator stores references to
1416-
the Axis data and view limits
1414+
Note that the same locator should not be used across multiple
1415+
`~matplotlib.axis.Axis` because the locator stores references to the Axis
1416+
data and view limits.
14171417
"""
14181418

14191419
# Some automatic tick locators can generate so many ticks they
@@ -1463,12 +1463,15 @@ def raise_if_exceeds(self, locs):
14631463
len(locs), locs[0], locs[-1]))
14641464
return locs
14651465

1466+
def nonsingular(self, v0, v1):
1467+
"""Modify the endpoints of a range as needed to avoid singularities."""
1468+
return mtransforms.nonsingular(v0, v1, increasing=False, expander=.05)
1469+
14661470
def view_limits(self, vmin, vmax):
14671471
"""
1468-
select a scale for the range from vmin to vmax
1472+
Select a scale for the range from vmin to vmax.
14691473
1470-
Normally this method is overridden by subclasses to
1471-
change locator behaviour.
1474+
Subclasses should override this method to change locator behaviour.
14721475
"""
14731476
return mtransforms.nonsingular(vmin, vmax)
14741477

lib/mpl_toolkits/mplot3d/axes3d.py

Lines changed: 16 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -536,11 +536,7 @@ def autoscale_view(self, tight=None, scalex=True, scaley=True,
536536
self._shared_x_axes.clean()
537537
x0, x1 = self.xy_dataLim.intervalx
538538
xlocator = self.xaxis.get_major_locator()
539-
try:
540-
x0, x1 = xlocator.nonsingular(x0, x1)
541-
except AttributeError:
542-
x0, x1 = mtransforms.nonsingular(x0, x1, increasing=False,
543-
expander=0.05)
539+
x0, x1 = xlocator.nonsingular(x0, x1)
544540
if self._xmargin > 0:
545541
delta = (x1 - x0) * self._xmargin
546542
x0 -= delta
@@ -553,11 +549,7 @@ def autoscale_view(self, tight=None, scalex=True, scaley=True,
553549
self._shared_y_axes.clean()
554550
y0, y1 = self.xy_dataLim.intervaly
555551
ylocator = self.yaxis.get_major_locator()
556-
try:
557-
y0, y1 = ylocator.nonsingular(y0, y1)
558-
except AttributeError:
559-
y0, y1 = mtransforms.nonsingular(y0, y1, increasing=False,
560-
expander=0.05)
552+
y0, y1 = ylocator.nonsingular(y0, y1)
561553
if self._ymargin > 0:
562554
delta = (y1 - y0) * self._ymargin
563555
y0 -= delta
@@ -570,11 +562,7 @@ def autoscale_view(self, tight=None, scalex=True, scaley=True,
570562
self._shared_z_axes.clean()
571563
z0, z1 = self.zz_dataLim.intervalx
572564
zlocator = self.zaxis.get_major_locator()
573-
try:
574-
z0, z1 = zlocator.nonsingular(z0, z1)
575-
except AttributeError:
576-
z0, z1 = mtransforms.nonsingular(z0, z1, increasing=False,
577-
expander=0.05)
565+
z0, z1 = zlocator.nonsingular(z0, z1)
578566
if self._zmargin > 0:
579567
delta = (z1 - z0) * self._zmargin
580568
z0 -= delta
@@ -633,10 +621,9 @@ def set_xlim3d(self, left=None, right=None, emit=True, auto=False,
633621

634622
if left == right:
635623
cbook._warn_external(
636-
('Attempting to set identical left==right results\n'
637-
'in singular transformations; automatically expanding.\n'
638-
'left=%s, right=%s') % (left, right))
639-
left, right = mtransforms.nonsingular(left, right, increasing=False)
624+
f"Attempting to set identical left == right == {left} results "
625+
f"in singular transformations; automatically expanding.")
626+
left, right = self.xaxis.get_major_locator().nonsingular(left, right)
640627
left, right = self.xaxis.limit_range_for_scale(left, right)
641628
self.xy_viewLim.intervalx = (left, right)
642629

@@ -689,12 +676,12 @@ def set_ylim3d(self, bottom=None, top=None, emit=True, auto=False,
689676
if top is None:
690677
top = old_top
691678

692-
if top == bottom:
679+
if bottom == top:
693680
cbook._warn_external(
694-
('Attempting to set identical bottom==top results\n'
695-
'in singular transformations; automatically expanding.\n'
696-
'bottom=%s, top=%s') % (bottom, top))
697-
bottom, top = mtransforms.nonsingular(bottom, top, increasing=False)
681+
f"Attempting to set identical bottom == top == {bottom} "
682+
f"results in singular transformations; automatically "
683+
f"expanding.")
684+
bottom, top = self.yaxis.get_major_locator().nonsingular(bottom, top)
698685
bottom, top = self.yaxis.limit_range_for_scale(bottom, top)
699686
self.xy_viewLim.intervaly = (bottom, top)
700687

@@ -747,12 +734,12 @@ def set_zlim3d(self, bottom=None, top=None, emit=True, auto=False,
747734
if top is None:
748735
top = old_top
749736

750-
if top == bottom:
737+
if bottom == top:
751738
cbook._warn_external(
752-
('Attempting to set identical bottom==top results\n'
753-
'in singular transformations; automatically expanding.\n'
754-
'bottom=%s, top=%s') % (bottom, top))
755-
bottom, top = mtransforms.nonsingular(bottom, top, increasing=False)
739+
f"Attempting to set identical bottom == top == {bottom} "
740+
f"results in singular transformations; automatically "
741+
f"expanding.")
742+
bottom, top = self.zaxis.get_major_locator().nonsingular(bottom, top)
756743
bottom, top = self.zaxis.limit_range_for_scale(bottom, top)
757744
self.zz_viewLim.intervalx = (bottom, top)
758745

0 commit comments

Comments
 (0)