From 5ce468e9494971cada98885c188f1f5e0e2ad175 Mon Sep 17 00:00:00 2001 From: Casey Brooks Date: Thu, 25 Dec 2025 13:18:48 +0000 Subject: [PATCH] fix: reuse categorical unitdata on shared axes (#62) Refs: task-283 --- lib/matplotlib/category.py | 13 +++++++ lib/matplotlib/tests/test_axes.py | 62 +++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+) diff --git a/lib/matplotlib/category.py b/lib/matplotlib/category.py index 4ac2379ea5f5..dedbbde9d24b 100644 --- a/lib/matplotlib/category.py +++ b/lib/matplotlib/category.py @@ -101,6 +101,19 @@ def default_units(data, axis): object storing string to integer mapping """ # the conversion call stack is default_units -> axis_info -> convert + if axis.units is None: + axis_name = axis.axis_name + shared_axes = axis.axes._shared_axes[axis_name].get_siblings( + axis.axes) + for shared in shared_axes: + if shared is axis.axes: + continue + sibling_axis = shared._axis_map[axis_name] + if isinstance(sibling_axis.units, UnitData): + axis.units = sibling_axis.units + axis._update_axisinfo() + break + if axis.units is None: axis.set_units(UnitData(data)) else: diff --git a/lib/matplotlib/tests/test_axes.py b/lib/matplotlib/tests/test_axes.py index 4f01752819f4..cbc860661c03 100644 --- a/lib/matplotlib/tests/test_axes.py +++ b/lib/matplotlib/tests/test_axes.py @@ -23,6 +23,7 @@ import matplotlib.dates as mdates from matplotlib.figure import Figure from matplotlib.axes import Axes +from matplotlib.category import UnitData import matplotlib.font_manager as mfont_manager import matplotlib.markers as mmarkers import matplotlib.patches as mpatches @@ -3036,6 +3037,67 @@ def layers(n, m): axs[1, 1].stackplot(range(100), d.T, baseline='weighted_wiggle') +def _stackplot_sample_data(): + x = ["16 May", "17 May"] + y1 = np.array([1, 2]) + y2 = np.array([3, 1]) + return x, y1, y2 + + +def test_stackplot_twinx_preserves_datalim(): + fig, ax1 = plt.subplots() + x, y1, y2 = _stackplot_sample_data() + ax1.stackplot(x, y1, y2) + before = ax1.dataLim.intervaly + + ax2 = ax1.twinx() + assert_allclose(ax1.dataLim.intervaly, before) + + ax2.plot(x, [2, 4]) + assert_allclose(ax1.dataLim.intervaly, before) + + +def test_stackplot_twinx_reuses_unitdata(): + fig, ax1 = plt.subplots() + x, y1, y2 = _stackplot_sample_data() + ax1.stackplot(x, y1, y2) + + ax2 = ax1.twinx() + ax2.plot(x, [2, 4]) + + assert isinstance(ax1.xaxis.units, UnitData) + assert ax2.xaxis.units is ax1.xaxis.units + + +def test_stackplot_twinx_numeric_x_units_none(): + fig, ax1 = plt.subplots() + x = [0, 1] + y1 = np.array([1, 2]) + y2 = np.array([3, 1]) + ax1.stackplot(x, y1, y2) + + ax2 = ax1.twinx() + ax2.plot(x, [2, 4]) + + assert ax1.xaxis.units is None + assert ax2.xaxis.units is None + + +def test_stackplot_categorical_primary_axis_units(): + fig, ax = plt.subplots() + x, y1, y2 = _stackplot_sample_data() + ax.stackplot(x, y1, y2) + + assert isinstance(ax.xaxis.units, UnitData) + + before = ax.dataLim.intervaly + ax.plot(x, [4, 5]) + after = ax.dataLim.intervaly + + assert after[0] <= before[0] + assert after[1] >= 5 + + def _bxp_test_helper( stats_kwargs={}, transform_stats=lambda s: s, bxp_kwargs={}): np.random.seed(937)