-
-
Notifications
You must be signed in to change notification settings - Fork 18.5k
BUG: Styler.apply
consistently manages Series return objects aligning labels.
#42014
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
jreback
merged 21 commits into
pandas-dev:master
from
attack68:styler_consistent_apply_funcs_index_columns
Aug 19, 2021
Merged
Changes from all commits
Commits
Show all changes
21 commits
Select commit
Hold shift + click to select a range
770c588
edit signature of Styler.apply for more consistent application with S…
attack68 c67092a
add tests
attack68 d63073c
allow DataFrame returns that do not have same size but valid labels
attack68 53bdc38
allow DataFrame returns that do not have same size but valid labels
attack68 b3b6f0a
more descript error msgs
attack68 b6fc1b0
more descript error msgs
attack68 681c0c8
whats new
attack68 c3c7a40
Merge remote-tracking branch 'upstream/master' into styler_consistent…
attack68 77557b5
Merge remote-tracking branch 'upstream/master' into styler_consistent…
attack68 e5fc3b3
Merge remote-tracking branch 'upstream/master' into styler_consistent…
attack68 5ddb99b
Merge remote-tracking branch 'upstream/master' into styler_consistent…
attack68 6c2a194
Merge remote-tracking branch 'upstream/master' into styler_consistent…
attack68 cd4614e
Merge remote-tracking branch 'upstream/master' into styler_consistent…
attack68 1095b21
Merge remote-tracking branch 'upstream/master' into styler_consistent…
attack68 9f6aca5
Merge remote-tracking branch 'upstream/master' into styler_consistent…
attack68 ddbcd6b
issue number (jreback)
attack68 fc55b5e
example (jreback)
attack68 a5c0fdb
Merge remote-tracking branch 'upstream/master' into styler_consistent…
attack68 7e72853
Merge remote-tracking branch 'upstream/master' into styler_consistent…
attack68 9599379
Merge remote-tracking branch 'upstream/master' into styler_consistent…
attack68 65411b7
Merge remote-tracking branch 'upstream/master' into styler_consistent…
attack68 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1024,7 +1024,7 @@ def _update_ctx(self, attrs: DataFrame) -> None: | |
|
||
for cn in attrs.columns: | ||
for rn, c in attrs[[cn]].itertuples(): | ||
if not c: | ||
if not c or pd.isna(c): | ||
continue | ||
css_list = maybe_convert_css_to_tuples(c) | ||
i, j = self.index.get_loc(rn), self.columns.get_loc(cn) | ||
|
@@ -1148,9 +1148,10 @@ def _apply( | |
subset = slice(None) if subset is None else subset | ||
subset = non_reducing_slice(subset) | ||
data = self.data.loc[subset] | ||
if axis is not None: | ||
result = data.apply(func, axis=axis, result_type="expand", **kwargs) | ||
result.columns = data.columns | ||
if axis in [0, "index"]: | ||
result = data.apply(func, axis=0, **kwargs) | ||
elif axis in [1, "columns"]: | ||
result = data.T.apply(func, axis=0, **kwargs).T # see GH 42005 | ||
else: | ||
result = func(data, **kwargs) | ||
if not isinstance(result, DataFrame): | ||
|
@@ -1166,19 +1167,28 @@ def _apply( | |
f"Expected shape: {data.shape}" | ||
) | ||
result = DataFrame(result, index=data.index, columns=data.columns) | ||
elif not ( | ||
result.index.equals(data.index) and result.columns.equals(data.columns) | ||
): | ||
raise ValueError( | ||
f"Result of {repr(func)} must have identical " | ||
f"index and columns as the input" | ||
) | ||
|
||
if result.shape != data.shape: | ||
if isinstance(result, Series): | ||
raise ValueError( | ||
f"Function {repr(func)} returned the wrong shape.\n" | ||
f"Result has shape: {result.shape}\n" | ||
f"Expected shape: {data.shape}" | ||
f"Function {repr(func)} resulted in the apply method collapsing to a " | ||
f"Series.\nUsually, this is the result of the function returning a " | ||
f"single value, instead of list-like." | ||
) | ||
msg = ( | ||
f"Function {repr(func)} created invalid {{0}} labels.\nUsually, this is " | ||
f"the result of the function returning a " | ||
f"{'Series' if axis is not None else 'DataFrame'} which contains invalid " | ||
f"labels, or returning an incorrectly shaped, list-like object which " | ||
f"cannot be mapped to labels, possibly due to applying the function along " | ||
f"the wrong axis.\n" | ||
f"Result {{0}} has shape: {{1}}\n" | ||
f"Expected {{0}} shape: {{2}}" | ||
) | ||
if not all(result.index.isin(data.index)): | ||
raise ValueError(msg.format("index", result.index.shape, data.index.shape)) | ||
if not all(result.columns.isin(data.columns)): | ||
raise ValueError( | ||
msg.format("columns", result.columns.shape, data.columns.shape) | ||
) | ||
self._update_ctx(result) | ||
return self | ||
|
@@ -1198,14 +1208,17 @@ def apply( | |
Parameters | ||
---------- | ||
func : function | ||
``func`` should take a Series if ``axis`` in [0,1] and return an object | ||
of same length, also with identical index if the object is a Series. | ||
``func`` should take a Series if ``axis`` in [0,1] and return a list-like | ||
object of same length, or a Series, not necessarily of same length, with | ||
valid index labels considering ``subset``. | ||
``func`` should take a DataFrame if ``axis`` is ``None`` and return either | ||
an ndarray with the same shape or a DataFrame with identical columns and | ||
index. | ||
an ndarray with the same shape or a DataFrame, not necessarily of the same | ||
shape, with valid index and columns labels considering ``subset``. | ||
|
||
.. versionchanged:: 1.3.0 | ||
|
||
.. versionchanged:: 1.4.0 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can you update the examples to show a Series return matching labels/index (e.g. not the same length) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. added |
||
|
||
axis : {0 or 'index', 1 or 'columns', None}, default 0 | ||
Apply to each column (``axis=0`` or ``'index'``), to each row | ||
(``axis=1`` or ``'columns'``), or to the entire DataFrame at once | ||
|
@@ -1260,6 +1273,13 @@ def apply( | |
>>> df.style.apply(highlight_max, color='red', subset=(slice(0,5,2), "A")) | ||
... # doctest: +SKIP | ||
|
||
Using a function which returns a Series / DataFrame of unequal length but | ||
containing valid index labels | ||
|
||
>>> df = pd.DataFrame([[1, 2], [3, 4], [4, 6]], index=["A1", "A2", "Total"]) | ||
>>> total_style = pd.Series("font-weight: bold;", index=["Total"]) | ||
>>> df.style.apply(lambda s: total_style) # doctest: +SKIP | ||
|
||
See `Table Visualization <../../user_guide/style.ipynb>`_ user guide for | ||
more details. | ||
""" | ||
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.