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

Skip to content

Fix get_tick_params #27408

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

Closed
wants to merge 1 commit into from
Closed
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
8 changes: 8 additions & 0 deletions doc/api/next_api_changes/behavior/27408-SR.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
Classes derived from Axis must implement get_tick_params
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't it be sufficient to implement the translation, either as a dict or as _translate_tick_params()?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, but _translate_tick_params is 18 LOC (not counting continuation lines) whereas get_tick_params is just 2.

Another thing is that set/get_tick_params currently doesn't work correctly for Axes3D (I'm going to open an issue about it) and I assume that it's easier fix with dedicated setters/getters (didn't look into it closely yet)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On second thought, I think you're right and it's less convoluted to make the translation dicts axis-specific in the first place rather than modify a generic dict. I'll change it later this week, changing this PR to draft in the meantime.

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Tick parameter translation depends on the concrete axis (x or y), so any
axis class derived from `~matplotlib.axis.Axis` must implement
`~matplotlib.axis.Axis.get_tick_params`. This is not necessary if the new axis
class is derived from `.XAxis` or `.YAxis` (as for instance the Axis classes
of `mpl_toolkits.mplot3d`).
2 changes: 2 additions & 0 deletions lib/matplotlib/axes/_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -3394,6 +3394,8 @@ def tick_params(self, axis='both', **kwargs):
Width of gridlines in points.
grid_linestyle : str
Any valid `.Line2D` line style spec.
gridOn : bool
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm hesitant to further expand the use of camelcase variables. But I don't have an overview of its usage and whether grid_on would be a viable alternative. (No code editor access right now).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

grid_on would be available as an alternative. gridOn is only used internally in 4 files, no big deal to rename.

As an alternative one could translate gridOn to grid_on (which wouldn't, however, prevent anyone to use the then undocumented keyword in set_tick_params etc., as it's the case now).

If we don't want to have gridOn I'd opt for renaming it to grid_on. This wouldn't be an API change as gridOn is not documented.

Whether to draw the grid lines.

Examples
--------
Expand Down
68 changes: 48 additions & 20 deletions lib/matplotlib/axis.py
Original file line number Diff line number Diff line change
Expand Up @@ -931,8 +931,7 @@ def set_tick_params(self, which='major', reset=False, **kwargs):
"""
Set appearance parameters for ticks, ticklabels, and gridlines.

For documentation of keyword arguments, see
:meth:`matplotlib.axes.Axes.tick_params`.
For documentation of keyword arguments, see `.Axes.tick_params`.

See Also
--------
Expand Down Expand Up @@ -976,6 +975,16 @@ def get_tick_params(self, which='major'):
"""
Get appearance parameters for ticks, ticklabels, and gridlines.

.. note::
This method only returns the values of the parameters *bottom*, *top*,
*labelbottom*, *labeltop* or *left*, *right*, *labelleft*, *labelright*,
respectively, and *girdOn* as well as all additional parameters that were
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
respectively, and *girdOn* as well as all additional parameters that were
respectively, and *gridOn* as well as all additional parameters that were

set with `.Axis.set_tick_params` or methods that use it internally, such
as `.Axes.tick_params`. The returned parameters may differ from the values
of the current elements if they have been set by any other means (e.g.
via set_* methods for individual tick objects, `.pyplot.xticks`/
`.pyplot.yticks` or `.rcParams`).

.. versionadded:: 3.7

Parameters
Expand All @@ -988,13 +997,6 @@ def get_tick_params(self, which='major'):
dict
Properties for styling tick elements added to the axis.

Notes
-----
This method returns the appearance parameters for styling *new*
elements added to this axis and may be different from the values
on current elements if they were modified directly by the user
(e.g., via ``set_*`` methods on individual tick objects).

Examples
--------
::
Expand All @@ -1019,15 +1021,10 @@ def get_tick_params(self, which='major'):


"""
_api.check_in_list(['major', 'minor'], which=which)
if which == 'major':
return self._translate_tick_params(
self._major_tick_kw, reverse=True
)
return self._translate_tick_params(self._minor_tick_kw, reverse=True)
raise NotImplementedError('Derived must override')

@staticmethod
def _translate_tick_params(kw, reverse=False):
def _translate_tick_params(kw, reverse=False, reverse_exclude=[]):
"""
Translate the kwargs supported by `.Axis.set_tick_params` to kwargs
supported by `.Tick._apply_params`.
Expand All @@ -1036,11 +1033,22 @@ def _translate_tick_params(kw, reverse=False):
to the generic tick1, tick2 logic of the axis. Additionally, there
are some other name translations.

Returns a new dict of translated kwargs.
Parameters
----------
kw
kwargs dict to translate.
reverse
whether to translate from set_tick_params kwargs to
_apply_params kwargs or back.
reverse_exclude
list of keys to be removed from the keymap before reverse
translating. This is necessary because there are multiple keys
with the same value in keymap, depending on the axis.

