Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit f0fde11

Browse files
authored
Merge pull request matplotlib#30328 from lukashergt/fix-legend-labelcolor-linecolor
Fix legend `labelcolor=‘linecolor’` to handle various corner cases, e.g. step histograms and transparent markers
2 parents b132b5b + 2a149cb commit f0fde11

File tree

2 files changed

+215
-13
lines changed

2 files changed

+215
-13
lines changed

lib/matplotlib/legend.py

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -576,7 +576,11 @@ def __init__(
576576
# set the text color
577577

578578
color_getters = { # getter function depends on line or patch
579-
'linecolor': ['get_color', 'get_facecolor'],
579+
'linecolor': ['get_markerfacecolor',
580+
'get_facecolor',
581+
'get_markeredgecolor',
582+
'get_edgecolor',
583+
'get_color'],
580584
'markerfacecolor': ['get_markerfacecolor', 'get_facecolor'],
581585
'mfc': ['get_markerfacecolor', 'get_facecolor'],
582586
'markeredgecolor': ['get_markeredgecolor', 'get_edgecolor'],
@@ -595,19 +599,22 @@ def __init__(
595599
for getter_name in getter_names:
596600
try:
597601
color = getattr(handle, getter_name)()
598-
if isinstance(color, np.ndarray):
599-
if (
600-
color.shape[0] == 1
601-
or np.isclose(color, color[0]).all()
602-
):
603-
text.set_color(color[0])
604-
else:
605-
pass
606-
else:
607-
text.set_color(color)
608-
break
609602
except AttributeError:
610-
pass
603+
continue
604+
if isinstance(color, np.ndarray):
605+
if color.size == 0:
606+
continue
607+
elif (color.shape[0] == 1 or np.isclose(color, color[0]).all()):
608+
text.set_color(color[0])
609+
else:
610+
pass
611+
elif cbook._str_lower_equal(color, 'none'):
612+
continue
613+
elif mpl.colors.to_rgba(color)[3] == 0:
614+
continue
615+
else:
616+
text.set_color(color)
617+
break
611618
elif cbook._str_equal(labelcolor, 'none'):
612619
for text in self.texts:
613620
text.set_color(labelcolor)

lib/matplotlib/tests/test_legend.py

Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1068,6 +1068,201 @@ def test_legend_labelcolor_rcparam_markerfacecolor_short():
10681068
assert mpl.colors.same_color(text.get_color(), color)
10691069

10701070

1071+
def assert_last_legend_patch_color(histogram, leg, expected_color,
1072+
facecolor=False, edgecolor=False):
1073+
"""
1074+
Check that histogram color, legend handle color, and legend label color all
1075+
match the expected input. Provide facecolor and edgecolor flags to clarify
1076+
which feature to match.
1077+
"""
1078+
label_color = leg.texts[-1].get_color()
1079+
patch = leg.get_patches()[-1]
1080+
histogram = histogram[-1][0]
1081+
assert mpl.colors.same_color(label_color, expected_color)
1082+
if facecolor:
1083+
assert mpl.colors.same_color(label_color, patch.get_facecolor())
1084+
assert mpl.colors.same_color(label_color, histogram.get_facecolor())
1085+
if edgecolor:
1086+
assert mpl.colors.same_color(label_color, patch.get_edgecolor())
1087+
assert mpl.colors.same_color(label_color, histogram.get_edgecolor())
1088+
1089+
1090+
def test_legend_labelcolor_linecolor_histograms():
1091+
x = np.arange(10)
1092+
1093+
# testing c kwarg for bar, step, and stepfilled histograms
1094+
fig, ax = plt.subplots()
1095+
h = ax.hist(x, histtype='bar', color='r', label="red bar hist with a red label")
1096+
leg = ax.legend(labelcolor='linecolor')
1097+
assert_last_legend_patch_color(h, leg, 'r', facecolor=True)
1098+
1099+
h = ax.hist(x, histtype='step', color='g', label="green step hist, green label")
1100+
leg = ax.legend(labelcolor='linecolor')
1101+
assert_last_legend_patch_color(h, leg, 'g', edgecolor=True)
1102+
1103+
h = ax.hist(x, histtype='stepfilled', color='b',
1104+
label="blue stepfilled hist with a blue label")
1105+
leg = ax.legend(labelcolor='linecolor')
1106+
assert_last_legend_patch_color(h, leg, 'b', facecolor=True)
1107+
1108+
# testing c, fc, and ec combinations for bar histograms
1109+
h = ax.hist(x, histtype='bar', color='r', ec='b',
1110+
label="red bar hist with blue edges and a red label")
1111+
leg = ax.legend(labelcolor='linecolor')
1112+
assert_last_legend_patch_color(h, leg, 'r', facecolor=True)
1113+
1114+
h = ax.hist(x, histtype='bar', fc='r', ec='b',
1115+
label="red bar hist with blue edges and a red label")
1116+
leg = ax.legend(labelcolor='linecolor')
1117+
assert_last_legend_patch_color(h, leg, 'r', facecolor=True)
1118+
1119+
h = ax.hist(x, histtype='bar', fc='none', ec='b',
1120+
label="unfilled blue bar hist with a blue label")
1121+
leg = ax.legend(labelcolor='linecolor')
1122+
assert_last_legend_patch_color(h, leg, 'b', edgecolor=True)
1123+
1124+
# testing c, and ec combinations for step histograms
1125+
h = ax.hist(x, histtype='step', color='r', ec='b',
1126+
label="blue step hist with a blue label")
1127+
leg = ax.legend(labelcolor='linecolor')
1128+
assert_last_legend_patch_color(h, leg, 'b', edgecolor=True)
1129+
1130+
h = ax.hist(x, histtype='step', ec='b',
1131+
label="blue step hist with a blue label")
1132+
leg = ax.legend(labelcolor='linecolor')
1133+
assert_last_legend_patch_color(h, leg, 'b', edgecolor=True)
1134+
1135+
# testing c, fc, and ec combinations for stepfilled histograms
1136+
h = ax.hist(x, histtype='stepfilled', color='r', ec='b',
1137+
label="red stepfilled hist, blue edges, red label")
1138+
leg = ax.legend(labelcolor='linecolor')
1139+
assert_last_legend_patch_color(h, leg, 'r', facecolor=True)
1140+
1141+
h = ax.hist(x, histtype='stepfilled', fc='r', ec='b',
1142+
label="red stepfilled hist, blue edges, red label")
1143+
leg = ax.legend(labelcolor='linecolor')
1144+
assert_last_legend_patch_color(h, leg, 'r', facecolor=True)
1145+
1146+
h = ax.hist(x, histtype='stepfilled', fc='none', ec='b',
1147+
label="unfilled blue stepfilled hist, blue label")
1148+
leg = ax.legend(labelcolor='linecolor')
1149+
assert_last_legend_patch_color(h, leg, 'b', edgecolor=True)
1150+
1151+
h = ax.hist(x, histtype='stepfilled', fc='r', ec='none',
1152+
label="edgeless red stepfilled hist with a red label")
1153+
leg = ax.legend(labelcolor='linecolor')
1154+
assert_last_legend_patch_color(h, leg, 'r', facecolor=True)
1155+
1156+
1157+
def assert_last_legend_linemarker_color(line_marker, leg, expected_color, color=False,
1158+
facecolor=False, edgecolor=False):
1159+
"""
1160+
Check that line marker color, legend handle color, and legend label color all
1161+
match the expected input. Provide color, facecolor and edgecolor flags to clarify
1162+
which feature to match.
1163+
"""
1164+
label_color = leg.texts[-1].get_color()
1165+
leg_marker = leg.get_lines()[-1]
1166+
assert mpl.colors.same_color(label_color, expected_color)
1167+
if color:
1168+
assert mpl.colors.same_color(label_color, leg_marker.get_color())
1169+
assert mpl.colors.same_color(label_color, line_marker.get_color())
1170+
if facecolor:
1171+
assert mpl.colors.same_color(label_color, leg_marker.get_markerfacecolor())
1172+
assert mpl.colors.same_color(label_color, line_marker.get_markerfacecolor())
1173+
if edgecolor:
1174+
assert mpl.colors.same_color(label_color, leg_marker.get_markeredgecolor())
1175+
assert mpl.colors.same_color(label_color, line_marker.get_markeredgecolor())
1176+
1177+
1178+
def test_legend_labelcolor_linecolor_plot():
1179+
x = np.arange(5)
1180+
1181+
# testing line plot
1182+
fig, ax = plt.subplots()
1183+
l, = ax.plot(x, c='r', label="red line with a red label")
1184+
leg = ax.legend(labelcolor='linecolor')
1185+
assert_last_legend_linemarker_color(l, leg, 'r', color=True)
1186+
1187+
# testing c, fc, and ec combinations for maker plots
1188+
l, = ax.plot(x, 'o', c='r', label="red circles with a red label")
1189+
leg = ax.legend(labelcolor='linecolor')
1190+
assert_last_legend_linemarker_color(l, leg, 'r', color=True)
1191+
1192+
l, = ax.plot(x, 'o', c='r', mec='b', label="red circles, blue edges, red label")
1193+
leg = ax.legend(labelcolor='linecolor')
1194+
assert_last_legend_linemarker_color(l, leg, 'r', color=True)
1195+
1196+
l, = ax.plot(x, 'o', mfc='r', mec='b', label="red circles, blue edges, red label")
1197+
leg = ax.legend(labelcolor='linecolor')
1198+
assert_last_legend_linemarker_color(l, leg, 'r', facecolor=True)
1199+
1200+
# 'none' cases
1201+
l, = ax.plot(x, 'o', mfc='none', mec='b',
1202+
label="blue unfilled circles, blue label")
1203+
leg = ax.legend(labelcolor='linecolor')
1204+
assert_last_legend_linemarker_color(l, leg, 'b', edgecolor=True)
1205+
1206+
l, = ax.plot(x, 'o', mfc='r', mec='none', label="red edgeless circles, red label")
1207+
leg = ax.legend(labelcolor='linecolor')
1208+
assert_last_legend_linemarker_color(l, leg, 'r', facecolor=True)
1209+
1210+
l, = ax.plot(x, 'o', c='none', mec='none',
1211+
label="black label despite invisible circles for dummy entries")
1212+
leg = ax.legend(labelcolor='linecolor')
1213+
assert_last_legend_linemarker_color(l, leg, 'k')
1214+
1215+
1216+
def assert_last_legend_scattermarker_color(scatter_marker, leg, expected_color,
1217+
facecolor=False, edgecolor=False):
1218+
"""
1219+
Check that scatter marker color, legend handle color, and legend label color all
1220+
match the expected input. Provide facecolor and edgecolor flags to clarify
1221+
which feature to match.
1222+
"""
1223+
label_color = leg.texts[-1].get_color()
1224+
leg_handle = leg.legend_handles[-1]
1225+
assert mpl.colors.same_color(label_color, expected_color)
1226+
if facecolor:
1227+
assert mpl.colors.same_color(label_color, leg_handle.get_facecolor())
1228+
assert mpl.colors.same_color(label_color, scatter_marker.get_facecolor())
1229+
if edgecolor:
1230+
assert mpl.colors.same_color(label_color, leg_handle.get_edgecolor())
1231+
assert mpl.colors.same_color(label_color, scatter_marker.get_edgecolor())
1232+
1233+
1234+
def test_legend_labelcolor_linecolor_scatter():
1235+
x = np.arange(5)
1236+
1237+
# testing c, fc, and ec combinations for scatter plots
1238+
fig, ax = plt.subplots()
1239+
s = ax.scatter(x, x, c='r', label="red circles with a red label")
1240+
leg = ax.legend(labelcolor='linecolor')
1241+
assert_last_legend_scattermarker_color(s, leg, 'r', facecolor=True)
1242+
1243+
s = ax.scatter(x, x, c='r', ec='b', label="red circles, blue edges, red label")
1244+
leg = ax.legend(labelcolor='linecolor')
1245+
assert_last_legend_scattermarker_color(s, leg, 'r', facecolor=True)
1246+
1247+
s = ax.scatter(x, x, fc='r', ec='b', label="red circles, blue edges, red label")
1248+
leg = ax.legend(labelcolor='linecolor')
1249+
assert_last_legend_scattermarker_color(s, leg, 'r', facecolor=True)
1250+
1251+
# 'none' cases
1252+
s = ax.scatter(x, x, fc='none', ec='b', label="blue unfilled circles, blue label")
1253+
leg = ax.legend(labelcolor='linecolor')
1254+
assert_last_legend_scattermarker_color(s, leg, 'b', edgecolor=True)
1255+
1256+
s = ax.scatter(x, x, fc='r', ec='none', label="red edgeless circles, red label")
1257+
leg = ax.legend(labelcolor='linecolor')
1258+
assert_last_legend_scattermarker_color(s, leg, 'r', facecolor=True)
1259+
1260+
s = ax.scatter(x, x, c='none', ec='none',
1261+
label="black label despite invisible circles for dummy entries")
1262+
leg = ax.legend(labelcolor='linecolor')
1263+
assert_last_legend_scattermarker_color(s, leg, 'k')
1264+
1265+
10711266
@pytest.mark.filterwarnings("ignore:No artists with labels found to put in legend")
10721267
def test_get_set_draggable():
10731268
legend = plt.legend()

0 commit comments

Comments
 (0)