Skip to content

Commit 66abbc3

Browse files
nmusolinoTomAugspurger
authored andcommitted
ENH: Add Styler.pipe() method (#23229) (#23384)
* Add Styler.pipe() method, akin to DataFrame.pipe()
1 parent 6b4b956 commit 66abbc3

File tree

4 files changed

+112
-0
lines changed

4 files changed

+112
-0
lines changed

doc/source/api.rst

+1
Original file line numberDiff line numberDiff line change
@@ -2482,6 +2482,7 @@ Style Application
24822482
Styler.set_properties
24832483
Styler.set_uuid
24842484
Styler.clear
2485+
Styler.pipe
24852486

24862487
Builtin Styles
24872488
~~~~~~~~~~~~~~

doc/source/whatsnew/v0.24.0.rst

+26
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,30 @@ array, but rather an ``ExtensionArray``:
184184
This is the same behavior as ``Series.values`` for categorical data. See
185185
:ref:`whatsnew_0240.api_breaking.interval_values` for more.
186186

187+
188+
.. _whatsnew_0240.enhancements.styler_pipe:
189+
190+
New ``Styler.pipe()`` method
191+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
192+
The :class:`~pandas.io.formats.style.Styler` class has gained a
193+
:meth:`~pandas.io.formats.style.Styler.pipe` method (:issue:`23229`). This provides a
194+
convenient way to apply users' predefined styling functions, and can help reduce
195+
"boilerplate" when using DataFrame styling functionality repeatedly within a notebook.
196+
197+
.. ipython:: python
198+
199+
df = pandas.DataFrame({'N': [1250, 1500, 1750], 'X': [0.25, 0.35, 0.50]})
200+
201+
def format_and_align(styler):
202+
return (styler.format({'N': '{:,}', 'X': '{:.1%}'})
203+
.set_properties(**{'text-align': 'right'}))
204+
205+
df.style.pipe(format_and_align).set_caption('Summary of results.')
206+
207+
Similar methods already exist for other classes in pandas, including :meth:`DataFrame.pipe`,
208+
:meth:`Groupby.pipe`, and :meth:`Resampler.pipe`.
209+
210+
187211
.. _whatsnew_0240.enhancements.join_with_two_multiindexes:
188212

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

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

276+
251277
.. _whatsnew_0240.enhancements.other:
252278

253279
Other Enhancements

pandas/io/formats/style.py

+69
Original file line numberDiff line numberDiff line change
@@ -1235,6 +1235,75 @@ class MyStyler(cls):
12351235

12361236
return MyStyler
12371237

1238+
def pipe(self, func, *args, **kwargs):
1239+
"""
1240+
Apply ``func(self, *args, **kwargs)``, and return the result.
1241+
1242+
.. versionadded:: 0.24.0
1243+
1244+
Parameters
1245+
----------
1246+
func : function
1247+
Function to apply to the Styler. Alternatively, a
1248+
``(callable, keyword)`` tuple where ``keyword`` is a string
1249+
indicating the keyword of ``callable`` that expects the Styler.
1250+
*args, **kwargs :
1251+
Arguments passed to `func`.
1252+
1253+
Returns
1254+
-------
1255+
object :
1256+
The value returned by ``func``.
1257+
1258+
See Also
1259+
--------
1260+
DataFrame.pipe : Analogous method for DataFrame.
1261+
Styler.apply : Apply a function row-wise, column-wise, or table-wise to
1262+
modify the dataframe's styling.
1263+
1264+
Notes
1265+
-----
1266+
Like :meth:`DataFrame.pipe`, this method can simplify the
1267+
application of several user-defined functions to a styler. Instead
1268+
of writing:
1269+
1270+
.. code-block:: python
1271+
1272+
f(g(df.style.set_precision(3), arg1=a), arg2=b, arg3=c)
1273+
1274+
users can write:
1275+
1276+
.. code-block:: python
1277+
1278+
(df.style.set_precision(3)
1279+
.pipe(g, arg1=a)
1280+
.pipe(f, arg2=b, arg3=c))
1281+
1282+
In particular, this allows users to define functions that take a
1283+
styler object, along with other parameters, and return the styler after
1284+
making styling changes (such as calling :meth:`Styler.apply` or
1285+
:meth:`Styler.set_properties`). Using ``.pipe``, these user-defined
1286+
style "transformations" can be interleaved with calls to the built-in
1287+
Styler interface.
1288+
1289+
Examples
1290+
--------
1291+
>>> def format_conversion(styler):
1292+
... return (styler.set_properties(**{'text-align': 'right'})
1293+
... .format({'conversion': '{:.1%}'}))
1294+
1295+
The user-defined ``format_conversion`` function above can be called
1296+
within a sequence of other style modifications:
1297+
1298+
>>> df = pd.DataFrame({'trial': list(range(5)),
1299+
... 'conversion': [0.75, 0.85, np.nan, 0.7, 0.72]})
1300+
>>> (df.style
1301+
... .highlight_min(subset=['conversion'], color='yellow')
1302+
... .pipe(format_conversion)
1303+
... .set_caption("Results with minimum conversion highlighted."))
1304+
"""
1305+
return com._pipe(self, func, *args, **kwargs)
1306+
12381307

12391308
def _is_visible(idx_row, idx_col, lengths):
12401309
"""

pandas/tests/io/formats/test_style.py

+16
Original file line numberDiff line numberDiff line change
@@ -1173,6 +1173,22 @@ def test_hide_columns_mult_levels(self):
11731173
assert ctx['body'][1][2]['is_visible']
11741174
assert ctx['body'][1][2]['display_value'] == 3
11751175

1176+
def test_pipe(self):
1177+
def set_caption_from_template(styler, a, b):
1178+
return styler.set_caption(
1179+
'Dataframe with a = {a} and b = {b}'.format(a=a, b=b))
1180+
1181+
styler = self.df.style.pipe(set_caption_from_template, 'A', b='B')
1182+
assert 'Dataframe with a = A and b = B' in styler.render()
1183+
1184+
# Test with an argument that is a (callable, keyword_name) pair.
1185+
def f(a, b, styler):
1186+
return (a, b, styler)
1187+
1188+
styler = self.df.style
1189+
result = styler.pipe((f, 'styler'), a=1, b=2)
1190+
assert result == (1, 2, styler)
1191+
11761192

11771193
@td.skip_if_no_mpl
11781194
class TestStylerMatplotlibDep(object):

0 commit comments

Comments
 (0)