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

Skip to content

Allow setting default AutoMinorLocator #18715

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
May 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions doc/users/next_whats_new/auto_minor_tick.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
rcParams for ``AutoMinorLocator`` divisions
-------------------------------------------
The rcParams :rc:`xtick.minor.ndivs` and :rc:`ytick.minor.ndivs` have been
added to enable setting the default number of divisions; if set to ``auto``,
the number of divisions will be chosen by the distance between major ticks.
2 changes: 2 additions & 0 deletions lib/matplotlib/mpl-data/matplotlibrc
Original file line number Diff line number Diff line change
Expand Up @@ -489,6 +489,7 @@
#xtick.major.bottom: True # draw x axis bottom major ticks
#xtick.minor.top: True # draw x axis top minor ticks
#xtick.minor.bottom: True # draw x axis bottom minor ticks
#xtick.minor.ndivs: auto # number of minor ticks between the major ticks on x-axis
#xtick.alignment: center # alignment of xticks

#ytick.left: True # draw ticks on the left side
Expand All @@ -510,6 +511,7 @@
#ytick.major.right: True # draw y axis right major ticks
#ytick.minor.left: True # draw y axis left minor ticks
#ytick.minor.right: True # draw y axis right minor ticks
#ytick.minor.ndivs: auto # number of minor ticks between the major ticks on y-axis
#ytick.alignment: center_baseline # alignment of yticks


Expand Down
30 changes: 30 additions & 0 deletions lib/matplotlib/rcsetup.py
Original file line number Diff line number Diff line change
Expand Up @@ -568,6 +568,14 @@ def _validate_greaterequal0_lessequal1(s):
raise RuntimeError(f'Value must be >=0 and <=1; got {s}')


def _validate_int_greaterequal0(s):
s = validate_int(s)
if s >= 0:
return s
else:
raise RuntimeError(f'Value must be >=0; got {s}')


