Skip to content

Commit 7d0fada

Browse files
authored
ENH: Styler.to_string (pandas-dev#44502)
1 parent 3ee23e4 commit 7d0fada

File tree

6 files changed

+147
-3
lines changed

6 files changed

+147
-3
lines changed

doc/source/reference/style.rst

+2
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ Styler properties
2727
Styler.template_html_style
2828
Styler.template_html_table
2929
Styler.template_latex
30+
Styler.template_string
3031
Styler.loader
3132

3233
Style application
@@ -74,5 +75,6 @@ Style export and import
7475
Styler.to_html
7576
Styler.to_latex
7677
Styler.to_excel
78+
Styler.to_string
7779
Styler.export
7880
Styler.use

doc/source/whatsnew/v1.5.0.rst

+5-3
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,12 @@ including other versions of pandas.
1414
Enhancements
1515
~~~~~~~~~~~~
1616

17-
.. _whatsnew_150.enhancements.enhancement1:
17+
.. _whatsnew_150.enhancements.styler:
1818

19-
enhancement1
20-
^^^^^^^^^^^^
19+
Styler
20+
^^^^^^
21+
22+
- New method :meth:`.Styler.to_string` for alternative customisable output methods (:issue:`44502`)
2123

2224
.. _whatsnew_150.enhancements.enhancement2:
2325

pandas/io/formats/style.py

+67
Original file line numberDiff line numberDiff line change
@@ -1190,6 +1190,73 @@ def to_html(
11901190
html, buf=buf, encoding=(encoding if buf is not None else None)
11911191
)
11921192

1193+
def to_string(
1194+
self,
1195+
buf=None,
1196+
*,
1197+
encoding=None,
1198+
sparse_index: bool | None = None,
1199+
sparse_columns: bool | None = None,
1200+
max_rows: int | None = None,
1201+
max_columns: int | None = None,
1202+
delimiter: str = " ",
1203+
):
1204+
"""
1205+
Write Styler to a file, buffer or string in text format.
1206+
1207+
.. versionadded:: 1.5.0
1208+
1209+
Parameters
1210+
----------
1211+
buf : str, Path, or StringIO-like, optional, default None
1212+
Buffer to write to. If ``None``, the output is returned as a string.
1213+
encoding : str, optional
1214+
Character encoding setting for file output.
1215+
Defaults to ``pandas.options.styler.render.encoding`` value of "utf-8".
1216+
sparse_index : bool, optional
1217+
Whether to sparsify the display of a hierarchical index. Setting to False
1218+
will display each explicit level element in a hierarchical key for each row.
1219+
Defaults to ``pandas.options.styler.sparse.index`` value.
1220+
sparse_columns : bool, optional
1221+
Whether to sparsify the display of a hierarchical index. Setting to False
1222+
will display each explicit level element in a hierarchical key for each
1223+
column. Defaults to ``pandas.options.styler.sparse.columns`` value.
1224+
max_rows : int, optional
1225+
The maximum number of rows that will be rendered. Defaults to
1226+
``pandas.options.styler.render.max_rows``, which is None.
1227+
max_columns : int, optional
1228+
The maximum number of columns that will be rendered. Defaults to
1229+
``pandas.options.styler.render.max_columns``, which is None.
1230+
1231+
Rows and columns may be reduced if the number of total elements is
1232+
large. This value is set to ``pandas.options.styler.render.max_elements``,
1233+
which is 262144 (18 bit browser rendering).
1234+
delimiter : str, default single space
1235+
The separator between data elements.
1236+
1237+
Returns
1238+
-------
1239+
str or None
1240+
If `buf` is None, returns the result as a string. Otherwise returns `None`.
1241+
"""
1242+
obj = self._copy(deepcopy=True)
1243+
1244+
if sparse_index is None:
1245+
sparse_index = get_option("styler.sparse.index")
1246+
if sparse_columns is None:
1247+
sparse_columns = get_option("styler.sparse.columns")
1248+
1249+
text = obj._render_string(
1250+
sparse_columns=sparse_columns,
1251+
sparse_index=sparse_index,
1252+
max_rows=max_rows,
1253+
max_cols=max_columns,
1254+
delimiter=delimiter,
1255+
)
1256+
return save_to_buffer(
1257+
text, buf=buf, encoding=(encoding if buf is not None else None)
1258+
)
1259+
11931260
def set_td_classes(self, classes: DataFrame) -> Styler:
11941261
"""
11951262
Set the DataFrame of strings added to the ``class`` attribute of ``<td>``

pandas/io/formats/style_render.py

+19
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ class StylerRenderer:
7474
template_html_table = _gl01_adjust(env.get_template("html_table.tpl"))
7575
template_html_style = _gl01_adjust(env.get_template("html_style.tpl"))
7676
template_latex = _gl01_adjust(env.get_template("latex.tpl"))
77+
template_string = _gl01_adjust(env.get_template("string.tpl"))
7778

7879
def __init__(
7980
self,
@@ -183,6 +184,24 @@ def _render_latex(
183184
d.update(kwargs)
184185
return self.template_latex.render(**d)
185186

187+
def _render_string(
188+
self,
189+
sparse_index: bool,
190+
sparse_columns: bool,
191+
max_rows: int | None = None,
192+
max_cols: int | None = None,
193+
**kwargs,
194+
) -> str:
195+
"""
196+
Render a Styler in string format
197+
"""
198+
self._compute()
199+
200+
d = self._translate(sparse_index, sparse_columns, max_rows, max_cols, blank="")
201+
202+
d.update(kwargs)
203+
return self.template_string.render(**d)
204+
186205
def _compute(self):
187206
"""
188207
Execute the style functions built up in `self._todo`.
+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{% for r in head %}
2+
{% for c in r %}{% if c["is_visible"] %}
3+
{{ c["display_value"] }}{% if not loop.last %}{{ delimiter }}{% endif %}
4+
{% endif %}{% endfor %}
5+
6+
{% endfor %}
7+
{% for r in body %}
8+
{% for c in r %}{% if c["is_visible"] %}
9+
{{ c["display_value"] }}{% if not loop.last %}{{ delimiter }}{% endif %}
10+
{% endif %}{% endfor %}
11+
12+
{% endfor %}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
from textwrap import dedent
2+
3+
import pytest
4+
5+
from pandas import DataFrame
6+
7+
pytest.importorskip("jinja2")
8+
from pandas.io.formats.style import Styler
9+
10+
11+
@pytest.fixture
12+
def df():
13+
return DataFrame({"A": [0, 1], "B": [-0.61, -1.22], "C": ["ab", "cd"]})
14+
15+
16+
@pytest.fixture
17+
def styler(df):
18+
return Styler(df, uuid_len=0, precision=2)
19+
20+
21+
def test_basic_string(styler):
22+
result = styler.to_string()
23+
expected = dedent(
24+
"""\
25+
A B C
26+
0 0 -0.61 ab
27+
1 1 -1.22 cd
28+
"""
29+
)
30+
assert result == expected
31+
32+
33+
def test_string_delimiter(styler):
34+
result = styler.to_string(delimiter=";")
35+
expected = dedent(
36+
"""\
37+
;A;B;C
38+
0;0;-0.61;ab
39+
1;1;-1.22;cd
40+
"""
41+
)
42+
assert result == expected

0 commit comments

Comments
 (0)