From dabaf623246b4f3a3dc7e0dc06ee693c2c9fb787 Mon Sep 17 00:00:00 2001 From: lukashergt Date: Fri, 18 Jul 2025 02:59:47 +0200 Subject: [PATCH 01/10] add tests for various corner cases of legends with `labelcolor` set to `linecolor`, e.g. ensuring that histograms with `step` histtype do not end up with an empty label --- lib/matplotlib/tests/test_legend.py | 238 ++++++++++++++++++++++++++++ 1 file changed, 238 insertions(+) diff --git a/lib/matplotlib/tests/test_legend.py b/lib/matplotlib/tests/test_legend.py index 9b100037cc41..3f13aed87439 100644 --- a/lib/matplotlib/tests/test_legend.py +++ b/lib/matplotlib/tests/test_legend.py @@ -1068,6 +1068,244 @@ def test_legend_labelcolor_rcparam_markerfacecolor_short(): assert mpl.colors.same_color(text.get_color(), color) +def test_legend_labelcolor_linecolor_histograms(): + x = np.arange(10) + + # testing c kwarg for bar, step, and stepfilled histograms + fig, ax = plt.subplots() + _, _, h = ax.hist(x, histtype='bar', color='r', + label="red bar hist with a red label") + leg = ax.legend(loc=1, labelcolor='linecolor') + tc = leg.texts[0].get_color() + assert mpl.colors.same_color(tc, 'r') + assert mpl.colors.same_color(tc, leg.get_patches()[0].get_facecolor()) + assert mpl.colors.same_color(tc, h[0].get_facecolor()) + + fig, ax = plt.subplots() + _, _, h = ax.hist(x, histtype='step', color='g', + label="green step hist with a green label") + leg = ax.legend(loc=1, labelcolor='linecolor') + tc = leg.texts[0].get_color() + assert mpl.colors.same_color(tc, 'g') + assert mpl.colors.same_color(tc, leg.get_patches()[0].get_edgecolor()) + assert mpl.colors.same_color(tc, h[0].get_edgecolor()) + + fig, ax = plt.subplots() + _, _, h = ax.hist(x, histtype='stepfilled', color='b', + label="blue stepfilled hist with a blue label") + leg = ax.legend(loc=1, labelcolor='linecolor') + tc = leg.texts[0].get_color() + assert mpl.colors.same_color(tc, 'b') + assert mpl.colors.same_color(tc, leg.get_patches()[0].get_facecolor()) + assert mpl.colors.same_color(tc, h[0].get_facecolor()) + + # testing c, fc, and ec combinations for bar histograms + fig, ax = plt.subplots() + _, _, h = ax.hist(x, histtype='bar', color='r', ec='b', + label="red bar hist with blue edges and a red label") + leg = ax.legend(loc=1, labelcolor='linecolor') + tc = leg.texts[0].get_color() + assert mpl.colors.same_color(tc, 'r') + assert mpl.colors.same_color(tc, leg.get_patches()[0].get_facecolor()) + assert mpl.colors.same_color(tc, h[0].get_facecolor()) + + fig, ax = plt.subplots() + _, _, h = ax.hist(x, histtype='bar', fc='r', ec='b', + label="red bar hist with blue edges and a red label") + leg = ax.legend(loc=1, labelcolor='linecolor') + tc = leg.texts[0].get_color() + assert mpl.colors.same_color(tc, 'r') + assert mpl.colors.same_color(tc, leg.get_patches()[0].get_facecolor()) + assert mpl.colors.same_color(tc, h[0].get_facecolor()) + + fig, ax = plt.subplots() + _, _, h = ax.hist(x, histtype='bar', fc='none', ec='b', + label="unfilled blue bar hist with a blue label") + leg = ax.legend(loc=1, labelcolor='linecolor') + tc = leg.texts[0].get_color() + assert mpl.colors.same_color(tc, 'b') + assert mpl.colors.same_color(tc, leg.get_patches()[0].get_edgecolor()) + assert mpl.colors.same_color(tc, h[0].get_edgecolor()) + + # testing c, and ec combinations for step histograms + fig, ax = plt.subplots() + _, _, h = ax.hist(x, histtype='step', color='r', ec='b', + label="blue step hist with a blue label") + leg = ax.legend(loc=1, labelcolor='linecolor') + tc = leg.texts[0].get_color() + assert mpl.colors.same_color(tc, 'b') + assert mpl.colors.same_color(tc, leg.get_patches()[0].get_edgecolor()) + assert mpl.colors.same_color(tc, h[0].get_edgecolor()) + + fig, ax = plt.subplots() + _, _, h = ax.hist(x, histtype='step', ec='b', + label="blue step hist with a blue label") + leg = ax.legend(loc=1, labelcolor='linecolor') + tc = leg.texts[0].get_color() + assert mpl.colors.same_color(tc, 'b') + assert mpl.colors.same_color(tc, leg.get_patches()[0].get_edgecolor()) + assert mpl.colors.same_color(tc, h[0].get_edgecolor()) + + # testing c, fc, and ec combinations for stepfilled histograms + fig, ax = plt.subplots() + _, _, h = ax.hist(x, histtype='stepfilled', color='r', ec='b', + label="red stepfilled hist, blue edges, red label") + leg = ax.legend(loc=1, labelcolor='linecolor') + tc = leg.texts[0].get_color() + assert mpl.colors.same_color(tc, 'r') + assert mpl.colors.same_color(tc, leg.get_patches()[0].get_facecolor()) + assert mpl.colors.same_color(tc, h[0].get_facecolor()) + + fig, ax = plt.subplots() + _, _, h = ax.hist(x, histtype='stepfilled', fc='r', ec='b', + label="red stepfilled hist, blue edges, red label") + leg = ax.legend(loc=1, labelcolor='linecolor') + tc = leg.texts[0].get_color() + assert mpl.colors.same_color(tc, 'r') + assert mpl.colors.same_color(tc, leg.get_patches()[0].get_facecolor()) + assert mpl.colors.same_color(tc, h[0].get_facecolor()) + + fig, ax = plt.subplots() + _, _, h = ax.hist(x, histtype='stepfilled', fc='none', ec='b', + label="unfilled blue stepfilled hist, blue label") + leg = ax.legend(loc=1, labelcolor='linecolor') + tc = leg.texts[0].get_color() + assert mpl.colors.same_color(tc, 'b') + assert mpl.colors.same_color(tc, leg.get_patches()[0].get_edgecolor()) + assert mpl.colors.same_color(tc, h[0].get_edgecolor()) + + fig, ax = plt.subplots() + _, _, h = ax.hist(x, histtype='stepfilled', fc='r', ec='none', + label="edgeless red stepfilled hist with a red label") + leg = ax.legend(loc=1, labelcolor='linecolor') + tc = leg.texts[0].get_color() + assert mpl.colors.same_color(tc, 'r') + assert mpl.colors.same_color(tc, leg.get_patches()[0].get_facecolor()) + assert mpl.colors.same_color(tc, h[0].get_facecolor()) + plt.close('all') + + +def test_legend_labelcolor_linecolor_plot(): + x = np.arange(5) + + # testing line plot + fig, ax = plt.subplots() + p = ax.plot(x, c='r', label="red line with a red label") + leg = ax.legend(loc=1, labelcolor='linecolor') + tc = leg.texts[0].get_color() + assert mpl.colors.same_color(tc, 'r') + assert mpl.colors.same_color(tc, leg.get_lines()[0].get_color()) + assert mpl.colors.same_color(tc, p[0].get_color()) + + # testing c, fc, and ec combinations for maker plots + fig, ax = plt.subplots() + p = ax.plot(x, 'o', c='r', label="red circles with a red label") + leg = ax.legend(loc=1, labelcolor='linecolor') + tc = leg.texts[0].get_color() + assert mpl.colors.same_color(tc, 'r') + assert mpl.colors.same_color(tc, leg.get_lines()[0].get_color()) + assert mpl.colors.same_color(tc, p[0].get_color()) + + fig, ax = plt.subplots() + p = ax.plot(x, 'o', c='r', mec='b', label="red circles, blue edges, red label") + leg = ax.legend(loc=1, labelcolor='linecolor') + tc = leg.texts[0].get_color() + assert mpl.colors.same_color(tc, 'r') + assert mpl.colors.same_color(tc, leg.get_lines()[0].get_color()) + assert mpl.colors.same_color(tc, p[0].get_color()) + + fig, ax = plt.subplots() + p = ax.plot(x, 'o', mfc='r', mec='b', label="red circles, blue edges, red label") + leg = ax.legend(loc=1, labelcolor='linecolor') + tc = leg.texts[0].get_color() + assert mpl.colors.same_color(tc, 'r') + assert mpl.colors.same_color(tc, leg.get_lines()[0].get_markerfacecolor()) + assert mpl.colors.same_color(tc, p[0].get_markerfacecolor()) + + # 'none' cases + fig, ax = plt.subplots() + p = ax.plot(x, 'o', mfc='none', mec='b', label="blue unfilled circles, blue label") + leg = ax.legend(loc=1, labelcolor='linecolor') + tc = leg.texts[0].get_color() + assert mpl.colors.same_color(tc, 'b') + assert mpl.colors.same_color(tc, leg.get_lines()[0].get_markeredgecolor()) + assert mpl.colors.same_color(tc, p[0].get_markeredgecolor()) + + fig, ax = plt.subplots() + p = ax.plot(x, 'o', mfc='r', mec='none', label="red edgeless circles, red label") + leg = ax.legend(loc=1, labelcolor='linecolor') + tc = leg.texts[0].get_color() + assert mpl.colors.same_color(tc, 'r') + assert mpl.colors.same_color(tc, leg.get_lines()[0].get_markerfacecolor()) + assert mpl.colors.same_color(tc, p[0].get_markerfacecolor()) + + fig, ax = plt.subplots() + p = ax.plot(x, 'o', c='none', label="invisible circles with invisible label") + leg = ax.legend(loc=1, labelcolor='linecolor') + tc = leg.texts[0].get_color() + assert tc == 'none' + assert tc == leg.get_lines()[0].get_markerfacecolor() + assert tc == leg.get_lines()[0].get_markeredgecolor() + assert tc == leg.get_lines()[0].get_color() + assert tc == p[0].get_markerfacecolor() + assert tc == p[0].get_markeredgecolor() + assert tc == p[0].get_color() + plt.close('all') + + +def test_legend_labelcolor_linecolor_scatter(): + x = np.arange(5) + + # testing c, fc, and ec combinations for scatter plots + fig, ax = plt.subplots() + p = ax.scatter(x, x, c='r', label="red circles with a red label") + leg = ax.legend(loc=1, labelcolor='linecolor') + tc = leg.texts[0].get_color() + assert mpl.colors.same_color(tc, 'r') + assert mpl.colors.same_color(tc, leg.legend_handles[0].get_facecolor()) + assert mpl.colors.same_color(tc, p.get_facecolor()) + + fig, ax = plt.subplots() + p = ax.scatter(x, x, c='r', ec='b', label="red circles, blue edges, red label") + leg = ax.legend(loc=1, labelcolor='linecolor') + tc = leg.texts[0].get_color() + assert mpl.colors.same_color(tc, 'r') + assert mpl.colors.same_color(tc, leg.legend_handles[0].get_facecolor()) + assert mpl.colors.same_color(tc, p.get_facecolor()) + + fig, ax = plt.subplots() + p = ax.scatter(x, x, fc='r', ec='b', label="red circles, blue edges, red label") + leg = ax.legend(loc=1, labelcolor='linecolor') + tc = leg.texts[0].get_color() + assert mpl.colors.same_color(tc, 'r') + assert mpl.colors.same_color(tc, leg.legend_handles[0].get_facecolor()) + assert mpl.colors.same_color(tc, p.get_facecolor()) + + # 'none' cases + fig, ax = plt.subplots() + p = ax.scatter(x, x, fc='none', ec='b', label="blue unfilled circles, blue label") + leg = ax.legend(loc=1, labelcolor='linecolor') + tc = leg.texts[0].get_color() + assert mpl.colors.same_color(tc, 'b') + assert mpl.colors.same_color(tc, leg.legend_handles[0].get_edgecolor()) + assert mpl.colors.same_color(tc, p.get_edgecolor()) + + fig, ax = plt.subplots() + p = ax.scatter(x, x, fc='r', ec='none', label="red edgeless circles, red label") + leg = ax.legend(loc=1, labelcolor='linecolor') + tc = leg.texts[0].get_color() + assert mpl.colors.same_color(tc, 'r') + assert mpl.colors.same_color(tc, leg.legend_handles[0].get_facecolor()) + assert mpl.colors.same_color(tc, p.get_facecolor()) + + fig, ax = plt.subplots() + p = ax.scatter(x, x, c='none', label="invisible circles with invisible label") + leg = ax.legend(loc=1, labelcolor='linecolor') + tc = leg.texts[0].get_color() + assert tc == 'none' + plt.close('all') + + @pytest.mark.filterwarnings("ignore:No artists with labels found to put in legend") def test_get_set_draggable(): legend = plt.legend() From 335e76e350a08a8ca9ea2967eef59b2b6ec1a011 Mon Sep 17 00:00:00 2001 From: lukashergt Date: Fri, 18 Jul 2025 04:01:11 +0200 Subject: [PATCH 02/10] fix legends with `labelcolor` set to `linecolor`: change ordering from `c, fc` to `mfc, fc, mec, ec, c`; check if `color` is empty, `none` or transparent and loop on if so --- lib/matplotlib/legend.py | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/lib/matplotlib/legend.py b/lib/matplotlib/legend.py index 2fb14e52c58c..671a65a502e2 100644 --- a/lib/matplotlib/legend.py +++ b/lib/matplotlib/legend.py @@ -576,7 +576,11 @@ def __init__( # set the text color color_getters = { # getter function depends on line or patch - 'linecolor': ['get_color', 'get_facecolor'], + 'linecolor': ['get_markerfacecolor', + 'get_facecolor', + 'get_markeredgecolor', + 'get_edgecolor', + 'get_color'], 'markerfacecolor': ['get_markerfacecolor', 'get_facecolor'], 'mfc': ['get_markerfacecolor', 'get_facecolor'], 'markeredgecolor': ['get_markeredgecolor', 'get_edgecolor'], @@ -596,18 +600,27 @@ def __init__( try: color = getattr(handle, getter_name)() if isinstance(color, np.ndarray): - if ( - color.shape[0] == 1 - or np.isclose(color, color[0]).all() + if color.size == 0: + continue + elif ( + color.shape[0] == 1 + or np.isclose(color, color[0]).all() ): text.set_color(color[0]) else: pass + elif isinstance(color, str) and str(color).lower() == 'none': + continue + elif (len(mpl.colors.to_rgba(color)) == 4 + and mpl.colors.to_rgba(color)[3] == 0): + continue else: text.set_color(color) break except AttributeError: - pass + continue + else: + text.set_color('none') elif cbook._str_equal(labelcolor, 'none'): for text in self.texts: text.set_color(labelcolor) From 8d9555ebdeacaf2ac642a5af929cc8597145ab68 Mon Sep 17 00:00:00 2001 From: lukashergt Date: Fri, 18 Jul 2025 04:51:13 +0200 Subject: [PATCH 03/10] account for the `classic` style in the mpl tests; need to specify `none` for both `c` and `ec` to ensure invisibility, in classic black edges are default --- lib/matplotlib/tests/test_legend.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/matplotlib/tests/test_legend.py b/lib/matplotlib/tests/test_legend.py index 3f13aed87439..da399f1fc8cb 100644 --- a/lib/matplotlib/tests/test_legend.py +++ b/lib/matplotlib/tests/test_legend.py @@ -1240,7 +1240,7 @@ def test_legend_labelcolor_linecolor_plot(): assert mpl.colors.same_color(tc, p[0].get_markerfacecolor()) fig, ax = plt.subplots() - p = ax.plot(x, 'o', c='none', label="invisible circles with invisible label") + p = ax.plot(x, 'o', c='none', mec='none', label="invisible circles and label") leg = ax.legend(loc=1, labelcolor='linecolor') tc = leg.texts[0].get_color() assert tc == 'none' @@ -1299,7 +1299,7 @@ def test_legend_labelcolor_linecolor_scatter(): assert mpl.colors.same_color(tc, p.get_facecolor()) fig, ax = plt.subplots() - p = ax.scatter(x, x, c='none', label="invisible circles with invisible label") + p = ax.scatter(x, x, c='none', ec='none', label="invisible circles and label") leg = ax.legend(loc=1, labelcolor='linecolor') tc = leg.texts[0].get_color() assert tc == 'none' From 0fc6fbe00d27c5601e3fb80d00aaa010feac549d Mon Sep 17 00:00:00 2001 From: lukashergt Date: Fri, 18 Jul 2025 04:55:31 +0200 Subject: [PATCH 04/10] remove unnecessary `loc=1` in new tests for `labelcolor_linecolor` --- lib/matplotlib/tests/test_legend.py | 50 ++++++++++++++--------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/lib/matplotlib/tests/test_legend.py b/lib/matplotlib/tests/test_legend.py index da399f1fc8cb..088a27061356 100644 --- a/lib/matplotlib/tests/test_legend.py +++ b/lib/matplotlib/tests/test_legend.py @@ -1075,7 +1075,7 @@ def test_legend_labelcolor_linecolor_histograms(): fig, ax = plt.subplots() _, _, h = ax.hist(x, histtype='bar', color='r', label="red bar hist with a red label") - leg = ax.legend(loc=1, labelcolor='linecolor') + leg = ax.legend(labelcolor='linecolor') tc = leg.texts[0].get_color() assert mpl.colors.same_color(tc, 'r') assert mpl.colors.same_color(tc, leg.get_patches()[0].get_facecolor()) @@ -1084,7 +1084,7 @@ def test_legend_labelcolor_linecolor_histograms(): fig, ax = plt.subplots() _, _, h = ax.hist(x, histtype='step', color='g', label="green step hist with a green label") - leg = ax.legend(loc=1, labelcolor='linecolor') + leg = ax.legend(labelcolor='linecolor') tc = leg.texts[0].get_color() assert mpl.colors.same_color(tc, 'g') assert mpl.colors.same_color(tc, leg.get_patches()[0].get_edgecolor()) @@ -1093,7 +1093,7 @@ def test_legend_labelcolor_linecolor_histograms(): fig, ax = plt.subplots() _, _, h = ax.hist(x, histtype='stepfilled', color='b', label="blue stepfilled hist with a blue label") - leg = ax.legend(loc=1, labelcolor='linecolor') + leg = ax.legend(labelcolor='linecolor') tc = leg.texts[0].get_color() assert mpl.colors.same_color(tc, 'b') assert mpl.colors.same_color(tc, leg.get_patches()[0].get_facecolor()) @@ -1103,7 +1103,7 @@ def test_legend_labelcolor_linecolor_histograms(): fig, ax = plt.subplots() _, _, h = ax.hist(x, histtype='bar', color='r', ec='b', label="red bar hist with blue edges and a red label") - leg = ax.legend(loc=1, labelcolor='linecolor') + leg = ax.legend(labelcolor='linecolor') tc = leg.texts[0].get_color() assert mpl.colors.same_color(tc, 'r') assert mpl.colors.same_color(tc, leg.get_patches()[0].get_facecolor()) @@ -1112,7 +1112,7 @@ def test_legend_labelcolor_linecolor_histograms(): fig, ax = plt.subplots() _, _, h = ax.hist(x, histtype='bar', fc='r', ec='b', label="red bar hist with blue edges and a red label") - leg = ax.legend(loc=1, labelcolor='linecolor') + leg = ax.legend(labelcolor='linecolor') tc = leg.texts[0].get_color() assert mpl.colors.same_color(tc, 'r') assert mpl.colors.same_color(tc, leg.get_patches()[0].get_facecolor()) @@ -1121,7 +1121,7 @@ def test_legend_labelcolor_linecolor_histograms(): fig, ax = plt.subplots() _, _, h = ax.hist(x, histtype='bar', fc='none', ec='b', label="unfilled blue bar hist with a blue label") - leg = ax.legend(loc=1, labelcolor='linecolor') + leg = ax.legend(labelcolor='linecolor') tc = leg.texts[0].get_color() assert mpl.colors.same_color(tc, 'b') assert mpl.colors.same_color(tc, leg.get_patches()[0].get_edgecolor()) @@ -1131,7 +1131,7 @@ def test_legend_labelcolor_linecolor_histograms(): fig, ax = plt.subplots() _, _, h = ax.hist(x, histtype='step', color='r', ec='b', label="blue step hist with a blue label") - leg = ax.legend(loc=1, labelcolor='linecolor') + leg = ax.legend(labelcolor='linecolor') tc = leg.texts[0].get_color() assert mpl.colors.same_color(tc, 'b') assert mpl.colors.same_color(tc, leg.get_patches()[0].get_edgecolor()) @@ -1140,7 +1140,7 @@ def test_legend_labelcolor_linecolor_histograms(): fig, ax = plt.subplots() _, _, h = ax.hist(x, histtype='step', ec='b', label="blue step hist with a blue label") - leg = ax.legend(loc=1, labelcolor='linecolor') + leg = ax.legend(labelcolor='linecolor') tc = leg.texts[0].get_color() assert mpl.colors.same_color(tc, 'b') assert mpl.colors.same_color(tc, leg.get_patches()[0].get_edgecolor()) @@ -1150,7 +1150,7 @@ def test_legend_labelcolor_linecolor_histograms(): fig, ax = plt.subplots() _, _, h = ax.hist(x, histtype='stepfilled', color='r', ec='b', label="red stepfilled hist, blue edges, red label") - leg = ax.legend(loc=1, labelcolor='linecolor') + leg = ax.legend(labelcolor='linecolor') tc = leg.texts[0].get_color() assert mpl.colors.same_color(tc, 'r') assert mpl.colors.same_color(tc, leg.get_patches()[0].get_facecolor()) @@ -1159,7 +1159,7 @@ def test_legend_labelcolor_linecolor_histograms(): fig, ax = plt.subplots() _, _, h = ax.hist(x, histtype='stepfilled', fc='r', ec='b', label="red stepfilled hist, blue edges, red label") - leg = ax.legend(loc=1, labelcolor='linecolor') + leg = ax.legend(labelcolor='linecolor') tc = leg.texts[0].get_color() assert mpl.colors.same_color(tc, 'r') assert mpl.colors.same_color(tc, leg.get_patches()[0].get_facecolor()) @@ -1168,7 +1168,7 @@ def test_legend_labelcolor_linecolor_histograms(): fig, ax = plt.subplots() _, _, h = ax.hist(x, histtype='stepfilled', fc='none', ec='b', label="unfilled blue stepfilled hist, blue label") - leg = ax.legend(loc=1, labelcolor='linecolor') + leg = ax.legend(labelcolor='linecolor') tc = leg.texts[0].get_color() assert mpl.colors.same_color(tc, 'b') assert mpl.colors.same_color(tc, leg.get_patches()[0].get_edgecolor()) @@ -1177,7 +1177,7 @@ def test_legend_labelcolor_linecolor_histograms(): fig, ax = plt.subplots() _, _, h = ax.hist(x, histtype='stepfilled', fc='r', ec='none', label="edgeless red stepfilled hist with a red label") - leg = ax.legend(loc=1, labelcolor='linecolor') + leg = ax.legend(labelcolor='linecolor') tc = leg.texts[0].get_color() assert mpl.colors.same_color(tc, 'r') assert mpl.colors.same_color(tc, leg.get_patches()[0].get_facecolor()) @@ -1191,7 +1191,7 @@ def test_legend_labelcolor_linecolor_plot(): # testing line plot fig, ax = plt.subplots() p = ax.plot(x, c='r', label="red line with a red label") - leg = ax.legend(loc=1, labelcolor='linecolor') + leg = ax.legend(labelcolor='linecolor') tc = leg.texts[0].get_color() assert mpl.colors.same_color(tc, 'r') assert mpl.colors.same_color(tc, leg.get_lines()[0].get_color()) @@ -1200,7 +1200,7 @@ def test_legend_labelcolor_linecolor_plot(): # testing c, fc, and ec combinations for maker plots fig, ax = plt.subplots() p = ax.plot(x, 'o', c='r', label="red circles with a red label") - leg = ax.legend(loc=1, labelcolor='linecolor') + leg = ax.legend(labelcolor='linecolor') tc = leg.texts[0].get_color() assert mpl.colors.same_color(tc, 'r') assert mpl.colors.same_color(tc, leg.get_lines()[0].get_color()) @@ -1208,7 +1208,7 @@ def test_legend_labelcolor_linecolor_plot(): fig, ax = plt.subplots() p = ax.plot(x, 'o', c='r', mec='b', label="red circles, blue edges, red label") - leg = ax.legend(loc=1, labelcolor='linecolor') + leg = ax.legend(labelcolor='linecolor') tc = leg.texts[0].get_color() assert mpl.colors.same_color(tc, 'r') assert mpl.colors.same_color(tc, leg.get_lines()[0].get_color()) @@ -1216,7 +1216,7 @@ def test_legend_labelcolor_linecolor_plot(): fig, ax = plt.subplots() p = ax.plot(x, 'o', mfc='r', mec='b', label="red circles, blue edges, red label") - leg = ax.legend(loc=1, labelcolor='linecolor') + leg = ax.legend(labelcolor='linecolor') tc = leg.texts[0].get_color() assert mpl.colors.same_color(tc, 'r') assert mpl.colors.same_color(tc, leg.get_lines()[0].get_markerfacecolor()) @@ -1225,7 +1225,7 @@ def test_legend_labelcolor_linecolor_plot(): # 'none' cases fig, ax = plt.subplots() p = ax.plot(x, 'o', mfc='none', mec='b', label="blue unfilled circles, blue label") - leg = ax.legend(loc=1, labelcolor='linecolor') + leg = ax.legend(labelcolor='linecolor') tc = leg.texts[0].get_color() assert mpl.colors.same_color(tc, 'b') assert mpl.colors.same_color(tc, leg.get_lines()[0].get_markeredgecolor()) @@ -1233,7 +1233,7 @@ def test_legend_labelcolor_linecolor_plot(): fig, ax = plt.subplots() p = ax.plot(x, 'o', mfc='r', mec='none', label="red edgeless circles, red label") - leg = ax.legend(loc=1, labelcolor='linecolor') + leg = ax.legend(labelcolor='linecolor') tc = leg.texts[0].get_color() assert mpl.colors.same_color(tc, 'r') assert mpl.colors.same_color(tc, leg.get_lines()[0].get_markerfacecolor()) @@ -1241,7 +1241,7 @@ def test_legend_labelcolor_linecolor_plot(): fig, ax = plt.subplots() p = ax.plot(x, 'o', c='none', mec='none', label="invisible circles and label") - leg = ax.legend(loc=1, labelcolor='linecolor') + leg = ax.legend(labelcolor='linecolor') tc = leg.texts[0].get_color() assert tc == 'none' assert tc == leg.get_lines()[0].get_markerfacecolor() @@ -1259,7 +1259,7 @@ def test_legend_labelcolor_linecolor_scatter(): # testing c, fc, and ec combinations for scatter plots fig, ax = plt.subplots() p = ax.scatter(x, x, c='r', label="red circles with a red label") - leg = ax.legend(loc=1, labelcolor='linecolor') + leg = ax.legend(labelcolor='linecolor') tc = leg.texts[0].get_color() assert mpl.colors.same_color(tc, 'r') assert mpl.colors.same_color(tc, leg.legend_handles[0].get_facecolor()) @@ -1267,7 +1267,7 @@ def test_legend_labelcolor_linecolor_scatter(): fig, ax = plt.subplots() p = ax.scatter(x, x, c='r', ec='b', label="red circles, blue edges, red label") - leg = ax.legend(loc=1, labelcolor='linecolor') + leg = ax.legend(labelcolor='linecolor') tc = leg.texts[0].get_color() assert mpl.colors.same_color(tc, 'r') assert mpl.colors.same_color(tc, leg.legend_handles[0].get_facecolor()) @@ -1275,7 +1275,7 @@ def test_legend_labelcolor_linecolor_scatter(): fig, ax = plt.subplots() p = ax.scatter(x, x, fc='r', ec='b', label="red circles, blue edges, red label") - leg = ax.legend(loc=1, labelcolor='linecolor') + leg = ax.legend(labelcolor='linecolor') tc = leg.texts[0].get_color() assert mpl.colors.same_color(tc, 'r') assert mpl.colors.same_color(tc, leg.legend_handles[0].get_facecolor()) @@ -1284,7 +1284,7 @@ def test_legend_labelcolor_linecolor_scatter(): # 'none' cases fig, ax = plt.subplots() p = ax.scatter(x, x, fc='none', ec='b', label="blue unfilled circles, blue label") - leg = ax.legend(loc=1, labelcolor='linecolor') + leg = ax.legend(labelcolor='linecolor') tc = leg.texts[0].get_color() assert mpl.colors.same_color(tc, 'b') assert mpl.colors.same_color(tc, leg.legend_handles[0].get_edgecolor()) @@ -1292,7 +1292,7 @@ def test_legend_labelcolor_linecolor_scatter(): fig, ax = plt.subplots() p = ax.scatter(x, x, fc='r', ec='none', label="red edgeless circles, red label") - leg = ax.legend(loc=1, labelcolor='linecolor') + leg = ax.legend(labelcolor='linecolor') tc = leg.texts[0].get_color() assert mpl.colors.same_color(tc, 'r') assert mpl.colors.same_color(tc, leg.legend_handles[0].get_facecolor()) @@ -1300,7 +1300,7 @@ def test_legend_labelcolor_linecolor_scatter(): fig, ax = plt.subplots() p = ax.scatter(x, x, c='none', ec='none', label="invisible circles and label") - leg = ax.legend(loc=1, labelcolor='linecolor') + leg = ax.legend(labelcolor='linecolor') tc = leg.texts[0].get_color() assert tc == 'none' plt.close('all') From db46a5cb514f5a78579b54d2b8fc7cdb400905a1 Mon Sep 17 00:00:00 2001 From: lukashergt Date: Fri, 18 Jul 2025 04:59:49 +0200 Subject: [PATCH 05/10] use `mpl.colors.same_color` also for the `none` checks --- lib/matplotlib/tests/test_legend.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/matplotlib/tests/test_legend.py b/lib/matplotlib/tests/test_legend.py index 088a27061356..39bfb8d329d2 100644 --- a/lib/matplotlib/tests/test_legend.py +++ b/lib/matplotlib/tests/test_legend.py @@ -1243,13 +1243,13 @@ def test_legend_labelcolor_linecolor_plot(): p = ax.plot(x, 'o', c='none', mec='none', label="invisible circles and label") leg = ax.legend(labelcolor='linecolor') tc = leg.texts[0].get_color() - assert tc == 'none' - assert tc == leg.get_lines()[0].get_markerfacecolor() - assert tc == leg.get_lines()[0].get_markeredgecolor() - assert tc == leg.get_lines()[0].get_color() - assert tc == p[0].get_markerfacecolor() - assert tc == p[0].get_markeredgecolor() - assert tc == p[0].get_color() + assert mpl.colors.same_color(tc, 'none') + assert mpl.colors.same_color(tc, leg.get_lines()[0].get_markerfacecolor()) + assert mpl.colors.same_color(tc, leg.get_lines()[0].get_markeredgecolor()) + assert mpl.colors.same_color(tc, leg.get_lines()[0].get_color()) + assert mpl.colors.same_color(tc, p[0].get_markerfacecolor()) + assert mpl.colors.same_color(tc, p[0].get_markeredgecolor()) + assert mpl.colors.same_color(tc, p[0].get_color()) plt.close('all') @@ -1302,7 +1302,7 @@ def test_legend_labelcolor_linecolor_scatter(): p = ax.scatter(x, x, c='none', ec='none', label="invisible circles and label") leg = ax.legend(labelcolor='linecolor') tc = leg.texts[0].get_color() - assert tc == 'none' + assert mpl.colors.same_color(tc, 'none') plt.close('all') From 64e3a86fbfaacefa8550434a71f1c7b6f195391b Mon Sep 17 00:00:00 2001 From: Lukas Hergt Date: Fri, 18 Jul 2025 17:03:16 +0200 Subject: [PATCH 06/10] Apply suggestions from code review Using helper for `'none'` string equality and using the fact that `to_rgba` always returns a 4-element tuple to simplify the code. Co-authored-by: Tim Hoffmann <2836374+timhoffm@users.noreply.github.com> --- lib/matplotlib/legend.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/matplotlib/legend.py b/lib/matplotlib/legend.py index 671a65a502e2..5ed8f818208c 100644 --- a/lib/matplotlib/legend.py +++ b/lib/matplotlib/legend.py @@ -609,10 +609,9 @@ def __init__( text.set_color(color[0]) else: pass - elif isinstance(color, str) and str(color).lower() == 'none': + elif cbook._str_lower_equal(color, 'none'): continue - elif (len(mpl.colors.to_rgba(color)) == 4 - and mpl.colors.to_rgba(color)[3] == 0): + elif mpl.colors.to_rgba(color)[3] == 0: continue else: text.set_color(color) From dc425b0482220d9f9d7a37bf8d2c9de011f6111f Mon Sep 17 00:00:00 2001 From: lukashergt Date: Wed, 23 Jul 2025 10:16:37 +0200 Subject: [PATCH 07/10] revert to original behaviour of having black legend labels for invisible handles; can pass empty string `" "` to achieve empty/invisible label instead; having a black legend label by default allows the creation of neutrally coloured dummy entries --- lib/matplotlib/legend.py | 2 -- lib/matplotlib/tests/test_legend.py | 16 ++++++---------- 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/lib/matplotlib/legend.py b/lib/matplotlib/legend.py index 5ed8f818208c..3a1769381bd2 100644 --- a/lib/matplotlib/legend.py +++ b/lib/matplotlib/legend.py @@ -618,8 +618,6 @@ def __init__( break except AttributeError: continue - else: - text.set_color('none') elif cbook._str_equal(labelcolor, 'none'): for text in self.texts: text.set_color(labelcolor) diff --git a/lib/matplotlib/tests/test_legend.py b/lib/matplotlib/tests/test_legend.py index 39bfb8d329d2..7be5c5c6d36e 100644 --- a/lib/matplotlib/tests/test_legend.py +++ b/lib/matplotlib/tests/test_legend.py @@ -1240,16 +1240,11 @@ def test_legend_labelcolor_linecolor_plot(): assert mpl.colors.same_color(tc, p[0].get_markerfacecolor()) fig, ax = plt.subplots() - p = ax.plot(x, 'o', c='none', mec='none', label="invisible circles and label") + p = ax.plot(x, 'o', c='none', mec='none', + label="black label despite invisible circles for dummy entries") leg = ax.legend(labelcolor='linecolor') tc = leg.texts[0].get_color() - assert mpl.colors.same_color(tc, 'none') - assert mpl.colors.same_color(tc, leg.get_lines()[0].get_markerfacecolor()) - assert mpl.colors.same_color(tc, leg.get_lines()[0].get_markeredgecolor()) - assert mpl.colors.same_color(tc, leg.get_lines()[0].get_color()) - assert mpl.colors.same_color(tc, p[0].get_markerfacecolor()) - assert mpl.colors.same_color(tc, p[0].get_markeredgecolor()) - assert mpl.colors.same_color(tc, p[0].get_color()) + assert mpl.colors.same_color(tc, 'k') plt.close('all') @@ -1299,10 +1294,11 @@ def test_legend_labelcolor_linecolor_scatter(): assert mpl.colors.same_color(tc, p.get_facecolor()) fig, ax = plt.subplots() - p = ax.scatter(x, x, c='none', ec='none', label="invisible circles and label") + p = ax.scatter(x, x, c='none', ec='none', + label="black label despite invisible circles for dummy entries") leg = ax.legend(labelcolor='linecolor') tc = leg.texts[0].get_color() - assert mpl.colors.same_color(tc, 'none') + assert mpl.colors.same_color(tc, 'k') plt.close('all') From e2122db26124862afcc6ac49b06bd5458dd99d2f Mon Sep 17 00:00:00 2001 From: lukashergt Date: Thu, 24 Jul 2025 11:56:01 +0200 Subject: [PATCH 08/10] compactify tests for `legend_labelcolor_linecolor` as suggested in PR --- lib/matplotlib/tests/test_legend.py | 248 ++++++++++++---------------- 1 file changed, 106 insertions(+), 142 deletions(-) diff --git a/lib/matplotlib/tests/test_legend.py b/lib/matplotlib/tests/test_legend.py index 7be5c5c6d36e..a9099a6489ea 100644 --- a/lib/matplotlib/tests/test_legend.py +++ b/lib/matplotlib/tests/test_legend.py @@ -1068,123 +1068,115 @@ def test_legend_labelcolor_rcparam_markerfacecolor_short(): assert mpl.colors.same_color(text.get_color(), color) +def assert_last_legend_patch_color(histogram, leg, expected_color, + facecolor=False, edgecolor=False): + """ + Check that histogram color, legend handle color, and legend label color all + match the expected input. Provide facecolor and edgecolor flags to clarify + which feature to match. + """ + label_color = leg.texts[-1].get_color() + patch = leg.get_patches()[-1] + histogram = histogram[-1][0] + assert mpl.colors.same_color(label_color, expected_color) + if facecolor: + assert mpl.colors.same_color(label_color, patch.get_facecolor()) + assert mpl.colors.same_color(label_color, histogram.get_facecolor()) + if edgecolor: + assert mpl.colors.same_color(label_color, patch.get_edgecolor()) + assert mpl.colors.same_color(label_color, histogram.get_edgecolor()) + + def test_legend_labelcolor_linecolor_histograms(): x = np.arange(10) # testing c kwarg for bar, step, and stepfilled histograms fig, ax = plt.subplots() - _, _, h = ax.hist(x, histtype='bar', color='r', - label="red bar hist with a red label") + h = ax.hist(x, histtype='bar', color='r', label="red bar hist with a red label") leg = ax.legend(labelcolor='linecolor') - tc = leg.texts[0].get_color() - assert mpl.colors.same_color(tc, 'r') - assert mpl.colors.same_color(tc, leg.get_patches()[0].get_facecolor()) - assert mpl.colors.same_color(tc, h[0].get_facecolor()) + assert_last_legend_patch_color(h, leg, 'r', facecolor=True) - fig, ax = plt.subplots() - _, _, h = ax.hist(x, histtype='step', color='g', - label="green step hist with a green label") + h = ax.hist(x, histtype='step', color='g', label="green step hist, green label") leg = ax.legend(labelcolor='linecolor') - tc = leg.texts[0].get_color() - assert mpl.colors.same_color(tc, 'g') - assert mpl.colors.same_color(tc, leg.get_patches()[0].get_edgecolor()) - assert mpl.colors.same_color(tc, h[0].get_edgecolor()) + assert_last_legend_patch_color(h, leg, 'g', edgecolor=True) - fig, ax = plt.subplots() - _, _, h = ax.hist(x, histtype='stepfilled', color='b', - label="blue stepfilled hist with a blue label") + h = ax.hist(x, histtype='stepfilled', color='b', + label="blue stepfilled hist with a blue label") leg = ax.legend(labelcolor='linecolor') - tc = leg.texts[0].get_color() - assert mpl.colors.same_color(tc, 'b') - assert mpl.colors.same_color(tc, leg.get_patches()[0].get_facecolor()) - assert mpl.colors.same_color(tc, h[0].get_facecolor()) + assert_last_legend_patch_color(h, leg, 'b', facecolor=True) # testing c, fc, and ec combinations for bar histograms - fig, ax = plt.subplots() - _, _, h = ax.hist(x, histtype='bar', color='r', ec='b', - label="red bar hist with blue edges and a red label") + h = ax.hist(x, histtype='bar', color='r', ec='b', + label="red bar hist with blue edges and a red label") leg = ax.legend(labelcolor='linecolor') - tc = leg.texts[0].get_color() - assert mpl.colors.same_color(tc, 'r') - assert mpl.colors.same_color(tc, leg.get_patches()[0].get_facecolor()) - assert mpl.colors.same_color(tc, h[0].get_facecolor()) + assert_last_legend_patch_color(h, leg, 'r', facecolor=True) - fig, ax = plt.subplots() - _, _, h = ax.hist(x, histtype='bar', fc='r', ec='b', - label="red bar hist with blue edges and a red label") + h = ax.hist(x, histtype='bar', fc='r', ec='b', + label="red bar hist with blue edges and a red label") leg = ax.legend(labelcolor='linecolor') - tc = leg.texts[0].get_color() - assert mpl.colors.same_color(tc, 'r') - assert mpl.colors.same_color(tc, leg.get_patches()[0].get_facecolor()) - assert mpl.colors.same_color(tc, h[0].get_facecolor()) + assert_last_legend_patch_color(h, leg, 'r', facecolor=True) - fig, ax = plt.subplots() - _, _, h = ax.hist(x, histtype='bar', fc='none', ec='b', - label="unfilled blue bar hist with a blue label") + h = ax.hist(x, histtype='bar', fc='none', ec='b', + label="unfilled blue bar hist with a blue label") leg = ax.legend(labelcolor='linecolor') - tc = leg.texts[0].get_color() - assert mpl.colors.same_color(tc, 'b') - assert mpl.colors.same_color(tc, leg.get_patches()[0].get_edgecolor()) - assert mpl.colors.same_color(tc, h[0].get_edgecolor()) + assert_last_legend_patch_color(h, leg, 'b', edgecolor=True) # testing c, and ec combinations for step histograms - fig, ax = plt.subplots() - _, _, h = ax.hist(x, histtype='step', color='r', ec='b', - label="blue step hist with a blue label") + h = ax.hist(x, histtype='step', color='r', ec='b', + label="blue step hist with a blue label") leg = ax.legend(labelcolor='linecolor') - tc = leg.texts[0].get_color() - assert mpl.colors.same_color(tc, 'b') - assert mpl.colors.same_color(tc, leg.get_patches()[0].get_edgecolor()) - assert mpl.colors.same_color(tc, h[0].get_edgecolor()) + assert_last_legend_patch_color(h, leg, 'b', edgecolor=True) - fig, ax = plt.subplots() - _, _, h = ax.hist(x, histtype='step', ec='b', - label="blue step hist with a blue label") + h = ax.hist(x, histtype='step', ec='b', + label="blue step hist with a blue label") leg = ax.legend(labelcolor='linecolor') - tc = leg.texts[0].get_color() - assert mpl.colors.same_color(tc, 'b') - assert mpl.colors.same_color(tc, leg.get_patches()[0].get_edgecolor()) - assert mpl.colors.same_color(tc, h[0].get_edgecolor()) + assert_last_legend_patch_color(h, leg, 'b', edgecolor=True) # testing c, fc, and ec combinations for stepfilled histograms - fig, ax = plt.subplots() - _, _, h = ax.hist(x, histtype='stepfilled', color='r', ec='b', - label="red stepfilled hist, blue edges, red label") + h = ax.hist(x, histtype='stepfilled', color='r', ec='b', + label="red stepfilled hist, blue edges, red label") leg = ax.legend(labelcolor='linecolor') - tc = leg.texts[0].get_color() - assert mpl.colors.same_color(tc, 'r') - assert mpl.colors.same_color(tc, leg.get_patches()[0].get_facecolor()) - assert mpl.colors.same_color(tc, h[0].get_facecolor()) + assert_last_legend_patch_color(h, leg, 'r', facecolor=True) - fig, ax = plt.subplots() - _, _, h = ax.hist(x, histtype='stepfilled', fc='r', ec='b', - label="red stepfilled hist, blue edges, red label") + h = ax.hist(x, histtype='stepfilled', fc='r', ec='b', + label="red stepfilled hist, blue edges, red label") leg = ax.legend(labelcolor='linecolor') - tc = leg.texts[0].get_color() - assert mpl.colors.same_color(tc, 'r') - assert mpl.colors.same_color(tc, leg.get_patches()[0].get_facecolor()) - assert mpl.colors.same_color(tc, h[0].get_facecolor()) + assert_last_legend_patch_color(h, leg, 'r', facecolor=True) - fig, ax = plt.subplots() - _, _, h = ax.hist(x, histtype='stepfilled', fc='none', ec='b', - label="unfilled blue stepfilled hist, blue label") + h = ax.hist(x, histtype='stepfilled', fc='none', ec='b', + label="unfilled blue stepfilled hist, blue label") leg = ax.legend(labelcolor='linecolor') - tc = leg.texts[0].get_color() - assert mpl.colors.same_color(tc, 'b') - assert mpl.colors.same_color(tc, leg.get_patches()[0].get_edgecolor()) - assert mpl.colors.same_color(tc, h[0].get_edgecolor()) + assert_last_legend_patch_color(h, leg, 'b', edgecolor=True) - fig, ax = plt.subplots() - _, _, h = ax.hist(x, histtype='stepfilled', fc='r', ec='none', - label="edgeless red stepfilled hist with a red label") + h = ax.hist(x, histtype='stepfilled', fc='r', ec='none', + label="edgeless red stepfilled hist with a red label") leg = ax.legend(labelcolor='linecolor') - tc = leg.texts[0].get_color() - assert mpl.colors.same_color(tc, 'r') - assert mpl.colors.same_color(tc, leg.get_patches()[0].get_facecolor()) - assert mpl.colors.same_color(tc, h[0].get_facecolor()) + assert_last_legend_patch_color(h, leg, 'r', facecolor=True) plt.close('all') +def assert_last_legend_linemarker_color(plot, leg, expected_color, + color=False, facecolor=False, edgecolor=False): + """ + Check that line marker color, legend handle color, and legend label color all + match the expected input. Provide color, facecolor and edgecolor flags to clarify + which feature to match. + """ + label_color = leg.texts[-1].get_color() + leg_marker = leg.get_lines()[-1] + plot_marker = plot[0] + assert mpl.colors.same_color(label_color, expected_color) + if color: + assert mpl.colors.same_color(label_color, leg_marker.get_color()) + assert mpl.colors.same_color(label_color, plot_marker.get_color()) + if facecolor: + assert mpl.colors.same_color(label_color, leg_marker.get_markerfacecolor()) + assert mpl.colors.same_color(label_color, plot_marker.get_markerfacecolor()) + if edgecolor: + assert mpl.colors.same_color(label_color, leg_marker.get_markeredgecolor()) + assert mpl.colors.same_color(label_color, plot_marker.get_markeredgecolor()) + + def test_legend_labelcolor_linecolor_plot(): x = np.arange(5) @@ -1192,62 +1184,55 @@ def test_legend_labelcolor_linecolor_plot(): fig, ax = plt.subplots() p = ax.plot(x, c='r', label="red line with a red label") leg = ax.legend(labelcolor='linecolor') - tc = leg.texts[0].get_color() - assert mpl.colors.same_color(tc, 'r') - assert mpl.colors.same_color(tc, leg.get_lines()[0].get_color()) - assert mpl.colors.same_color(tc, p[0].get_color()) + assert_last_legend_linemarker_color(p, leg, 'r', color=True) # testing c, fc, and ec combinations for maker plots - fig, ax = plt.subplots() p = ax.plot(x, 'o', c='r', label="red circles with a red label") leg = ax.legend(labelcolor='linecolor') - tc = leg.texts[0].get_color() - assert mpl.colors.same_color(tc, 'r') - assert mpl.colors.same_color(tc, leg.get_lines()[0].get_color()) - assert mpl.colors.same_color(tc, p[0].get_color()) + assert_last_legend_linemarker_color(p, leg, 'r', color=True) - fig, ax = plt.subplots() p = ax.plot(x, 'o', c='r', mec='b', label="red circles, blue edges, red label") leg = ax.legend(labelcolor='linecolor') - tc = leg.texts[0].get_color() - assert mpl.colors.same_color(tc, 'r') - assert mpl.colors.same_color(tc, leg.get_lines()[0].get_color()) - assert mpl.colors.same_color(tc, p[0].get_color()) + assert_last_legend_linemarker_color(p, leg, 'r', color=True) - fig, ax = plt.subplots() p = ax.plot(x, 'o', mfc='r', mec='b', label="red circles, blue edges, red label") leg = ax.legend(labelcolor='linecolor') - tc = leg.texts[0].get_color() - assert mpl.colors.same_color(tc, 'r') - assert mpl.colors.same_color(tc, leg.get_lines()[0].get_markerfacecolor()) - assert mpl.colors.same_color(tc, p[0].get_markerfacecolor()) + assert_last_legend_linemarker_color(p, leg, 'r', facecolor=True) # 'none' cases - fig, ax = plt.subplots() p = ax.plot(x, 'o', mfc='none', mec='b', label="blue unfilled circles, blue label") leg = ax.legend(labelcolor='linecolor') - tc = leg.texts[0].get_color() - assert mpl.colors.same_color(tc, 'b') - assert mpl.colors.same_color(tc, leg.get_lines()[0].get_markeredgecolor()) - assert mpl.colors.same_color(tc, p[0].get_markeredgecolor()) + assert_last_legend_linemarker_color(p, leg, 'b', edgecolor=True) - fig, ax = plt.subplots() p = ax.plot(x, 'o', mfc='r', mec='none', label="red edgeless circles, red label") leg = ax.legend(labelcolor='linecolor') - tc = leg.texts[0].get_color() - assert mpl.colors.same_color(tc, 'r') - assert mpl.colors.same_color(tc, leg.get_lines()[0].get_markerfacecolor()) - assert mpl.colors.same_color(tc, p[0].get_markerfacecolor()) + assert_last_legend_linemarker_color(p, leg, 'r', facecolor=True) - fig, ax = plt.subplots() p = ax.plot(x, 'o', c='none', mec='none', label="black label despite invisible circles for dummy entries") leg = ax.legend(labelcolor='linecolor') - tc = leg.texts[0].get_color() - assert mpl.colors.same_color(tc, 'k') + assert_last_legend_linemarker_color(p, leg, 'k') plt.close('all') +def assert_last_legend_scattermarker_color(scatter_marker, leg, expected_color, + facecolor=False, edgecolor=False): + """ + Check that scatter marker color, legend handle color, and legend label color all + match the expected input. Provide facecolor and edgecolor flags to clarify + which feature to match. + """ + label_color = leg.texts[-1].get_color() + leg_handle = leg.legend_handles[-1] + assert mpl.colors.same_color(label_color, expected_color) + if facecolor: + assert mpl.colors.same_color(label_color, leg_handle.get_facecolor()) + assert mpl.colors.same_color(label_color, scatter_marker.get_facecolor()) + if edgecolor: + assert mpl.colors.same_color(label_color, leg_handle.get_edgecolor()) + assert mpl.colors.same_color(label_color, scatter_marker.get_edgecolor()) + + def test_legend_labelcolor_linecolor_scatter(): x = np.arange(5) @@ -1255,50 +1240,29 @@ def test_legend_labelcolor_linecolor_scatter(): fig, ax = plt.subplots() p = ax.scatter(x, x, c='r', label="red circles with a red label") leg = ax.legend(labelcolor='linecolor') - tc = leg.texts[0].get_color() - assert mpl.colors.same_color(tc, 'r') - assert mpl.colors.same_color(tc, leg.legend_handles[0].get_facecolor()) - assert mpl.colors.same_color(tc, p.get_facecolor()) + assert_last_legend_scattermarker_color(p, leg, 'r', facecolor=True) - fig, ax = plt.subplots() p = ax.scatter(x, x, c='r', ec='b', label="red circles, blue edges, red label") leg = ax.legend(labelcolor='linecolor') - tc = leg.texts[0].get_color() - assert mpl.colors.same_color(tc, 'r') - assert mpl.colors.same_color(tc, leg.legend_handles[0].get_facecolor()) - assert mpl.colors.same_color(tc, p.get_facecolor()) + assert_last_legend_scattermarker_color(p, leg, 'r', facecolor=True) - fig, ax = plt.subplots() p = ax.scatter(x, x, fc='r', ec='b', label="red circles, blue edges, red label") leg = ax.legend(labelcolor='linecolor') - tc = leg.texts[0].get_color() - assert mpl.colors.same_color(tc, 'r') - assert mpl.colors.same_color(tc, leg.legend_handles[0].get_facecolor()) - assert mpl.colors.same_color(tc, p.get_facecolor()) + assert_last_legend_scattermarker_color(p, leg, 'r', facecolor=True) # 'none' cases - fig, ax = plt.subplots() p = ax.scatter(x, x, fc='none', ec='b', label="blue unfilled circles, blue label") leg = ax.legend(labelcolor='linecolor') - tc = leg.texts[0].get_color() - assert mpl.colors.same_color(tc, 'b') - assert mpl.colors.same_color(tc, leg.legend_handles[0].get_edgecolor()) - assert mpl.colors.same_color(tc, p.get_edgecolor()) + assert_last_legend_scattermarker_color(p, leg, 'b', edgecolor=True) - fig, ax = plt.subplots() p = ax.scatter(x, x, fc='r', ec='none', label="red edgeless circles, red label") leg = ax.legend(labelcolor='linecolor') - tc = leg.texts[0].get_color() - assert mpl.colors.same_color(tc, 'r') - assert mpl.colors.same_color(tc, leg.legend_handles[0].get_facecolor()) - assert mpl.colors.same_color(tc, p.get_facecolor()) + assert_last_legend_scattermarker_color(p, leg, 'r', facecolor=True) - fig, ax = plt.subplots() p = ax.scatter(x, x, c='none', ec='none', label="black label despite invisible circles for dummy entries") leg = ax.legend(labelcolor='linecolor') - tc = leg.texts[0].get_color() - assert mpl.colors.same_color(tc, 'k') + assert_last_legend_scattermarker_color(p, leg, 'k') plt.close('all') From e6aa6a1133012695eb39d9b0c7bc29a0be0b9d7d Mon Sep 17 00:00:00 2001 From: lukashergt Date: Thu, 24 Jul 2025 20:12:54 +0200 Subject: [PATCH 09/10] remove unneeded calls to `plt.close` --- lib/matplotlib/tests/test_legend.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/lib/matplotlib/tests/test_legend.py b/lib/matplotlib/tests/test_legend.py index a9099a6489ea..510af69da1af 100644 --- a/lib/matplotlib/tests/test_legend.py +++ b/lib/matplotlib/tests/test_legend.py @@ -1152,7 +1152,6 @@ def test_legend_labelcolor_linecolor_histograms(): label="edgeless red stepfilled hist with a red label") leg = ax.legend(labelcolor='linecolor') assert_last_legend_patch_color(h, leg, 'r', facecolor=True) - plt.close('all') def assert_last_legend_linemarker_color(plot, leg, expected_color, @@ -1212,7 +1211,6 @@ def test_legend_labelcolor_linecolor_plot(): label="black label despite invisible circles for dummy entries") leg = ax.legend(labelcolor='linecolor') assert_last_legend_linemarker_color(p, leg, 'k') - plt.close('all') def assert_last_legend_scattermarker_color(scatter_marker, leg, expected_color, @@ -1263,7 +1261,6 @@ def test_legend_labelcolor_linecolor_scatter(): label="black label despite invisible circles for dummy entries") leg = ax.legend(labelcolor='linecolor') assert_last_legend_scattermarker_color(p, leg, 'k') - plt.close('all') @pytest.mark.filterwarnings("ignore:No artists with labels found to put in legend") From 7d2f76bba882084e8bde77eba7f67659248c2247 Mon Sep 17 00:00:00 2001 From: lukashergt Date: Thu, 24 Jul 2025 20:25:18 +0200 Subject: [PATCH 10/10] use tuple unpacking in `legend_labelcolor_linecolor` tests as suggested in PR review --- lib/matplotlib/tests/test_legend.py | 66 ++++++++++++++--------------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/lib/matplotlib/tests/test_legend.py b/lib/matplotlib/tests/test_legend.py index 510af69da1af..61fae63a298e 100644 --- a/lib/matplotlib/tests/test_legend.py +++ b/lib/matplotlib/tests/test_legend.py @@ -1154,8 +1154,8 @@ def test_legend_labelcolor_linecolor_histograms(): assert_last_legend_patch_color(h, leg, 'r', facecolor=True) -def assert_last_legend_linemarker_color(plot, leg, expected_color, - color=False, facecolor=False, edgecolor=False): +def assert_last_legend_linemarker_color(line_marker, leg, expected_color, color=False, + facecolor=False, edgecolor=False): """ Check that line marker color, legend handle color, and legend label color all match the expected input. Provide color, facecolor and edgecolor flags to clarify @@ -1163,17 +1163,16 @@ def assert_last_legend_linemarker_color(plot, leg, expected_color, """ label_color = leg.texts[-1].get_color() leg_marker = leg.get_lines()[-1] - plot_marker = plot[0] assert mpl.colors.same_color(label_color, expected_color) if color: assert mpl.colors.same_color(label_color, leg_marker.get_color()) - assert mpl.colors.same_color(label_color, plot_marker.get_color()) + assert mpl.colors.same_color(label_color, line_marker.get_color()) if facecolor: assert mpl.colors.same_color(label_color, leg_marker.get_markerfacecolor()) - assert mpl.colors.same_color(label_color, plot_marker.get_markerfacecolor()) + assert mpl.colors.same_color(label_color, line_marker.get_markerfacecolor()) if edgecolor: assert mpl.colors.same_color(label_color, leg_marker.get_markeredgecolor()) - assert mpl.colors.same_color(label_color, plot_marker.get_markeredgecolor()) + assert mpl.colors.same_color(label_color, line_marker.get_markeredgecolor()) def test_legend_labelcolor_linecolor_plot(): @@ -1181,36 +1180,37 @@ def test_legend_labelcolor_linecolor_plot(): # testing line plot fig, ax = plt.subplots() - p = ax.plot(x, c='r', label="red line with a red label") + l, = ax.plot(x, c='r', label="red line with a red label") leg = ax.legend(labelcolor='linecolor') - assert_last_legend_linemarker_color(p, leg, 'r', color=True) + assert_last_legend_linemarker_color(l, leg, 'r', color=True) # testing c, fc, and ec combinations for maker plots - p = ax.plot(x, 'o', c='r', label="red circles with a red label") + l, = ax.plot(x, 'o', c='r', label="red circles with a red label") leg = ax.legend(labelcolor='linecolor') - assert_last_legend_linemarker_color(p, leg, 'r', color=True) + assert_last_legend_linemarker_color(l, leg, 'r', color=True) - p = ax.plot(x, 'o', c='r', mec='b', label="red circles, blue edges, red label") + l, = ax.plot(x, 'o', c='r', mec='b', label="red circles, blue edges, red label") leg = ax.legend(labelcolor='linecolor') - assert_last_legend_linemarker_color(p, leg, 'r', color=True) + assert_last_legend_linemarker_color(l, leg, 'r', color=True) - p = ax.plot(x, 'o', mfc='r', mec='b', label="red circles, blue edges, red label") + l, = ax.plot(x, 'o', mfc='r', mec='b', label="red circles, blue edges, red label") leg = ax.legend(labelcolor='linecolor') - assert_last_legend_linemarker_color(p, leg, 'r', facecolor=True) + assert_last_legend_linemarker_color(l, leg, 'r', facecolor=True) # 'none' cases - p = ax.plot(x, 'o', mfc='none', mec='b', label="blue unfilled circles, blue label") + l, = ax.plot(x, 'o', mfc='none', mec='b', + label="blue unfilled circles, blue label") leg = ax.legend(labelcolor='linecolor') - assert_last_legend_linemarker_color(p, leg, 'b', edgecolor=True) + assert_last_legend_linemarker_color(l, leg, 'b', edgecolor=True) - p = ax.plot(x, 'o', mfc='r', mec='none', label="red edgeless circles, red label") + l, = ax.plot(x, 'o', mfc='r', mec='none', label="red edgeless circles, red label") leg = ax.legend(labelcolor='linecolor') - assert_last_legend_linemarker_color(p, leg, 'r', facecolor=True) + assert_last_legend_linemarker_color(l, leg, 'r', facecolor=True) - p = ax.plot(x, 'o', c='none', mec='none', - label="black label despite invisible circles for dummy entries") + l, = ax.plot(x, 'o', c='none', mec='none', + label="black label despite invisible circles for dummy entries") leg = ax.legend(labelcolor='linecolor') - assert_last_legend_linemarker_color(p, leg, 'k') + assert_last_legend_linemarker_color(l, leg, 'k') def assert_last_legend_scattermarker_color(scatter_marker, leg, expected_color, @@ -1236,31 +1236,31 @@ def test_legend_labelcolor_linecolor_scatter(): # testing c, fc, and ec combinations for scatter plots fig, ax = plt.subplots() - p = ax.scatter(x, x, c='r', label="red circles with a red label") + s = ax.scatter(x, x, c='r', label="red circles with a red label") leg = ax.legend(labelcolor='linecolor') - assert_last_legend_scattermarker_color(p, leg, 'r', facecolor=True) + assert_last_legend_scattermarker_color(s, leg, 'r', facecolor=True) - p = ax.scatter(x, x, c='r', ec='b', label="red circles, blue edges, red label") + s = ax.scatter(x, x, c='r', ec='b', label="red circles, blue edges, red label") leg = ax.legend(labelcolor='linecolor') - assert_last_legend_scattermarker_color(p, leg, 'r', facecolor=True) + assert_last_legend_scattermarker_color(s, leg, 'r', facecolor=True) - p = ax.scatter(x, x, fc='r', ec='b', label="red circles, blue edges, red label") + s = ax.scatter(x, x, fc='r', ec='b', label="red circles, blue edges, red label") leg = ax.legend(labelcolor='linecolor') - assert_last_legend_scattermarker_color(p, leg, 'r', facecolor=True) + assert_last_legend_scattermarker_color(s, leg, 'r', facecolor=True) # 'none' cases - p = ax.scatter(x, x, fc='none', ec='b', label="blue unfilled circles, blue label") + s = ax.scatter(x, x, fc='none', ec='b', label="blue unfilled circles, blue label") leg = ax.legend(labelcolor='linecolor') - assert_last_legend_scattermarker_color(p, leg, 'b', edgecolor=True) + assert_last_legend_scattermarker_color(s, leg, 'b', edgecolor=True) - p = ax.scatter(x, x, fc='r', ec='none', label="red edgeless circles, red label") + s = ax.scatter(x, x, fc='r', ec='none', label="red edgeless circles, red label") leg = ax.legend(labelcolor='linecolor') - assert_last_legend_scattermarker_color(p, leg, 'r', facecolor=True) + assert_last_legend_scattermarker_color(s, leg, 'r', facecolor=True) - p = ax.scatter(x, x, c='none', ec='none', + s = ax.scatter(x, x, c='none', ec='none', label="black label despite invisible circles for dummy entries") leg = ax.legend(labelcolor='linecolor') - assert_last_legend_scattermarker_color(p, leg, 'k') + assert_last_legend_scattermarker_color(s, leg, 'k') @pytest.mark.filterwarnings("ignore:No artists with labels found to put in legend")