Note: Use reverse=True to translate from those supported by
`.Tick._apply_params` back to those supported by
`.Axis.set_tick_params`.
Returns
-------
dict
new dict of translated kwargs
"""
kw_ = {**kw}

Expand Down Expand Up @@ -1069,6 +1077,8 @@ def _translate_tick_params(kw, reverse=False):
'labeltop': 'label2On',
}
if reverse:
for key in reverse_exclude:
del keymap[key]
kwtrans = {
oldkey: kw_.pop(newkey)
for oldkey, newkey in keymap.items() if newkey in kw_
Expand Down Expand Up @@ -2518,6 +2528,15 @@ def get_tick_space(self):
else:
return 2**31 - 1

def get_tick_params(self, which='major'):
# docstring inherited
_api.check_in_list(['major', 'minor'], which=which)
return self._translate_tick_params(
getattr(self, f'_{which}_tick_kw'),
reverse=True,
reverse_exclude=['left', 'right', 'labelleft', 'labelright'],
)


class YAxis(Axis):
__name__ = 'yaxis'
Expand Down Expand Up @@ -2759,3 +2778,12 @@ def get_tick_space(self):
return int(np.floor(length / size))
else:
return 2**31 - 1

def get_tick_params(self, which='major'):
# docstring inherited
_api.check_in_list(['major', 'minor'], which=which)
return self._translate_tick_params(
getattr(self, f'_{which}_tick_kw'),
reverse=True,
reverse_exclude=['bottom', 'top', 'labelbottom', 'labeltop'],
)
40 changes: 0 additions & 40 deletions lib/matplotlib/tests/test_axes.py
Original file line number Diff line number Diff line change
Expand Up @@ -6777,46 +6777,6 @@ def test_pandas_bar_align_center(pd):
fig.canvas.draw()


def test_axis_get_tick_params():
axis = plt.subplot().yaxis
initial_major_style_translated = {**axis.get_tick_params(which='major')}
initial_minor_style_translated = {**axis.get_tick_params(which='minor')}

translated_major_kw = axis._translate_tick_params(
axis._major_tick_kw, reverse=True
)
translated_minor_kw = axis._translate_tick_params(
axis._minor_tick_kw, reverse=True
)

assert translated_major_kw == initial_major_style_translated
assert translated_minor_kw == initial_minor_style_translated
axis.set_tick_params(labelsize=30, labelcolor='red',
direction='out', which='both')

new_major_style_translated = {**axis.get_tick_params(which='major')}
new_minor_style_translated = {**axis.get_tick_params(which='minor')}
new_major_style = axis._translate_tick_params(new_major_style_translated)
new_minor_style = axis._translate_tick_params(new_minor_style_translated)
assert initial_major_style_translated != new_major_style_translated
assert axis._major_tick_kw == new_major_style
assert initial_minor_style_translated != new_minor_style_translated
assert axis._minor_tick_kw == new_minor_style


def test_axis_set_tick_params_labelsize_labelcolor():
# Tests fix for issue 4346
axis_1 = plt.subplot()
axis_1.yaxis.set_tick_params(labelsize=30, labelcolor='red',
direction='out')

# Expected values after setting the ticks
assert axis_1.yaxis.majorTicks[0]._size == 4.0
assert axis_1.yaxis.majorTicks[0].tick1line.get_color() == 'k'
assert axis_1.yaxis.majorTicks[0].label1.get_size() == 30.0
assert axis_1.yaxis.majorTicks[0].label1.get_color() == 'red'


def test_axes_tick_params_gridlines():
# Now treating grid params like other Tick params
ax = plt.subplot()
Expand Down
52 changes: 52 additions & 0 deletions lib/matplotlib/tests/test_axis.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import numpy as np
import pytest

import matplotlib.pyplot as plt
from matplotlib.axis import XTick
Expand All @@ -8,3 +9,54 @@ def test_tick_labelcolor_array():
# Smoke test that we can instantiate a Tick with labelcolor as array.
ax = plt.axes()
XTick(ax, 0, labelcolor=np.array([1, 0, 0, 1]))


@pytest.mark.parametrize("which", ["major", "minor"])
@pytest.mark.parametrize(
"axis, expected_basic",
[
(
"x",
{
"bottom": True,
"top": True, # tests use classic.mplstyle with top = True
"labelbottom": True,
"labeltop": False,
"gridOn": False,
},
),
(
"y",
{
"left": True,
"right": True, # tests use classic.mplstyle with right = True
"labelleft": True,
"labelright": False,
"gridOn": False,
},
),
],
ids=["xaxis", "yaxis"],
)
def test_axis_get_tick_params(axis, expected_basic, which):
axis = getattr(plt.subplot(), axis + "axis")
additional_kw = {"labelsize": 42}

axis.set_tick_params(which=which, **additional_kw)
expected = {**expected_basic, **additional_kw}
assert expected == axis.get_tick_params(which=which)
other = "minor" if which == "major" else "major"
assert expected_basic == axis.get_tick_params(which=other)


def test_axis_set_tick_params_labelsize_labelcolor():
# Tests fix for issue 4346
axis_1 = plt.subplot()
axis_1.yaxis.set_tick_params(labelsize=30, labelcolor='red',
direction='out')

# Expected values after setting the ticks
assert axis_1.yaxis.majorTicks[0]._size == 4.0
assert axis_1.yaxis.majorTicks[0].tick1line.get_color() == "k"
assert axis_1.yaxis.majorTicks[0].label1.get_size() == 30.0
assert axis_1.yaxis.majorTicks[0].label1.get_color() == "red"