def validate_hatch(s):
r"""
Validate a hatch pattern.
Expand All @@ -587,6 +595,24 @@ def validate_hatch(s):
validate_dashlist = _listify_validator(validate_floatlist)


def _validate_minor_tick_ndivs(n):
"""
Validate ndiv parameter related to the minor ticks.
It controls the number of minor ticks to be placed between
two major ticks.
"""

if isinstance(n, str) and n.lower() == 'auto':
return n
try:
n = _validate_int_greaterequal0(n)
return n
except (RuntimeError, ValueError):
pass

raise ValueError("'tick.minor.ndivs' must be 'auto' or non-negative int")


_prop_validators = {
'color': _listify_validator(validate_color_for_prop_cycle,
allow_stringlist=True),
Expand Down Expand Up @@ -1093,6 +1119,8 @@ def _convert_validator_spec(key, conv):
"xtick.minor.bottom": validate_bool, # draw bottom minor xticks
"xtick.major.top": validate_bool, # draw top major xticks
"xtick.major.bottom": validate_bool, # draw bottom major xticks
# number of minor xticks
"xtick.minor.ndivs": _validate_minor_tick_ndivs,
"xtick.labelsize": validate_fontsize, # fontsize of xtick labels
"xtick.direction": ["out", "in", "inout"], # direction of xticks
"xtick.alignment": ["center", "right", "left"],
Expand All @@ -1114,6 +1142,8 @@ def _convert_validator_spec(key, conv):
"ytick.minor.right": validate_bool, # draw right minor yticks
"ytick.major.left": validate_bool, # draw left major yticks
"ytick.major.right": validate_bool, # draw right major yticks
# number of minor yticks
"ytick.minor.ndivs": _validate_minor_tick_ndivs,
"ytick.labelsize": validate_fontsize, # fontsize of ytick labels
"ytick.direction": ["out", "in", "inout"], # direction of yticks
"ytick.alignment": [
Expand Down
54 changes: 54 additions & 0 deletions lib/matplotlib/tests/test_ticker.py
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,60 @@ def test_additional(self, lim, ref):

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

@pytest.mark.parametrize('use_rcparam', [False, True])
@pytest.mark.parametrize(
'lim, ref', [
((0, 1.39),
[0.05, 0.1, 0.15, 0.25, 0.3, 0.35, 0.45, 0.5, 0.55, 0.65, 0.7,
0.75, 0.85, 0.9, 0.95, 1.05, 1.1, 1.15, 1.25, 1.3, 1.35]),
((0, 0.139),
[0.005, 0.01, 0.015, 0.025, 0.03, 0.035, 0.045, 0.05, 0.055,
0.065, 0.07, 0.075, 0.085, 0.09, 0.095, 0.105, 0.11, 0.115,
0.125, 0.13, 0.135]),
])
def test_number_of_minor_ticks_auto(self, lim, ref, use_rcparam):
if use_rcparam:
context = {'xtick.minor.ndivs': 'auto', 'ytick.minor.ndivs': 'auto'}
kwargs = {}
else:
context = {}
kwargs = {'n': 'auto'}

with mpl.rc_context(context):
fig, ax = plt.subplots()
ax.set_xlim(*lim)
ax.set_ylim(*lim)
ax.xaxis.set_minor_locator(mticker.AutoMinorLocator(**kwargs))
ax.yaxis.set_minor_locator(mticker.AutoMinorLocator(**kwargs))
assert_almost_equal(ax.xaxis.get_ticklocs(minor=True), ref)
assert_almost_equal(ax.yaxis.get_ticklocs(minor=True), ref)

@pytest.mark.parametrize('use_rcparam', [False, True])
@pytest.mark.parametrize(
'n, lim, ref', [
(2, (0, 4), [0.5, 1.5, 2.5, 3.5]),
(4, (0, 2), [0.25, 0.5, 0.75, 1.25, 1.5, 1.75]),
(10, (0, 1), [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9]),
])
def test_number_of_minor_ticks_int(self, n, lim, ref, use_rcparam):
if use_rcparam:
context = {'xtick.minor.ndivs': n, 'ytick.minor.ndivs': n}
kwargs = {}
else:
context = {}
kwargs = {'n': n}

with mpl.rc_context(context):
fig, ax = plt.subplots()
ax.set_xlim(*lim)
ax.set_ylim(*lim)
ax.xaxis.set_major_locator(mticker.MultipleLocator(1))
ax.xaxis.set_minor_locator(mticker.AutoMinorLocator(**kwargs))
ax.yaxis.set_major_locator(mticker.MultipleLocator(1))
ax.yaxis.set_minor_locator(mticker.AutoMinorLocator(**kwargs))
assert_almost_equal(ax.xaxis.get_ticklocs(minor=True), ref)
assert_almost_equal(ax.yaxis.get_ticklocs(minor=True), ref)


class TestLogLocator:
def test_basic(self):
Expand Down
14 changes: 13 additions & 1 deletion lib/matplotlib/ticker.py
Original file line number Diff line number Diff line change
Expand Up @@ -2869,7 +2869,11 @@ def __init__(self, n=None):
major ticks; e.g., n=2 will place a single minor tick midway
between major ticks.

If *n* is omitted or None, it will be set to 5 or 4.
If *n* is omitted or None, the value stored in rcParams will be used.
In case *n* is set to 'auto', it will be set to 4 or 5. If the distance
between the major ticks equals 1, 2.5, 5 or 10 it can be perfectly
divided in 5 equidistant sub-intervals with a length multiple of
0.05. Otherwise it is divided in 4 sub-intervals.
"""
self.ndivs = n

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

if self.ndivs is None:

if self.axis.axis_name == 'y':
self.ndivs = mpl.rcParams['ytick.minor.ndivs']
else:
# for x and z axis
self.ndivs = mpl.rcParams['xtick.minor.ndivs']

if self.ndivs == 'auto':

majorstep_no_exponent = 10 ** (np.log10(majorstep) % 1)

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