Skip to content

Commit 02cea49

Browse files
m-kuhnjreback
authored andcommitted
ENH: Add an 'escape' keyword to DataFrame.to_latex (GH6472)
The new keyword prevents the conversion from escaping column names
1 parent 2c83a97 commit 02cea49

File tree

4 files changed

+55
-12
lines changed

4 files changed

+55
-12
lines changed

doc/source/release.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,7 @@ Improvements to existing features
264264
- :ref:`Holidays and holiday calendars<timeseries.holiday>` are now available and can be used with CustomBusinessDay (:issue:`6719`)
265265
- ``Float64Index`` is now backed by a ``float64`` dtype ndarray instead of an
266266
``object`` dtype array (:issue:`6471`).
267+
- Add option to turn off escaping in ``DataFrame.to_latex`` (:issue:`6472`)
267268

268269
.. _release.bug_fixes-0.14.0:
269270

pandas/core/format.py

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,7 @@ def to_latex(self, column_format=None, longtable=False):
422422
"""
423423
Render a DataFrame to a LaTeX tabular/longtable environment output.
424424
"""
425+
self.escape = self.kwds.get('escape', True)
425426
#TODO: column_format is not settable in df.to_latex
426427
def get_col_type(dtype):
427428
if issubclass(dtype.type, np.number):
@@ -471,16 +472,19 @@ def write(buf, frame, column_format, strcols, longtable=False):
471472
buf.write('\endfoot\n\n')
472473
buf.write('\\bottomrule\n')
473474
buf.write('\\endlastfoot\n')
474-
crow = [(x.replace('\\', '\\textbackslash') # escape backslashes first
475-
.replace('_', '\\_')
476-
.replace('%', '\\%')
477-
.replace('$', '\\$')
478-
.replace('#', '\\#')
479-
.replace('{', '\\{')
480-
.replace('}', '\\}')
481-
.replace('~', '\\textasciitilde')
482-
.replace('^', '\\textasciicircum')
483-
.replace('&', '\\&') if x else '{}') for x in row]
475+
if self.escape:
476+
crow = [(x.replace('\\', '\\textbackslash') # escape backslashes first
477+
.replace('_', '\\_')
478+
.replace('%', '\\%')
479+
.replace('$', '\\$')
480+
.replace('#', '\\#')
481+
.replace('{', '\\{')
482+
.replace('}', '\\}')
483+
.replace('~', '\\textasciitilde')
484+
.replace('^', '\\textasciicircum')
485+
.replace('&', '\\&') if x else '{}') for x in row]
486+
else:
487+
crow = [x if x else '{}' for x in row]
484488
buf.write(' & '.join(crow))
485489
buf.write(' \\\\\n')
486490

pandas/core/frame.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1348,7 +1348,7 @@ def to_html(self, buf=None, columns=None, col_space=None, colSpace=None,
13481348
def to_latex(self, buf=None, columns=None, col_space=None, colSpace=None,
13491349
header=True, index=True, na_rep='NaN', formatters=None,
13501350
float_format=None, sparsify=None, index_names=True,
1351-
bold_rows=True, longtable=False):
1351+
bold_rows=True, longtable=False, escape=True):
13521352
"""
13531353
Render a DataFrame to a tabular environment table. You can splice
13541354
this into a LaTeX document. Requires \\usepackage(booktabs}.
@@ -1360,6 +1360,9 @@ def to_latex(self, buf=None, columns=None, col_space=None, colSpace=None,
13601360
longtable : boolean, default False
13611361
Use a longtable environment instead of tabular. Requires adding
13621362
a \\usepackage{longtable} to your LaTeX preamble.
1363+
escape : boolean, default True
1364+
When set to False prevents from escaping latex special
1365+
characters in column names.
13631366
13641367
"""
13651368

@@ -1375,7 +1378,8 @@ def to_latex(self, buf=None, columns=None, col_space=None, colSpace=None,
13751378
float_format=float_format,
13761379
bold_rows=bold_rows,
13771380
sparsify=sparsify,
1378-
index_names=index_names)
1381+
index_names=index_names,
1382+
escape=escape)
13791383
formatter.to_latex(longtable=longtable)
13801384

13811385
if buf is None:

pandas/tests/test_format.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1671,6 +1671,40 @@ def test_to_latex(self):
16711671
"""
16721672
self.assertEqual(withoutindex_result, withoutindex_expected)
16731673

1674+
def test_to_latex_escape(self):
1675+
a = 'a'
1676+
b = 'b'
1677+
1678+
test_dict = {u('co^l1') : {a: "a",
1679+
b: "b"},
1680+
u('co$e^x$'): {a: "a",
1681+
b: "b"}}
1682+
1683+
unescaped_result = pd.DataFrame(test_dict).to_latex(escape=False)
1684+
escaped_result = pd.DataFrame(test_dict).to_latex() # default: escape=True
1685+
1686+
unescaped_expected = r'''\begin{tabular}{lll}
1687+
\toprule
1688+
{} & co$e^x$ & co^l1 \\
1689+
\midrule
1690+
a & a & a \\
1691+
b & b & b \\
1692+
\bottomrule
1693+
\end{tabular}
1694+
'''
1695+
1696+
escaped_expected = r'''\begin{tabular}{lll}
1697+
\toprule
1698+
{} & co\$e\textasciicircumx\$ & co\textasciicircuml1 \\
1699+
\midrule
1700+
a & a & a \\
1701+
b & b & b \\
1702+
\bottomrule
1703+
\end{tabular}
1704+
'''
1705+
self.assertEqual(unescaped_result, unescaped_expected)
1706+
self.assertEqual(escaped_result, escaped_expected)
1707+
16741708
def test_to_latex_longtable(self):
16751709
self.frame.to_latex(longtable=True)
16761710

0 commit comments

Comments
 (0)