Skip to content
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

ENH: Styler.to_latex(): conditional styling with native latex format #40422

Merged
merged 136 commits into from
May 24, 2021
Merged
Show file tree
Hide file tree
Changes from 108 commits
Commits
Show all changes
136 commits
Select commit Hold shift + click to select a range
bb501d3
MVP for Styler.to_latex
attack68 Mar 10, 2021
6066449
MVP for Styler.to_latex
attack68 Mar 10, 2021
6e2b788
rules
attack68 Mar 11, 2021
2f74690
hidden columns and index
attack68 Mar 11, 2021
9c9405e
basic cell colors and background colors parsing.
attack68 Mar 11, 2021
a6772e7
basic cell colors and background colors parsing.
attack68 Mar 11, 2021
6505564
basic cell colors and background colors parsing.
attack68 Mar 11, 2021
b25644f
column_format arg input
attack68 Mar 11, 2021
2ba7e02
add file buffer
attack68 Mar 11, 2021
79b978b
optional table wrapping
attack68 Mar 11, 2021
ed8b405
refactor
attack68 Mar 11, 2021
f7d52f4
more flexible table_styles
attack68 Mar 11, 2021
f35c7e1
docs to parse_latex
attack68 Mar 12, 2021
521aee2
auto column_format for numerics
attack68 Mar 13, 2021
849656f
to_latex unit tests
attack68 Mar 13, 2021
cce7285
more unit tests and code bugs removed
attack68 Mar 13, 2021
26edba4
deal with multi col headers
attack68 Mar 13, 2021
3d7c614
deal with sparsification with multirow and multicol
attack68 Mar 13, 2021
e2f0f0c
tests for multirow and multicol
attack68 Mar 13, 2021
3243ed7
comprehensive test
attack68 Mar 13, 2021
0decf2d
refactor
attack68 Mar 13, 2021
c8dc5e5
change -wrap- to --wrap
attack68 Mar 13, 2021
8c58538
remove redundant comments
attack68 Mar 13, 2021
5c9d50a
docs
attack68 Mar 13, 2021
563aef6
docs
attack68 Mar 13, 2021
99abe1c
doc edits
attack68 Mar 14, 2021
5185f27
mypy fix
attack68 Mar 14, 2021
a824f13
docs
attack68 Mar 14, 2021
f6211e8
Merge remote-tracking branch 'upstream/master' into latex_styler_mvp
attack68 Mar 14, 2021
b46a9af
docs
attack68 Mar 14, 2021
7e3c5e1
docs
attack68 Mar 14, 2021
80d3cac
docs
attack68 Mar 14, 2021
9388dec
docs
attack68 Mar 14, 2021
ccac263
check fix
attack68 Mar 14, 2021
de69c21
col format for basic render
attack68 Mar 14, 2021
05f5b34
dependency fix
attack68 Mar 14, 2021
4d98615
Merge remote-tracking branch 'upstream/master' into latex_styler_mvp
attack68 Mar 15, 2021
f036d25
test for multicols and hidden cols combined
attack68 Mar 15, 2021
a9e0ce4
test for hidden columns in a multiindex
attack68 Mar 17, 2021
989278f
better test
attack68 Mar 17, 2021
3a79966
better test
attack68 Mar 17, 2021
9051bfe
Merge remote-tracking branch 'upstream/master' into latex_styler_mvp
attack68 Mar 21, 2021
938a0e8
fix latex for " "
attack68 Mar 21, 2021
0aed431
Merge remote-tracking branch 'upstream/master' into latex_styler_mvp
attack68 Mar 24, 2021
8af3c81
enhance the wrapping arguments
attack68 Mar 29, 2021
2e0aee6
remove render(latex=True) option
attack68 Mar 29, 2021
5067ffc
remove render(latex=True) option tests
attack68 Mar 29, 2021
ff4954e
remove render latex
attack68 Mar 29, 2021
d9836aa
remove render latex
attack68 Mar 29, 2021
5bdcb4e
put column headers in braces if not multicol
attack68 Mar 30, 2021
6f4a44b
add siunitx option, and expand docs
attack68 Mar 30, 2021
c211480
add sparsify as input argument and tests
attack68 Mar 30, 2021
2d32556
multirow and multicol alignment options
attack68 Mar 30, 2021
816e62f
test hidden index
attack68 Mar 30, 2021
9c577ce
change 'float' to 'position_float' to avoid shadow name
attack68 Mar 30, 2021
74721a8
doc internals
attack68 Mar 30, 2021
7c7f0de
change default wrap
attack68 Mar 30, 2021
f381011
Merge remote-tracking branch 'upstream/master' into latex_styler_mvp
attack68 Mar 30, 2021
b9ff43d
documentation
attack68 Mar 30, 2021
2f5cdec
documentation
attack68 Mar 31, 2021
4eacb12
clarify code
attack68 Mar 31, 2021
fd95e34
simplify code
attack68 Apr 1, 2021
7126bda
simplify code
attack68 Apr 1, 2021
25bcba9
simplify code
attack68 Apr 1, 2021
5ec08d8
basic subclassing
attack68 Apr 2, 2021
b74057b
basic subclassing
attack68 Apr 2, 2021
a49deeb
non_reducing_slice deprivatized
attack68 Apr 2, 2021
228f146
move io methods
attack68 Apr 2, 2021
44ead2d
import typing aliases
attack68 Apr 2, 2021
0ae8c39
rename renderer
attack68 Apr 2, 2021
70067c7
move to_excel and _repr_html_ back
attack68 Apr 2, 2021
3772cc8
move to_excel and _repr_html_ back
attack68 Apr 2, 2021
19828c3
Merge remote-tracking branch 'upstream/master' into basic_subclassing…
attack68 Apr 2, 2021
79ad3a6
Merge remote-tracking branch 'upstream/master' into basic_subclassing…
attack68 Apr 6, 2021
03415e5
fix typing to new standard
attack68 Apr 7, 2021
5697ff9
Merge remote-tracking branch 'upstream/master' into basic_subclassing…
attack68 Apr 9, 2021
41760e0
merge upstream master
attack68 Apr 10, 2021
92c11d1
Merge remote-tracking branch 'upstream/master' into basic_subclassing…
attack68 Apr 10, 2021
6547c6d
Merge branch 'basic_subclassing_styler' into latex_styler_mvp
attack68 Apr 10, 2021
3910fcf
Merge branch 'basic_subclassing_styler' into latex_styler_mvp
attack68 Apr 10, 2021
0164d90
documentation
attack68 Apr 11, 2021
463a54b
isort fix
attack68 Apr 11, 2021
4b7298f
doc improvements
attack68 Apr 11, 2021
47a31a9
doc improvements
attack68 Apr 11, 2021
c373bb6
Merge remote-tracking branch 'upstream/master' into latex_styler_mvp
attack68 Apr 12, 2021
8b00376
doc improvements
attack68 Apr 12, 2021
b1e230d
remove column_format branch
attack68 Apr 12, 2021
fd19d97
Merge remote-tracking branch 'upstream/master' into latex_styler_mvp
attack68 Apr 12, 2021
e31dba0
Merge remote-tracking branch 'upstream/master' into latex_styler_mvp
attack68 Apr 13, 2021
bdab13d
Merge remote-tracking branch 'upstream/master' into latex_styler_mvp
attack68 Apr 13, 2021
1074b62
Merge remote-tracking branch 'upstream/master' into latex_styler_mvp
attack68 Apr 13, 2021
394bc3a
Merge remote-tracking branch 'upstream/master' into latex_styler_mvp
attack68 Apr 14, 2021
034960f
doc fix
attack68 Apr 14, 2021
8b62f8d
Merge remote-tracking branch 'upstream/master' into latex_styler_mvp
attack68 Apr 14, 2021
a0f1e79
Merge remote-tracking branch 'upstream/master' into latex_styler_mvp
attack68 Apr 15, 2021
2e714e9
Merge remote-tracking branch 'upstream/master' into latex_styler_mvp
attack68 Apr 18, 2021
38c62eb
Merge remote-tracking branch 'upstream/master' into latex_styler_mvp
attack68 Apr 20, 2021
f95c21e
Merge remote-tracking branch 'upstream/master' into latex_styler_mvp
attack68 Apr 21, 2021
c925958
Merge remote-tracking branch 'upstream/master' into latex_styler_mvp
attack68 Apr 23, 2021
2cc8ad2
mutate d, so return None instead
attack68 Apr 24, 2021
7d962df
review the main to_latex docs (rhshadrach requests)
attack68 Apr 24, 2021
a6f6af2
validate position_float (rhshadrach request)
attack68 Apr 24, 2021
dce66d6
grammar fix
attack68 Apr 24, 2021
8fc9f0b
_parse_latex_table_wrapping doc and bool return (rhshadrach request)
attack68 Apr 24, 2021
bb4479b
_parse_latex_table_styles doc
attack68 Apr 24, 2021
e2ea5ae
_parse_latex_cell_styles doc chg and break (rhshadrach request)
attack68 Apr 24, 2021
518485d
fix boolean
attack68 Apr 24, 2021
d99245c
_parse_latex_header_span docs (rhshadrach request)
attack68 Apr 24, 2021
766ad49
_translate_latex docs and return (rhshadrach request)
attack68 Apr 24, 2021
ee92f37
Merge remote-tracking branch 'upstream/master' into latex_styler_mvp
attack68 Apr 26, 2021
b8e3418
Merge remote-tracking branch 'upstream/master' into latex_styler_mvp
attack68 Apr 26, 2021
2aca649
Merge remote-tracking branch 'upstream/master' into latex_styler_mvp
attack68 Apr 27, 2021
cf2f1e1
Merge remote-tracking branch 'upstream/master' into latex_styler_mvp
attack68 Apr 29, 2021
4d23e5e
Merge remote-tracking branch 'upstream/master' into latex_styler_mvp
attack68 May 1, 2021
1787084
CLN: index numeric columns whilst being duplicate proof.
attack68 May 1, 2021
9f71ac6
Merge remote-tracking branch 'upstream/master' into latex_styler_mvp
attack68 May 2, 2021
4c0d768
Merge remote-tracking branch 'upstream/master' into latex_styler_mvp
attack68 May 3, 2021
50afe1b
doc: removal of ] in docs (rhshadrach req)
attack68 May 4, 2021
987b11d
Merge remote-tracking branch 'upstream/master' into latex_styler_mvp
attack68 May 4, 2021
5eee5e5
doc: rewrite tables styles (rhshadrach req)
attack68 May 4, 2021
d271b0f
whats new
attack68 May 4, 2021
3675492
Merge remote-tracking branch 'upstream/master' into latex_styler_mvp
attack68 May 6, 2021
97aef70
version added
attack68 May 6, 2021
f11ece9
make most args keyword only
attack68 May 6, 2021
2db0b17
Merge remote-tracking branch 'upstream/master' into latex_styler_mvp
attack68 May 7, 2021
a4e29b5
non-unique latex test
attack68 May 7, 2021
c9e27f5
Merge remote-tracking branch 'upstream/master' into latex_styler_mvp
attack68 May 8, 2021
e4c9f00
Merge remote-tracking branch 'upstream/master' into latex_styler_mvp
attack68 May 10, 2021
c00fece
merge upsteam
attack68 May 12, 2021
c9f85ed
Merge remote-tracking branch 'upstream/master' into latex_styler_mvp
attack68 May 13, 2021
a406ff5
Merge remote-tracking branch 'upstream/master' into latex_styler_mvp
attack68 May 14, 2021
f3ce4ff
Merge remote-tracking branch 'upstream/master' into latex_styler_mvp
attack68 May 17, 2021
652c102
Merge remote-tracking branch 'upstream/master' into latex_styler_mvp
attack68 May 18, 2021
6c017c8
Merge remote-tracking branch 'upstream/master' into latex_styler_mvp
attack68 May 22, 2021
6f2f8a1
separate sparsify index and cols after recent upgrade on master
attack68 May 22, 2021
cbd189f
reactive to Styler option context tests
attack68 May 22, 2021
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
Binary file added doc/source/_static/style/latex_1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/source/_static/style/latex_2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions doc/source/reference/style.rst
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ Styler properties

