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 c73a275

Browse filesBrowse files
committed
Better choice of offset-text.
The axis offset text is chosen as follows: xlims => offsettext 123, 189 => 0 12341, 12349 => 12340 99999.5, 100010.5 => 100000 # (also a test for #5780) 99990.5, 100000.5 => 100000 1233999, 1234001 => 1234000 (and the same for negative limits). See #5755.
1 parent f35177e commit c73a275
Copy full SHA for c73a275

File tree

2 files changed

+85
-19
lines changed
Filter options

2 files changed

+85
-19
lines changed

‎lib/matplotlib/tests/test_ticker.py

Copy file name to clipboardExpand all lines: lib/matplotlib/tests/test_ticker.py
+50-1Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
from matplotlib.externals import six
55
import nose.tools
6-
from nose.tools import assert_raises
6+
from nose.tools import assert_equal, assert_raises
77
from numpy.testing import assert_almost_equal
88
import numpy as np
99
import matplotlib
@@ -159,6 +159,55 @@ def test_SymmetricalLogLocator_set_params():
159159
nose.tools.assert_equal(sym.numticks, 8)
160160

161161

162+
@cleanup
163+
def test_ScalarFormatter_offset_value():
164+
fig, ax = plt.subplots()
165+
formatter = ax.get_xaxis().get_major_formatter()
166+
167+
def update_ticks(ax):
168+
return next(ax.get_xaxis().iter_ticks())
169+
170+
ax.set_xlim(123, 189)
171+
update_ticks(ax)
172+
assert_equal(formatter.offset, 0)
173+
174+
ax.set_xlim(-189, -123)
175+
update_ticks(ax)
176+
assert_equal(formatter.offset, 0)
177+
178+
ax.set_xlim(12341, 12349)
179+
update_ticks(ax)
180+
assert_equal(formatter.offset, 12340)
181+
182+
ax.set_xlim(-12349, -12341)
183+
update_ticks(ax)
184+
assert_equal(formatter.offset, -12340)
185+
186+
ax.set_xlim(99999.5, 100010.5)
187+
update_ticks(ax)
188+
assert_equal(formatter.offset, 100000)
189+
190+
ax.set_xlim(-100010.5, -99999.5)
191+
update_ticks(ax)
192+
assert_equal(formatter.offset, -100000)
193+
194+
ax.set_xlim(99990.5, 100000.5)
195+
update_ticks(ax)
196+
assert_equal(formatter.offset, 100000)
197+
198+
ax.set_xlim(-100000.5, -99990.5)
199+
update_ticks(ax)
200+
assert_equal(formatter.offset, -100000)
201+
202+
ax.set_xlim(1233999, 1234001)
203+
update_ticks(ax)
204+
assert_equal(formatter.offset, 1234000)
205+
206+
ax.set_xlim(-1234001, -1233999)
207+
update_ticks(ax)
208+
assert_equal(formatter.offset, -1234000)
209+
210+
162211
def _logfe_helper(formatter, base, locs, i, expected_result):
163212
vals = base**locs
164213
labels = [formatter(x, pos) for (x, pos) in zip(vals, i)]

‎lib/matplotlib/ticker.py

Copy file name to clipboardExpand all lines: lib/matplotlib/ticker.py
+35-18Lines changed: 35 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -548,33 +548,50 @@ def set_locs(self, locs):
548548
vmin, vmax = self.axis.get_view_interval()
549549
d = abs(vmax - vmin)
550550
if self._useOffset:
551-
self._set_offset(d)
551+
self._compute_offset()
552552
self._set_orderOfMagnitude(d)
553553
self._set_format(vmin, vmax)
554554

555-
def _set_offset(self, range):
556-
# offset of 20,001 is 20,000, for example
555+
def _compute_offset(self):
557556
locs = self.locs
558-
559-
if locs is None or not len(locs) or range == 0:
557+
if locs is None or not len(locs):
560558
self.offset = 0
561559
return
560+
# Restrict to visible ticks.
562561
vmin, vmax = sorted(self.axis.get_view_interval())
563562
locs = np.asarray(locs)
564563
locs = locs[(vmin <= locs) & (locs <= vmax)]
565-
ave_loc = np.mean(locs)
566-
if ave_loc: # dont want to take log10(0)
567-
ave_oom = math.floor(math.log10(np.mean(np.absolute(locs))))
568-
range_oom = math.floor(math.log10(range))
569-
570-
if np.absolute(ave_oom - range_oom) >= 3: # four sig-figs
571-
p10 = 10 ** range_oom
572-
if ave_loc < 0:
573-
self.offset = (math.ceil(np.max(locs) / p10) * p10)
574-
else:
575-
self.offset = (math.floor(np.min(locs) / p10) * p10)
576-
else:
577-
self.offset = 0
564+
lmin, lmax = locs.min(), locs.max()
565+
# min, max comparing absolute values (we want division to round towards
566+
# zero so we work on absolute values).
567+
abs_min, abs_max = sorted(map(abs, [lmin, lmax]))
568+
# Only use offset if there are at least two ticks, every tick has the
569+
# same sign, and if the span is small compared to the absolute values.
570+
if (lmin == lmax or lmin <= 0 <= lmax or
571+
(abs_max - abs_min) / abs_max >= 1e-2):
572+
self.offset = 0
573+
return
574+
sign = math.copysign(1, lmin)
575+
# What is the smallest power of ten such that abs_min and abs_max are
576+
# equal up to that precision?
577+
oom = 10 ** int(math.log10(abs_max) + 1)
578+
while True:
579+
if abs_min // oom != abs_max // oom:
580+
oom *= 10
581+
break
582+
oom /= 10
583+
if (abs_max - abs_min) / oom <= 1e-2:
584+
# Handle the case of straddling a multiple of a large power of ten
585+
# (relative to the span).
586+
# What is the smallest power of ten such that abs_min and abs_max
587+
# at most 1 apart?
588+
oom = 10 ** int(math.log10(abs_max) + 1)
589+
while True:
590+
if abs_max // oom - abs_min // oom > 1:
591+
oom *= 10
592+
break
593+
oom /= 10
594+
self.offset = sign * (abs_max // oom) * oom
578595

579596
def _set_orderOfMagnitude(self, range):
580597
# if scientific notation is to be used, find the appropriate exponent

0 commit comments

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