Skip to content

Commit cb94eb2

Browse files
TomAugspurgerjorisvandenbossche
authored andcommitted
BUG: Fix MI repr with long names (pandas-dev#21655)
(cherry picked from commit ad76ffc)
1 parent 0e213e1 commit cb94eb2

File tree

3 files changed

+46
-3
lines changed

3 files changed

+46
-3
lines changed

doc/source/whatsnew/v0.23.2.txt

+1
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ Fixed Regressions
5555
- Fixed regression in :meth:`to_csv` when handling file-like object incorrectly (:issue:`21471`)
5656
- Re-allowed duplicate level names of a ``MultiIndex``. Accessing a level that has a duplicate name by name still raises an error (:issue:`19029`).
5757
- Bug in both :meth:`DataFrame.first_valid_index` and :meth:`Series.first_valid_index` raised for a row index having duplicate values (:issue:`21441`)
58+
- Fixed printing of DataFrames with hierarchical columns with long names (:issue:`21180`)
5859
- Fixed regression in :meth:`~DataFrame.reindex` and :meth:`~DataFrame.groupby`
5960
with a MultiIndex or multiple keys that contains categorical datetime-like values (:issue:`21390`).
6061
- Fixed regression in unary negative operations with object dtype (:issue:`21380`)

pandas/io/formats/format.py

+7-3
Original file line numberDiff line numberDiff line change
@@ -636,10 +636,14 @@ def to_string(self):
636636
mid = int(round(n_cols / 2.))
637637
mid_ix = col_lens.index[mid]
638638
col_len = col_lens[mid_ix]
639-
adj_dif -= (col_len + 1) # adjoin adds one
639+
# adjoin adds one
640+
adj_dif -= (col_len + 1)
640641
col_lens = col_lens.drop(mid_ix)
641642
n_cols = len(col_lens)
642-
max_cols_adj = n_cols - self.index # subtract index column
643+
# subtract index column
644+
max_cols_adj = n_cols - self.index
645+
# GH-21180. Ensure that we print at least two.
646+
max_cols_adj = max(max_cols_adj, 2)
643647
self.max_cols_adj = max_cols_adj
644648

645649
# Call again _chk_truncate to cut frame appropriately
@@ -778,7 +782,7 @@ def space_format(x, y):
778782

779783
str_columns = list(zip(*[[space_format(x, y) for y in x]
780784
for x in fmt_columns]))
781-
if self.sparsify:
785+
if self.sparsify and len(str_columns):
782786
str_columns = _sparsify(str_columns)
783787

784788
str_columns = [list(x) for x in zip(*str_columns)]

pandas/tests/io/formats/test_format.py

+38
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,44 @@ def test_repr_non_interactive(self):
305305
assert not has_truncated_repr(df)
306306
assert not has_expanded_repr(df)
307307

308+
def test_repr_truncates_terminal_size(self):
309+
# https://github.com/pandas-dev/pandas/issues/21180
310+
# TODO: use mock fixutre.
311+
# This is being backported, so doing it directly here.
312+
try:
313+
from unittest import mock
314+
except ImportError:
315+
mock = pytest.importorskip("mock")
316+
317+
terminal_size = (118, 96)
318+
p1 = mock.patch('pandas.io.formats.console.get_terminal_size',
319+
return_value=terminal_size)
320+
p2 = mock.patch('pandas.io.formats.format.get_terminal_size',
321+
return_value=terminal_size)
322+
323+
index = range(5)
324+
columns = pd.MultiIndex.from_tuples([
325+
('This is a long title with > 37 chars.', 'cat'),
326+
('This is a loooooonger title with > 43 chars.', 'dog'),
327+
])
328+
df = pd.DataFrame(1, index=index, columns=columns)
329+
330+
with p1, p2:
331+
result = repr(df)
332+
333+
h1, h2 = result.split('\n')[:2]
334+
assert 'long' in h1
335+
assert 'loooooonger' in h1
336+
assert 'cat' in h2
337+
assert 'dog' in h2
338+
339+
# regular columns
340+
df2 = pd.DataFrame({"A" * 41: [1, 2], 'B' * 41: [1, 2]})
341+
with p1, p2:
342+
result = repr(df2)
343+
344+
assert df2.columns[0] in result.split('\n')[0]
345+
308346
def test_repr_max_columns_max_rows(self):
309347
term_width, term_height = get_terminal_size()
310348
if term_width < 10 or term_height < 10:

0 commit comments

Comments
 (0)