Skip to content

Commit 26a6316

Browse files
authored
EHN: df.to_latex(escape=True) also escape index names (#61307)
* use same format_index option to format_index_names * test * fix test * add ref to issues * rm blank line * Remove overwrite format_index_names when header defined * add test for columns.name
1 parent b519aa7 commit 26a6316

File tree

2 files changed

+50
-1
lines changed

2 files changed

+50
-1
lines changed

pandas/core/generic.py

+10-1
Original file line numberDiff line numberDiff line change
@@ -3568,6 +3568,7 @@ def _wrap(x, alt_format_):
35683568
elif formatters is None and float_format is not None:
35693569
formatters_ = partial(_wrap, alt_format_=lambda v: v)
35703570
format_index_ = [index_format_, column_format_]
3571+
format_index_names_ = [index_format_, column_format_]
35713572

35723573
# Deal with hiding indexes and relabelling column names
35733574
hide_: list[dict] = []
@@ -3616,6 +3617,7 @@ def _wrap(x, alt_format_):
36163617
relabel_index=relabel_index_,
36173618
format={"formatter": formatters_, **base_format_},
36183619
format_index=format_index_,
3620+
format_index_names=format_index_names_,
36193621
render_kwargs=render_kwargs_,
36203622
)
36213623

@@ -3628,6 +3630,7 @@ def _to_latex_via_styler(
36283630
relabel_index: dict | list[dict] | None = None,
36293631
format: dict | list[dict] | None = None,
36303632
format_index: dict | list[dict] | None = None,
3633+
format_index_names: dict | list[dict] | None = None,
36313634
render_kwargs: dict | None = None,
36323635
):
36333636
"""
@@ -3672,7 +3675,13 @@ def _to_latex_via_styler(
36723675
self = cast("DataFrame", self)
36733676
styler = Styler(self, uuid="")
36743677

3675-
for kw_name in ["hide", "relabel_index", "format", "format_index"]:
3678+
for kw_name in [
3679+
"hide",
3680+
"relabel_index",
3681+
"format",
3682+
"format_index",
3683+
"format_index_names",
3684+
]:
36763685
kw = vars()[kw_name]
36773686
if isinstance(kw, dict):
36783687
getattr(styler, kw_name)(**kw)

pandas/tests/io/formats/test_to_latex.py

+40
Original file line numberDiff line numberDiff line change
@@ -824,6 +824,46 @@ def test_to_latex_escape_special_chars(self):
824824
)
825825
assert result == expected
826826

827+
def test_to_latex_escape_special_chars_in_index_names(self):
828+
# https://github.com/pandas-dev/pandas/issues/61309
829+
# https://github.com/pandas-dev/pandas/issues/57362
830+
index = "&%$#_{}}~^\\"
831+
df = DataFrame({index: [1, 2, 3]}).set_index(index)
832+
result = df.to_latex(escape=True)
833+
expected = _dedent(
834+
r"""
835+
\begin{tabular}{l}
836+
\toprule
837+
\&\%\$\#\_\{\}\}\textasciitilde \textasciicircum \textbackslash \\
838+
\midrule
839+
1 \\
840+
2 \\
841+
3 \\
842+
\bottomrule
843+
\end{tabular}
844+
"""
845+
)
846+
assert result == expected
847+
848+
def test_to_latex_escape_special_chars_in_column_name(self):
849+
df = DataFrame({"A": [1, 2, 3], "B": ["a", "b", "c"]})
850+
df.columns.name = "_^~"
851+
result = df.to_latex(escape=True)
852+
expected = _dedent(
853+
r"""
854+
\begin{tabular}{lrl}
855+
\toprule
856+
\_\textasciicircum \textasciitilde & A & B \\
857+
\midrule
858+
0 & 1 & a \\
859+
1 & 2 & b \\
860+
2 & 3 & c \\
861+
\bottomrule
862+
\end{tabular}
863+
"""
864+
)
865+
assert result == expected
866+
827867
def test_to_latex_specified_header_special_chars_without_escape(self):
828868
# GH 7124
829869
df = DataFrame({"a": [1, 2], "b": ["b1", "b2"]})

0 commit comments

Comments
 (0)