From 6cd414515377c96ef2b59eb6e5f610d498a2253e Mon Sep 17 00:00:00 2001 From: Hans Kirchner Date: Mon, 23 Oct 2017 22:33:52 +0200 Subject: [PATCH 1/3] BUG: Fix to_latex with longtable (#17959) pandas.DataFrame.to_latex(longtable=True) always contained \multicolumn{3}{r}{{Continued on next page}} regardless of the number of columns in the output. --- doc/source/whatsnew/v0.21.0.txt | 1 + pandas/io/formats/format.py | 4 ++-- pandas/tests/io/formats/test_to_latex.py | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/doc/source/whatsnew/v0.21.0.txt b/doc/source/whatsnew/v0.21.0.txt index 89e2d3006696c..bbb4887f55e17 100644 --- a/doc/source/whatsnew/v0.21.0.txt +++ b/doc/source/whatsnew/v0.21.0.txt @@ -1089,6 +1089,7 @@ I/O - Bug in :meth:`DataFrame.to_html` in which there was no validation of the ``justify`` parameter (:issue:`17527`) - Bug in :func:`HDFStore.select` when reading a contiguous mixed-data table featuring VLArray (:issue:`17021`) - Bug in :func:`to_json` where several conditions (including objects with unprintable symbols, objects with deep recursion, overlong labels) caused segfaults instead of raising the appropriate exception (:issue:`14256`) +- Bug in :meth:`DataFrame.to_latex` with ``longtable=True`` where a latex multicolumn always spanned over three columns (:issue:`17959`) Plotting ^^^^^^^^ diff --git a/pandas/io/formats/format.py b/pandas/io/formats/format.py index 97abf60a40a5b..49233085c9e63 100644 --- a/pandas/io/formats/format.py +++ b/pandas/io/formats/format.py @@ -962,8 +962,8 @@ def get_col_type(dtype): if self.longtable: buf.write('\\endhead\n') buf.write('\\midrule\n') - buf.write('\\multicolumn{3}{r}{{Continued on next ' - 'page}} \\\\\n') + buf.write('\\multicolumn{{{n}}}{{r}}{{{{Continued on next ' + 'page}}}} \\\\\n'.format(n=len(row))) buf.write('\\midrule\n') buf.write('\\endfoot\n\n') buf.write('\\bottomrule\n') diff --git a/pandas/tests/io/formats/test_to_latex.py b/pandas/tests/io/formats/test_to_latex.py index 7d42ff20ea31e..81c2f90e9e1ff 100644 --- a/pandas/tests/io/formats/test_to_latex.py +++ b/pandas/tests/io/formats/test_to_latex.py @@ -367,7 +367,7 @@ def test_to_latex_longtable(self, frame): \midrule \endhead \midrule -\multicolumn{3}{r}{{Continued on next page}} \\ +\multicolumn{2}{r}{{Continued on next page}} \\ \midrule \endfoot From 60a4fc84f07428315620136bde49c91707601fab Mon Sep 17 00:00:00 2001 From: Hans Kirchner Date: Tue, 7 Nov 2017 17:36:59 +0100 Subject: [PATCH 2/3] Add test cases with 1 and 3 columns --- pandas/tests/io/formats/test_to_latex.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/pandas/tests/io/formats/test_to_latex.py b/pandas/tests/io/formats/test_to_latex.py index 81c2f90e9e1ff..efc9a676c01b3 100644 --- a/pandas/tests/io/formats/test_to_latex.py +++ b/pandas/tests/io/formats/test_to_latex.py @@ -400,6 +400,14 @@ def test_to_latex_longtable(self, frame): assert withoutindex_result == withoutindex_expected + df = DataFrame({'a': [1, 2]}) + with1column_result = df.to_latex(index=False, longtable=True) + assert "\multicolumn{1}" in with1column_result + + df = DataFrame({'a': [1, 2], 'b': [3, 4], 'c': [5, 6]}) + with3columns_result = df.to_latex(index=False, longtable=True) + assert "\multicolumn{3}" in with3columns_result + def test_to_latex_escape_special_chars(self): special_characters = ['&', '%', '$', '#', '_', '{', '}', '~', '^', '\\'] From 930471da320ca80a01fb8aec76635421beac11a4 Mon Sep 17 00:00:00 2001 From: gfyoung Date: Thu, 7 Dec 2017 21:23:52 -0800 Subject: [PATCH 3/3] MAINT: Address reviewer comments * Move whatsnew to 0.21.1.txt * Empty tests for empty DataFrame in to_latex --- doc/source/whatsnew/v0.21.0.txt | 1 - doc/source/whatsnew/v0.21.1.txt | 1 + pandas/tests/io/formats/test_to_latex.py | 29 +++++++++++++++++++++--- 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/doc/source/whatsnew/v0.21.0.txt b/doc/source/whatsnew/v0.21.0.txt index bbb4887f55e17..89e2d3006696c 100644 --- a/doc/source/whatsnew/v0.21.0.txt +++ b/doc/source/whatsnew/v0.21.0.txt @@ -1089,7 +1089,6 @@ I/O - Bug in :meth:`DataFrame.to_html` in which there was no validation of the ``justify`` parameter (:issue:`17527`) - Bug in :func:`HDFStore.select` when reading a contiguous mixed-data table featuring VLArray (:issue:`17021`) - Bug in :func:`to_json` where several conditions (including objects with unprintable symbols, objects with deep recursion, overlong labels) caused segfaults instead of raising the appropriate exception (:issue:`14256`) -- Bug in :meth:`DataFrame.to_latex` with ``longtable=True`` where a latex multicolumn always spanned over three columns (:issue:`17959`) Plotting ^^^^^^^^ diff --git a/doc/source/whatsnew/v0.21.1.txt b/doc/source/whatsnew/v0.21.1.txt index fbfbb403b2a17..ffeff4b59134c 100644 --- a/doc/source/whatsnew/v0.21.1.txt +++ b/doc/source/whatsnew/v0.21.1.txt @@ -127,6 +127,7 @@ I/O - Bug in :func:`pandas.io.json.json_normalize` to avoid modification of ``meta`` (:issue:`18610`) - Bug in :func:`to_latex` where repeated multi-index values were not printed even though a higher level index differed from the previous row (:issue:`14484`) - Bug when reading NaN-only categorical columns in :class:`HDFStore` (:issue:`18413`) +- Bug in :meth:`DataFrame.to_latex` with ``longtable=True`` where a latex multicolumn always spanned over three columns (:issue:`17959`) Plotting ^^^^^^^^ diff --git a/pandas/tests/io/formats/test_to_latex.py b/pandas/tests/io/formats/test_to_latex.py index efc9a676c01b3..600dd843fcdb4 100644 --- a/pandas/tests/io/formats/test_to_latex.py +++ b/pandas/tests/io/formats/test_to_latex.py @@ -91,6 +91,29 @@ def test_to_latex_format(self, frame): assert withindex_result == withindex_expected + def test_to_latex_empty(self): + df = DataFrame() + result = df.to_latex() + expected = r"""\begin{tabular}{l} +\toprule +Empty DataFrame +Columns: Index([], dtype='object') +Index: Index([], dtype='object') \\ +\bottomrule +\end{tabular} +""" + assert result == expected + + result = df.to_latex(longtable=True) + expected = r"""\begin{longtable}{l} +\toprule +Empty DataFrame +Columns: Index([], dtype='object') +Index: Index([], dtype='object') \\ +\end{longtable} +""" + assert result == expected + def test_to_latex_with_formatters(self): df = DataFrame({'int': [1, 2, 3], 'float': [1.0, 2.0, 3.0], @@ -367,7 +390,7 @@ def test_to_latex_longtable(self, frame): \midrule \endhead \midrule -\multicolumn{2}{r}{{Continued on next page}} \\ +\multicolumn{3}{r}{{Continued on next page}} \\ \midrule \endfoot @@ -377,7 +400,7 @@ def test_to_latex_longtable(self, frame): 1 & 2 & b2 \\ \end{longtable} """ - + open("expected.txt", "w").write(withindex_result) assert withindex_result == withindex_expected withoutindex_result = df.to_latex(index=False, longtable=True) @@ -387,7 +410,7 @@ def test_to_latex_longtable(self, frame): \midrule \endhead \midrule -\multicolumn{3}{r}{{Continued on next page}} \\ +\multicolumn{2}{r}{{Continued on next page}} \\ \midrule \endfoot