Styler.env
Styler.template_html
Styler.template_latex
attack68 marked this conversation as resolved.
Show resolved Hide resolved
Styler.loader

Style application
Expand Down Expand Up @@ -66,3 +67,4 @@ Style export and import
Styler.export
Styler.use
Styler.to_excel
Styler.to_latex
304 changes: 304 additions & 0 deletions pandas/io/formats/style.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

from pandas._typing import (
Axis,
FilePathOrBuffer,
FrameOrSeries,
FrameOrSeriesUnion,
IndexLabel,
Expand All @@ -37,6 +38,8 @@
)
from pandas.core.generic import NDFrame

from pandas.io.formats.format import save_to_buffer

jinja2 = import_optional_dependency("jinja2", extra="DataFrame.style requires jinja2.")

from pandas.io.formats.style_render import (
Expand Down Expand Up @@ -340,6 +343,307 @@ def to_excel(
engine=engine,
)

def to_latex(
self,
buf: FilePathOrBuffer[str] | None = None,
column_format: str | None = None,
position: str | None = None,
position_float: str | None = None,
hrules: bool = False,
label: str | None = None,
caption: str | None = None,
sparsify: bool | None = None,
multirow_align: str = "c",
multicol_align: str = "r",
siunitx: bool = False,
encoding: str | None = None,
):
r"""
Write Styler to a file, buffer or string in LaTeX format.

.. versionadded:: TODO
attack68 marked this conversation as resolved.
Show resolved Hide resolved

Parameters
----------
buf : str, Path, or StringIO-like, optional, default None
Buffer to write to. If ``None``, the output is returned as a string.
column_format : str, optional
The LaTeX column specification placed in location:

\\begin{tabular}{<column_format>}

Defaults to 'l' for index and
non-numeric data columns, and, for numeric data columns,
to 'r' by default, or 'S' if ``siunitx`` is ``True``.
position : str, optional
The LaTeX positional argument (e.g. 'h!') for tables, placed in location:

\\begin{table}[<position>]
position_float : {"centering", "raggedleft", "raggedright"}, optional
The LaTeX float command placed in location:

\\begin{table}[<position>]

\\<position_float>
hrules : bool, default False
Set to `True` to add \\toprule, \\midrule and \\bottomrule from the
{booktabs} LaTeX package.
label : str, optional
The LaTeX label included as: \\label{<label>}.
This is used with \\ref{<label>} in the main .tex file.
caption : str, optional
jreback marked this conversation as resolved.
Show resolved Hide resolved
The LaTeX table caption included as: \\caption{<caption>}.
sparsify : bool, optional
Set to ``False`` to print every item of a hierarchical MultiIndex. Defaults
to the pandas ``multi_sparse`` display option.
multirow_align : {"c", "t", "b"}
If sparsifying hierarchical MultiIndexes whether to align text centrally,
at the top or bottom.
multicol_align : {"r", "c", "l"}
If sparsifying hierarchical MultiIndex columns whether to align text at
the left, centrally, or at the right.
siunitx : bool, default False
Set to ``True`` to structure LaTeX compatible with the {siunitx} package.
encoding : str, default "utf-8"
Character encoding setting.

Returns
-------
str or None
If `buf` is None, returns the result as a string. Otherwise returns `None`.

See Also
--------
Styler.format: Format the text display value of cells.

Notes
-----
**Latex Packages**

For the following features we recommend the following LaTeX inclusions:

===================== ==========================================================
Feature Inclusion
===================== ==========================================================
sparse columns none: included within default {tabular} environment
sparse rows \\usepackage{multirow}
hrules \\usepackage{booktabs}
colors \\usepackage[table]{xcolor}
siunitx \\usepackage{siunitx}
bold (with siunitx) | \\usepackage{etoolbox}
| \\robustify\\bfseries
| \\sisetup{detect-all = true} *(within {document})*
italic (with siunitx) | \\usepackage{etoolbox}
| \\robustify\\itshape
| \\sisetup{detect-all = true} *(within {document})*
===================== ==========================================================

**Cell Styles**

LaTeX styling can only be rendered if the accompanying styling functions have
been constructed with appropriate LaTeX commands. All styling
functionality is built around the concept of a CSS ``(<attribute>, <value>)``
pair (see `Table Visualization <../../user_guide/style.ipynb>`_), and this
should be replaced by a LaTeX
``(<command>, <options>)`` approach. Each cell will be styled individually
using nested LaTeX commands with their accompanied options.

For example the following code will highlight and bold a cell in HTML-CSS:

>>> df = pd.DataFrame([[1,2], [3,4]])
>>> s = df.style.highlight_max(axis=None,
... props='background-color:red; font-weight:bold;')
>>> s.render()

The equivalent using LaTeX only commands is the following:

>>> s = df.style.highlight_max(axis=None,
... props='cellcolor:{red}; bfseries: ;')
rhshadrach marked this conversation as resolved.
Show resolved Hide resolved
>>> s.to_latex()

Internally these structured LaTeX ``(<command>, <options>)`` pairs
are translated to the
``display_value`` with the default structure:
``\<command><options> <display_value>``.
rhshadrach marked this conversation as resolved.
Show resolved Hide resolved
Where there are multiple commands the latter is nested recursively, so that
the above example highlighed cell is rendered as
``\cellcolor{red} \bfseries 4``.

Occasionally this format does not suit the applied command, or
combination of LaTeX packages that is in use, so additional flags can be
added to the ``<options>``, within the tuple, to result in different
positions of required braces (the **default** being the same as ``--nowrap``):

=================================== ============================================
Tuple Format Output Structure
=================================== ============================================
(<command>,<options>) \\<command><options> <display_value>
(<command>,<options> ``--nowrap``) \\<command><options> <display_value>
(<command>,<options> ``--rwrap``) \\<command><options>{<display_value>}
(<command>,<options> ``--wrap``) {\\<command><options> <display_value>}
(<command>,<options> ``--lwrap``) {\\<command><options>} <display_value>
(<command>,<options> ``--dwrap``) {\\<command><options>}{<display_value>}
=================================== ============================================

For example the `textbf` command for font-weight
should always be used with `--rwrap` so ``('textbf', '--rwrap')`` will render a
working cell, wrapped with braces, as ``\textbf{<display_value>}``.

A more comprehensive example is as follows:

>>> df = pd.DataFrame([[1, 2.2, "dogs"], [3, 4.4, "cats"], [2, 6.6, "cows"]],
... index=["ix1", "ix2", "ix3"],
... columns=["Integers", "Floats", "Strings"])
>>> s = df.style.highlight_max(
... props='cellcolor:[HTML]{FFFF00}; color:{red};'
... 'textit:--rwrap; textbf:--rwrap;'
... )
>>> s.to_latex()

.. figure:: ../../_static/style/latex_1.png

**Table Styles**

Internally Styler uses its ``table_styles`` object to parse the
``column_format``, ``position``, ``position_float``, ``hrules`` and ``label``
input arguments. There is additional scope to add custom LaTeX commands,
which are included and positioned
immediately above the '\\begin{tabular}' command. For example to add odd and
even row coloring, from the {colortbl} package, use:
rhshadrach marked this conversation as resolved.
Show resolved Hide resolved

>>> s.set_table_styles([{'selector': 'rowcolors', 'props': ':{1}{pink}{red};'}],
... overwrite=False])
attack68 marked this conversation as resolved.
Show resolved Hide resolved

Instead of using ``hrules`` it is also possible to change the rule definition,
for example by setting just a ``toprule`` and ``bottomrule`` and ignoring
any ``midrule``:

>>> s.set_table_styles([{'selector': 'toprule', 'props': ':toprule;'},
... {'selector': 'bottomrule', 'props': ':hline;'}],
... overwrite=False])

A more comprehensive example using these arguments is as follows:

>>> df.columns = pd.MultiIndex.from_tuples([
... ("Numeric", "Integers"),
... ("Numeric", "Floats"),
... ("Non-Numeric", "Strings")
... ])
>>> df.index = pd.MultiIndex.from_tuples([
... ("L0", "ix1"), ("L0", "ix2"), ("L1", "ix3")
... ])
>>> s = df.style.highlight_max(
... props='cellcolor:[HTML]{FFFF00}; color:{red}; itshape:; bfseries:;'
... )
>>> s.to_latex(
... column_format="rrrrr", position="h", position_float="centering",
... hrules=True, label="table:5", caption="Styled LaTeX Table",
... multirow_align="t", multicol_align="r"
... )

.. figure:: ../../_static/style/latex_2.png

**Formatting**

To format values :meth:`Styler.format` should be used prior to calling
`Styler.to_latex`, as well as other method such as :meth:`Styler.hide_index`
or :meth:`Styler.hide_columns`, for example:

>>> s.clear()
>>> s.table_styles = []
>>> s.caption = None
>>> s.format({
... ("Numeric", "Integers"): '\${}',
... ("Numeric", "Floats"): '{:.3f}',
... ("Non-Numeric", "Strings"): str.upper
... })
>>> s.to_latex()
\\begin{tabular}{llrrl}
{} & {} & \\multicolumn{2}{r}{Numeric} & {Non-Numeric} \\\\
{} & {} & {Integers} & {Floats} & {Strings} \\\\
\\multirow[c]{2}{*}{L0} & ix1 & \\$1 & 2.200 & DOGS \\
& ix2 & \\$3 & 4.400 & CATS \\\\
L1 & ix3 & \\$2 & 6.600 & COWS \\\\
\\end{tabular}
"""
table_selectors = (
[style["selector"] for style in self.table_styles]
if self.table_styles is not None
else []
)

if column_format is not None:
# add more recent setting to table_styles
self.set_table_styles(
[{"selector": "column_format", "props": f":{column_format}"}],
overwrite=False,
)
elif "column_format" in table_selectors:
pass # adopt what has been previously set in table_styles
else:
rhshadrach marked this conversation as resolved.
Show resolved Hide resolved
# create a default: set float, complex, int cols to 'r' ('S'), index to 'l'
numeric_cols = list(self.data.select_dtypes(include=[np.number]).columns)
rhshadrach marked this conversation as resolved.
Show resolved Hide resolved
numeric_cols = list(self.columns.get_indexer_for(numeric_cols))
rhshadrach marked this conversation as resolved.
Show resolved Hide resolved
column_format = "" if self.hidden_index else "l" * self.data.index.nlevels
for ci, _ in enumerate(self.data.columns):
if ci not in self.hidden_columns:
column_format += (
("r" if not siunitx else "S") if ci in numeric_cols else "l"
)
self.set_table_styles(
[{"selector": "column_format", "props": f":{column_format}"}],
overwrite=False,
)

if position:
rhshadrach marked this conversation as resolved.
Show resolved Hide resolved
self.set_table_styles(
[{"selector": "position", "props": f":{position}"}],
overwrite=False,
)

if position_float:
rhshadrach marked this conversation as resolved.
Show resolved Hide resolved
if position_float not in ["raggedright", "raggedleft", "centering"]:
raise ValueError(
f"`position_float` should be one of "
f"'raggedright', 'raggedleft', 'centering', "
f"got: '{position_float}'"
)
self.set_table_styles(
[{"selector": "position_float", "props": f":{position_float}"}],
overwrite=False,
)

if hrules:
self.set_table_styles(
[
{"selector": "toprule", "props": ":toprule"},
{"selector": "midrule", "props": ":midrule"},
{"selector": "bottomrule", "props": ":bottomrule"},
],
overwrite=False,
)

if label:
self.set_table_styles(
[{"selector": "label", "props": f":{{{label.replace(':', '§')}}}"}],
overwrite=False,
)

if caption:
self.set_caption(caption)

if sparsify is not None:
with pd.option_context("display.multi_sparse", sparsify):
latex = self._render_latex(
multirow_align=multirow_align, multicol_align=multicol_align
)
else:
latex = self._render_latex(
multirow_align=multirow_align, multicol_align=multicol_align
)
Copy link
Member

Choose a reason for hiding this comment

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

could maybe use contextlib.nullcontext or pass through sparsify to ._render_latex and handle there?

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 good idea, would prefer to do this more generically as a follow-on: #41142 (logged an issue)


return save_to_buffer(latex, buf=buf, encoding=encoding)

def set_td_classes(self, classes: DataFrame) -> Styler:
"""
Set the DataFrame of strings added to the ``class`` attribute of ``<td>``
Expand Down
Loading