From f6513e7c04a225bed5fd5391f8a8a4ad86d35c2a Mon Sep 17 00:00:00 2001 From: NabeelShar Date: Sat, 13 Dec 2025 11:01:34 +0500 Subject: [PATCH 1/3] Fix Axes.grid() to respect alpha in color tuples When calling ax.grid(color=(R, G, B, A)) with a 4-element color tuple, the alpha channel was being ignored, causing gridlines to appear fully opaque instead of with the specified transparency. The issue occurred in two locations: 1. Tick.__init__: When creating ticks, if grid_alpha was None but the color had an alpha channel, the alpha wasn't extracted from the color 2. Tick._apply_params: When updating gridlines via grid(), colors with alpha weren't being decomposed into separate color and alpha params This fix extracts the alpha value from color tuples using mcolors.to_rgba() and sets both the color (RGB only) and alpha separately, ensuring proper transparency rendering. Fixes #22231 --- lib/matplotlib/axis.py | 34 +++++++++++++++++++++---------- lib/matplotlib/tests/test_axes.py | 22 ++++++++++++++++++++ 2 files changed, 45 insertions(+), 11 deletions(-) diff --git a/lib/matplotlib/axis.py b/lib/matplotlib/axis.py index c3b6fcac569f..900682511713 100644 --- a/lib/matplotlib/axis.py +++ b/lib/matplotlib/axis.py @@ -140,17 +140,20 @@ def __init__( f"grid.{major_minor}.linewidth", "grid.linewidth", ) - if grid_alpha is None and not mcolors._has_alpha_channel(grid_color): - # alpha precedence: kwarg > color alpha > rcParams['grid.alpha'] - # Note: only resolve to rcParams if the color does not have alpha - # otherwise `grid(color=(1, 1, 1, 0.5))` would work like - # grid(color=(1, 1, 1, 0.5), alpha=rcParams['grid.alpha']) - # so the that the rcParams default would override color alpha. - grid_alpha = mpl._val_or_rc( - # grid_alpha is None so we can use the first key - mpl.rcParams[f"grid.{major_minor}.alpha"], - "grid.alpha", - ) + if grid_alpha is None: + if mcolors._has_alpha_channel(grid_color): + # Extract alpha from the color + # alpha precedence: kwarg > color alpha > rcParams['grid.alpha'] + rgba = mcolors.to_rgba(grid_color) + grid_color = rgba[:3] # RGB only + grid_alpha = rgba[3] # Alpha from color + else: + # No alpha in color, use rcParams + grid_alpha = mpl._val_or_rc( + # grid_alpha is None so we can use the first key + mpl.rcParams[f"grid.{major_minor}.alpha"], + "grid.alpha", + ) grid_kw = {k[5:]: v for k, v in kwargs.items() if k != "rotation_mode"} @@ -348,6 +351,15 @@ def _apply_params(self, **kwargs): grid_kw = {k[5:]: v for k, v in kwargs.items() if k in _gridline_param_names} + # If grid_color has an alpha channel and grid_alpha is not explicitly + # set, extract the alpha from the color. + if 'color' in grid_kw and 'alpha' not in grid_kw: + grid_color = grid_kw['color'] + if mcolors._has_alpha_channel(grid_color): + # Convert to rgba to extract alpha + rgba = mcolors.to_rgba(grid_color) + grid_kw['color'] = rgba[:3] # RGB only + grid_kw['alpha'] = rgba[3] # Alpha channel self.gridline.set(**grid_kw) def update_position(self, loc): diff --git a/lib/matplotlib/tests/test_axes.py b/lib/matplotlib/tests/test_axes.py index 6e839ef2f189..18817f9fc82f 100644 --- a/lib/matplotlib/tests/test_axes.py +++ b/lib/matplotlib/tests/test_axes.py @@ -6133,6 +6133,28 @@ def test_grid(): assert not ax.xaxis.majorTicks[0].gridline.get_visible() +def test_grid_color_with_alpha(): + """Test that grid(color=(..., alpha)) respects the alpha value.""" + fig, ax = plt.subplots() + ax.plot([0, 1], [0, 1]) + + # Test 1: Color tuple with alpha + ax.grid(True, color=(0.5, 0.6, 0.7, 0.3)) + fig.canvas.draw() + + # Check that alpha is extracted from color tuple + for tick in ax.xaxis.get_major_ticks(): + assert tick.gridline.get_alpha() == 0.3, \ + f"Expected alpha=0.3, got {tick.gridline.get_alpha()}" + # Color should be RGB only, without alpha component + color = tick.gridline.get_color() + assert len(color) in (3, 4), f"Unexpected color format: {color}" + + for tick in ax.yaxis.get_major_ticks(): + assert tick.gridline.get_alpha() == 0.3, \ + f"Expected alpha=0.3, got {tick.gridline.get_alpha()}" + + def test_reset_grid(): fig, ax = plt.subplots() ax.tick_params(reset=True, which='major', labelsize=10) From b1d1094ec4e579d26001bbd518e3e52375d63829 Mon Sep 17 00:00:00 2001 From: NabeelShar Date: Fri, 19 Dec 2025 10:12:33 +0500 Subject: [PATCH 2/3] Simplify test_grid_color_with_alpha per reviewer feedback - Remove unnecessary ax.plot() call - Remove unnecessary fig.canvas.draw() call - Remove unnecessary color format assertion --- lib/matplotlib/tests/test_axes.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/lib/matplotlib/tests/test_axes.py b/lib/matplotlib/tests/test_axes.py index 18817f9fc82f..905541094820 100644 --- a/lib/matplotlib/tests/test_axes.py +++ b/lib/matplotlib/tests/test_axes.py @@ -6136,19 +6136,12 @@ def test_grid(): def test_grid_color_with_alpha(): """Test that grid(color=(..., alpha)) respects the alpha value.""" fig, ax = plt.subplots() - ax.plot([0, 1], [0, 1]) - - # Test 1: Color tuple with alpha ax.grid(True, color=(0.5, 0.6, 0.7, 0.3)) - fig.canvas.draw() # Check that alpha is extracted from color tuple for tick in ax.xaxis.get_major_ticks(): assert tick.gridline.get_alpha() == 0.3, \ f"Expected alpha=0.3, got {tick.gridline.get_alpha()}" - # Color should be RGB only, without alpha component - color = tick.gridline.get_color() - assert len(color) in (3, 4), f"Unexpected color format: {color}" for tick in ax.yaxis.get_major_ticks(): assert tick.gridline.get_alpha() == 0.3, \ From 56ffbe932ddb5c68f91cd8276ef4723e89b9885e Mon Sep 17 00:00:00 2001 From: NabeelShar Date: Fri, 19 Dec 2025 10:13:49 +0500 Subject: [PATCH 3/3] Fix trailing whitespace linting issues --- lib/matplotlib/tests/test_axes.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/matplotlib/tests/test_axes.py b/lib/matplotlib/tests/test_axes.py index 905541094820..b9076d86dc98 100644 --- a/lib/matplotlib/tests/test_axes.py +++ b/lib/matplotlib/tests/test_axes.py @@ -6137,12 +6137,12 @@ def test_grid_color_with_alpha(): """Test that grid(color=(..., alpha)) respects the alpha value.""" fig, ax = plt.subplots() ax.grid(True, color=(0.5, 0.6, 0.7, 0.3)) - + # Check that alpha is extracted from color tuple for tick in ax.xaxis.get_major_ticks(): assert tick.gridline.get_alpha() == 0.3, \ f"Expected alpha=0.3, got {tick.gridline.get_alpha()}" - + for tick in ax.yaxis.get_major_ticks(): assert tick.gridline.get_alpha() == 0.3, \ f"Expected alpha=0.3, got {tick.gridline.get_alpha()}"