Skip to content

Commit ce03883

Browse files
authored
To latex position (#35284)
1 parent a21ce87 commit ce03883

File tree

4 files changed

+82
-15
lines changed

4 files changed

+82
-15
lines changed

pandas/core/generic.py

+5
Original file line numberDiff line numberDiff line change
@@ -2840,6 +2840,7 @@ def to_latex(
28402840
multirow=None,
28412841
caption=None,
28422842
label=None,
2843+
position=None,
28432844
):
28442845
r"""
28452846
Render object to a LaTeX tabular, longtable, or nested table/tabular.
@@ -2925,6 +2926,9 @@ def to_latex(
29252926
This is used with ``\ref{}`` in the main ``.tex`` file.
29262927
29272928
.. versionadded:: 1.0.0
2929+
position : str, optional
2930+
The LaTeX positional argument for tables, to be placed after
2931+
``\begin{}`` in the output.
29282932
%(returns)s
29292933
See Also
29302934
--------
@@ -2986,6 +2990,7 @@ def to_latex(
29862990
multirow=multirow,
29872991
caption=caption,
29882992
label=label,
2993+
position=position,
29892994
)
29902995

29912996
def to_csv(

pandas/io/formats/format.py

+2
Original file line numberDiff line numberDiff line change
@@ -931,6 +931,7 @@ def to_latex(
931931
multirow: bool = False,
932932
caption: Optional[str] = None,
933933
label: Optional[str] = None,
934+
position: Optional[str] = None,
934935
) -> Optional[str]:
935936
"""
936937
Render a DataFrame to a LaTeX tabular/longtable environment output.
@@ -946,6 +947,7 @@ def to_latex(
946947
multirow=multirow,
947948
caption=caption,
948949
label=label,
950+
position=position,
949951
).get_result(buf=buf, encoding=encoding)
950952

951953
def _format_col(self, i: int) -> List[str]:

pandas/io/formats/latex.py

+27-15
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ def __init__(
3838
multirow: bool = False,
3939
caption: Optional[str] = None,
4040
label: Optional[str] = None,
41+
position: Optional[str] = None,
4142
):
4243
self.fmt = formatter
4344
self.frame = self.fmt.frame
@@ -50,6 +51,8 @@ def __init__(
5051
self.caption = caption
5152
self.label = label
5253
self.escape = self.fmt.escape
54+
self.position = position
55+
self._table_float = any(p is not None for p in (caption, label, position))
5356

5457
def write_result(self, buf: IO[str]) -> None:
5558
"""
@@ -284,7 +287,7 @@ def _write_tabular_begin(self, buf, column_format: str):
284287
<https://en.wikibooks.org/wiki/LaTeX/Tables>`__ e.g 'rcl'
285288
for 3 columns
286289
"""
287-
if self.caption is not None or self.label is not None:
290+
if self._table_float:
288291
# then write output in a nested table/tabular environment
289292
if self.caption is None:
290293
caption_ = ""
@@ -296,7 +299,12 @@ def _write_tabular_begin(self, buf, column_format: str):
296299
else:
297300
label_ = f"\n\\label{{{self.label}}}"
298301

299-
buf.write(f"\\begin{{table}}\n\\centering{caption_}{label_}\n")
302+
if self.position is None:
303+
position_ = ""
304+
else:
305+
position_ = f"[{self.position}]"
306+
307+
buf.write(f"\\begin{{table}}{position_}\n\\centering{caption_}{label_}\n")
300308
else:
301309
# then write output only in a tabular environment
302310
pass
@@ -317,7 +325,7 @@ def _write_tabular_end(self, buf):
317325
"""
318326
buf.write("\\bottomrule\n")
319327
buf.write("\\end{tabular}\n")
320-
if self.caption is not None or self.label is not None:
328+
if self._table_float:
321329
buf.write("\\end{table}\n")
322330
else:
323331
pass
@@ -337,25 +345,29 @@ def _write_longtable_begin(self, buf, column_format: str):
337345
<https://en.wikibooks.org/wiki/LaTeX/Tables>`__ e.g 'rcl'
338346
for 3 columns
339347
"""
340-
buf.write(f"\\begin{{longtable}}{{{column_format}}}\n")
348+
if self.caption is None:
349+
caption_ = ""
350+
else:
351+
caption_ = f"\\caption{{{self.caption}}}"
341352

342-
if self.caption is not None or self.label is not None:
343-
if self.caption is None:
344-
pass
345-
else:
346-
buf.write(f"\\caption{{{self.caption}}}")
353+
if self.label is None:
354+
label_ = ""
355+
else:
356+
label_ = f"\\label{{{self.label}}}"
347357

348-
if self.label is None:
349-
pass
350-
else:
351-
buf.write(f"\\label{{{self.label}}}")
358+
if self.position is None:
359+
position_ = ""
360+
else:
361+
position_ = f"[{self.position}]"
352362

363+
buf.write(
364+
f"\\begin{{longtable}}{position_}{{{column_format}}}\n{caption_}{label_}"
365+
)
366+
if self.caption is not None or self.label is not None:
353367
# a double-backslash is required at the end of the line
354368
# as discussed here:
355369
# https://tex.stackexchange.com/questions/219138
356370
buf.write("\\\\\n")
357-
else:
358-
pass
359371

360372
@staticmethod
361373
def _write_longtable_end(buf):

pandas/tests/io/formats/test_to_latex.py

+48
Original file line numberDiff line numberDiff line change
@@ -573,6 +573,54 @@ def test_to_latex_longtable_caption_label(self):
573573
"""
574574
assert result_cl == expected_cl
575575

576+
def test_to_latex_position(self):
577+
the_position = "h"
578+
579+
df = DataFrame({"a": [1, 2], "b": ["b1", "b2"]})
580+
581+
# test when only the position is provided
582+
result_p = df.to_latex(position=the_position)
583+
584+
expected_p = r"""\begin{table}[h]
585+
\centering
586+
\begin{tabular}{lrl}
587+
\toprule
588+
{} & a & b \\
589+
\midrule
590+
0 & 1 & b1 \\
591+
1 & 2 & b2 \\
592+
\bottomrule
593+
\end{tabular}
594+
\end{table}
595+
"""
596+
assert result_p == expected_p
597+
598+
def test_to_latex_longtable_position(self):
599+
the_position = "t"
600+
601+
df = DataFrame({"a": [1, 2], "b": ["b1", "b2"]})
602+
603+
# test when only the position is provided
604+
result_p = df.to_latex(longtable=True, position=the_position)
605+
606+
expected_p = r"""\begin{longtable}[t]{lrl}
607+
\toprule
608+
{} & a & b \\
609+
\midrule
610+
\endhead
611+
\midrule
612+
\multicolumn{3}{r}{{Continued on next page}} \\
613+
\midrule
614+
\endfoot
615+
616+
\bottomrule
617+
\endlastfoot
618+
0 & 1 & b1 \\
619+
1 & 2 & b2 \\
620+
\end{longtable}
621+
"""
622+
assert result_p == expected_p
623+
576624
def test_to_latex_escape_special_chars(self):
577625
special_characters = ["&", "%", "$", "#", "_", "{", "}", "~", "^", "\\"]
578626
df = DataFrame(data=special_characters)

0 commit comments

Comments
 (0)