Skip to content

Commit 8a21e19

Browse files
committed
ENH/BUG: color cannot be applied to line subplots
1 parent 39fa180 commit 8a21e19

File tree

3 files changed

+114
-25
lines changed

3 files changed

+114
-25
lines changed

doc/source/whatsnew/v0.16.1.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ Bug Fixes
119119
- Bug in unequal comparisons between a ``Series`` of dtype `"category"` and a scalar (e.g. ``Series(Categorical(list("abc"), categories=list("cba"), ordered=True)) > "b"``, which wouldn't use the order of the categories but use the lexicographical order. (:issue:`9848`)
120120

121121

122-
122+
- Bug in ``DataFrame.plot(kind='line')`` cannot accept multiple colors when ``subplots=True`` (:issue:`9894`)
123123

124124

125125

pandas/tests/test_graphics.py

+87
Original file line numberDiff line numberDiff line change
@@ -2800,6 +2800,48 @@ def test_line_colors(self):
28002800
ax = df.ix[:, [0]].plot(color='DodgerBlue')
28012801
self._check_colors(ax.lines, linecolors=['DodgerBlue'])
28022802

2803+
@slow
2804+
def test_line_colors_and_styles_subplots(self):
2805+
from matplotlib import cm
2806+
2807+
custom_colors = 'rgcby'
2808+
df = DataFrame(randn(5, 5))
2809+
2810+
axes = df.plot(subplots=True)
2811+
for ax, c in zip(axes, list(custom_colors)):
2812+
self._check_colors(ax.get_lines(), linecolors=['k'])
2813+
tm.close()
2814+
2815+
axes = df.plot(color=custom_colors, subplots=True)
2816+
for ax, c in zip(axes, list(custom_colors)):
2817+
self._check_colors(ax.get_lines(), linecolors=[c])
2818+
tm.close()
2819+
2820+
rgba_colors = lmap(cm.jet, np.linspace(0, 1, len(df)))
2821+
for cmap in ['jet', cm.jet]:
2822+
axes = df.plot(colormap=cmap, subplots=True)
2823+
for ax, c in zip(axes, rgba_colors):
2824+
self._check_colors(ax.get_lines(), linecolors=[c])
2825+
tm.close()
2826+
2827+
# make color a list if plotting one column frame
2828+
# handles cases like df.plot(color='DodgerBlue')
2829+
axes = df.ix[:, [0]].plot(color='DodgerBlue', subplots=True)
2830+
self._check_colors(axes[0].lines, linecolors=['DodgerBlue'])
2831+
2832+
# single character style
2833+
axes = df.plot(style='r', subplots=True)
2834+
for ax in axes:
2835+
self._check_colors(ax.get_lines(), linecolors=['r'])
2836+
tm.close()
2837+
2838+
# list of styles
2839+
styles = list('rgcby')
2840+
axes = df.plot(style=styles, subplots=True)
2841+
for ax, c in zip(axes, styles):
2842+
self._check_colors(ax.get_lines(), linecolors=[c])
2843+
tm.close()
2844+
28032845
@slow
28042846
def test_area_colors(self):
28052847
from matplotlib import cm
@@ -2898,6 +2940,51 @@ def test_kde_colors(self):
28982940
rgba_colors = lmap(cm.jet, np.linspace(0, 1, len(df)))
28992941
self._check_colors(ax.get_lines(), linecolors=rgba_colors)
29002942

2943+
@slow
2944+
def test_kde_colors_and_styles_subplots(self):
2945+
tm._skip_if_no_scipy()
2946+
_skip_if_no_scipy_gaussian_kde()
2947+
2948+
from matplotlib import cm
2949+
2950+
custom_colors = 'rgcby'
2951+
df = DataFrame(randn(5, 5))
2952+
2953+
axes = df.plot(kind='kde', subplots=True)
2954+
for ax, c in zip(axes, list(custom_colors)):
2955+
self._check_colors(ax.get_lines(), linecolors=['k'])
2956+
tm.close()
2957+
2958+
axes = df.plot(kind='kde', color=custom_colors, subplots=True)
2959+
for ax, c in zip(axes, list(custom_colors)):
2960+
self._check_colors(ax.get_lines(), linecolors=[c])
2961+
tm.close()
2962+
2963+
rgba_colors = lmap(cm.jet, np.linspace(0, 1, len(df)))
2964+
for cmap in ['jet', cm.jet]:
2965+
axes = df.plot(kind='kde', colormap=cmap, subplots=True)
2966+
for ax, c in zip(axes, rgba_colors):
2967+
self._check_colors(ax.get_lines(), linecolors=[c])
2968+
tm.close()
2969+
2970+
# make color a list if plotting one column frame
2971+
# handles cases like df.plot(color='DodgerBlue')
2972+
axes = df.ix[:, [0]].plot(kind='kde', color='DodgerBlue', subplots=True)
2973+
self._check_colors(axes[0].lines, linecolors=['DodgerBlue'])
2974+
2975+
# single character style
2976+
axes = df.plot(kind='kde', style='r', subplots=True)
2977+
for ax in axes:
2978+
self._check_colors(ax.get_lines(), linecolors=['r'])
2979+
tm.close()
2980+
2981+
# list of styles
2982+
styles = list('rgcby')
2983+
axes = df.plot(kind='kde', style=styles, subplots=True)
2984+
for ax, c in zip(axes, styles):
2985+
self._check_colors(ax.get_lines(), linecolors=[c])
2986+
tm.close()
2987+
29012988
@slow
29022989
def test_boxplot_colors(self):
29032990

pandas/tools/plotting.py

+26-24
Original file line numberDiff line numberDiff line change
@@ -1250,36 +1250,39 @@ def on_right(self, i):
12501250
if isinstance(self.secondary_y, (tuple, list, np.ndarray, Index)):
12511251
return self.data.columns[i] in self.secondary_y
12521252

1253-
def _get_style(self, i, col_name):
1254-
style = ''
1255-
if self.subplots:
1256-
style = 'k'
1253+
def _get_colors(self, num_colors=None, color_kwds='color'):
1254+
if num_colors is None:
1255+
num_colors = self.nseries
1256+
1257+
return _get_standard_colors(num_colors=num_colors,
1258+
colormap=self.colormap,
1259+
color=self.kwds.get(color_kwds))
12571260

1261+
def _apply_style_colors(self, colors, kwds, col_num, label):
1262+
"""
1263+
Manage style and color based on column number and its label.
1264+
Returns tuple of appropriate style and kwds which "color" may be added.
1265+
"""
1266+
style = None
12581267
if self.style is not None:
12591268
if isinstance(self.style, list):
12601269
try:
1261-
style = self.style[i]
1270+
style = self.style[col_num]
12621271
except IndexError:
12631272
pass
12641273
elif isinstance(self.style, dict):
1265-
style = self.style.get(col_name, style)
1274+
style = self.style.get(label, style)
12661275
else:
12671276
style = self.style
12681277

1269-
return style or None
1270-
1271-
def _get_colors(self, num_colors=None, color_kwds='color'):
1272-
if num_colors is None:
1273-
num_colors = self.nseries
1274-
1275-
return _get_standard_colors(num_colors=num_colors,
1276-
colormap=self.colormap,
1277-
color=self.kwds.get(color_kwds))
1278-
1279-
def _maybe_add_color(self, colors, kwds, style, i):
12801278
has_color = 'color' in kwds or self.colormap is not None
1281-
if has_color and (style is None or re.match('[a-z]+', style) is None):
1282-
kwds['color'] = colors[i % len(colors)]
1279+
if has_color:
1280+
if style is None or re.match('[a-z]+', style) is None:
1281+
kwds['color'] = colors[col_num % len(colors)]
1282+
else:
1283+
if self.subplots and style is None:
1284+
style = 'k'
1285+
return style, kwds
12831286

12841287
def _parse_errorbars(self, label, err):
12851288
'''
@@ -1600,9 +1603,8 @@ def _make_plot(self):
16001603
colors = self._get_colors()
16011604
for i, (label, y) in enumerate(it):
16021605
ax = self._get_ax(i)
1603-
style = self._get_style(i, label)
16041606
kwds = self.kwds.copy()
1605-
self._maybe_add_color(colors, kwds, style, i)
1607+
style, kwds = self._apply_style_colors(colors, kwds, i, label)
16061608

16071609
errors = self._get_errorbars(label=label, index=i)
16081610
kwds = dict(kwds, **errors)
@@ -1956,13 +1958,13 @@ def _make_plot(self):
19561958
colors = self._get_colors()
19571959
for i, (label, y) in enumerate(self._iter_data()):
19581960
ax = self._get_ax(i)
1959-
style = self._get_style(i, label)
1960-
label = com.pprint_thing(label)
19611961

19621962
kwds = self.kwds.copy()
1963+
1964+
label = com.pprint_thing(label)
19631965
kwds['label'] = label
1964-
self._maybe_add_color(colors, kwds, style, i)
19651966

1967+
style, kwds = self._apply_style_colors(colors, kwds, i, label)
19661968
if style is not None:
19671969
kwds['style'] = style
19681970

0 commit comments

Comments
 (0)