diff --git a/doc/source/whatsnew/v1.3.0.rst b/doc/source/whatsnew/v1.3.0.rst index 74710ca48308c..6099ab4a9c365 100644 --- a/doc/source/whatsnew/v1.3.0.rst +++ b/doc/source/whatsnew/v1.3.0.rst @@ -796,7 +796,8 @@ I/O - Bug in :func:`read_sas` raising ``ValueError`` when ``datetimes`` were null (:issue:`39725`) - Bug in :func:`read_excel` dropping empty values from single-column spreadsheets (:issue:`39808`) - Bug in :func:`read_excel` raising ``AttributeError`` with ``MultiIndex`` header followed by two empty rows and no index, and bug affecting :func:`read_excel`, :func:`read_csv`, :func:`read_table`, :func:`read_fwf`, and :func:`read_clipboard` where one blank row after a ``MultiIndex`` header with no index would be dropped (:issue:`40442`) -- Bug in :meth:`DataFrame.to_string` misplacing the truncation column when ``index=False`` (:issue:`40907`) +- Bug in :meth:`DataFrame.to_string` misplacing the truncation column when ``index=False`` (:issue:`40904`) +- Bug in :meth:`DataFrame.to_string` adding an extra dot and misaligning the truncation row when ``index=False`` (:issue:`40904`) - Bug in :func:`read_orc` always raising ``AttributeError`` (:issue:`40918`) - Bug in the conversion from pyarrow to pandas (e.g. for reading Parquet) with nullable dtypes and a pyarrow array whose data buffer size is not a multiple of dtype size (:issue:`40896`) diff --git a/pandas/io/formats/string.py b/pandas/io/formats/string.py index de53646b5f95f..20fc84a4df303 100644 --- a/pandas/io/formats/string.py +++ b/pandas/io/formats/string.py @@ -74,11 +74,14 @@ def _insert_dot_separators(self, strcols: List[List[str]]) -> List[List[str]]: return strcols + @property + def _adjusted_tr_col_num(self) -> int: + return self.fmt.tr_col_num + 1 if self.fmt.index else self.fmt.tr_col_num + def _insert_dot_separator_horizontal( self, strcols: List[List[str]], index_length: int ) -> List[List[str]]: - tr_col_num = self.fmt.tr_col_num + 1 if self.fmt.index else self.fmt.tr_col_num - strcols.insert(tr_col_num, [" ..."] * index_length) + strcols.insert(self._adjusted_tr_col_num, [" ..."] * index_length) return strcols def _insert_dot_separator_vertical( @@ -90,7 +93,7 @@ def _insert_dot_separator_vertical( cwidth = self.adj.len(col[row_num]) if self.fmt.is_truncated_horizontally: - is_dot_col = ix == self.fmt.tr_col_num + 1 + is_dot_col = ix == self._adjusted_tr_col_num else: is_dot_col = False @@ -99,7 +102,7 @@ def _insert_dot_separator_vertical( else: dots = ".." - if ix == 0: + if ix == 0 and self.fmt.index: dot_mode = "left" elif is_dot_col: cwidth = 4 diff --git a/pandas/tests/io/formats/test_to_string.py b/pandas/tests/io/formats/test_to_string.py index f9b3cac3527ef..65a438ad6108b 100644 --- a/pandas/tests/io/formats/test_to_string.py +++ b/pandas/tests/io/formats/test_to_string.py @@ -107,37 +107,51 @@ def test_format_remove_leading_space_dataframe(input_array, expected): @pytest.mark.parametrize( - "max_cols, expected", + "max_cols, max_rows, expected", [ ( 10, - [ - " 0 1 2 3 4 ... 6 7 8 9 10", - " 0 0 0 0 0 ... 0 0 0 0 0", - " 0 0 0 0 0 ... 0 0 0 0 0", - ], + None, + " 0 1 2 3 4 ... 6 7 8 9 10\n" + " 0 0 0 0 0 ... 0 0 0 0 0\n" + " 0 0 0 0 0 ... 0 0 0 0 0\n" + " 0 0 0 0 0 ... 0 0 0 0 0\n" + " 0 0 0 0 0 ... 0 0 0 0 0", + ), + ( + None, + 2, + " 0 1 2 3 4 5 6 7 8 9 10\n" + " 0 0 0 0 0 0 0 0 0 0 0\n" + " .. .. .. .. .. .. .. .. .. .. ..\n" + " 0 0 0 0 0 0 0 0 0 0 0", + ), + ( + 10, + 2, + " 0 1 2 3 4 ... 6 7 8 9 10\n" + " 0 0 0 0 0 ... 0 0 0 0 0\n" + " .. .. .. .. .. ... .. .. .. .. ..\n" + " 0 0 0 0 0 ... 0 0 0 0 0", ), ( 9, - [ - " 0 1 2 3 ... 7 8 9 10", - " 0 0 0 0 ... 0 0 0 0", - " 0 0 0 0 ... 0 0 0 0", - ], + 2, + " 0 1 2 3 ... 7 8 9 10\n" + " 0 0 0 0 ... 0 0 0 0\n" + " .. .. .. .. ... .. .. .. ..\n" + " 0 0 0 0 ... 0 0 0 0", ), ( 1, - [ - " 0 ...", - " 0 ...", - " 0 ...", - ], + 1, + " 0 ...\n 0 ...\n.. ...", ), ], ) -def test_truncation_col_placement_no_index(max_cols, expected): - df = DataFrame([[0] * 11] * 2) - assert df.to_string(index=False, max_cols=max_cols).split("\n") == expected +def test_truncation_no_index(max_cols, max_rows, expected): + df = DataFrame([[0] * 11] * 4) + assert df.to_string(index=False, max_cols=max_cols, max_rows=max_rows) == expected def test_to_string_unicode_columns(float_frame):