Skip to content

Commit

Permalink
Fix legend yerr (#40777)
Browse files Browse the repository at this point in the history
  • Loading branch information
MarcoGorelli authored Apr 9, 2021
1 parent 1ad8d5d commit d625880
Show file tree
Hide file tree
Showing 4 changed files with 203 additions and 157 deletions.
4 changes: 3 additions & 1 deletion doc/source/whatsnew/v1.3.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -734,7 +734,9 @@ Plotting

- Bug in :func:`scatter_matrix` raising when 2d ``ax`` argument passed (:issue:`16253`)
- Prevent warnings when matplotlib's ``constrained_layout`` is enabled (:issue:`25261`)
-
- 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`)
- 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`)


Groupby/resample/rolling
^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down
12 changes: 5 additions & 7 deletions pandas/plotting/_matplotlib/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -596,7 +596,7 @@ def _append_legend_handles_labels(self, handle: Artist, label: str) -> None:
self.legend_labels.append(label)

def _make_legend(self):
ax, leg, handle = self._get_ax_legend_handle(self.axes[0])
ax, leg = self._get_ax_legend(self.axes[0])

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

if self.legend:
Expand Down Expand Up @@ -637,22 +637,20 @@ def _make_legend(self):
if ax.get_visible():
ax.legend(loc="best")

def _get_ax_legend_handle(self, ax: Axes):
def _get_ax_legend(self, ax: Axes):
"""
Take in axes and return ax, legend and handle under different scenarios
Take in axes and return ax and legend under different scenarios
"""
leg = ax.get_legend()

# Get handle from axes
handle, _ = ax.get_legend_handles_labels()
other_ax = getattr(ax, "left_ax", None) or getattr(ax, "right_ax", None)
other_leg = None
if other_ax is not None:
other_leg = other_ax.get_legend()
if leg is None and other_leg is not None:
leg = other_leg
ax = other_ax
return ax, leg, handle
return ax, leg

@cache_readonly
def plt(self):
Expand Down
149 changes: 0 additions & 149 deletions pandas/tests/plotting/frame/test_frame.py
Original file line number Diff line number Diff line change
Expand Up @@ -1163,127 +1163,6 @@ def test_plot_int_columns(self):
df = DataFrame(np.random.randn(100, 4)).cumsum()
_check_plot_works(df.plot, legend=True)

def test_df_legend_labels(self):
kinds = ["line", "bar", "barh", "kde", "area", "hist"]
df = DataFrame(np.random.rand(3, 3), columns=["a", "b", "c"])
df2 = DataFrame(np.random.rand(3, 3), columns=["d", "e", "f"])
df3 = DataFrame(np.random.rand(3, 3), columns=["g", "h", "i"])
df4 = DataFrame(np.random.rand(3, 3), columns=["j", "k", "l"])

for kind in kinds:

ax = df.plot(kind=kind, legend=True)
self._check_legend_labels(ax, labels=df.columns)

ax = df2.plot(kind=kind, legend=False, ax=ax)
self._check_legend_labels(ax, labels=df.columns)

ax = df3.plot(kind=kind, legend=True, ax=ax)
self._check_legend_labels(ax, labels=df.columns.union(df3.columns))

ax = df4.plot(kind=kind, legend="reverse", ax=ax)
expected = list(df.columns.union(df3.columns)) + list(reversed(df4.columns))
self._check_legend_labels(ax, labels=expected)

# Secondary Y
ax = df.plot(legend=True, secondary_y="b")
self._check_legend_labels(ax, labels=["a", "b (right)", "c"])
ax = df2.plot(legend=False, ax=ax)
self._check_legend_labels(ax, labels=["a", "b (right)", "c"])
ax = df3.plot(kind="bar", legend=True, secondary_y="h", ax=ax)
self._check_legend_labels(
ax, labels=["a", "b (right)", "c", "g", "h (right)", "i"]
)

# Time Series
ind = date_range("1/1/2014", periods=3)
df = DataFrame(np.random.randn(3, 3), columns=["a", "b", "c"], index=ind)
df2 = DataFrame(np.random.randn(3, 3), columns=["d", "e", "f"], index=ind)
df3 = DataFrame(np.random.randn(3, 3), columns=["g", "h", "i"], index=ind)
ax = df.plot(legend=True, secondary_y="b")
self._check_legend_labels(ax, labels=["a", "b (right)", "c"])
ax = df2.plot(legend=False, ax=ax)
self._check_legend_labels(ax, labels=["a", "b (right)", "c"])
ax = df3.plot(legend=True, ax=ax)
self._check_legend_labels(ax, labels=["a", "b (right)", "c", "g", "h", "i"])

# scatter
ax = df.plot.scatter(x="a", y="b", label="data1")
self._check_legend_labels(ax, labels=["data1"])
ax = df2.plot.scatter(x="d", y="e", legend=False, label="data2", ax=ax)
self._check_legend_labels(ax, labels=["data1"])
ax = df3.plot.scatter(x="g", y="h", label="data3", ax=ax)
self._check_legend_labels(ax, labels=["data1", "data3"])

