Skip to content

BUG: DataFrame.plot raises ValueError when color name is specified by multiple characters #10387

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 1 commit into from
Jul 1, 2015
Merged
Show file tree
Hide file tree
Changes from all 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
2 changes: 1 addition & 1 deletion doc/source/whatsnew/v0.17.0.txt
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ Bug Fixes

- Bug in ``pd.Series`` when setting a value on an empty ``Series`` whose index has a frequency. (:issue:`10193`)


- Bug in ``DataFrame.plot`` raises ``ValueError`` when color name is specified by multiple characters (:issue:`10387`)
- Bug in ``DataFrame.reset_index`` when index contains `NaT`. (:issue:`10388`)


Expand Down
61 changes: 60 additions & 1 deletion pandas/tests/test_graphics.py
Original file line number Diff line number Diff line change
Expand Up @@ -1146,6 +1146,53 @@ def test_series_grid_settings(self):
self._check_grid_settings(Series([1,2,3]),
plotting._series_kinds + plotting._common_kinds)

@slow
def test_standard_colors(self):
for c in ['r', 'red', 'green', '#FF0000']:
result = plotting._get_standard_colors(1, color=c)
self.assertEqual(result, [c])

result = plotting._get_standard_colors(1, color=[c])
self.assertEqual(result, [c])

result = plotting._get_standard_colors(3, color=c)
self.assertEqual(result, [c] * 3)

result = plotting._get_standard_colors(3, color=[c])
self.assertEqual(result, [c] * 3)

@slow
def test_standard_colors_all(self):
import matplotlib.colors as colors

# multiple colors like mediumaquamarine
for c in colors.cnames:
result = plotting._get_standard_colors(num_colors=1, color=c)
self.assertEqual(result, [c])

result = plotting._get_standard_colors(num_colors=1, color=[c])
self.assertEqual(result, [c])

result = plotting._get_standard_colors(num_colors=3, color=c)
self.assertEqual(result, [c] * 3)

result = plotting._get_standard_colors(num_colors=3, color=[c])
self.assertEqual(result, [c] * 3)

# single letter colors like k
for c in colors.ColorConverter.colors:
result = plotting._get_standard_colors(num_colors=1, color=c)
self.assertEqual(result, [c])

result = plotting._get_standard_colors(num_colors=1, color=[c])
self.assertEqual(result, [c])

result = plotting._get_standard_colors(num_colors=3, color=c)
self.assertEqual(result, [c] * 3)

result = plotting._get_standard_colors(num_colors=3, color=[c])
self.assertEqual(result, [c] * 3)


@tm.mplskip
class TestDataFramePlots(TestPlotBase):
Expand Down Expand Up @@ -1736,7 +1783,6 @@ def test_bar_colors(self):

default_colors = plt.rcParams.get('axes.color_cycle')


df = DataFrame(randn(5, 5))
ax = df.plot(kind='bar')
self._check_colors(ax.patches[::5], facecolors=default_colors[:5])
Expand All @@ -1762,6 +1808,11 @@ def test_bar_colors(self):

ax = df.ix[:, [0]].plot(kind='bar', color='DodgerBlue')
self._check_colors([ax.patches[0]], facecolors=['DodgerBlue'])
tm.close()

ax = df.plot(kind='bar', color='green')
self._check_colors(ax.patches[::5], facecolors=['green'] * 5)
tm.close()

@slow
def test_bar_linewidth(self):
Expand Down Expand Up @@ -2897,6 +2948,10 @@ def test_line_colors(self):
ax = df.ix[:, [0]].plot(color='DodgerBlue')
self._check_colors(ax.lines, linecolors=['DodgerBlue'])

ax = df.plot(color='red')
self._check_colors(ax.get_lines(), linecolors=['red'] * 5)
tm.close()

@slow
def test_area_colors(self):
from matplotlib import cm
Expand Down Expand Up @@ -2972,6 +3027,10 @@ def test_hist_colors(self):
ax = df.ix[:, [0]].plot(kind='hist', color='DodgerBlue')
self._check_colors([ax.patches[0]], facecolors=['DodgerBlue'])

ax = df.plot(kind='hist', color='green')
self._check_colors(ax.patches[::10], facecolors=['green'] * 5)
tm.close()

@slow
def test_kde_colors(self):
tm._skip_if_no_scipy()
Expand Down
26 changes: 26 additions & 0 deletions pandas/tools/plotting.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,32 @@ def random_color(column):
else:
raise ValueError("color_type must be either 'default' or 'random'")

if isinstance(colors, compat.string_types):
import matplotlib.colors
conv = matplotlib.colors.ColorConverter()
def _maybe_valid_colors(colors):
try:
[conv.to_rgba(c) for c in colors]
return True
except ValueError:
return False

# check whether the string can be convertable to single color
maybe_single_color = _maybe_valid_colors([colors])
# check whether each character can be convertable to colors
maybe_color_cycle = _maybe_valid_colors(list(colors))
if maybe_single_color and maybe_color_cycle and len(colors) > 1:
msg = ("'{0}' can be parsed as both single color and "
"color cycle. Specify each color using a list "
"like ['{0}'] or {1}")
raise ValueError(msg.format(colors, list(colors)))
elif maybe_single_color:
colors = [colors]
else:
# ``colors`` is regarded as color cycle.
# mpl will raise error any of them is invalid
pass

if len(colors) != num_colors:
multiple = num_colors//len(colors) - 1
mod = num_colors % len(colors)
Expand Down