Skip to content

Fix styling of DataFrame for columns with boolean label #47848

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 5 commits into from
Aug 1, 2022
Merged
Show file tree
Hide file tree
Changes from 2 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
9 changes: 6 additions & 3 deletions pandas/io/formats/style.py
Original file line number Diff line number Diff line change
Expand Up @@ -2977,6 +2977,9 @@ def hide(
# A collection of "builtin" styles
# -----------------------------------------------------------------------

def _get_subset_default(self):
return self.data.columns.isin(self.data.select_dtypes(include=np.number))

@doc(
name="background",
alt="text",
Expand Down Expand Up @@ -3120,7 +3123,7 @@ def background_gradient(
.. figure:: ../../_static/style/{image_prefix}_axNone_gmap.png
"""
if subset is None and gmap is None:
subset = self.data.select_dtypes(include=np.number).columns
subset = self._get_subset_default()

self.apply(
_background_gradient,
Expand Down Expand Up @@ -3155,7 +3158,7 @@ def text_gradient(
gmap: Sequence | None = None,
) -> Styler:
if subset is None and gmap is None:
subset = self.data.select_dtypes(include=np.number).columns
subset = self._get_subset_default()

return self.apply(
_background_gradient,
Expand Down Expand Up @@ -3308,7 +3311,7 @@ def bar(
raise ValueError(f"`height` must be a value in [0, 100], got {height}")

if subset is None:
subset = self.data.select_dtypes(include=np.number).columns
subset = self._get_subset_default()

self.apply(
_bar,
Expand Down
66 changes: 66 additions & 0 deletions pandas/tests/io/formats/style/test_style.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import copy
from itertools import combinations
import re
from textwrap import dedent

Expand Down Expand Up @@ -461,6 +462,31 @@ def test_apply_map_header_raises(mi_styler):
mi_styler.applymap_index(lambda v: "attr: val;", axis="bad")._compute()


def _gen_test_cases_subset_defaults(df_test_subset_defaults, styled_cols_expected):
"generate list of test cases from all subsets of columns of `df`"
# Iterate over all possible column in df
for n_cols in range(1, df_test_subset_defaults.shape[1] + 1):
for input_cols in combinations(df_test_subset_defaults.columns, n_cols):
# Use 'isin' to work around the difficulty with indexing
# when a column label is boolean
df_test_case = df_test_subset_defaults.loc[
:, df_test_subset_defaults.columns.isin(input_cols)
]
styled_cols_expected_subset = list(
set(styled_cols_expected).intersection(df_test_case)
)

styled_elements_expected = {
(i, j)
for i in range(df_test_case.shape[0])
for j in np.where(
df_test_case.columns.isin(styled_cols_expected_subset)
)[0]
}

yield df_test_case, styled_elements_expected


class TestStyler:
def test_init_non_pandas(self):
msg = "``data`` must be a Series or DataFrame"
Expand Down Expand Up @@ -645,6 +671,46 @@ def test_apply_dataframe_return(self, index, columns):
assert (result[(1, 0)] == [("color", "red")]) is columns # (Y,X) only if cols
assert (result[(0, 0)] == [("color", "red")]) is (index and columns) # (X,X)

@pytest.mark.parametrize(
# styled_elements_expected is a set of tuples (i, j) with integer indices,
# where we expect .ctx to be set after calling _compute on the styler
"df_test_case, styled_elements_expected",
(
list(
_gen_test_cases_subset_defaults(
DataFrame(
{
True: [1, 2],
False: [3, 4],
"num_column": [5, 6],
"non_num_column": ["a", "b"],
}
),
[True, False, "num_column"],
)
)
+ list(
_gen_test_cases_subset_defaults(
DataFrame(
{
True: ["a", "b"],
False: [3, 4],
"num_column": [5, 6],
}
),
[False, "num_column"],
)
)
),
)
@pytest.mark.parametrize(
"stylefunc", ["background_gradient", "bar", "text_gradient"]
)
def test_subset_defaults(self, df_test_case, styled_elements_expected, stylefunc):
styled = getattr(df_test_case.style, stylefunc)()
styled._compute()
assert set(styled.ctx) == set(styled_elements_expected)

@pytest.mark.parametrize(
"slice_",
[
Expand Down