Skip to content

BUG: repair 'style' kwd handling in DataFrame.plot (#21003) #33821

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 20 commits into from
Sep 5, 2020
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions doc/source/whatsnew/v1.1.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -593,6 +593,7 @@ Plotting
- Bug in :meth:`DataFrame.plot.hist` where weights are not working for multiple columns (:issue:`33173`)
- Bug in :meth:`DataFrame.boxplot` and :meth:`DataFrame.plot.boxplot` lost color attributes of ``medianprops``, ``whiskerprops``, ``capprops`` and ``medianprops`` (:issue:`30346`)
- Bug in :meth:`DataFrame.plot.scatter` that when adding multiple plots with different ``cmap``, colorbars alway use the first ``cmap`` (:issue:`33389`)
- Bug in :meth:`DataFrame.plot` where valid style kwds were rejected (:issue:`21003`)


Groupby/resample/rolling
Expand Down
30 changes: 20 additions & 10 deletions pandas/plotting/_matplotlib/core.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import re
from typing import Optional
import warnings

Expand Down Expand Up @@ -193,7 +192,6 @@ def __init__(
self._validate_color_args()

def _validate_color_args(self):
import matplotlib.colors

if (
"color" in self.kwds
Expand Down Expand Up @@ -226,13 +224,25 @@ def _validate_color_args(self):
styles = [self.style]
# need only a single match
for s in styles:
for char in s:
if char in matplotlib.colors.BASE_COLORS:
raise ValueError(
"Cannot pass 'style' string with a color symbol and "
"'color' keyword argument. Please use one or the other or "
"pass 'style' without a color symbol"
)
if self._color_in_style(s):
raise ValueError(
"Cannot pass 'style' string with a color symbol and "
"'color' keyword argument. Please use one or the "
"other or pass 'style' without a color symbol"
)

@staticmethod
def _color_in_style(style):
"""
Is there a color letter in the style string?

Returns
-------
bool
"""
from matplotlib.colors import BASE_COLORS

return not set(BASE_COLORS).isdisjoint(style)

def _iter_data(self, data=None, keep_index=False, fillna=None):
if data is None:
Expand Down Expand Up @@ -723,7 +733,7 @@ def _apply_style_colors(self, colors, kwds, col_num, label):
style = self.style

has_color = "color" in kwds or self.colormap is not None
nocolor_style = style is None or re.match("[a-z]+", style) is None
nocolor_style = style is None or not self._color_in_style(style)
if (has_color or self.subplots) and nocolor_style:
if isinstance(colors, dict):
kwds["color"] = colors[label]
Expand Down
17 changes: 17 additions & 0 deletions pandas/tests/plotting/test_frame.py
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,23 @@ def test_color_and_style_arguments(self):
with pytest.raises(ValueError):
df.plot(color=["red", "black"], style=["k-", "r--"])

def test_color_and_marker(self):
# GH21003 2018-05-10
df = DataFrame(np.random.random((7, 4)))
# combining a color string and a marker letter should be allowed
df.plot(color="green", style="d") # d for diamond
Copy link
Member

@charlesdong1991 charlesdong1991 May 17, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could we also check color and style here?
something like:

ax = df.plot(color="green", style="d")
assert ax.lines[0].get_color() == 'green'
assert ax.lines[0].get_marker() == 'd'

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see my reply below.


def test_color_list_and_marker(self):
# GH21003 2018-04-23
df = DataFrame(np.random.random((7, 4)))
# combining a color list and a marker letter should be allowed
color = ["yellow", "red", "green", "blue"]
ax = df.plot(color=color, style="d")
output_colors = [line.get_color() for line in ax.lines]
assert output_colors == color # each "line" is one of the four colors
# In the Github bug the color list was passed to MPL like this:
# ax.lines[i].get_color() == ['yellow', 'red', 'green', 'blue']

def test_nonnumeric_exclude(self):
df = DataFrame({"A": ["x", "y", "z"], "B": [1, 2, 3]})
ax = df.plot()
Expand Down
2 changes: 1 addition & 1 deletion pandas/tests/plotting/test_series.py
Original file line number Diff line number Diff line change
Expand Up @@ -933,4 +933,4 @@ def test_plot_no_numeric_data(self):
def test_style_single_ok(self):
s = pd.Series([1, 2])
ax = s.plot(style="s", color="C3")
assert ax.lines[0].get_color() == ["C3"]
assert ax.lines[0].get_color() == "C3"