Skip to content

Commit 4f1704e

Browse files
Sörenjreback
Sören
authored andcommitted
Sharey keyword for boxplot (#20968)
1 parent abfac97 commit 4f1704e

File tree

3 files changed

+82
-2
lines changed

3 files changed

+82
-2
lines changed

doc/source/whatsnew/v0.23.1.txt

+13
Original file line numberDiff line numberDiff line change
@@ -48,40 +48,53 @@ Bug Fixes
4848
~~~~~~~~~
4949

5050
Groupby/Resample/Rolling
51+
~~~~~~~~~~~~~~~~~~~~~~~~
5152

5253
- Bug in :func:`DataFrame.agg` where applying multiple aggregation functions to a :class:`DataFrame` with duplicated column names would cause a stack overflow (:issue:`21063`)
5354
- Bug in :func:`pandas.core.groupby.GroupBy.ffill` and :func:`pandas.core.groupby.GroupBy.bfill` where the fill within a grouping would not always be applied as intended due to the implementations' use of a non-stable sort (:issue:`21207`)
5455
- Bug in :func:`pandas.core.groupby.GroupBy.rank` where results did not scale to 100% when specifying ``method='dense'`` and ``pct=True``
5556

5657
Data-type specific
58+
~~~~~~~~~~~~~~~~~~
5759

5860
- Bug in :meth:`Series.str.replace()` where the method throws `TypeError` on Python 3.5.2 (:issue: `21078`)
5961
- Bug in :class:`Timedelta`: where passing a float with a unit would prematurely round the float precision (:issue: `14156`)
6062
- Bug in :func:`pandas.testing.assert_index_equal` which raised ``AssertionError`` incorrectly, when comparing two :class:`CategoricalIndex` objects with param ``check_categorical=False`` (:issue:`19776`)
6163

6264
Sparse
65+
~~~~~~
6366

6467
- Bug in :attr:`SparseArray.shape` which previously only returned the shape :attr:`SparseArray.sp_values` (:issue:`21126`)
6568

6669
Indexing
70+
~~~~~~~~
6771

6872
- Bug in :meth:`Series.reset_index` where appropriate error was not raised with an invalid level name (:issue:`20925`)
6973
- Bug in :func:`interval_range` when ``start``/``periods`` or ``end``/``periods`` are specified with float ``start`` or ``end`` (:issue:`21161`)
7074
- Bug in :meth:`MultiIndex.set_names` where error raised for a ``MultiIndex`` with ``nlevels == 1`` (:issue:`21149`)
7175
- Bug in :class:`IntervalIndex` constructors where creating an ``IntervalIndex`` from categorical data was not fully supported (:issue:`21243`, issue:`21253`)
7276
- Bug in :meth:`MultiIndex.sort_index` which was not guaranteed to sort correctly with ``level=1``; this was also causing data misalignment in particular :meth:`DataFrame.stack` operations (:issue:`20994`, :issue:`20945`, :issue:`21052`)
7377

78+
Plotting
79+
~~~~~~~~
80+
81+
- New keywords (sharex, sharey) to turn on/off sharing of x/y-axis by subplots generated with pandas.DataFrame().groupby().boxplot() (:issue: `20968`)
82+
7483
I/O
84+
~~~
7585

7686
- Bug in IO methods specifying ``compression='zip'`` which produced uncompressed zip archives (:issue:`17778`, :issue:`21144`)
7787
- Bug in :meth:`DataFrame.to_stata` which prevented exporting DataFrames to buffers and most file-like objects (:issue:`21041`)
7888
- Bug in :meth:`read_stata` and :class:`StataReader` which did not correctly decode utf-8 strings on Python 3 from Stata 14 files (dta version 118) (:issue:`21244`)
7989

90+
8091
Reshaping
92+
~~~~~~~~~
8193

8294
- Bug in :func:`concat` where error was raised in concatenating :class:`Series` with numpy scalar and tuple names (:issue:`21015`)
8395
- Bug in :func:`concat` warning message providing the wrong guidance for future behavior (:issue:`21101`)
8496

8597
Other
98+
~~~~~
8699

87100
- Tab completion on :class:`Index` in IPython no longer outputs deprecation warnings (:issue:`21125`)

pandas/plotting/_core.py

+10-2
Original file line numberDiff line numberDiff line change
@@ -2548,7 +2548,7 @@ def plot_group(group, ax):
25482548

25492549
def boxplot_frame_groupby(grouped, subplots=True, column=None, fontsize=None,
25502550
rot=0, grid=True, ax=None, figsize=None,
2551-
layout=None, **kwds):
2551+
layout=None, sharex=False, sharey=True, **kwds):
25522552
"""
25532553
Make box plots from DataFrameGroupBy data.
25542554
@@ -2567,6 +2567,14 @@ def boxplot_frame_groupby(grouped, subplots=True, column=None, fontsize=None,
25672567
figsize : A tuple (width, height) in inches
25682568
layout : tuple (optional)
25692569
(rows, columns) for the layout of the plot
2570+
sharex : bool, default False
2571+
Whether x-axes will be shared among subplots
2572+
2573+
.. versionadded:: 0.23.1
2574+
sharey : bool, default True
2575+
Whether y-axes will be shared among subplots
2576+
2577+
.. versionadded:: 0.23.1
25702578
`**kwds` : Keyword Arguments
25712579
All other plotting keyword arguments to be passed to
25722580
matplotlib's boxplot function
@@ -2598,7 +2606,7 @@ def boxplot_frame_groupby(grouped, subplots=True, column=None, fontsize=None,
25982606
if subplots is True:
25992607
naxes = len(grouped)
26002608
fig, axes = _subplots(naxes=naxes, squeeze=False,
2601-
ax=ax, sharex=False, sharey=True,
2609+
ax=ax, sharex=sharex, sharey=sharey,
26022610
figsize=figsize, layout=layout)
26032611
axes = _flatten(axes)
26042612

pandas/tests/plotting/test_frame.py

+59
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,14 @@ def setup_method(self, method):
4040
"C": np.arange(20) + np.random.uniform(
4141
size=20)})
4242

43+
def _assert_ytickslabels_visibility(self, axes, expected):
44+
for ax, exp in zip(axes, expected):
45+
self._check_visible(ax.get_yticklabels(), visible=exp)
46+
47+
def _assert_xtickslabels_visibility(self, axes, expected):
48+
for ax, exp in zip(axes, expected):
49+
self._check_visible(ax.get_xticklabels(), visible=exp)
50+
4351
@pytest.mark.slow
4452
def test_plot(self):
4553
df = self.tdf
@@ -367,6 +375,57 @@ def test_subplots(self):
367375
for ax in axes:
368376
assert ax.get_legend() is None
369377

378+
def test_groupby_boxplot_sharey(self):
379+
# https://github.com/pandas-dev/pandas/issues/20968
380+
# sharey can now be switched check whether the right
381+
# pair of axes is turned on or off
382+
383+
df = DataFrame({'a': [-1.43, -0.15, -3.70, -1.43, -0.14],
384+
'b': [0.56, 0.84, 0.29, 0.56, 0.85],
385+
'c': [0, 1, 2, 3, 1]},
386+
index=[0, 1, 2, 3, 4])
387+
388+
# behavior without keyword
389+
axes = df.groupby('c').boxplot()
390+
expected = [True, False, True, False]
391+
self._assert_ytickslabels_visibility(axes, expected)
392+
393+
# set sharey=True should be identical
394+
axes = df.groupby('c').boxplot(sharey=True)
395+
expected = [True, False, True, False]
396+
self._assert_ytickslabels_visibility(axes, expected)
397+
398+
# sharey=False, all yticklabels should be visible
399+
axes = df.groupby('c').boxplot(sharey=False)
400+
expected = [True, True, True, True]
401+
self._assert_ytickslabels_visibility(axes, expected)
402+
403+
def test_groupby_boxplot_sharex(self):
404+
# https://github.com/pandas-dev/pandas/issues/20968
405+
# sharex can now be switched check whether the right
406+
# pair of axes is turned on or off
407+
408+
df = DataFrame({'a': [-1.43, -0.15, -3.70, -1.43, -0.14],
409+
'b': [0.56, 0.84, 0.29, 0.56, 0.85],
410+
'c': [0, 1, 2, 3, 1]},
411+
index=[0, 1, 2, 3, 4])
412+
413+
# behavior without keyword
414+
axes = df.groupby('c').boxplot()
415+
expected = [True, True, True, True]
416+
self._assert_xtickslabels_visibility(axes, expected)
417+
418+
# set sharex=False should be identical
419+
axes = df.groupby('c').boxplot(sharex=False)
420+
expected = [True, True, True, True]
421+
self._assert_xtickslabels_visibility(axes, expected)
422+
423+
# sharex=True, yticklabels should be visible
424+
# only for bottom plots
425+
axes = df.groupby('c').boxplot(sharex=True)
426+
expected = [False, False, True, True]
427+
self._assert_xtickslabels_visibility(axes, expected)
428+
370429
@pytest.mark.slow
371430
def test_subplots_timeseries(self):
372431
idx = date_range(start='2014-07-01', freq='M', periods=10)

0 commit comments

Comments
 (0)