Skip to content

Commit ebc4fed

Browse files
author
Tom Augspurger
committed
release conflict
1 parent 49f3616 commit ebc4fed

File tree

4 files changed

+229
-142
lines changed

4 files changed

+229
-142
lines changed

doc/source/release.rst

+2
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,7 @@ Improvements to existing features
333333
- Arrays of strings can be wrapped to a specified width (``str.wrap``) (:issue:`6999`)
334334
- ``GroupBy.count()`` is now implemented in Cython and is much faster for large
335335
numbers of groups (:issue:`7016`).
336+
- ``boxplot`` now supports ``layout`` keyword (:issue:`6769`)
336337

337338
.. _release.bug_fixes-0.14.0:
338339

@@ -488,6 +489,7 @@ Bug Fixes
488489
- Bug in DatetimeIndex creation from string ndarray with ``dayfirst=True`` (:issue:`5917`)
489490
- Bug in ``MultiIndex.from_arrays`` created from ``DatetimeIndex`` doesn't preserve ``freq`` and ``tz`` (:issue:`7090`)
490491
- Bug in ``unstack`` raises ``ValueError`` when ``MultiIndex`` contains ``PeriodIndex`` (:issue:`4342`)
492+
- Bug in ``boxplot`` and ``hist`` draws unnecessary axes (:issue:`6769`)
491493

492494
pandas 0.13.1
493495
-------------

doc/source/v0.14.0.txt

+2
Original file line numberDiff line numberDiff line change
@@ -391,6 +391,8 @@ Plotting
391391
positional argument ``frame`` instead of ``data``. A ``FutureWarning`` is
392392
raised if the old ``data`` argument is used by name. (:issue:`6956`)
393393

394+
- ``boxplot`` now supports ``layout`` keyword (:issue:`6769`)
395+
394396
.. _whatsnew_0140.prior_deprecations:
395397

396398
Prior Version Deprecations/Changes

pandas/tests/test_graphics.py

+117-31
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
from pandas.compat import range, lrange, StringIO, lmap, lzip, u, zip
1414
import pandas.util.testing as tm
1515
from pandas.util.testing import ensure_clean
16+
import pandas.core.common as com
1617
from pandas.core.config import set_option
1718

1819

@@ -1837,6 +1838,19 @@ def test_errorbar_scatter(self):
18371838

18381839
@tm.mplskip
18391840
class TestDataFrameGroupByPlots(tm.TestCase):
1841+
1842+
def setUp(self):
1843+
n = 100
1844+
with tm.RNGContext(42):
1845+
gender = tm.choice(['Male', 'Female'], size=n)
1846+
classroom = tm.choice(['A', 'B', 'C'], size=n)
1847+
1848+
self.hist_df = DataFrame({'gender': gender,
1849+
'classroom': classroom,
1850+
'height': random.normal(66, 4, size=n),
1851+
'weight': random.normal(161, 32, size=n),
1852+
'category': random.randint(4, size=n)})
1853+
18401854
def tearDown(self):
18411855
tm.close()
18421856

@@ -1924,39 +1938,117 @@ def test_grouped_hist(self):
19241938
with tm.assertRaises(AttributeError):
19251939
plotting.grouped_hist(df.A, by=df.C, foo='bar')
19261940

