Skip to content

Commit c5b9ce4

Browse files
committed
Avoid 1-tick or 0-tick log-scaled axis.
... by switching to AutoLocator when the minor LogLocator would produce no more than one tick.
1 parent f8b425d commit c5b9ce4

File tree

2 files changed

+27
-14
lines changed

2 files changed

+27
-14
lines changed

lib/matplotlib/tests/test_ticker.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import warnings
22

33
import numpy as np
4-
from numpy.testing import assert_almost_equal
4+
from numpy.testing import assert_almost_equal, assert_array_equal
55
import pytest
66

77
import matplotlib
@@ -179,6 +179,11 @@ def test_basic(self):
179179
test_value = np.array([0.5, 1., 2., 4., 8., 16., 32., 64., 128., 256.])
180180
assert_almost_equal(loc.tick_values(1, 100), test_value)
181181

182+
def test_switch_to_autolocator(self):
183+
loc = mticker.LogLocator(subs="all")
184+
assert_array_equal(loc.tick_values(0.45, 0.55),
185+
[0.44, 0.46, 0.48, 0.5, 0.52, 0.54, 0.56])
186+
182187
def test_set_params(self):
183188
"""
184189
Create log locator with default value, base=10.0, subs=[1.0],

lib/matplotlib/ticker.py

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2165,13 +2165,13 @@ def tick_values(self, vmin, vmax):
21652165
"log-scaled.")
21662166

21672167
_log.debug('vmin %s vmax %s', vmin, vmax)
2168-
vmin = math.log(vmin) / math.log(b)
2169-
vmax = math.log(vmax) / math.log(b)
21702168

21712169
if vmax < vmin:
21722170
vmin, vmax = vmax, vmin
2171+
log_vmin = math.log(vmin) / math.log(b)
2172+
log_vmax = math.log(vmax) / math.log(b)
21732173

2174-
numdec = math.floor(vmax) - math.ceil(vmin)
2174+
numdec = math.floor(log_vmax) - math.ceil(log_vmin)
21752175

21762176
if isinstance(self._subs, str):
21772177
_first = 2.0 if self._subs == 'auto' else 1.0
@@ -2195,32 +2195,40 @@ def tick_values(self, vmin, vmax):
21952195
while numdec // stride + 1 > numticks:
21962196
stride += 1
21972197

2198-
# Does subs include anything other than 1?
2198+
# Does subs include anything other than 1? Essentially a hack to know
2199+
# whether we're a major or a minor locator.
21992200
have_subs = len(subs) > 1 or (len(subs) == 1 and subs[0] != 1.0)
22002201

2201-
decades = np.arange(math.floor(vmin) - stride,
2202-
math.ceil(vmax) + 2 * stride, stride)
2202+
decades = np.arange(math.floor(log_vmin) - stride,
2203+
math.ceil(log_vmax) + 2 * stride, stride)
22032204

22042205
if hasattr(self, '_transform'):
22052206
ticklocs = self._transform.inverted().transform(decades)
22062207
if have_subs:
22072208
if stride == 1:
22082209
ticklocs = np.ravel(np.outer(subs, ticklocs))
22092210
else:
2210-
# no ticklocs if we have more than one decade
2211-
# between major ticks.
2212-
ticklocs = []
2211+
# No ticklocs if we have >1 decade between major ticks.
2212+
ticklocs = np.array([])
22132213
else:
22142214
if have_subs:
2215-
ticklocs = []
22162215
if stride == 1:
2217-
for decadeStart in b ** decades:
2218-
ticklocs.extend(subs * decadeStart)
2216+
ticklocs = np.concatenate(
2217+
[subs * decade_start for decade_start in b ** decades])
2218+
else:
2219+
ticklocs = np.array([])
22192220
else:
22202221
ticklocs = b ** decades
22212222

22222223
_log.debug('ticklocs %r', ticklocs)
2223-
return self.raise_if_exceeds(np.asarray(ticklocs))
2224+
if (len(subs) > 1
2225+
and stride == 1
2226+
and ((vmin <= ticklocs) & (ticklocs <= vmax)).sum() <= 1):
2227+
# If we're a minor locator *that expects at least two ticks per
2228+
# decade* and the major locator stride is 1 and there's no more
2229+
# than one minor tick, switch to AutoLocator.
2230+
return AutoLocator().tick_values(vmin, vmax)
2231+
return self.raise_if_exceeds(ticklocs)
22242232

22252233
def view_limits(self, vmin, vmax):
22262234
'Try to choose the view limits intelligently'

0 commit comments

Comments
 (0)