Skip to content

Commit 06cf4fa

Browse files
committed
ENH: add more informative error message when dupe style and color args are given
1 parent 5ab4f2e commit 06cf4fa

File tree

5 files changed

+60
-43
lines changed

5 files changed

+60
-43
lines changed

doc/source/release.rst

+2
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ pandas 0.13
4444
- Text parser now treats anything that reads like inf ("inf", "Inf", "-Inf",
4545
"iNf", etc.) to infinity. (:issue:`4220`, :issue:`4219`), affecting
4646
``read_table``, ``read_csv``, etc.
47+
- Added a more informative error message when plot arguments contain
48+
overlapping color and style arguments (:issue:`4402`)
4749

4850
**API Changes**
4951

doc/source/v0.13.0.txt

+2
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ Enhancements
3838
``ValueError`` (:issue:`4303`, :issue:`4305`)
3939
- Added a test for ``read_clipboard()`` and ``to_clipboard()`` (:issue:`4282`)
4040
- Clipboard functionality now works with PySide (:issue:`4282`)
41+
- Added a more informative error message when plot arguments contain
42+
overlapping color and style arguments (:issue:`4402`)
4143

4244
Bug Fixes
4345
~~~~~~~~~

pandas/tests/test_graphics.py

+46-40
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,15 @@
66
from datetime import datetime, date
77

88
from pandas import Series, DataFrame, MultiIndex, PeriodIndex, date_range
9-
from pandas.compat import range, lrange, StringIO, lmap, lzip, u, map, zip
9+
from pandas.compat import range, lrange, StringIO, lmap, lzip, u, zip
1010
import pandas.util.testing as tm
1111
from pandas.util.testing import ensure_clean
1212
from pandas.core.config import set_option
1313

1414

1515
import numpy as np
1616
from numpy import random
17+
from numpy.random import randn
1718

1819
from numpy.testing import assert_array_equal
1920
from numpy.testing.decorators import slow
@@ -64,7 +65,7 @@ def test_plot(self):
6465
_check_plot_works(self.series[:5].plot, kind='barh')
6566
_check_plot_works(self.series[:10].plot, kind='barh')
6667

67-
Series(np.random.randn(10)).plot(kind='bar', color='black')
68+
Series(randn(10)).plot(kind='bar', color='black')
6869

6970
# figsize and title
7071
import matplotlib.pyplot as plt
@@ -84,7 +85,7 @@ def test_bar_colors(self):
8485
custom_colors = 'rgcby'
8586

8687
plt.close('all')
87-
df = DataFrame(np.random.randn(5, 5))
88+
df = DataFrame(randn(5, 5))
8889
ax = df.plot(kind='bar')
8990

9091
rects = ax.patches
@@ -141,7 +142,7 @@ def test_bar_colors(self):
141142

142143
@slow
143144
def test_bar_linewidth(self):
144-
df = DataFrame(np.random.randn(5, 5))
145+
df = DataFrame(randn(5, 5))
145146

146147
# regular
147148
ax = df.plot(kind='bar', linewidth=2)
@@ -160,15 +161,15 @@ def test_bar_linewidth(self):
160161
self.assert_(r.get_linewidth() == 2)
161162

162163
def test_rotation(self):
163-
df = DataFrame(np.random.randn(5, 5))
164+
df = DataFrame(randn(5, 5))
164165
ax = df.plot(rot=30)
165166
for l in ax.get_xticklabels():
166167
self.assert_(l.get_rotation() == 30)
167168

168169
def test_irregular_datetime(self):
169170
rng = date_range('1/1/2000', '3/1/2000')
170171
rng = rng[[0, 1, 2, 3, 5, 9, 10, 11, 12]]
171-
ser = Series(np.random.randn(len(rng)), rng)
172+
ser = Series(randn(len(rng)), rng)
172173
ax = ser.plot()
173174
xp = datetime(1999, 1, 1).toordinal()
174175
ax.set_xlim('1/1/1999', '1/1/2001')
@@ -224,6 +225,25 @@ def test_hist_layout_with_by(self):
224225
_check_plot_works(df.weight.hist, by=df.category, layout=(4, 1))
225226
plt.close('all')
226227

228+
@slow
229+
def test_hist_no_overlap(self):
230+
from matplotlib.pyplot import subplot, gcf, close
231+
x = Series(randn(2))
232+
y = Series(randn(2))
233+
subplot(121)
234+
x.hist()
235+
subplot(122)
236+
y.hist()
237+
fig = gcf()
238+
axes = fig.get_axes()
239+
self.assertEqual(len(axes), 2)
240+
close('all')
241+
242+
@slow
243+
def test_plot_fails_with_dupe_color_and_style(self):
244+
x = Series(randn(2))
245+
self.assertRaises(ValueError, x.plot, style='k--', color='k')
246+
227247
def test_plot_fails_when_ax_differs_from_figure(self):
228248
from pylab import figure
229249
fig1 = figure()
@@ -362,7 +382,7 @@ def test_nonnumeric_exclude(self):
362382
def test_label(self):
363383
import matplotlib.pyplot as plt
364384
plt.close('all')
365-
df = DataFrame(np.random.randn(10, 3), columns=['a', 'b', 'c'])
385+
df = DataFrame(randn(10, 3), columns=['a', 'b', 'c'])
366386
ax = df.plot(x='a', y='b')
367387
self.assert_(ax.xaxis.get_label().get_text() == 'a')
368388