1941+
def _check_axes_shape(self, axes, axes_num=None, layout=None, figsize=(8.0, 6.0)):
1942+
"""
1943+
Check expected number of axes is drawn in expected layout
1944+
1945+
Parameters
1946+
----------
1947+
axes : matplotlib Axes object, or its list-like
1948+
axes_num : number
1949+
expected number of axes. Unnecessary axes should be set to invisible.
1950+
layout : tuple
1951+
expected layout
1952+
figsize : tuple
1953+
expected figsize. default is matplotlib default
1954+
"""
1955+
visible_axes = self._flatten_visible(axes)
1956+
1957+
if axes_num is not None:
1958+
self.assertEqual(len(visible_axes), axes_num)
1959+
for ax in visible_axes:
1960+
# check something drawn on visible axes
1961+
self.assert_(len(ax.get_children()) > 0)
1962+
1963+
if layout is not None:
1964+
if isinstance(axes, list):
1965+
self.assertEqual((len(axes), ), layout)
1966+
elif isinstance(axes, np.ndarray):
1967+
self.assertEqual(axes.shape, layout)
1968+
else:
1969+
# in case of AxesSubplot
1970+
self.assertEqual((1, ), layout)
1971+
1972+
self.assert_numpy_array_equal(np.round(visible_axes[0].figure.get_size_inches()),
1973+
np.array(figsize))
1974+
1975+
def _flatten_visible(self, axes):
1976+
axes = plotting._flatten(axes)
1977+
axes = [ax for ax in axes if ax.get_visible()]
1978+
return axes
1979+
19271980
@slow
1928-
def test_grouped_hist_layout(self):
1981+
def test_grouped_box_layout(self):
19291982
import matplotlib.pyplot as plt
1930-
n = 100
1931-
gender = tm.choice(['Male', 'Female'], size=n)
1932-
df = DataFrame({'gender': gender,
1933-
'height': random.normal(66, 4, size=n),
1934-
'weight': random.normal(161, 32, size=n),
1935-
'category': random.randint(4, size=n)})
1936-
self.assertRaises(ValueError, df.hist, column='weight', by=df.gender,
1983+
df = self.hist_df
1984+
1985+
self.assertRaises(ValueError, df.boxplot, column=['weight', 'height'], by=df.gender,
19371986
layout=(1, 1))
1987+
self.assertRaises(ValueError, df.boxplot, column=['height', 'weight', 'category'],
1988+
layout=(2, 1))
1989+
1990+
box = _check_plot_works(df.groupby('gender').boxplot, column='height')
1991+
self._check_axes_shape(plt.gcf().axes, axes_num=2)
1992+
1993+
box = _check_plot_works(df.groupby('category').boxplot, column='height')
1994+
self._check_axes_shape(plt.gcf().axes, axes_num=4)
1995+
1996+
# GH 6769
1997+
box = _check_plot_works(df.groupby('classroom').boxplot, column='height')
1998+
self._check_axes_shape(plt.gcf().axes, axes_num=3)
1999+
2000+
box = df.boxplot(column=['height', 'weight', 'category'], by='gender')
2001+
self._check_axes_shape(plt.gcf().axes, axes_num=3)
2002+
2003+
box = df.groupby('classroom').boxplot(column=['height', 'weight', 'category'])
2004+
self._check_axes_shape(plt.gcf().axes, axes_num=3)
2005+
2006+
box = _check_plot_works(df.groupby('category').boxplot, column='height', layout=(3, 2))
2007+
self._check_axes_shape(plt.gcf().axes, axes_num=4)
2008+
2009+
box = df.boxplot(column=['height', 'weight', 'category'], by='gender', layout=(4, 1))
2010+
self._check_axes_shape(plt.gcf().axes, axes_num=3)
2011+
2012+
box = df.groupby('classroom').boxplot(column=['height', 'weight', 'category'], layout=(1, 4))
2013+
self._check_axes_shape(plt.gcf().axes, axes_num=3)
2014+
2015+
@slow
2016+
def test_grouped_hist_layout(self):
2017+
2018+
df = self.hist_df
19382019
self.assertRaises(ValueError, df.hist, column='weight', by=df.gender,
1939-
layout=(1,))
2020+
layout=(1, 1))
19402021
self.assertRaises(ValueError, df.hist, column='height', by=df.category,
19412022
layout=(1, 3))
1942-
self.assertRaises(ValueError, df.hist, column='height', by=df.category,
1943-
layout=(2, 1))
1944-
self.assertEqual(df.hist(column='height', by=df.gender,
1945-
layout=(2, 1)).shape, (2,))
1946-
tm.close()
1947-
self.assertEqual(df.hist(column='height', by=df.category,
1948-
layout=(4, 1)).shape, (4,))
1949-
tm.close()
1950-
self.assertEqual(df.hist(column='height', by=df.category,
1951-
layout=(4, 2)).shape, (4, 2))
2023+
2024+
axes = _check_plot_works(df.hist, column='height', by=df.gender, layout=(2, 1))
2025+
self._check_axes_shape(axes, axes_num=2, layout=(2, ), figsize=(10, 5))
2026+
2027+
axes = _check_plot_works(df.hist, column='height', by=df.category, layout=(4, 1))
2028+
self._check_axes_shape(axes, axes_num=4, layout=(4, ), figsize=(10, 5))
2029+
2030+
axes = _check_plot_works(df.hist, column='height', by=df.category,
2031+
layout=(4, 2), figsize=(12, 8))
2032+
self._check_axes_shape(axes, axes_num=4, layout=(4, 2), figsize=(12, 8))
2033+
2034+
# GH 6769
2035+
axes = _check_plot_works(df.hist, column='height', by='classroom', layout=(2, 2))
2036+
self._check_axes_shape(axes, axes_num=3, layout=(2, 2), figsize=(10, 5))
2037+
2038+
# without column
2039+
axes = _check_plot_works(df.hist, by='classroom')
2040+
self._check_axes_shape(axes, axes_num=3, layout=(2, 2), figsize=(10, 5))
2041+
2042+
axes = _check_plot_works(df.hist, by='gender', layout=(3, 5))
2043+
self._check_axes_shape(axes, axes_num=2, layout=(3, 5), figsize=(10, 5))
2044+
2045+
axes = _check_plot_works(df.hist, column=['height', 'weight', 'category'])
2046+
self._check_axes_shape(axes, axes_num=3, layout=(2, 2), figsize=(10, 5))
19522047

19532048
@slow
19542049
def test_axis_share_x(self):
2050+
df = self.hist_df
19552051
# GH4089
1956-
n = 100
1957-
df = DataFrame({'gender': tm.choice(['Male', 'Female'], size=n),
1958-
'height': random.normal(66, 4, size=n),
1959-
'weight': random.normal(161, 32, size=n)})
19602052
ax1, ax2 = df.hist(column='height', by=df.gender, sharex=True)
19612053

19622054
# share x
@@ -1969,10 +2061,7 @@ def test_axis_share_x(self):
19692061

19702062
@slow
19712063
def test_axis_share_y(self):
1972-
n = 100
1973-
df = DataFrame({'gender': tm.choice(['Male', 'Female'], size=n),
1974-
'height': random.normal(66, 4, size=n),
1975-
'weight': random.normal(161, 32, size=n)})
2064+
df = self.hist_df
19762065
ax1, ax2 = df.hist(column='height', by=df.gender, sharey=True)
19772066

19782067
# share y
@@ -1985,10 +2074,7 @@ def test_axis_share_y(self):
19852074

19862075
@slow
19872076
def test_axis_share_xy(self):
1988-
n = 100
1989-
df = DataFrame({'gender': tm.choice(['Male', 'Female'], size=n),
1990-
'height': random.normal(66, 4, size=n),
1991-
'weight': random.normal(161, 32, size=n)})
2077+
df = self.hist_df
19922078
ax1, ax2 = df.hist(column='height', by=df.gender, sharex=True,
19932079
sharey=True)
19942080

0 commit comments

Comments
 (0)