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

Skip to content

Commit bebb206

Browse files
authored
Logit scale nonsingular (#14928)
Logit scale nonsingular
2 parents 463349a + e14ee84 commit bebb206

File tree

2 files changed

+68
-23
lines changed

2 files changed

+68
-23
lines changed

lib/matplotlib/tests/test_ticker.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
except ImportError:
44
from contextlib import ExitStack as nullcontext # Py 3.6.
55
import re
6+
import itertools
67

78
import numpy as np
89
from numpy.testing import assert_almost_equal, assert_array_equal
@@ -368,6 +369,44 @@ def test_minor_attr(self):
368369
loc.set_params(minor=False)
369370
assert not loc.minor
370371

372+
acceptable_vmin_vmax = [
373+
*(2.5 ** np.arange(-3, 0)),
374+
*(1 - 2.5 ** np.arange(-3, 0)),
375+
]
376+
377+
@pytest.mark.parametrize(
378+
"lims",
379+
[
380+
(a, b)
381+
for (a, b) in itertools.product(acceptable_vmin_vmax, repeat=2)
382+
if a != b
383+
],
384+
)
385+
def test_nonsingular_ok(self, lims):
386+
"""
387+
Create logit locator, and test the nonsingular method for acceptable
388+
value
389+
"""
390+
loc = mticker.LogitLocator()
391+
lims2 = loc.nonsingular(*lims)
392+
assert sorted(lims) == sorted(lims2)
393+
394+
@pytest.mark.parametrize("okval", acceptable_vmin_vmax)
395+
def test_nonsingular_nok(self, okval):
396+
"""
397+
Create logit locator, and test the nonsingular method for non
398+
acceptable value
399+
"""
400+
loc = mticker.LogitLocator()
401+
vmin, vmax = (-1, okval)
402+
vmin2, vmax2 = loc.nonsingular(vmin, vmax)
403+
assert vmax2 == vmax
404+
assert 0 < vmin2 < vmax2
405+
vmin, vmax = (okval, 2)
406+
vmin2, vmax2 = loc.nonsingular(vmin, vmax)
407+
assert vmin2 == vmin
408+
assert vmin2 < vmax2 < 1
409+
371410

372411
class TestFixedLocator:
373412
def test_set_params(self):

lib/matplotlib/ticker.py

Lines changed: 29 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2791,32 +2791,38 @@ def ideal_ticks(x):
27912791
return MaxNLocator.tick_values(self, vmin, vmax)
27922792

27932793
def nonsingular(self, vmin, vmax):
2794-
initial_range = (1e-7, 1 - 1e-7)
2795-
if not np.isfinite(vmin) or not np.isfinite(vmax):
2796-
return initial_range # no data plotted yet
2797-
2794+
standard_minpos = 1e-7
2795+
initial_range = (standard_minpos, 1 - standard_minpos)
27982796
if vmin > vmax:
27992797
vmin, vmax = vmax, vmin
2800-
2801-
# what to do if a window beyond ]0, 1[ is chosen
2802-
if self.axis is not None:
2803-
minpos = self.axis.get_minpos()
2804-
if not np.isfinite(minpos):
2805-
return initial_range # again, no data plotted
2798+
if not np.isfinite(vmin) or not np.isfinite(vmax):
2799+
vmin, vmax = initial_range # Initial range, no data plotted yet.
2800+
elif vmax <= 0 or vmin >= 1:
2801+
# vmax <= 0 occurs when all values are negative
2802+
# vmin >= 1 occurs when all values are greater than one
2803+
cbook._warn_external(
2804+
"Data has no values between 0 and 1, and therefore cannot be "
2805+
"logit-scaled."
2806+
)
2807+
vmin, vmax = initial_range
28062808
else:
2807-
minpos = 1e-7 # should not occur in normal use
2808-
2809-
# NOTE: for vmax, we should query a property similar to get_minpos, but
2810-
# related to the maximal, less-than-one data point. Unfortunately,
2811-
# Bbox._minpos is defined very deep in the BBox and updated with data,
2812-
# so for now we use 1 - minpos as a substitute.
2813-
2814-
if vmin <= 0:
2815-
vmin = minpos
2816-
if vmax >= 1:
2817-
vmax = 1 - minpos
2818-
if vmin == vmax:
2819-
return 0.1 * vmin, 1 - 0.1 * vmin
2809+
minpos = (
2810+
self.axis.get_minpos()
2811+
if self.axis is not None
2812+
else standard_minpos
2813+
)
2814+
if not np.isfinite(minpos):
2815+
minpos = standard_minpos # This should never take effect.
2816+
if vmin <= 0:
2817+
vmin = minpos
2818+
# NOTE: for vmax, we should query a property similar to get_minpos,
2819+
# but related to the maximal, less-than-one data point.
2820+
# Unfortunately, Bbox._minpos is defined very deep in the BBox and
2821+
# updated with data, so for now we use 1 - minpos as a substitute.
2822+
if vmax >= 1:
2823+
vmax = 1 - minpos
2824+
if vmin == vmax:
2825+
vmin, vmax = 0.1 * vmin, 1 - 0.1 * vmin
28202826

28212827
return vmin, vmax
28222828

0 commit comments

Comments
 (0)