Skip to content

BUG/VIS: fix Series.hist so that users can create hist subplots without the mpl API #4414

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 2 commits into from
Jul 31, 2013
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
4 changes: 4 additions & 0 deletions doc/source/release.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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**

Expand Down Expand Up @@ -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
===========
Expand Down
2 changes: 2 additions & 0 deletions doc/source/v0.13.0.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
~~~~~~~~~
Expand Down
75 changes: 47 additions & 28 deletions pandas/tests/test_graphics.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,15 @@
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


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
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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)
Expand All @@ -160,15 +161,15 @@ 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)

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')
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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')

Expand Down Expand Up @@ -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'])

Expand All @@ -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')
Expand Down Expand Up @@ -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
Expand All @@ -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')
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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):
Expand Down Expand Up @@ -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']
Expand All @@ -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'],
Expand All @@ -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)

Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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')


Expand Down Expand Up @@ -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')
Expand 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)
Expand Down Expand Up @@ -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')


Expand Down
14 changes: 11 additions & 3 deletions pandas/tools/plotting.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)):
Expand Down Expand Up @@ -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)
Expand All @@ -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

Expand Down
5 changes: 2 additions & 3 deletions pandas/tseries/tests/test_plotting.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down