Skip to content

ENH: Add Styler.pipe() method (#23229) #23384

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 18 commits into from
Nov 28, 2018
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
1 change: 1 addition & 0 deletions doc/source/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2410,6 +2410,7 @@ Style Application
Styler.set_properties
Styler.set_uuid
Styler.clear
Styler.pipe

Builtin Styles
~~~~~~~~~~~~~~
Expand Down
1 change: 1 addition & 0 deletions doc/source/whatsnew/v0.24.0.txt
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,7 @@ Other Enhancements
- Compatibility with Matplotlib 3.0 (:issue:`22790`).
- Added :meth:`Interval.overlaps`, :meth:`IntervalArray.overlaps`, and :meth:`IntervalIndex.overlaps` for determining overlaps between interval-like objects (:issue:`21998`)
- :meth:`Timestamp.tz_localize`, :meth:`DatetimeIndex.tz_localize`, and :meth:`Series.tz_localize` have gained the ``nonexistent`` argument for alternative handling of nonexistent times. See :ref:`timeseries.timezone_nonexsistent` (:issue:`8917`)
- :meth:`Styler.pipe` method added, to simplify application of user-defined functions that operate on stylers.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reference the issue number.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, you should create a mini-section explaining the enhancement in more detail so that end users can understand the benefit.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, I can do that.


.. _whatsnew_0240.api_breaking:

Expand Down
29 changes: 29 additions & 0 deletions pandas/io/formats/style.py
Original file line number Diff line number Diff line change
Expand Up @@ -1222,6 +1222,35 @@ class MyStyler(cls):

return MyStyler

def pipe(self, func, *args, **kwargs):
"""
Apply func(self, *args, **kwargs)
Copy link
Member

@gfyoung gfyoung Oct 27, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be a little more descriptive. Apply func to what? Also, for what purpose?

(yes, as reviewers, we can see what the rationale was from your PR, so just put that rationale into the docstring)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, I'll change the doctoring, and try to provide some additional context/background.


Parameters
----------
func : function
function to apply to the Styler.
``args``, and ``kwargs`` are passed into ``func``.
Alternatively a ``(callable, data_keyword)`` tuple where
``data_keyword`` is a string indicating the keyword of
``callable`` that expects the Styler.
args : iterable, optional
positional arguments passed into ``func``.
kwargs : mapping, optional
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add the * before args and kwargs. I'd prefer dict intead of mapping. Parameter descriptions should start with a capital letter.

If you run ./scripts/validate_docstrings.py pandas.Styler.pipe you should get a report with most of the docstring issues.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. As mentioned above, now validating.

a dictionary of keyword arguments passed into ``func``.

Returns
-------
result : the value returned by ``func``.

See Also
--------
Styler.apply
Styler.applymap
pandas.DataFrame.pipe
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pandas. prefix not needed. Please add a description on why those are relevant in the context of Styler.pipe.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

"""
return com._pipe(self, func, *args, **kwargs)


def _is_visible(idx_row, idx_col, lengths):
"""
Expand Down
19 changes: 19 additions & 0 deletions pandas/tests/io/formats/test_style.py
Original file line number Diff line number Diff line change
Expand Up @@ -1173,6 +1173,25 @@ def test_hide_columns_mult_levels(self):
assert ctx['body'][1][2]['is_visible']
assert ctx['body'][1][2]['display_value'] == 3

def test_pipe(self):
def set_caption_from_template(styler, a, b):
return styler.set_caption(
'Dataframe with a = {a} and b = {b}'.format(a=a, b=b))
styler = self.df.style.pipe(set_caption_from_template, 'A', b='B')
assert 'Dataframe with a = A and b = B' in styler.render()

def f(s, *args, **kwargs):
return s, args, kwargs

result = self.df.style.pipe(f, 0, a=1)
assert result[1] == (0,)
assert result[2] == dict(a=1)

def g(**kwargs):
assert 'styler' in kwargs
return kwargs['styler'].data
assert self.df.style.pipe((g, 'styler')) is self.df
Copy link
Member

@gfyoung gfyoung Oct 27, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you comment here explaining why you're using is instead of tm.assert_frame_equal ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, add a comment explaining why you're creating this g function in the first place (perhaps a more descriptive function name is needed).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I can rewrite this a bit to simplify it. Essentially, I wanted to test that when pipe() is called with a (callable, string) tuple, it works as advertised.



@td.skip_if_no_mpl
class TestStylerMatplotlibDep(object):
Expand Down