diff --git a/doc/source/release.rst b/doc/source/release.rst index a2b525a737879..90f7585ba7ab9 100644 --- a/doc/source/release.rst +++ b/doc/source/release.rst @@ -44,6 +44,8 @@ pandas 0.13 - Text parser now treats anything that reads like inf ("inf", "Inf", "-Inf", "iNf", etc.) to infinity. (:issue:`4220`, :issue:`4219`), affecting ``read_table``, ``read_csv``, etc. + - Added a more informative error message when plot arguments contain + overlapping color and style arguments (:issue:`4402`) **API Changes** @@ -98,6 +100,8 @@ pandas 0.13 with the usecols parameter (:issue: `3192`) - Fix an issue in merging blocks where the resulting DataFrame had partially set _ref_locs (:issue:`4403`) + - Fixed an issue where hist subplots were being overwritten when they were + called using the top level matplotlib API (:issue:`4408`) pandas 0.12 =========== diff --git a/doc/source/v0.13.0.txt b/doc/source/v0.13.0.txt index 2d46507f061a5..0a62322fa2996 100644 --- a/doc/source/v0.13.0.txt +++ b/doc/source/v0.13.0.txt @@ -38,6 +38,8 @@ Enhancements ``ValueError`` (:issue:`4303`, :issue:`4305`) - Added a test for ``read_clipboard()`` and ``to_clipboard()`` (:issue:`4282`) - Clipboard functionality now works with PySide (:issue:`4282`) + - Added a more informative error message when plot arguments contain + overlapping color and style arguments (:issue:`4402`) Bug Fixes ~~~~~~~~~ diff --git a/pandas/tests/test_graphics.py b/pandas/tests/test_graphics.py index b1fbbc797f743..faaac1cbb5419 100644 --- a/pandas/tests/test_graphics.py +++ b/pandas/tests/test_graphics.py @@ -6,7 +6,7 @@ from datetime import datetime, date from pandas import Series, DataFrame, MultiIndex, PeriodIndex, date_range -from pandas.compat import range, lrange, StringIO, lmap, lzip, u, map, zip +from pandas.compat import range, lrange, StringIO, lmap, lzip, u, zip import pandas.util.testing as tm from pandas.util.testing import ensure_clean from pandas.core.config import set_option @@ -14,6 +14,7 @@ import numpy as np from numpy import random +from numpy.random import randn from numpy.testing import assert_array_equal from numpy.testing.decorators import slow @@ -64,7 +65,7 @@ def test_plot(self): _check_plot_works(self.series[:5].plot, kind='barh') _check_plot_works(self.series[:10].plot, kind='barh') - Series(np.random.randn(10)).plot(kind='bar', color='black') + Series(randn(10)).plot(kind='bar', color='black') # figsize and title import matplotlib.pyplot as plt @@ -84,7 +85,7 @@ def test_bar_colors(self): custom_colors = 'rgcby' plt.close('all') - df = DataFrame(np.random.randn(5, 5)) + df = DataFrame(randn(5, 5)) ax = df.plot(kind='bar') rects = ax.patches @@ -141,7 +142,7 @@ def test_bar_colors(self): @slow def test_bar_linewidth(self): - df = DataFrame(np.random.randn(5, 5)) + df = DataFrame(randn(5, 5)) # regular ax = df.plot(kind='bar', linewidth=2) @@ -160,7 +161,7 @@ def test_bar_linewidth(self): self.assert_(r.get_linewidth() == 2) def test_rotation(self): - df = DataFrame(np.random.randn(5, 5)) + df = DataFrame(randn(5, 5)) ax = df.plot(rot=30) for l in ax.get_xticklabels(): self.assert_(l.get_rotation() == 30) @@ -168,7 +169,7 @@ def test_rotation(self): def test_irregular_datetime(self): rng = date_range('1/1/2000', '3/1/2000') rng = rng[[0, 1, 2, 3, 5, 9, 10, 11, 12]] - ser = Series(np.random.randn(len(rng)), rng) + ser = Series(randn(len(rng)), rng) ax = ser.plot() xp = datetime(1999, 1, 1).toordinal() ax.set_xlim('1/1/1999', '1/1/2001') @@ -224,6 +225,25 @@ def test_hist_layout_with_by(self): _check_plot_works(df.weight.hist, by=df.category, layout=(4, 1)) plt.close('all') + @slow + def test_hist_no_overlap(self): + from matplotlib.pyplot import subplot, gcf, close + x = Series(randn(2)) + y = Series(randn(2)) + subplot(121) + x.hist() + subplot(122) + y.hist() + fig = gcf() + axes = fig.get_axes() + self.assertEqual(len(axes), 2) + close('all') + + @slow + def test_plot_fails_with_dupe_color_and_style(self): + x = Series(randn(2)) + self.assertRaises(ValueError, x.plot, style='k--', color='k') + def test_plot_fails_when_ax_differs_from_figure(self): from pylab import figure fig1 = figure() @@ -362,7 +382,7 @@ def test_nonnumeric_exclude(self): def test_label(self): import matplotlib.pyplot as plt plt.close('all') - df = DataFrame(np.random.randn(10, 3), columns=['a', 'b', 'c']) + df = DataFrame(randn(10, 3), columns=['a', 'b', 'c']) ax = df.plot(x='a', y='b') self.assert_(ax.xaxis.get_label().get_text() == 'a') @@ -487,7 +507,7 @@ def test_subplots(self): @slow def test_plot_bar(self): - df = DataFrame(np.random.randn(6, 4), + df = DataFrame(randn(6, 4), index=list(string.ascii_letters[:6]), columns=['one', 'two', 'three', 'four']) @@ -496,7 +516,7 @@ def test_plot_bar(self): _check_plot_works(df.plot, kind='bar', subplots=True) _check_plot_works(df.plot, kind='bar', stacked=True) - df = DataFrame(np.random.randn(10, 15), + df = DataFrame(randn(10, 15), index=list(string.ascii_letters[:10]), columns=lrange(15)) _check_plot_works(df.plot, kind='bar') @@ -537,7 +557,7 @@ def test_bar_log(self): @slow def test_boxplot(self): - df = DataFrame(np.random.randn(6, 4), + df = DataFrame(randn(6, 4), index=list(string.ascii_letters[:6]), columns=['one', 'two', 'three', 'four']) df['indic'] = ['foo', 'bar'] * 3 @@ -563,7 +583,7 @@ def test_boxplot(self): @slow def test_kde(self): _skip_if_no_scipy() - df = DataFrame(np.random.randn(100, 4)) + df = DataFrame(randn(100, 4)) _check_plot_works(df.plot, kind='kde') _check_plot_works(df.plot, kind='kde', subplots=True) ax = df.plot(kind='kde') @@ -575,21 +595,21 @@ def test_kde(self): @slow def test_hist(self): import matplotlib.pyplot as plt - df = DataFrame(np.random.randn(100, 4)) + df = DataFrame(randn(100, 4)) _check_plot_works(df.hist) _check_plot_works(df.hist, grid=False) # make sure layout is handled - df = DataFrame(np.random.randn(100, 3)) + df = DataFrame(randn(100, 3)) _check_plot_works(df.hist) axes = df.hist(grid=False) self.assert_(not axes[1, 1].get_visible()) - df = DataFrame(np.random.randn(100, 1)) + df = DataFrame(randn(100, 1)) _check_plot_works(df.hist) # make sure layout is handled - df = DataFrame(np.random.randn(100, 6)) + df = DataFrame(randn(100, 6)) _check_plot_works(df.hist) # make sure sharex, sharey is handled @@ -641,7 +661,7 @@ def test_hist(self): def test_hist_layout(self): import matplotlib.pyplot as plt plt.close('all') - df = DataFrame(np.random.randn(100, 4)) + df = DataFrame(randn(100, 4)) layout_to_expected_size = ( {'layout': None, 'expected_size': (2, 2)}, # default is 2x2 @@ -666,8 +686,7 @@ def test_hist_layout(self): def test_scatter(self): _skip_if_no_scipy() - df = DataFrame(np.random.randn(100, 4)) - df = DataFrame(np.random.randn(100, 2)) + df = DataFrame(randn(100, 2)) import pandas.tools.plotting as plt def scat(**kwds): @@ -730,11 +749,11 @@ def test_radviz(self): @slow def test_plot_int_columns(self): - df = DataFrame(np.random.randn(100, 4)).cumsum() + df = DataFrame(randn(100, 4)).cumsum() _check_plot_works(df.plot, legend=True) def test_legend_name(self): - multi = DataFrame(np.random.randn(4, 4), + multi = DataFrame(randn(4, 4), columns=[np.array(['a', 'a', 'b', 'b']), np.array(['x', 'y', 'x', 'y'])]) multi.columns.names = ['group', 'individual'] @@ -751,7 +770,7 @@ def test_style_by_column(self): import matplotlib.pyplot as plt fig = plt.gcf() - df = DataFrame(np.random.randn(100, 3)) + df = DataFrame(randn(100, 3)) for markers in [{0: '^', 1: '+', 2: 'o'}, {0: '^', 1: '+'}, ['^', '+', 'o'], @@ -771,7 +790,7 @@ def test_line_colors(self): custom_colors = 'rgcby' plt.close('all') - df = DataFrame(np.random.randn(5, 5)) + df = DataFrame(randn(5, 5)) ax = df.plot(color=custom_colors) @@ -826,7 +845,7 @@ def test_default_color_cycle(self): plt.rcParams['axes.color_cycle'] = list('rgbk') plt.close('all') - df = DataFrame(np.random.randn(5, 3)) + df = DataFrame(randn(5, 3)) ax = df.plot() lines = ax.get_lines() @@ -856,13 +875,13 @@ def test_all_invalid_plot_data(self): @slow def test_partially_invalid_plot_data(self): kinds = 'line', 'bar', 'barh', 'kde', 'density' - df = DataFrame(np.random.randn(10, 2), dtype=object) + df = DataFrame(randn(10, 2), dtype=object) df[np.random.rand(df.shape[0]) > 0.5] = 'a' for kind in kinds: self.assertRaises(TypeError, df.plot, kind=kind) def test_invalid_kind(self): - df = DataFrame(np.random.randn(10, 2)) + df = DataFrame(randn(10, 2)) self.assertRaises(ValueError, df.plot, kind='aasdf') @@ -919,7 +938,7 @@ def test_time_series_plot_color_kwargs(self): def test_time_series_plot_color_with_empty_kwargs(self): import matplotlib as mpl import matplotlib.pyplot as plt - + def_colors = mpl.rcParams['axes.color_cycle'] plt.close('all') @@ -933,7 +952,7 @@ def test_time_series_plot_color_with_empty_kwargs(self): @slow def test_grouped_hist(self): import matplotlib.pyplot as plt - df = DataFrame(np.random.randn(500, 2), columns=['A', 'B']) + df = DataFrame(randn(500, 2), columns=['A', 'B']) df['C'] = np.random.randint(0, 4, 500) axes = plotting.grouped_hist(df.A, by=df.C) self.assert_(len(axes.ravel()) == 4) @@ -1036,7 +1055,7 @@ def test_option_mpl_style(self): pass def test_invalid_colormap(self): - df = DataFrame(np.random.randn(3, 2), columns=['A', 'B']) + df = DataFrame(randn(3, 2), columns=['A', 'B']) self.assertRaises(ValueError, df.plot, colormap='invalid_colormap') diff --git a/pandas/tools/plotting.py b/pandas/tools/plotting.py index 3e3fff32a654a..5deff90244135 100644 --- a/pandas/tools/plotting.py +++ b/pandas/tools/plotting.py @@ -821,6 +821,14 @@ def _validate_color_args(self): warnings.warn("'color' and 'colormap' cannot be used " "simultaneously. Using 'color'") + if 'color' in self.kwds and self.style is not None: + # need only a single match + if re.match('^[a-z]+?', self.style) is not None: + 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") + def _iter_data(self): from pandas.core.frame import DataFrame if isinstance(self.data, (Series, np.ndarray)): @@ -2026,7 +2034,7 @@ def hist_series(self, by=None, ax=None, grid=True, xlabelsize=None, """ import matplotlib.pyplot as plt - fig = kwds.get('figure', plt.gcf() + fig = kwds.get('figure', _gcf() if plt.get_fignums() else plt.figure(figsize=figsize)) if figsize is not None and tuple(figsize) != tuple(fig.get_size_inches()): fig.set_size_inches(*figsize, forward=True) @@ -2036,8 +2044,8 @@ def hist_series(self, by=None, ax=None, grid=True, xlabelsize=None, raise ValueError("The 'layout' keyword is not supported when " "'by' is None") if ax is None: - ax = fig.add_subplot(111) - if ax.get_figure() != fig: + ax = fig.gca() + elif ax.get_figure() != fig: raise AssertionError('passed axis not bound to passed figure') values = self.dropna().values diff --git a/pandas/tseries/tests/test_plotting.py b/pandas/tseries/tests/test_plotting.py index 717e7bfe5da96..87cb65601bdd9 100644 --- a/pandas/tseries/tests/test_plotting.py +++ b/pandas/tseries/tests/test_plotting.py @@ -127,11 +127,10 @@ def test_both_style_and_color(self): plt.close('all') ts = tm.makeTimeSeries() - ts.plot(style='b-', color='#000099') # works + self.assertRaises(ValueError, ts.plot, style='b-', color='#000099') - plt.close('all') s = ts.reset_index(drop=True) - s.plot(style='b-', color='#000099') # non-tsplot + self.assertRaises(ValueError, s.plot, style='b-', color='#000099') @slow def test_high_freq(self):