@@ -487,7 +507,7 @@ def test_subplots(self):
487507

488508
@slow
489509
def test_plot_bar(self):
490-
df = DataFrame(np.random.randn(6, 4),
510+
df = DataFrame(randn(6, 4),
491511
index=list(string.ascii_letters[:6]),
492512
columns=['one', 'two', 'three', 'four'])
493513

@@ -496,7 +516,7 @@ def test_plot_bar(self):
496516
_check_plot_works(df.plot, kind='bar', subplots=True)
497517
_check_plot_works(df.plot, kind='bar', stacked=True)
498518

499-
df = DataFrame(np.random.randn(10, 15),
519+
df = DataFrame(randn(10, 15),
500520
index=list(string.ascii_letters[:10]),
501521
columns=lrange(15))
502522
_check_plot_works(df.plot, kind='bar')
@@ -537,7 +557,7 @@ def test_bar_log(self):
537557

538558
@slow
539559
def test_boxplot(self):
540-
df = DataFrame(np.random.randn(6, 4),
560+
df = DataFrame(randn(6, 4),
541561
index=list(string.ascii_letters[:6]),
542562
columns=['one', 'two', 'three', 'four'])
543563
df['indic'] = ['foo', 'bar'] * 3
@@ -563,7 +583,7 @@ def test_boxplot(self):
563583
@slow
564584
def test_kde(self):
565585
_skip_if_no_scipy()
566-
df = DataFrame(np.random.randn(100, 4))
586+
df = DataFrame(randn(100, 4))
567587
_check_plot_works(df.plot, kind='kde')
568588
_check_plot_works(df.plot, kind='kde', subplots=True)
569589
ax = df.plot(kind='kde')
@@ -575,21 +595,21 @@ def test_kde(self):
575595
@slow
576596
def test_hist(self):
577597
import matplotlib.pyplot as plt
578-
df = DataFrame(np.random.randn(100, 4))
598+
df = DataFrame(randn(100, 4))
579599
_check_plot_works(df.hist)
580600
_check_plot_works(df.hist, grid=False)
581601

582602
# make sure layout is handled
583-
df = DataFrame(np.random.randn(100, 3))
603+
df = DataFrame(randn(100, 3))
584604
_check_plot_works(df.hist)
585605
axes = df.hist(grid=False)
586606
self.assert_(not axes[1, 1].get_visible())
587607

588-
df = DataFrame(np.random.randn(100, 1))
608+
df = DataFrame(randn(100, 1))
589609
_check_plot_works(df.hist)
590610

591611
# make sure layout is handled
592-
df = DataFrame(np.random.randn(100, 6))
612+
df = DataFrame(randn(100, 6))
593613
_check_plot_works(df.hist)
594614

595615
# make sure sharex, sharey is handled
@@ -641,7 +661,7 @@ def test_hist(self):
641661
def test_hist_layout(self):
642662
import matplotlib.pyplot as plt
643663
plt.close('all')
644-
df = DataFrame(np.random.randn(100, 4))
664+
df = DataFrame(randn(100, 4))
645665

646666
layout_to_expected_size = (
647667
{'layout': None, 'expected_size': (2, 2)}, # default is 2x2
@@ -662,25 +682,11 @@ def test_hist_layout(self):
662682
# invalid format for layout
663683
self.assertRaises(ValueError, df.hist, layout=(1,))
664684

665-
@slow
666-
def test_hist_no_overlap(self):
667-
from matplotlib.pyplot import subplot, close, gcf
668-
x = Series(np.random.randn(2))
669-
y = Series(np.random.randn(2))
670-
subplot(121)
671-
x.hist()
672-
subplot(122)
673-
y.hist()
674-
fig = gcf()
675-
axes = fig.get_axes()
676-
self.assertEqual(len(axes), 2)
677-
close('all')
678-
679685
@slow
680686
def test_scatter(self):
681687
_skip_if_no_scipy()
682688

683-
df = DataFrame(np.random.randn(100, 2))
689+
df = DataFrame(randn(100, 2))
684690
import pandas.tools.plotting as plt
685691

686692
def scat(**kwds):
@@ -743,11 +749,11 @@ def test_radviz(self):
743749

744750
@slow
745751
def test_plot_int_columns(self):
746-
df = DataFrame(np.random.randn(100, 4)).cumsum()
752+
df = DataFrame(randn(100, 4)).cumsum()
747753
_check_plot_works(df.plot, legend=True)
748754

749755
def test_legend_name(self):
750-
multi = DataFrame(np.random.randn(4, 4),
756+
multi = DataFrame(randn(4, 4),
751757
columns=[np.array(['a', 'a', 'b', 'b']),
752758
np.array(['x', 'y', 'x', 'y'])])
753759
multi.columns.names = ['group', 'individual']
@@ -764,7 +770,7 @@ def test_style_by_column(self):
764770
import matplotlib.pyplot as plt
765771
fig = plt.gcf()
766772

767-
df = DataFrame(np.random.randn(100, 3))
773+
df = DataFrame(randn(100, 3))
768774
for markers in [{0: '^', 1: '+', 2: 'o'},
769775
{0: '^', 1: '+'},
770776
['^', '+', 'o'],
@@ -784,7 +790,7 @@ def test_line_colors(self):
784790
custom_colors = 'rgcby'
785791

786792
plt.close('all')
787-
df = DataFrame(np.random.randn(5, 5))
793+
df = DataFrame(randn(5, 5))
788794

789795
ax = df.plot(color=custom_colors)
790796

@@ -839,7 +845,7 @@ def test_default_color_cycle(self):
839845
plt.rcParams['axes.color_cycle'] = list('rgbk')
840846

841847
plt.close('all')
842-
df = DataFrame(np.random.randn(5, 3))
848+
df = DataFrame(randn(5, 3))
843849
ax = df.plot()
844850

845851
lines = ax.get_lines()
@@ -869,13 +875,13 @@ def test_all_invalid_plot_data(self):
869875
@slow
870876
def test_partially_invalid_plot_data(self):
871877
kinds = 'line', 'bar', 'barh', 'kde', 'density'
872-
df = DataFrame(np.random.randn(10, 2), dtype=object)
878+
df = DataFrame(randn(10, 2), dtype=object)
873879
df[np.random.rand(df.shape[0]) > 0.5] = 'a'
874880
for kind in kinds:
875881
self.assertRaises(TypeError, df.plot, kind=kind)
876882

877883
def test_invalid_kind(self):
878-
df = DataFrame(np.random.randn(10, 2))
884+
df = DataFrame(randn(10, 2))
879885
self.assertRaises(ValueError, df.plot, kind='aasdf')
880886

881887

@@ -946,7 +952,7 @@ def test_time_series_plot_color_with_empty_kwargs(self):
946952
@slow
947953
def test_grouped_hist(self):
948954
import matplotlib.pyplot as plt
949-
df = DataFrame(np.random.randn(500, 2), columns=['A', 'B'])
955+
df = DataFrame(randn(500, 2), columns=['A', 'B'])
950956
df['C'] = np.random.randint(0, 4, 500)
951957
axes = plotting.grouped_hist(df.A, by=df.C)
952958
self.assert_(len(axes.ravel()) == 4)
@@ -1049,7 +1055,7 @@ def test_option_mpl_style(self):
10491055
pass
10501056

10511057
def test_invalid_colormap(self):
1052-
df = DataFrame(np.random.randn(3, 2), columns=['A', 'B'])
1058+
df = DataFrame(randn(3, 2), columns=['A', 'B'])
10531059
self.assertRaises(ValueError, df.plot, colormap='invalid_colormap')
10541060

10551061

pandas/tools/plotting.py

+8
Original file line numberDiff line numberDiff line change
@@ -821,6 +821,14 @@ def _validate_color_args(self):
821821
warnings.warn("'color' and 'colormap' cannot be used "
822822
"simultaneously. Using 'color'")
823823

824+
if 'color' in self.kwds and self.style is not None:
825+
# need only a single match
826+
if re.match('^[a-z]+?', self.style) is not None:
827+
raise ValueError("Cannot pass 'style' string with a color "
828+
"symbol and 'color' keyword argument. Please"
829+
" use one or the other or pass 'style' "
830+
"without a color symbol")
831+
824832
def _iter_data(self):
825833
from pandas.core.frame import DataFrame
826834
if isinstance(self.data, (Series, np.ndarray)):

pandas/tseries/tests/test_plotting.py

+2-3
Original file line numberDiff line numberDiff line change
@@ -127,11 +127,10 @@ def test_both_style_and_color(self):
127127
plt.close('all')
128128

129129
ts = tm.makeTimeSeries()
130-
ts.plot(style='b-', color='#000099') # works
130+
self.assertRaises(ValueError, ts.plot, style='b-', color='#000099')
131131

132-
plt.close('all')
133132
s = ts.reset_index(drop=True)
134-
s.plot(style='b-', color='#000099') # non-tsplot
133+
self.assertRaises(ValueError, s.plot, style='b-', color='#000099')
135134

136135
@slow
137136
def test_high_freq(self):

0 commit comments

Comments
 (0)