From 6a9e339033b5af8115db98edc2cc8462986b99a4 Mon Sep 17 00:00:00 2001 From: Antony Lee Date: Fri, 5 Feb 2021 13:55:14 +0100 Subject: [PATCH] Fix default label visibility for top-or-left-labeled shared subplots(). On the following example ```python from pylab import * rcParams.update({"xtick.labeltop": 1, "xtick.labelbottom": 0, "ytick.labelright": 1, "ytick.labelleft": 0}) subplots(3, 3, sharex=True, sharey=True) ``` subplots() now correctly leaves the xlabels on the first row and the ylabels on the last column, rather than the other way round. On the following example ```python from pylab import * rcParams.update({"xtick.labeltop": 1, "xtick.labelbottom": 1, "ytick.labelright": 1, "ytick.labelleft": 1}) subplots(3, 3, sharex=True, sharey=True) show() ``` subplots() now correctly leaves the xlabels on the first and last row and the ylabels on the first and last column. --- .../top-left-shared-subplots.rst | 10 +++++++ lib/matplotlib/gridspec.py | 26 ++++++++++++------- lib/matplotlib/tests/test_subplots.py | 22 ++++++++++++++++ 3 files changed, 48 insertions(+), 10 deletions(-) create mode 100644 doc/users/next_whats_new/top-left-shared-subplots.rst diff --git a/doc/users/next_whats_new/top-left-shared-subplots.rst b/doc/users/next_whats_new/top-left-shared-subplots.rst new file mode 100644 index 000000000000..71ca83208f69 --- /dev/null +++ b/doc/users/next_whats_new/top-left-shared-subplots.rst @@ -0,0 +1,10 @@ +Shared-axes ``subplots`` tick label visibility is now correct for top or left labels +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +When calling ``subplots(..., sharex=True, sharey=True)``, Matplotlib +automatically hides x tick labels for axes not in the first column and y tick +labels for axes not in the last row. This behavior is incorrect if rcParams +specify that axes should be labeled on the top (``rcParams["xtick.labeltop"] = +True``) or on the right (``rcParams["ytick.labelright"] = True``). + +Such cases are now handled correctly (adjusting visibility as needed on the +first row and last column of axes). diff --git a/lib/matplotlib/gridspec.py b/lib/matplotlib/gridspec.py index 7fda61373ec3..973d3d66b157 100644 --- a/lib/matplotlib/gridspec.py +++ b/lib/matplotlib/gridspec.py @@ -309,17 +309,23 @@ def subplots(self, *, sharex=False, sharey=False, squeeze=True, # turn off redundant tick labeling if sharex in ["col", "all"]: - # turn off all but the bottom row - for ax in axarr[:-1, :].flat: - ax.xaxis.set_tick_params(which='both', - labelbottom=False, labeltop=False) - ax.xaxis.offsetText.set_visible(False) + for ax in axarr[:-1, :].flat: # Remove bottom labels/offsettexts. + ax.xaxis.set_tick_params(which="both", labelbottom=False) + if ax.xaxis.offsetText.get_position()[1] == 0: + ax.xaxis.offsetText.set_visible(False) + for ax in axarr[1:, :].flat: # Remove top labels/offsettexts. + ax.xaxis.set_tick_params(which="both", labeltop=False) + if ax.xaxis.offsetText.get_position()[1] == 1: + ax.xaxis.offsetText.set_visible(False) if sharey in ["row", "all"]: - # turn off all but the first column - for ax in axarr[:, 1:].flat: - ax.yaxis.set_tick_params(which='both', - labelleft=False, labelright=False) - ax.yaxis.offsetText.set_visible(False) + for ax in axarr[:, 1:].flat: # Remove left labels/offsettexts. + ax.yaxis.set_tick_params(which="both", labelleft=False) + if ax.yaxis.offsetText.get_position()[0] == 0: + ax.yaxis.offsetText.set_visible(False) + for ax in axarr[:, :-1].flat: # Remove right labels/offsettexts. + ax.yaxis.set_tick_params(which="both", labelright=False) + if ax.yaxis.offsetText.get_position()[0] == 1: + ax.yaxis.offsetText.set_visible(False) if squeeze: # Discarding unneeded dimensions that equal 1. If we only have one diff --git a/lib/matplotlib/tests/test_subplots.py b/lib/matplotlib/tests/test_subplots.py index 6f6d97bb1c0c..39d48f9340df 100644 --- a/lib/matplotlib/tests/test_subplots.py +++ b/lib/matplotlib/tests/test_subplots.py @@ -160,6 +160,28 @@ def test_subplots_offsettext(): axs[1, 1].plot(y, x) +@pytest.mark.parametrize("top", [True, False]) +@pytest.mark.parametrize("bottom", [True, False]) +@pytest.mark.parametrize("left", [True, False]) +@pytest.mark.parametrize("right", [True, False]) +def test_subplots_hide_labels(top, bottom, left, right): + # Ideally, we would also test offset-text visibility (and remove + # test_subplots_offsettext), but currently, setting rcParams fails to move + # the offset texts as well. + with plt.rc_context({"xtick.labeltop": top, "xtick.labelbottom": bottom, + "ytick.labelleft": left, "ytick.labelright": right}): + axs = plt.figure().subplots(3, 3, sharex=True, sharey=True) + for (i, j), ax in np.ndenumerate(axs): + xtop = ax.xaxis._major_tick_kw["label2On"] + xbottom = ax.xaxis._major_tick_kw["label1On"] + yleft = ax.yaxis._major_tick_kw["label1On"] + yright = ax.yaxis._major_tick_kw["label2On"] + assert xtop == (top and i == 0) + assert xbottom == (bottom and i == 2) + assert yleft == (left and j == 0) + assert yright == (right and j == 2) + + def test_get_gridspec(): # ahem, pretty trivial, but... fig, ax = plt.subplots()