Skip to content

Commit 2320fb3

Browse files
committed
ENH: add math mode with parentheses II
1 parent 0801f6a commit 2320fb3

File tree

2 files changed

+63
-22
lines changed

2 files changed

+63
-22
lines changed

pandas/io/formats/style_render.py

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1118,7 +1118,7 @@ def format(
11181118
\end{tabular}
11191119
11201120
Applying ``escape`` in 'latex-math' mode. In the example below
1121-
we enter math mode using the charackter ``$``.
1121+
we enter math mode using the character ``$``.
11221122
11231123
>>> df = pd.DataFrame([[r"$\sum_{i=1}^{10} a_i$ a~b $\alpha \
11241124
... = \frac{\beta}{\zeta^2}$"], ["%#^ $ \$x^2 $"]])
@@ -1130,7 +1130,7 @@ def format(
11301130
1 & \%\#\textasciicircum \space $ \$x^2 $ \\
11311131
\end{tabular}
11321132
1133-
We can use the charackter ``\(`` to enter math mode and the charackter ``\)``
1133+
We can use the character ``\(`` to enter math mode and the character ``\)``
11341134
to close math mode.
11351135
11361136
>>> df = pd.DataFrame([[r"\(\sum_{i=1}^{10} a_i\) a~b \(\alpha \
@@ -2359,7 +2359,8 @@ def _escape_latex(s):
23592359
Escaped string
23602360
"""
23612361
return (
2362-
s.replace("\\", "ab2§=§8yz") # rare string for final conversion: avoid \\ clash
2362+
s.replace("\\ ", "ab2§=§8yz")
2363+
.replace("\\", "ab2§=§8yz") # rare string for final conversion: avoid \\ clash
23632364
.replace("ab2§=§8yz ", "ab2§=§8yz\\space ") # since \backslash gobbles spaces
23642365
.replace("&", "\\&")
23652366
.replace("%", "\\%")
@@ -2372,8 +2373,6 @@ def _escape_latex(s):
23722373
.replace("~", "\\textasciitilde ")
23732374
.replace("^ ", "^\\space ") # since \textasciicircum gobbles spaces
23742375
.replace("^", "\\textasciicircum ")
2375-
.replace("ab2§=§8yz(", "\\( ")
2376-
.replace("ab2§=§8yz)", "\\) ")
23772376
.replace("ab2§=§8yz", "\\textbackslash ")
23782377
)
23792378

@@ -2385,7 +2384,6 @@ def _escape_latex_math(s):
23852384
The substrings in LaTeX math mode, which either are surrounded
23862385
by two characters ``$`` or start with the character ``\(`` and end with ``\)``,
23872386
are preserved without escaping. Otherwise regular LaTeX escaping applies.
2388-
See ``_escape_latex()``.
23892387
23902388
Parameters
23912389
----------
@@ -2419,15 +2417,33 @@ def _math_mode_with_parentheses(s):
24192417
for item in re.split(r"LEFT§=§6yz|ab5§=§RIGHT", s):
24202418
if item.startswith("LEFT") and item.endswith("RIGHT"):
24212419
res.append(item.replace("LEFT", r"\(").replace("RIGHT", r"\)"))
2422-
else:
2420+
elif "LEFT" in item and "RIGHT" in item:
24232421
res.append(
24242422
_escape_latex(item).replace("LEFT", r"\(").replace("RIGHT", r"\)")
24252423
)
2424+
else:
2425+
res.append(
2426+
_escape_latex(item)
2427+
.replace("LEFT", r"\textbackslash (")
2428+
.replace("RIGHT", r"\textbackslash )")
2429+
)
24262430
return "".join(res)
24272431

2428-
if s.replace(r"\$", "ab").find(r"$") > -1:
2429-
return _math_mode_with_dollar(s)
2430-
elif s.find(r"\(") > -1:
2431-
return _math_mode_with_parentheses(s)
2432+
s = s.replace(r"\$", r"rt8§=§7wz")
2433+
pattern_d = re.compile(r"\$.*?\$")
2434+
pattern_p = re.compile(r"\\(.*?\\)")
2435+
pos_d = 0
2436+
pos_p = 0
2437+
ps_d = pattern_d.search(s, pos_d)
2438+
ps_p = pattern_p.search(s, pos_p)
2439+
mode = []
2440+
if ps_d:
2441+
mode.append(ps_d.span()[0])
2442+
if ps_p:
2443+
mode.append(ps_p.span()[0])
2444+
if len(mode) == 0:
2445+
return _escape_latex(s.replace(r"\$", r"rt8§=§7wz"))
2446+
if s[min(mode)] == r"$":
2447+
return _math_mode_with_dollar(s.replace(r"\$", r"rt8§=§7wz"))
24322448
else:
2433-
return _escape_latex(s)
2449+
return _math_mode_with_parentheses(s.replace(r"\$", r"rt8§=§7wz"))

pandas/tests/io/formats/style/test_format.py

Lines changed: 35 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ def test_format_clear(styler, func, attr, kwargs):
167167
"latex",
168168
'<>\\&"\\%\\$\\#\\_\\{\\}\\textasciitilde \\textasciicircum '
169169
"\\textbackslash \\textasciitilde \\space \\textasciicircum \\space "
170-
"\\textbackslash \\space ",
170+
"\\textbackslash ",
171171
),
172172
],
173173
)
@@ -195,19 +195,44 @@ def test_format_escape_html(escape, exp):
195195
@pytest.mark.parametrize(
196196
"chars, expected",
197197
[
198-
(r"$\frac{1}{2} \$ x^2$ ", r"$\frac{1}{2} \$ x^2$ "),
199-
(r"\(\frac{1}{2} \$ x^2\) ", r"\(\frac{1}{2} \$ x^2\) "),
200-
(r"\)", r"\) "),
198+
(
199+
r"$ \$&%#_{}~^\ $ &%#_{}~^\ $",
200+
"".join(
201+
[
202+
r"$ \$&%#_{}~^\ $ ",
203+
r"\&\%\#\_\{\}\textasciitilde \textasciicircum \textbackslash \$",
204+
]
205+
),
206+
),
207+
(
208+
r"\( &%#_{}~^\ \) &%#_{}~^\ \(",
209+
"".join(
210+
[
211+
r"\( &%#_{}~^\ \) ",
212+
r"\&\%\#\_\{\}\textasciitilde \textasciicircum ",
213+
r"\textbackslash \textbackslash (",
214+
]
215+
),
216+
),
217+
(
218+
r"$ \frac{1}{2} $ \( \frac{1}{2} \)",
219+
"".join(
220+
[
221+
r"$ \frac{1}{2} $",
222+
r" \textbackslash ( \textbackslash frac\{1\}\{2\} \textbackslash )",
223+
]
224+
),
225+
),
201226
],
202227
)
203228
def test_format_escape_latex_math(chars, expected):
204-
df = DataFrame([["".join([chars, "~%#^"])]])
205-
229+
# GH 51903
230+
# latex-math escape works for each DataFrame cell separately.
231+
# If we have a combination of dollar signs and brackets,
232+
# the sign which occurs first would apply.
233+
df = DataFrame([[chars]])
206234
s = df.style.format("{0}", escape="latex-math")
207-
assert (
208-
"".join([expected, r"\textasciitilde \%\#\textasciicircum "])
209-
== s._translate(True, True)["body"][0][1]["display_value"]
210-
)
235+
assert s._translate(True, True)["body"][0][1]["display_value"] == expected
211236

212237

213238
def test_format_escape_na_rep():

0 commit comments

Comments
 (0)