From 538f2ebb0b3910bf69b3b0188a8af869e0f7a13a Mon Sep 17 00:00:00 2001 From: Steffen Rehberg Date: Tue, 28 Nov 2023 15:42:58 +0100 Subject: [PATCH] Fix get_tick_params - show values for x axis too - fix nonfunctional test - move axis tests from test_axes.py to test_axis.py - make note in get_tick_params docstring more precise - add GridOn to set_tick_params as it's always returned by get_tick_params, so it would be illogical if you couldn't set the paramter in the setter --- .../next_api_changes/behavior/27408-SR.rst | 8 +++ lib/matplotlib/axes/_base.py | 2 + lib/matplotlib/axis.py | 68 +++++++++++++------ lib/matplotlib/tests/test_axes.py | 40 ----------- lib/matplotlib/tests/test_axis.py | 52 ++++++++++++++ 5 files changed, 110 insertions(+), 60 deletions(-) create mode 100644 doc/api/next_api_changes/behavior/27408-SR.rst diff --git a/doc/api/next_api_changes/behavior/27408-SR.rst b/doc/api/next_api_changes/behavior/27408-SR.rst new file mode 100644 index 000000000000..bf95670921d2 --- /dev/null +++ b/doc/api/next_api_changes/behavior/27408-SR.rst @@ -0,0 +1,8 @@ +Classes derived from Axis must implement get_tick_params +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +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`). diff --git a/lib/matplotlib/axes/_base.py b/lib/matplotlib/axes/_base.py index b113b0f21156..56a400a42e79 100644 --- a/lib/matplotlib/axes/_base.py +++ b/lib/matplotlib/axes/_base.py @@ -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 + Whether to draw the grid lines. Examples -------- diff --git a/lib/matplotlib/axis.py b/lib/matplotlib/axis.py index e7f6724c4372..4acbcbdf56dc 100644 --- a/lib/matplotlib/axis.py +++ b/lib/matplotlib/axis.py @@ -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 -------- @@ -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 + 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 @@ -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 -------- :: @@ -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`. @@ -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} @@ -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_ @@ -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' @@ -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'], + ) diff --git a/lib/matplotlib/tests/test_axes.py b/lib/matplotlib/tests/test_axes.py index dffbb2377a23..851b2643c7d2 100644 --- a/lib/matplotlib/tests/test_axes.py +++ b/lib/matplotlib/tests/test_axes.py @@ -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() diff --git a/lib/matplotlib/tests/test_axis.py b/lib/matplotlib/tests/test_axis.py index 97b5f88dede1..26ae30800b88 100644 --- a/lib/matplotlib/tests/test_axis.py +++ b/lib/matplotlib/tests/test_axis.py @@ -1,4 +1,5 @@ import numpy as np +import pytest import matplotlib.pyplot as plt from matplotlib.axis import XTick @@ -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"