# ensure label args pass through and
# index name does not mutate
# column names don't mutate
df5 = df.set_index("a")
ax = df5.plot(y="b")
self._check_legend_labels(ax, labels=["b"])
ax = df5.plot(y="b", label="LABEL_b")
self._check_legend_labels(ax, labels=["LABEL_b"])
self._check_text_labels(ax.xaxis.get_label(), "a")
ax = df5.plot(y="c", label="LABEL_c", ax=ax)
self._check_legend_labels(ax, labels=["LABEL_b", "LABEL_c"])
assert df5.columns.tolist() == ["b", "c"]

def test_missing_marker_multi_plots_on_same_ax(self):
# GH 18222
df = DataFrame(data=[[1, 1, 1, 1], [2, 2, 4, 8]], columns=["x", "r", "g", "b"])
fig, ax = self.plt.subplots(nrows=1, ncols=3)
# Left plot
df.plot(x="x", y="r", linewidth=0, marker="o", color="r", ax=ax[0])
df.plot(x="x", y="g", linewidth=1, marker="x", color="g", ax=ax[0])
df.plot(x="x", y="b", linewidth=1, marker="o", color="b", ax=ax[0])
self._check_legend_labels(ax[0], labels=["r", "g", "b"])
self._check_legend_marker(ax[0], expected_markers=["o", "x", "o"])
# Center plot
df.plot(x="x", y="b", linewidth=1, marker="o", color="b", ax=ax[1])
df.plot(x="x", y="r", linewidth=0, marker="o", color="r", ax=ax[1])
df.plot(x="x", y="g", linewidth=1, marker="x", color="g", ax=ax[1])
self._check_legend_labels(ax[1], labels=["b", "r", "g"])
self._check_legend_marker(ax[1], expected_markers=["o", "o", "x"])
# Right plot
df.plot(x="x", y="g", linewidth=1, marker="x", color="g", ax=ax[2])
df.plot(x="x", y="b", linewidth=1, marker="o", color="b", ax=ax[2])
df.plot(x="x", y="r", linewidth=0, marker="o", color="r", ax=ax[2])
self._check_legend_labels(ax[2], labels=["g", "b", "r"])
self._check_legend_marker(ax[2], expected_markers=["x", "o", "o"])

def test_legend_name(self):
multi = DataFrame(
np.random.randn(4, 4),
columns=[np.array(["a", "a", "b", "b"]), np.array(["x", "y", "x", "y"])],
)
multi.columns.names = ["group", "individual"]

ax = multi.plot()
leg_title = ax.legend_.get_title()
self._check_text_labels(leg_title, "group,individual")

df = DataFrame(np.random.randn(5, 5))
ax = df.plot(legend=True, ax=ax)
leg_title = ax.legend_.get_title()
self._check_text_labels(leg_title, "group,individual")

df.columns.name = "new"
ax = df.plot(legend=False, ax=ax)
leg_title = ax.legend_.get_title()
self._check_text_labels(leg_title, "group,individual")

ax = df.plot(legend=True, ax=ax)
leg_title = ax.legend_.get_title()
self._check_text_labels(leg_title, "new")

def test_no_legend(self):
kinds = ["line", "bar", "barh", "kde", "area", "hist"]
df = DataFrame(np.random.rand(3, 3), columns=["a", "b", "c"])

for kind in kinds:
ax = df.plot(kind=kind, legend=False)
self._check_legend_labels(ax, visible=False)

def test_style_by_column(self):
import matplotlib.pyplot as plt

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

def test_missing_markers_legend(self):
# 14958
df = DataFrame(np.random.randn(8, 3), columns=["A", "B", "C"])
ax = df.plot(y=["A"], marker="x", linestyle="solid")
df.plot(y=["B"], marker="o", linestyle="dotted", ax=ax)
df.plot(y=["C"], marker="<", linestyle="dotted", ax=ax)

self._check_legend_labels(ax, labels=["A", "B", "C"])
self._check_legend_marker(ax, expected_markers=["x", "o", "<"])

def test_missing_markers_legend_using_style(self):
# 14563
df = DataFrame(
{
"A": [1, 2, 3, 4, 5, 6],
"B": [2, 4, 1, 3, 2, 4],
"C": [3, 3, 2, 6, 4, 2],
"X": [1, 2, 3, 4, 5, 6],
}
)

fig, ax = self.plt.subplots()
for kind in "ABC":
df.plot("X", kind, label=kind, ax=ax, style=".")

self._check_legend_labels(ax, labels=["A", "B", "C"])
self._check_legend_marker(ax, expected_markers=[".", ".", "."])

@pytest.mark.parametrize(
"index_name, old_label, new_label",
[
Expand Down
Loading

0 comments on commit d625880

Please sign in to comment.