Skip to content

BUG: fix duplicate entries in LaTeX List of Tables when using longtable environments #36297

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Sep 19, 2020
1 change: 1 addition & 0 deletions doc/source/whatsnew/v1.2.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,7 @@ I/O
- :meth:`to_csv` did not support zip compression for binary file object not having a filename (:issue:`35058`)
- :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`)
- :meth:`to_picke` and :meth:`read_pickle` did not support compression for file-objects (:issue:`26237`, :issue:`29054`, and :issue:`29570`)
- Bug in :func:`LongTableBuilder.middle_separator` was duplicating LaTeX longtable entires in the List of Tables of a LaTeX document (:issue:`34360`)
- 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`)

Plotting
Expand Down
22 changes: 18 additions & 4 deletions pandas/io/formats/latex.py
Original file line number Diff line number Diff line change
Expand Up @@ -431,13 +431,18 @@ class LongTableBuilder(GenericTableBuilder):
>>> from pandas.io.formats import format as fmt
>>> df = DataFrame({"a": [1, 2], "b": ["b1", "b2"]})
>>> formatter = fmt.DataFrameFormatter(df)
>>> builder = LongTableBuilder(formatter, caption='caption', label='lab',
... column_format='lrl')
>>> builder = LongTableBuilder(formatter, caption='a long table',
... label='tab:long', column_format='lrl')
>>> table = builder.get_result()
>>> print(table)
\\begin{longtable}{lrl}
\\caption{caption}
\\label{lab}\\\\
\\caption{a long table}
\\label{tab:long}\\\\
\\toprule
{} & a & b \\\\
\\midrule
\\endfirsthead
\\caption[]{a long table} \\\\
\\toprule
{} & a & b \\\\
\\midrule
Expand Down Expand Up @@ -476,7 +481,16 @@ def _caption_and_label(self) -> str:
@property
def middle_separator(self) -> str:
iterator = self._create_row_iterator(over="header")

# the content between \endfirsthead and \endhead commands
# mitigates repeated List of Tables entries in the final LaTeX
# document when dealing with longtable environments; GH #34360
elements = [
"\\midrule",
"\\endfirsthead",
f"\\caption[]{{{self.caption}}} \\\\" if self.caption else "",
self.top_separator,
self.header,
"\\midrule",
"\\endhead",
"\\midrule",
Expand Down
33 changes: 33 additions & 0 deletions pandas/tests/io/formats/test_to_latex.py
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,11 @@ def test_to_latex_longtable(self):
df = DataFrame({"a": [1, 2], "b": ["b1", "b2"]})
withindex_result = df.to_latex(longtable=True)
withindex_expected = r"""\begin{longtable}{lrl}
\toprule
{} & a & b \\
\midrule
\endfirsthead

\toprule
{} & a & b \\
\midrule
Expand All @@ -430,6 +435,11 @@ def test_to_latex_longtable(self):

withoutindex_result = df.to_latex(index=False, longtable=True)
withoutindex_expected = r"""\begin{longtable}{rl}
\toprule
a & b \\
\midrule
\endfirsthead

\toprule
a & b \\
\midrule
Expand Down Expand Up @@ -525,6 +535,9 @@ def test_to_latex_longtable_caption_label(self):

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

# test when no caption and no label is provided
# is performed by test_to_latex_longtable()

# test when only the caption is provided
result_c = df.to_latex(longtable=True, caption=the_caption)

Expand All @@ -533,6 +546,11 @@ def test_to_latex_longtable_caption_label(self):
\toprule
{} & a & b \\
\midrule
\endfirsthead
\caption[]{a table in a \texttt{longtable} environment} \\
\toprule
{} & a & b \\
\midrule
\endhead
\midrule
\multicolumn{3}{r}{{Continued on next page}} \\
Expand All @@ -552,6 +570,11 @@ def test_to_latex_longtable_caption_label(self):

expected_l = r"""\begin{longtable}{lrl}
\label{tab:longtable}\\
\toprule
{} & a & b \\
\midrule
\endfirsthead

\toprule
{} & a & b \\
\midrule
Expand All @@ -578,6 +601,11 @@ def test_to_latex_longtable_caption_label(self):
\toprule
{} & a & b \\
\midrule
\endfirsthead
\caption[]{a table in a \texttt{longtable} environment} \\
\toprule
{} & a & b \\
\midrule
\endhead
\midrule
\multicolumn{3}{r}{{Continued on next page}} \\
Expand Down Expand Up @@ -623,6 +651,11 @@ def test_to_latex_longtable_position(self):
result_p = df.to_latex(longtable=True, position=the_position)

expected_p = r"""\begin{longtable}[t]{lrl}
\toprule
{} & a & b \\
\midrule
\endfirsthead

\toprule
{} & a & b \\
\midrule
Expand Down