diff --git a/doc/source/whatsnew/v0.25.0.rst b/doc/source/whatsnew/v0.25.0.rst index 284943cf49070..ab2f8d66c37da 100644 --- a/doc/source/whatsnew/v0.25.0.rst +++ b/doc/source/whatsnew/v0.25.0.rst @@ -215,6 +215,7 @@ I/O - Bug in :func:`read_json` for ``orient='table'`` and float index, as it infers index dtype by default, which is not applicable because index dtype is already defined in the JSON schema (:issue:`25433`) - Bug in :func:`read_json` for ``orient='table'`` and string of float column names, as it makes a column name type conversion to Timestamp, which is not applicable because column names are already defined in the JSON schema (:issue:`25435`) - :meth:`DataFrame.to_html` now raises ``TypeError`` when using an invalid type for the ``classes`` parameter instead of ``AsseertionError`` (:issue:`25608`) +- Bug in :meth:`DataFrame.to_string` and :meth:`DataFrame.to_latex` that would lead to incorrect output when the ``header`` keyword is used (:issue:`16718`) - - diff --git a/pandas/io/formats/format.py b/pandas/io/formats/format.py index f68ef2cc39006..91e5edc8de9f4 100644 --- a/pandas/io/formats/format.py +++ b/pandas/io/formats/format.py @@ -528,6 +528,10 @@ def _to_str_columns(self): else: str_columns = self._get_formatted_column_labels(frame) + if self.show_row_idx_names: + for x in str_columns: + x.append('') + stringified = [] for i, c in enumerate(frame): cheader = str_columns[i] @@ -770,11 +774,6 @@ def space_format(x, y): need_leadsp[x] else x] for i, (col, x) in enumerate(zip(columns, fmt_columns))] - - if self.show_row_idx_names: - for x in str_columns: - x.append('') - # self.str_columns = str_columns return str_columns diff --git a/pandas/tests/io/formats/test_format.py b/pandas/tests/io/formats/test_format.py index b0cf5a2f17609..43bb382ea3f20 100644 --- a/pandas/tests/io/formats/test_format.py +++ b/pandas/tests/io/formats/test_format.py @@ -2380,6 +2380,14 @@ def test_to_string_header(self): exp = '0 0\n ..\n9 9' assert res == exp + def test_to_string_multindex_header(self): + # GH 16718 + df = (pd.DataFrame({'a': [0], 'b': [1], 'c': [2], 'd': [3]}) + .set_index(['a', 'b'])) + res = df.to_string(header=['r1', 'r2']) + exp = ' r1 r2\na b \n0 1 2 3' + assert res == exp + def _three_digit_exp(): return '{x:.4g}'.format(x=1.7e8) == '1.7e+008' diff --git a/pandas/tests/io/formats/test_to_latex.py b/pandas/tests/io/formats/test_to_latex.py index 1653e474aa7b0..4bec3bca1820b 100644 --- a/pandas/tests/io/formats/test_to_latex.py +++ b/pandas/tests/io/formats/test_to_latex.py @@ -735,3 +735,19 @@ def test_to_latex_float_format_no_fixed_width(self): \end{tabular} """ assert df.to_latex(float_format='%.0f') == expected + + def test_to_latex_multindex_header(self): + # GH 16718 + df = (pd.DataFrame({'a': [0], 'b': [1], 'c': [2], 'd': [3]}) + .set_index(['a', 'b'])) + observed = df.to_latex(header=['r1', 'r2']) + expected = r"""\begin{tabular}{llrr} +\toprule + & & r1 & r2 \\ +a & b & & \\ +\midrule +0 & 1 & 2 & 3 \\ +\bottomrule +\end{tabular} +""" + assert observed == expected