Skip to content

Commit c4c5d44

Browse files
Merge pull request #10387 from sinhrks/plot_color_str
BUG: DataFrame.plot raises ValueError when color name is specified by multiple characters
2 parents cbb2673 + 0451bc3 commit c4c5d44

File tree

3 files changed

+87
-2
lines changed

3 files changed

+87
-2
lines changed

doc/source/whatsnew/v0.17.0.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ Bug Fixes
107107

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

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

113113

pandas/tests/test_graphics.py

+60-1
Original file line numberDiff line numberDiff line change
@@ -1146,6 +1146,53 @@ def test_series_grid_settings(self):
11461146
self._check_grid_settings(Series([1,2,3]),
11471147
plotting._series_kinds + plotting._common_kinds)
11481148

1149+
@slow
1150+
def test_standard_colors(self):
1151+
for c in ['r', 'red', 'green', '#FF0000']:
1152+
result = plotting._get_standard_colors(1, color=c)
1153+
self.assertEqual(result, [c])
1154+
1155+
result = plotting._get_standard_colors(1, color=[c])
1156+
self.assertEqual(result, [c])
1157+
1158+
result = plotting._get_standard_colors(3, color=c)
1159+
self.assertEqual(result, [c] * 3)
1160+
1161+
result = plotting._get_standard_colors(3, color=[c])
1162+
self.assertEqual(result, [c] * 3)
1163+
1164+
@slow
1165+
def test_standard_colors_all(self):
1166+
import matplotlib.colors as colors
1167+
1168+
# multiple colors like mediumaquamarine
1169+
for c in colors.cnames:
1170+
result = plotting._get_standard_colors(num_colors=1, color=c)
1171+
self.assertEqual(result, [c])
1172+
1173+
result = plotting._get_standard_colors(num_colors=1, color=[c])
1174+
self.assertEqual(result, [c])
1175+
1176+
result = plotting._get_standard_colors(num_colors=3, color=c)
1177+
self.assertEqual(result, [c] * 3)
1178+
1179+
result = plotting._get_standard_colors(num_colors=3, color=[c])
1180+
self.assertEqual(result, [c] * 3)
1181+
1182+
# single letter colors like k
1183+
for c in colors.ColorConverter.colors:
1184+
result = plotting._get_standard_colors(num_colors=1, color=c)
1185+
self.assertEqual(result, [c])
1186+
1187+
result = plotting._get_standard_colors(num_colors=1, color=[c])
1188+
self.assertEqual(result, [c])
1189+
1190+
result = plotting._get_standard_colors(num_colors=3, color=c)
1191+
self.assertEqual(result, [c] * 3)
1192+
1193+
result = plotting._get_standard_colors(num_colors=3, color=[c])
1194+
self.assertEqual(result, [c] * 3)
1195+
11491196

11501197
@tm.mplskip
11511198
class TestDataFramePlots(TestPlotBase):
@@ -1736,7 +1783,6 @@ def test_bar_colors(self):
17361783

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

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

17631809
ax = df.ix[:, [0]].plot(kind='bar', color='DodgerBlue')
17641810
self._check_colors([ax.patches[0]], facecolors=['DodgerBlue'])
1811+
tm.close()
1812+
1813+
ax = df.plot(kind='bar', color='green')
1814+
self._check_colors(ax.patches[::5], facecolors=['green'] * 5)
1815+
tm.close()
17651816

17661817
@slow
17671818
def test_bar_linewidth(self):
@@ -2897,6 +2948,10 @@ def test_line_colors(self):
28972948
ax = df.ix[:, [0]].plot(color='DodgerBlue')
28982949
self._check_colors(ax.lines, linecolors=['DodgerBlue'])
28992950

2951+
ax = df.plot(color='red')
2952+
self._check_colors(ax.get_lines(), linecolors=['red'] * 5)
2953+
tm.close()
2954+
29002955
@slow
29012956
def test_area_colors(self):
29022957
from matplotlib import cm
@@ -2972,6 +3027,10 @@ def test_hist_colors(self):
29723027
ax = df.ix[:, [0]].plot(kind='hist', color='DodgerBlue')
29733028
self._check_colors([ax.patches[0]], facecolors=['DodgerBlue'])
29743029

3030+
ax = df.plot(kind='hist', color='green')
3031+
self._check_colors(ax.patches[::10], facecolors=['green'] * 5)
3032+
tm.close()
3033+
29753034
@slow
29763035
def test_kde_colors(self):
29773036
tm._skip_if_no_scipy()

pandas/tools/plotting.py

+26
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,32 @@ def random_color(column):
134134
else:
135135
raise ValueError("color_type must be either 'default' or 'random'")
136136

137+
if isinstance(colors, compat.string_types):
138+
import matplotlib.colors
139+
conv = matplotlib.colors.ColorConverter()
140+
def _maybe_valid_colors(colors):
141+
try:
142+
[conv.to_rgba(c) for c in colors]
143+
return True
144+
except ValueError:
145+
return False
146+
147+
# check whether the string can be convertable to single color
148+
maybe_single_color = _maybe_valid_colors([colors])
149+
# check whether each character can be convertable to colors
150+
maybe_color_cycle = _maybe_valid_colors(list(colors))
151+
if maybe_single_color and maybe_color_cycle and len(colors) > 1:
152+
msg = ("'{0}' can be parsed as both single color and "
153+
"color cycle. Specify each color using a list "
154+
"like ['{0}'] or {1}")
155+
raise ValueError(msg.format(colors, list(colors)))
156+
elif maybe_single_color:
157+
colors = [colors]
158+
else:
159+
# ``colors`` is regarded as color cycle.
160+
# mpl will raise error any of them is invalid
161+
pass
162+
137163
if len(colors) != num_colors:
138164
multiple = num_colors//len(colors) - 1
139165
mod = num_colors % len(colors)

0 commit comments

Comments
 (0)