Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

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)

AltStyle によって変換されたページ (->オリジナル) /