Skip to content

Commit d625880

Browse files
authored
Fix legend yerr (#40777)
1 parent 1ad8d5d commit d625880

File tree

4 files changed

+203
-157
lines changed

4 files changed

+203
-157
lines changed

doc/source/whatsnew/v1.3.0.rst

+3-1
Original file line numberDiff line numberDiff line change
@@ -734,7 +734,9 @@ Plotting
734734

735735
- Bug in :func:`scatter_matrix` raising when 2d ``ax`` argument passed (:issue:`16253`)
736736
- Prevent warnings when matplotlib's ``constrained_layout`` is enabled (:issue:`25261`)
737-
-
737+
- Bug in :func:`DataFrame.plot` was showing the wrong colors in the legend if the function was called repeatedly and some calls used ``yerr`` while others didn't (partial fix of :issue:`39522`)
738+
- Bug in :func:`DataFrame.plot` was showing the wrong colors in the legend if the function was called repeatedly and some calls used ``secondary_y`` and others use ``legend=False`` (:issue:`40044`)
739+
738740

739741
Groupby/resample/rolling
740742
^^^^^^^^^^^^^^^^^^^^^^^^

pandas/plotting/_matplotlib/core.py

+5-7
Original file line numberDiff line numberDiff line change
@@ -596,7 +596,7 @@ def _append_legend_handles_labels(self, handle: Artist, label: str) -> None:
596596
self.legend_labels.append(label)
597597

598598
def _make_legend(self):
599-
ax, leg, handle = self._get_ax_legend_handle(self.axes[0])
599+
ax, leg = self._get_ax_legend(self.axes[0])
600600

601601
handles = []
602602
labels = []
@@ -606,7 +606,7 @@ def _make_legend(self):
606606
if leg is not None:
607607
title = leg.get_title().get_text()
608608
# Replace leg.LegendHandles because it misses marker info
609-
handles.extend(handle)
609+
handles = leg.legendHandles
610610
labels = [x.get_text() for x in leg.get_texts()]
611611

612612
if self.legend:
@@ -637,22 +637,20 @@ def _make_legend(self):
637637
if ax.get_visible():
638638
ax.legend(loc="best")
639639

640-
def _get_ax_legend_handle(self, ax: Axes):
640+
def _get_ax_legend(self, ax: Axes):
641641
"""
642-
Take in axes and return ax, legend and handle under different scenarios
642+
Take in axes and return ax and legend under different scenarios
643643
"""
644644
leg = ax.get_legend()
645645

646-
# Get handle from axes
647-
handle, _ = ax.get_legend_handles_labels()
648646
other_ax = getattr(ax, "left_ax", None) or getattr(ax, "right_ax", None)
649647
other_leg = None
650648
if other_ax is not None:
651649
other_leg = other_ax.get_legend()
652650
if leg is None and other_leg is not None:
653651
leg = other_leg
654652
ax = other_ax
655-
return ax, leg, handle
653+
return ax, leg
656654

657655
@cache_readonly
658656
def plt(self):

pandas/tests/plotting/frame/test_frame.py

-149
Original file line numberDiff line numberDiff line change
@@ -1163,127 +1163,6 @@ def test_plot_int_columns(self):
11631163
df = DataFrame(np.random.randn(100, 4)).cumsum()
11641164
_check_plot_works(df.plot, legend=True)
11651165

1166-
def test_df_legend_labels(self):
1167-
kinds = ["line", "bar", "barh", "kde", "area", "hist"]
1168-
df = DataFrame(np.random.rand(3, 3), columns=["a", "b", "c"])
1169-
df2 = DataFrame(np.random.rand(3, 3), columns=["d", "e", "f"])
1170-
df3 = DataFrame(np.random.rand(3, 3), columns=["g", "h", "i"])
1171-
df4 = DataFrame(np.random.rand(3, 3), columns=["j", "k", "l"])
1172-
1173-
for kind in kinds:
1174-
1175-
ax = df.plot(kind=kind, legend=True)
1176-
self._check_legend_labels(ax, labels=df.columns)
1177-
1178-
ax = df2.plot(kind=kind, legend=False, ax=ax)
1179-
self._check_legend_labels(ax, labels=df.columns)
1180-
1181-
ax = df3.plot(kind=kind, legend=True, ax=ax)
1182-
self._check_legend_labels(ax, labels=df.columns.union(df3.columns))
1183-
1184-
ax = df4.plot(kind=kind, legend="reverse", ax=ax)
1185-
expected = list(df.columns.union(df3.columns)) + list(reversed(df4.columns))
1186-
self._check_legend_labels(ax, labels=expected)
1187-
1188-
# Secondary Y
1189-
ax = df.plot(legend=True, secondary_y="b")
1190-
self._check_legend_labels(ax, labels=["a", "b (right)", "c"])
1191-
ax = df2.plot(legend=False, ax=ax)
1192-
self._check_legend_labels(ax, labels=["a", "b (right)", "c"])
1193-
ax = df3.plot(kind="bar", legend=True, secondary_y="h", ax=ax)
1194-
self._check_legend_labels(
1195-
ax, labels=["a", "b (right)", "c", "g", "h (right)", "i"]
1196-
)
1197-
1198-
# Time Series
1199-
ind = date_range("1/1/2014", periods=3)
1200-
df = DataFrame(np.random.randn(3, 3), columns=["a", "b", "c"], index=ind)
1201-
df2 = DataFrame(np.random.randn(3, 3), columns=["d", "e", "f"], index=ind)
1202-
df3 = DataFrame(np.random.randn(3, 3), columns=["g", "h", "i"], index=ind)
1203-
ax = df.plot(legend=True, secondary_y="b")
1204-
self._check_legend_labels(ax, labels=["a", "b (right)", "c"])
1205-
ax = df2.plot(legend=False, ax=ax)
1206-
self._check_legend_labels(ax, labels=["a", "b (right)", "c"])
1207-
ax = df3.plot(legend=True, ax=ax)
1208-
self._check_legend_labels(ax, labels=["a", "b (right)", "c", "g", "h", "i"])
1209-
1210-
# scatter
1211-
ax = df.plot.scatter(x="a", y="b", label="data1")
1212-
self._check_legend_labels(ax, labels=["data1"])
1213-
ax = df2.plot.scatter(x="d", y="e", legend=False, label="data2", ax=ax)
1214-
self._check_legend_labels(ax, labels=["data1"])
1215-
ax = df3.plot.scatter(x="g", y="h", label="data3", ax=ax)
1216-
self._check_legend_labels(ax, labels=["data1", "data3"])
1217-
1218-
# ensure label args pass through and
1219-
# index name does not mutate
1220-
# column names don't mutate
1221-
df5 = df.set_index("a")
1222-
ax = df5.plot(y="b")
1223-
self._check_legend_labels(ax, labels=["b"])
1224-
ax = df5.plot(y="b", label="LABEL_b")
1225-
self._check_legend_labels(ax, labels=["LABEL_b"])
1226-
self._check_text_labels(ax.xaxis.get_label(), "a")
1227-
ax = df5.plot(y="c", label="LABEL_c", ax=ax)
1228-
self._check_legend_labels(ax, labels=["LABEL_b", "LABEL_c"])
1229-
assert df5.columns.tolist() == ["b", "c"]
1230-
1231-
def test_missing_marker_multi_plots_on_same_ax(self):
1232-
# GH 18222
1233-
df = DataFrame(data=[[1, 1, 1, 1], [2, 2, 4, 8]], columns=["x", "r", "g", "b"])
1234-
fig, ax = self.plt.subplots(nrows=1, ncols=3)
1235-
# Left plot
1236-
df.plot(x="x", y="r", linewidth=0, marker="o", color="r", ax=ax[0])
1237-
df.plot(x="x", y="g", linewidth=1, marker="x", color="g", ax=ax[0])
1238-
df.plot(x="x", y="b", linewidth=1, marker="o", color="b", ax=ax[0])
1239-
self._check_legend_labels(ax[0], labels=["r", "g", "b"])
1240-
self._check_legend_marker(ax[0], expected_markers=["o", "x", "o"])
1241-
# Center plot
1242-
df.plot(x="x", y="b", linewidth=1, marker="o", color="b", ax=ax[1])
1243-
df.plot(x="x", y="r", linewidth=0, marker="o", color="r", ax=ax[1])
1244-
df.plot(x="x", y="g", linewidth=1, marker="x", color="g", ax=ax[1])
1245-
self._check_legend_labels(ax[1], labels=["b", "r", "g"])
1246-
self._check_legend_marker(ax[1], expected_markers=["o", "o", "x"])
1247-
# Right plot
1248-
df.plot(x="x", y="g", linewidth=1, marker="x", color="g", ax=ax[2])
1249-
df.plot(x="x", y="b", linewidth=1, marker="o", color="b", ax=ax[2])
1250-
df.plot(x="x", y="r", linewidth=0, marker="o", color="r", ax=ax[2])
1251-
self._check_legend_labels(ax[2], labels=["g", "b", "r"])
1252-
self._check_legend_marker(ax[2], expected_markers=["x", "o", "o"])
1253-
1254-
def test_legend_name(self):
1255-
multi = DataFrame(
1256-
np.random.randn(4, 4),
1257-
columns=[np.array(["a", "a", "b", "b"]), np.array(["x", "y", "x", "y"])],
1258-
)
1259-
multi.columns.names = ["group", "individual"]
1260-
1261-
ax = multi.plot()
1262-
leg_title = ax.legend_.get_title()
1263-
self._check_text_labels(leg_title, "group,individual")
1264-
1265-
df = DataFrame(np.random.randn(5, 5))
1266-
ax = df.plot(legend=True, ax=ax)
1267-
leg_title = ax.legend_.get_title()
1268-
self._check_text_labels(leg_title, "group,individual")
1269-
1270-
df.columns.name = "new"
1271-
ax = df.plot(legend=False, ax=ax)
1272-
leg_title = ax.legend_.get_title()
1273-
self._check_text_labels(leg_title, "group,individual")
1274-
1275-
ax = df.plot(legend=True, ax=ax)
1276-
leg_title = ax.legend_.get_title()
1277-
self._check_text_labels(leg_title, "new")
1278-
1279-
def test_no_legend(self):
1280-
kinds = ["line", "bar", "barh", "kde", "area", "hist"]
1281-
df = DataFrame(np.random.rand(3, 3), columns=["a", "b", "c"])
1282-
1283-
for kind in kinds:
1284-
ax = df.plot(kind=kind, legend=False)
1285-
self._check_legend_labels(ax, visible=False)
1286-
12871166
def test_style_by_column(self):
12881167
import matplotlib.pyplot as plt
12891168

@@ -2160,34 +2039,6 @@ def test_plot_no_numeric_data(self):
21602039
with pytest.raises(TypeError, match="no numeric data to plot"):
21612040
df.plot()
21622041

2163-
def test_missing_markers_legend(self):
2164-
# 14958
2165-
df = DataFrame(np.random.randn(8, 3), columns=["A", "B", "C"])
2166-
ax = df.plot(y=["A"], marker="x", linestyle="solid")
2167-
df.plot(y=["B"], marker="o", linestyle="dotted", ax=ax)
2168-
df.plot(y=["C"], marker="<", linestyle="dotted", ax=ax)
2169-
2170-
self._check_legend_labels(ax, labels=["A", "B", "C"])
2171-
self._check_legend_marker(ax, expected_markers=["x", "o", "<"])
2172-
2173-
def test_missing_markers_legend_using_style(self):
2174-
# 14563
2175-
df = DataFrame(
2176-
{
2177-
"A": [1, 2, 3, 4, 5, 6],
2178-
"B": [2, 4, 1, 3, 2, 4],
2179-
"C": [3, 3, 2, 6, 4, 2],
2180-
"X": [1, 2, 3, 4, 5, 6],
2181-
}
2182-
)
2183-
2184-
fig, ax = self.plt.subplots()
2185-
for kind in "ABC":
2186-
df.plot("X", kind, label=kind, ax=ax, style=".")
2187-
2188-
self._check_legend_labels(ax, labels=["A", "B", "C"])
2189-
self._check_legend_marker(ax, expected_markers=[".", ".", "."])
2190-
21912042
@pytest.mark.parametrize(
21922043
"index_name, old_label, new_label",
21932044
[

0 commit comments

Comments
 (0)