diff --git a/doc/source/whatsnew/v0.21.0.txt b/doc/source/whatsnew/v0.21.0.txt index 722e19d2703b5..7dcee381a068d 100644 --- a/doc/source/whatsnew/v0.21.0.txt +++ b/doc/source/whatsnew/v0.21.0.txt @@ -524,6 +524,8 @@ Plotting ^^^^^^^^ - Bug in plotting methods using ``secondary_y`` and ``fontsize`` not setting secondary axis font size (:issue:`12565`) - Bug when plotting ``timedelta`` and ``datetime`` dtypes on y-axis (:issue:`16953`) +- Bug in ``Series.plot.bar`` or ``DataFramee.plot.bar`` with ``y`` not respecting user-passed ``color`` (:issue:`16822`) + Groupby/Resample/Rolling ^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/pandas/plotting/_core.py b/pandas/plotting/_core.py index a0b7e93efd05c..029ea3c416757 100644 --- a/pandas/plotting/_core.py +++ b/pandas/plotting/_core.py @@ -1150,6 +1150,9 @@ class BarPlot(MPLPlot): orientation = 'vertical' def __init__(self, data, **kwargs): + # we have to treat a series differently than a + # 1-column DataFrame w.r.t. color handling + self._is_series = isinstance(data, ABCSeries) self.bar_width = kwargs.pop('width', 0.5) pos = kwargs.pop('position', 0.5) kwargs.setdefault('align', 'center') @@ -1204,7 +1207,10 @@ def _make_plot(self): for i, (label, y) in enumerate(self._iter_data(fillna=0)): ax = self._get_ax(i) kwds = self.kwds.copy() - kwds['color'] = colors[i % ncolors] + if self._is_series: + kwds['color'] = colors + else: + kwds['color'] = colors[i % ncolors] errors = self._get_errorbars(label=label, index=i) kwds = dict(kwds, **errors) diff --git a/pandas/tests/plotting/test_frame.py b/pandas/tests/plotting/test_frame.py index f3b287a8889c3..545680ed70797 100644 --- a/pandas/tests/plotting/test_frame.py +++ b/pandas/tests/plotting/test_frame.py @@ -807,6 +807,20 @@ def test_bar_colors(self): self._check_colors(ax.patches[::5], facecolors=['green'] * 5) tm.close() + def test_bar_user_colors(self): + df = pd.DataFrame({"A": range(4), + "B": range(1, 5), + "color": ['red', 'blue', 'blue', 'red']}) + # This should *only* work when `y` is specified, else + # we use one color per column + ax = df.plot.bar(y='A', color=df['color']) + result = [p.get_facecolor() for p in ax.patches] + expected = [(1., 0., 0., 1.), + (0., 0., 1., 1.), + (0., 0., 1., 1.), + (1., 0., 0., 1.)] + assert result == expected + @pytest.mark.slow def test_bar_linewidth(self): df = DataFrame(randn(5, 5)) diff --git a/pandas/tests/plotting/test_series.py b/pandas/tests/plotting/test_series.py index 8164ad74a190a..2c708ecd39073 100644 --- a/pandas/tests/plotting/test_series.py +++ b/pandas/tests/plotting/test_series.py @@ -258,6 +258,16 @@ def test_bar_ignore_index(self): ax = df.plot.bar(use_index=False, ax=ax) self._check_text_labels(ax.get_xticklabels(), ['0', '1', '2', '3']) + def test_bar_user_colors(self): + s = Series([1, 2, 3, 4]) + ax = s.plot.bar(color=['red', 'blue', 'blue', 'red']) + result = [p.get_facecolor() for p in ax.patches] + expected = [(1., 0., 0., 1.), + (0., 0., 1., 1.), + (0., 0., 1., 1.), + (1., 0., 0., 1.)] + assert result == expected + def test_rotation(self): df = DataFrame(randn(5, 5)) # Default rot 0