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

Skip to content

Commit 6a323c0

Browse files
IlievskiVVladimirQuLogic
authored
Allow setting default AutoMinorLocator (#18715)
Fixes #14233 Co-authored-by: Vladimir <[email protected]> Co-authored-by: Elliott Sales de Andrade <[email protected]>
1 parent c8951c0 commit 6a323c0

File tree

5 files changed

+104
-1
lines changed

5 files changed

+104
-1
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
rcParams for ``AutoMinorLocator`` divisions
2+
-------------------------------------------
3+
The rcParams :rc:`xtick.minor.ndivs` and :rc:`ytick.minor.ndivs` have been
4+
added to enable setting the default number of divisions; if set to ``auto``,
5+
the number of divisions will be chosen by the distance between major ticks.

lib/matplotlib/mpl-data/matplotlibrc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -489,6 +489,7 @@
489489
#xtick.major.bottom: True # draw x axis bottom major ticks
490490
#xtick.minor.top: True # draw x axis top minor ticks
491491
#xtick.minor.bottom: True # draw x axis bottom minor ticks
492+
#xtick.minor.ndivs: auto # number of minor ticks between the major ticks on x-axis
492493
#xtick.alignment: center # alignment of xticks
493494

494495
#ytick.left: True # draw ticks on the left side
@@ -510,6 +511,7 @@
510511
#ytick.major.right: True # draw y axis right major ticks
511512
#ytick.minor.left: True # draw y axis left minor ticks
512513
#ytick.minor.right: True # draw y axis right minor ticks
514+
#ytick.minor.ndivs: auto # number of minor ticks between the major ticks on y-axis
513515
#ytick.alignment: center_baseline # alignment of yticks
514516

515517

lib/matplotlib/rcsetup.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -568,6 +568,14 @@ def _validate_greaterequal0_lessequal1(s):
568568
raise RuntimeError(f'Value must be >=0 and <=1; got {s}')
569569

570570

571+
def _validate_int_greaterequal0(s):
572+
s = validate_int(s)
573+
if s >= 0:
574+
return s
575+
else:
576+
raise RuntimeError(f'Value must be >=0; got {s}')
577+
578+
571579
def validate_hatch(s):
572580
r"""
573581
Validate a hatch pattern.
@@ -587,6 +595,24 @@ def validate_hatch(s):
587595
validate_dashlist = _listify_validator(validate_floatlist)
588596

589597

598+
def _validate_minor_tick_ndivs(n):
599+
"""
600+
Validate ndiv parameter related to the minor ticks.
601+
It controls the number of minor ticks to be placed between
602+
two major ticks.
603+
"""
604+
605+
if isinstance(n, str) and n.lower() == 'auto':
606+
return n
607+
try:
608+
n = _validate_int_greaterequal0(n)
609+
return n
610+
except (RuntimeError, ValueError):
611+
pass
612+
613+
raise ValueError("'tick.minor.ndivs' must be 'auto' or non-negative int")
614+
615+
590616
_prop_validators = {
591617
'color': _listify_validator(validate_color_for_prop_cycle,
592618
allow_stringlist=True),
@@ -1093,6 +1119,8 @@ def _convert_validator_spec(key, conv):
10931119
"xtick.minor.bottom": validate_bool, # draw bottom minor xticks
10941120
"xtick.major.top": validate_bool, # draw top major xticks
10951121
"xtick.major.bottom": validate_bool, # draw bottom major xticks
1122+
# number of minor xticks
1123+
"xtick.minor.ndivs": _validate_minor_tick_ndivs,
10961124
"xtick.labelsize": validate_fontsize, # fontsize of xtick labels
10971125
"xtick.direction": ["out", "in", "inout"], # direction of xticks
10981126
"xtick.alignment": ["center", "right", "left"],
@@ -1114,6 +1142,8 @@ def _convert_validator_spec(key, conv):
11141142
"ytick.minor.right": validate_bool, # draw right minor yticks
11151143
"ytick.major.left": validate_bool, # draw left major yticks
11161144
"ytick.major.right": validate_bool, # draw right major yticks
1145+
# number of minor yticks
1146+
"ytick.minor.ndivs": _validate_minor_tick_ndivs,
11171147
"ytick.labelsize": validate_fontsize, # fontsize of ytick labels
11181148
"ytick.direction": ["out", "in", "inout"], # direction of yticks
11191149
"ytick.alignment": [

lib/matplotlib/tests/test_ticker.py

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,60 @@ def test_additional(self, lim, ref):
211211

212212
assert_almost_equal(ax.yaxis.get_ticklocs(minor=True), ref)
213213

214+
@pytest.mark.parametrize('use_rcparam', [False, True])
215+
@pytest.mark.parametrize(
216+
'lim, ref', [
217+
((0, 1.39),
218+
[0.05, 0.1, 0.15, 0.25, 0.3, 0.35, 0.45, 0.5, 0.55, 0.65, 0.7,
219+
0.75, 0.85, 0.9, 0.95, 1.05, 1.1, 1.15, 1.25, 1.3, 1.35]),
220+
((0, 0.139),
221+
[0.005, 0.01, 0.015, 0.025, 0.03, 0.035, 0.045, 0.05, 0.055,
222+
0.065, 0.07, 0.075, 0.085, 0.09, 0.095, 0.105, 0.11, 0.115,
223+
0.125, 0.13, 0.135]),
224+
])
225+
def test_number_of_minor_ticks_auto(self, lim, ref, use_rcparam):
226+
if use_rcparam:
227+
context = {'xtick.minor.ndivs': 'auto', 'ytick.minor.ndivs': 'auto'}
228+
kwargs = {}
229+
else:
230+
context = {}
231+
kwargs = {'n': 'auto'}
232+
233+
with mpl.rc_context(context):
234+
fig, ax = plt.subplots()
235+
ax.set_xlim(*lim)
236+
ax.set_ylim(*lim)
237+
ax.xaxis.set_minor_locator(mticker.AutoMinorLocator(**kwargs))
238+
ax.yaxis.set_minor_locator(mticker.AutoMinorLocator(**kwargs))
239+
assert_almost_equal(ax.xaxis.get_ticklocs(minor=True), ref)
240+
assert_almost_equal(ax.yaxis.get_ticklocs(minor=True), ref)
241+
242+
@pytest.mark.parametrize('use_rcparam', [False, True])
243+
@pytest.mark.parametrize(
244+
'n, lim, ref', [
245+
(2, (0, 4), [0.5, 1.5, 2.5, 3.5]),
246+
(4, (0, 2), [0.25, 0.5, 0.75, 1.25, 1.5, 1.75]),
247+
(10, (0, 1), [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9]),
248+
])
249+
def test_number_of_minor_ticks_int(self, n, lim, ref, use_rcparam):
250+
if use_rcparam:
251+
context = {'xtick.minor.ndivs': n, 'ytick.minor.ndivs': n}
252+
kwargs = {}
253+
else:
254+
context = {}
255+
kwargs = {'n': n}
256+
257+
with mpl.rc_context(context):
258+
fig, ax = plt.subplots()
259+
ax.set_xlim(*lim)
260+
ax.set_ylim(*lim)
261+
ax.xaxis.set_major_locator(mticker.MultipleLocator(1))
262+
ax.xaxis.set_minor_locator(mticker.AutoMinorLocator(**kwargs))
263+
ax.yaxis.set_major_locator(mticker.MultipleLocator(1))
264+
ax.yaxis.set_minor_locator(mticker.AutoMinorLocator(**kwargs))
265+
assert_almost_equal(ax.xaxis.get_ticklocs(minor=True), ref)
266+
assert_almost_equal(ax.yaxis.get_ticklocs(minor=True), ref)
267+
214268

215269
class TestLogLocator:
216270
def test_basic(self):

lib/matplotlib/ticker.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2869,7 +2869,11 @@ def __init__(self, n=None):
28692869
major ticks; e.g., n=2 will place a single minor tick midway
28702870
between major ticks.
28712871
2872-
If *n* is omitted or None, it will be set to 5 or 4.
2872+
If *n* is omitted or None, the value stored in rcParams will be used.
2873+
In case *n* is set to 'auto', it will be set to 4 or 5. If the distance
2874+
between the major ticks equals 1, 2.5, 5 or 10 it can be perfectly
2875+
divided in 5 equidistant sub-intervals with a length multiple of
2876+
0.05. Otherwise it is divided in 4 sub-intervals.
28732877
"""
28742878
self.ndivs = n
28752879

@@ -2892,6 +2896,14 @@ def __call__(self):
28922896

28932897
if self.ndivs is None:
28942898

2899+
if self.axis.axis_name == 'y':
2900+
self.ndivs = mpl.rcParams['ytick.minor.ndivs']
2901+
else:
2902+
# for x and z axis
2903+
self.ndivs = mpl.rcParams['xtick.minor.ndivs']
2904+
2905+
if self.ndivs == 'auto':
2906+
28952907
majorstep_no_exponent = 10 ** (np.log10(majorstep) % 1)
28962908

28972909
if np.isclose(majorstep_no_exponent, [1.0, 2.5, 5.0, 10.0]).any():

0 commit comments

Comments
 (0)