Skip to content

Commit

Permalink
ENH: Add Styler.pipe() method (pandas-dev#23229) (pandas-dev#23384)
Browse files Browse the repository at this point in the history
* Add Styler.pipe() method, akin to DataFrame.pipe()
  • Loading branch information
nmusolino authored and Pingviinituutti committed Feb 28, 2019
1 parent eb65cdc commit a0532d3
Show file tree
Hide file tree
Showing 4 changed files with 112 additions and 0 deletions.
1 change: 1 addition & 0 deletions doc/source/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2482,6 +2482,7 @@ Style Application
Styler.set_properties
Styler.set_uuid
Styler.clear
Styler.pipe

Builtin Styles
~~~~~~~~~~~~~~
Expand Down
26 changes: 26 additions & 0 deletions doc/source/whatsnew/v0.24.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,30 @@ array, but rather an ``ExtensionArray``:
This is the same behavior as ``Series.values`` for categorical data. See
:ref:`whatsnew_0240.api_breaking.interval_values` for more.


.. _whatsnew_0240.enhancements.styler_pipe:

New ``Styler.pipe()`` method
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The :class:`~pandas.io.formats.style.Styler` class has gained a
:meth:`~pandas.io.formats.style.Styler.pipe` method (:issue:`23229`). This provides a
convenient way to apply users' predefined styling functions, and can help reduce
"boilerplate" when using DataFrame styling functionality repeatedly within a notebook.

.. ipython:: python
df = pandas.DataFrame({'N': [1250, 1500, 1750], 'X': [0.25, 0.35, 0.50]})
def format_and_align(styler):
return (styler.format({'N': '{:,}', 'X': '{:.1%}'})
.set_properties(**{'text-align': 'right'}))
df.style.pipe(format_and_align).set_caption('Summary of results.')
Similar methods already exist for other classes in pandas, including :meth:`DataFrame.pipe`,
:meth:`Groupby.pipe`, and :meth:`Resampler.pipe`.


.. _whatsnew_0240.enhancements.join_with_two_multiindexes:

Joining with two multi-indexes
Expand Down Expand Up @@ -225,6 +249,7 @@ For earlier versions this can be done using the following.
pd.merge(left.reset_index(), right.reset_index(),
on=['key'], how='inner').set_index(['key', 'X', 'Y'])
.. _whatsnew_0240.enhancements.rename_axis:

Renaming names in a MultiIndex
Expand All @@ -248,6 +273,7 @@ Example:
See the :ref:`advanced docs on renaming<advanced.index_names>` for more details.


.. _whatsnew_0240.enhancements.other:

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

return MyStyler

def pipe(self, func, *args, **kwargs):
"""
Apply ``func(self, *args, **kwargs)``, and return the result.
.. versionadded:: 0.24.0
Parameters
----------
func : function
Function to apply to the Styler. Alternatively, a
``(callable, keyword)`` tuple where ``keyword`` is a string
indicating the keyword of ``callable`` that expects the Styler.
*args, **kwargs :
Arguments passed to `func`.
Returns
-------
object :
The value returned by ``func``.
See Also
--------
DataFrame.pipe : Analogous method for DataFrame.
Styler.apply : Apply a function row-wise, column-wise, or table-wise to
modify the dataframe's styling.
Notes
-----
Like :meth:`DataFrame.pipe`, this method can simplify the
application of several user-defined functions to a styler. Instead
of writing:
.. code-block:: python
f(g(df.style.set_precision(3), arg1=a), arg2=b, arg3=c)
users can write:
.. code-block:: python
(df.style.set_precision(3)
.pipe(g, arg1=a)
.pipe(f, arg2=b, arg3=c))
In particular, this allows users to define functions that take a
styler object, along with other parameters, and return the styler after
making styling changes (such as calling :meth:`Styler.apply` or
:meth:`Styler.set_properties`). Using ``.pipe``, these user-defined
style "transformations" can be interleaved with calls to the built-in
Styler interface.
Examples
--------
>>> def format_conversion(styler):
... return (styler.set_properties(**{'text-align': 'right'})
... .format({'conversion': '{:.1%}'}))
The user-defined ``format_conversion`` function above can be called
within a sequence of other style modifications:
>>> df = pd.DataFrame({'trial': list(range(5)),
... 'conversion': [0.75, 0.85, np.nan, 0.7, 0.72]})
>>> (df.style
... .highlight_min(subset=['conversion'], color='yellow')
... .pipe(format_conversion)
... .set_caption("Results with minimum conversion highlighted."))
"""
return com._pipe(self, func, *args, **kwargs)


def _is_visible(idx_row, idx_col, lengths):
"""
Expand Down
16 changes: 16 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,22 @@ 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()

# Test with an argument that is a (callable, keyword_name) pair.
def f(a, b, styler):
return (a, b, styler)

styler = self.df.style
result = styler.pipe((f, 'styler'), a=1, b=2)
assert result == (1, 2, styler)


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

0 comments on commit a0532d3

Please sign in to comment.