Skip to content

Commit 5fd478d

Browse files
DataFrameGroupby.boxplot fails when subplots=False (#28102)
1 parent 0573c3a commit 5fd478d

File tree

3 files changed

+85
-0
lines changed

3 files changed

+85
-0
lines changed

doc/source/whatsnew/v1.2.0.rst

+2
Original file line numberDiff line numberDiff line change
@@ -510,6 +510,8 @@ Plotting
510510
- Bug in :meth:`DataFrame.plot` was rotating xticklabels when ``subplots=True``, even if the x-axis wasn't an irregular time series (:issue:`29460`)
511511
- Bug in :meth:`DataFrame.plot` where a marker letter in the ``style`` keyword sometimes causes a ``ValueError`` (:issue:`21003`)
512512
- Twinned axes were losing their tick labels which should only happen to all but the last row or column of 'externally' shared axes (:issue:`33819`)
513+
- Bug in :meth:`DataFrameGroupBy.boxplot` when ``subplots=False``, a KeyError would raise (:issue:`16748`)
514+
513515

514516
Groupby/resample/rolling
515517
^^^^^^^^^^^^^^^^^^^^^^^^

pandas/plotting/_matplotlib/boxplot.py

+10
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
from pandas.core.dtypes.missing import remove_na_arraylike
1010

1111
import pandas as pd
12+
import pandas.core.common as com
1213

1314
from pandas.io.formats.printing import pprint_thing
1415
from pandas.plotting._matplotlib.core import LinePlot, MPLPlot
@@ -443,6 +444,15 @@ def boxplot_frame_groupby(
443444
df = frames[0].join(frames[1::])
444445
else:
445446
df = frames[0]
447+
448+
# GH 16748, DataFrameGroupby fails when subplots=False and `column` argument
449+
# is assigned, and in this case, since `df` here becomes MI after groupby,
450+
# so we need to couple the keys (grouped values) and column (original df
451+
# column) together to search for subset to plot
452+
if column is not None:
453+
column = com.convert_to_list_like(column)
454+
multi_key = pd.MultiIndex.from_product([keys, column])
455+
column = list(multi_key.values)
446456
ret = df.boxplot(
447457
column=column,
448458
fontsize=fontsize,

pandas/tests/plotting/test_boxplot_method.py

+73
Original file line numberDiff line numberDiff line change
@@ -454,3 +454,76 @@ def test_fontsize(self):
454454
self._check_ticks_props(
455455
df.boxplot("a", by="b", fontsize=16), xlabelsize=16, ylabelsize=16
456456
)
457+
458+
@pytest.mark.parametrize(
459+
"col, expected_xticklabel",
460+
[
461+
("v", ["(a, v)", "(b, v)", "(c, v)", "(d, v)", "(e, v)"]),
462+
(["v"], ["(a, v)", "(b, v)", "(c, v)", "(d, v)", "(e, v)"]),
463+
("v1", ["(a, v1)", "(b, v1)", "(c, v1)", "(d, v1)", "(e, v1)"]),
464+
(
465+
["v", "v1"],
466+
[
467+
"(a, v)",
468+
"(a, v1)",
469+
"(b, v)",
470+
"(b, v1)",
471+
"(c, v)",
472+
"(c, v1)",
473+
"(d, v)",
474+
"(d, v1)",
475+
"(e, v)",
476+
"(e, v1)",
477+
],
478+
),
479+
(
480+
None,
481+
[
482+
"(a, v)",
483+
"(a, v1)",
484+
"(b, v)",
485+
"(b, v1)",
486+
"(c, v)",
487+
"(c, v1)",
488+
"(d, v)",
489+
"(d, v1)",
490+
"(e, v)",
491+
"(e, v1)",
492+
],
493+
),
494+
],
495+
)
496+
def test_groupby_boxplot_subplots_false(self, col, expected_xticklabel):
497+
# GH 16748
498+
df = DataFrame(
499+
{
500+
"cat": np.random.choice(list("abcde"), 100),
501+
"v": np.random.rand(100),
502+
"v1": np.random.rand(100),
503+
}
504+
)
505+
grouped = df.groupby("cat")
506+
507+
axes = _check_plot_works(
508+
grouped.boxplot, subplots=False, column=col, return_type="axes"
509+
)
510+
511+
result_xticklabel = [x.get_text() for x in axes.get_xticklabels()]
512+
assert expected_xticklabel == result_xticklabel
513+
514+
def test_boxplot_multiindex_column(self):
515+
# GH 16748
516+
arrays = [
517+
["bar", "bar", "baz", "baz", "foo", "foo", "qux", "qux"],
518+
["one", "two", "one", "two", "one", "two", "one", "two"],
519+
]
520+
tuples = list(zip(*arrays))
521+
index = MultiIndex.from_tuples(tuples, names=["first", "second"])
522+
df = DataFrame(np.random.randn(3, 8), index=["A", "B", "C"], columns=index)
523+
524+
col = [("bar", "one"), ("bar", "two")]
525+
axes = _check_plot_works(df.boxplot, column=col, return_type="axes")
526+
527+
expected_xticklabel = ["(bar, one)", "(bar, two)"]
528+
result_xticklabel = [x.get_text() for x in axes.get_xticklabels()]
529+
assert expected_xticklabel == result_xticklabel

0 commit comments

Comments
 (0)