Skip to content

Commit 475a980

Browse files
authored
BUG: fix duplicate entries in LaTeX List of Tables when using longtable environments (#36297)
1 parent 00a510b commit 475a980

File tree

3 files changed

+52
-4
lines changed

3 files changed

+52
-4
lines changed

doc/source/whatsnew/v1.2.0.rst

+1
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,7 @@ I/O
323323
- :meth:`to_csv` did not support zip compression for binary file object not having a filename (:issue:`35058`)
324324
- :meth:`to_csv` and :meth:`read_csv` did not honor `compression` and `encoding` for path-like objects that are internally converted to file-like objects (:issue:`35677`, :issue:`26124`, and :issue:`32392`)
325325
- :meth:`to_picke` and :meth:`read_pickle` did not support compression for file-objects (:issue:`26237`, :issue:`29054`, and :issue:`29570`)
326+
- Bug in :func:`LongTableBuilder.middle_separator` was duplicating LaTeX longtable entires in the List of Tables of a LaTeX document (:issue:`34360`)
326327
- Bug in :meth:`read_csv` with `engine='python'` truncating data if multiple items present in first row and first element started with BOM (:issue:`36343`)
327328

328329
Plotting

pandas/io/formats/latex.py

+18-4
Original file line numberDiff line numberDiff line change
@@ -431,13 +431,18 @@ class LongTableBuilder(GenericTableBuilder):
431431
>>> from pandas.io.formats import format as fmt
432432
>>> df = DataFrame({"a": [1, 2], "b": ["b1", "b2"]})
433433
>>> formatter = fmt.DataFrameFormatter(df)
434-
>>> builder = LongTableBuilder(formatter, caption='caption', label='lab',
435-
... column_format='lrl')
434+
>>> builder = LongTableBuilder(formatter, caption='a long table',
435+
... label='tab:long', column_format='lrl')
436436
>>> table = builder.get_result()
437437
>>> print(table)
438438
\\begin{longtable}{lrl}
439-
\\caption{caption}
440-
\\label{lab}\\\\
439+
\\caption{a long table}
440+
\\label{tab:long}\\\\
441+
\\toprule
442+
{} & a & b \\\\
443+
\\midrule
444+
\\endfirsthead
445+
\\caption[]{a long table} \\\\
441446
\\toprule
442447
{} & a & b \\\\
443448
\\midrule
@@ -476,7 +481,16 @@ def _caption_and_label(self) -> str:
476481
@property
477482
def middle_separator(self) -> str:
478483
iterator = self._create_row_iterator(over="header")
484+
485+
# the content between \endfirsthead and \endhead commands
486+
# mitigates repeated List of Tables entries in the final LaTeX
487+
# document when dealing with longtable environments; GH #34360
479488
elements = [
489+
"\\midrule",
490+
"\\endfirsthead",
491+
f"\\caption[]{{{self.caption}}} \\\\" if self.caption else "",
492+
self.top_separator,
493+
self.header,
480494
"\\midrule",
481495
"\\endhead",
482496
"\\midrule",

pandas/tests/io/formats/test_to_latex.py

+33
Original file line numberDiff line numberDiff line change
@@ -411,6 +411,11 @@ def test_to_latex_longtable(self):
411411
df = DataFrame({"a": [1, 2], "b": ["b1", "b2"]})
412412
withindex_result = df.to_latex(longtable=True)
413413
withindex_expected = r"""\begin{longtable}{lrl}
414+
\toprule
415+
{} & a & b \\
416+
\midrule
417+
\endfirsthead
418+
414419
\toprule
415420
{} & a & b \\
416421
\midrule
@@ -430,6 +435,11 @@ def test_to_latex_longtable(self):
430435

431436
withoutindex_result = df.to_latex(index=False, longtable=True)
432437
withoutindex_expected = r"""\begin{longtable}{rl}
438+
\toprule
439+
a & b \\
440+
\midrule
441+
\endfirsthead
442+
433443
\toprule
434444
a & b \\
435445
\midrule
@@ -525,6 +535,9 @@ def test_to_latex_longtable_caption_label(self):
525535

526536
df = DataFrame({"a": [1, 2], "b": ["b1", "b2"]})
527537

538+
# test when no caption and no label is provided
539+
# is performed by test_to_latex_longtable()
540+
528541
# test when only the caption is provided
529542
result_c = df.to_latex(longtable=True, caption=the_caption)
530543

@@ -533,6 +546,11 @@ def test_to_latex_longtable_caption_label(self):
533546
\toprule
534547
{} & a & b \\
535548
\midrule
549+
\endfirsthead
550+
\caption[]{a table in a \texttt{longtable} environment} \\
551+
\toprule
552+
{} & a & b \\
553+
\midrule
536554
\endhead
537555
\midrule
538556
\multicolumn{3}{r}{{Continued on next page}} \\
@@ -552,6 +570,11 @@ def test_to_latex_longtable_caption_label(self):
552570

553571
expected_l = r"""\begin{longtable}{lrl}
554572
\label{tab:longtable}\\
573+
\toprule
574+
{} & a & b \\
575+
\midrule
576+
\endfirsthead
577+
555578
\toprule
556579
{} & a & b \\
557580
\midrule
@@ -578,6 +601,11 @@ def test_to_latex_longtable_caption_label(self):
578601
\toprule
579602
{} & a & b \\
580603
\midrule
604+
\endfirsthead
605+
\caption[]{a table in a \texttt{longtable} environment} \\
606+
\toprule
607+
{} & a & b \\
608+
\midrule
581609
\endhead
582610
\midrule
583611
\multicolumn{3}{r}{{Continued on next page}} \\
@@ -623,6 +651,11 @@ def test_to_latex_longtable_position(self):
623651
result_p = df.to_latex(longtable=True, position=the_position)
624652

625653
expected_p = r"""\begin{longtable}[t]{lrl}
654+
\toprule
655+
{} & a & b \\
656+
\midrule
657+
\endfirsthead
658+
626659
\toprule
627660
{} & a & b \\
628661
\midrule

0 commit comments

Comments
 (0)