Repository: pandas-dev/pandas

Issue:
BUG: Wrong Latex Encoding
Assume a ``DataFrame`` ``df`` that looks like this:


    |      A      | B | ... |
    -------------------------
    |    a\b\c    | 2 | ... |
    |    p\y\c    | 9 | ... |
    |    a\d\x    | 4 | ... |

Calling ``to_latex`` on this ``DataFrame`` returns strings like ``a\textbackslashb\textbackslashc``, what obviously is an error for LaTeX. Expected and correct is  ``a\textbackslash b\textbackslash c``.

Tried with current master ``0.23.0.dev0+808.gd92d76e.dirty`` as well as with release ``0.22.0``.

Using ``escape=False`` returns ``a\b\c`` what is also an error for LaTeX (but expected). 
So there is no way currently to get valid LaTeX code from a DataFrame like this.


Discussion:

Resolving patch:
diff --git a/pandas/io/formats/latex.py b/pandas/io/formats/latex.py
--- a/pandas/io/formats/latex.py
+++ b/pandas/io/formats/latex.py
@@ -134,11 +134,13 @@ def pad_empties(x):
                     buf.write('\\endlastfoot\n')
             if self.fmt.kwds.get('escape', True):
                 # escape backslashes first
-                crow = [(x.replace('\\', '\\textbackslash').replace('_', '\\_')
+                crow = [(x.replace('\\', '\\textbackslash ')
+                         .replace('_', '\\_')
                          .replace('%', '\\%').replace('$', '\\$')
                          .replace('#', '\\#').replace('{', '\\{')
-                         .replace('}', '\\}').replace('~', '\\textasciitilde')
-                         .replace('^', '\\textasciicircum').replace('&', '\\&')
+                         .replace('}', '\\}').replace('~', '\\textasciitilde ')
+                         .replace('^', '\\textasciicircum ')
+                         .replace('&', '\\&')
                          if (x and x != '{}') else '{}') for x in row]
             else:
                 crow = [x if x else '{}' for x in row]


Test patch:
diff --git a/pandas/tests/io/formats/test_to_latex.py b/pandas/tests/io/formats/test_to_latex.py
--- a/pandas/tests/io/formats/test_to_latex.py
+++ b/pandas/tests/io/formats/test_to_latex.py
@@ -369,7 +369,7 @@ def test_to_latex_escape(self):
 
         escaped_expected = r'''\begin{tabular}{lll}
 \toprule
-{} & co\$e\textasciicircumx\$ & co\textasciicircuml1 \\
+{} & co\$e\textasciicircum x\$ & co\textasciicircum l1 \\
 \midrule
 a &       a &     a \\
 b &       b &     b \\
@@ -380,6 +380,22 @@ def test_to_latex_escape(self):
         assert unescaped_result == unescaped_expected
         assert escaped_result == escaped_expected
 
+    def test_to_latex_special_escape(self):
+        df = DataFrame([r"a\b\c", r"^a^b^c", r"~a~b~c"])
+
+        escaped_result = df.to_latex()
+        escaped_expected = r"""\begin{tabular}{ll}
+\toprule
+{} &       0 \\
+\midrule
+0 &   a\textbackslash b\textbackslash c \\
+1 &  \textasciicircum a\textasciicircum b\textasciicircum c \\
+2 &  \textasciitilde a\textasciitilde b\textasciitilde c \\
+\bottomrule
+\end{tabular}
+"""
+        assert escaped_result == escaped_expected
+
     def test_to_latex_longtable(self, frame):
         frame.to_latex(longtable=True)
 
@@ -447,9 +463,9 @@ def test_to_latex_escape_special_chars(self):
 4 &  \_ \\
 5 &  \{ \\
 6 &  \} \\
-7 &  \textasciitilde \\
-8 &  \textasciicircum \\
-9 &  \textbackslash \\
+7 &  \textasciitilde  \\
+8 &  \textasciicircum  \\
+9 &  \textbackslash  \\
 \bottomrule
 \end{tabular}
 """