Skip to content

Commit 8b70d96

Browse files
author
tp
committed
Improve MultiIndex repr str
1 parent bc37ea2 commit 8b70d96

File tree

3 files changed

+127
-5
lines changed

3 files changed

+127
-5
lines changed

doc/source/whatsnew/v0.23.1.txt

+30
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,36 @@ and bug fixes. We recommend that all users upgrade to this version.
1515
New features
1616
~~~~~~~~~~~~
1717

18+
.. _whatsnew_0231.enhancements.new_multi_index_repr_:
19+
20+
MultiIndex now has limits on many levels/labels are shown when printed
21+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
22+
23+
Outputting a :class:`MultiIndex` used to print all level/label of the
24+
multiindex. This could be a problem for large indices as the output could be
25+
slow to print and make the console output difficult to navigate.
26+
27+
Outputting of ``MultiIndex`` instances now has limits to the number of levels
28+
and labels shown ((:issue:`21145`):
29+
30+
.. ipython:: python
31+
32+
index1=range(1000)
33+
pd.MultiIndex.from_arrays([index1, index1])
34+
35+
Previously all 1000 index rows would have been shown.
36+
37+
For smaller number of values, all values will still be shown:
38+
39+
.. ipython:: python
40+
41+
index1=range(30)
42+
pd.MultiIndex.from_arrays([index1, index1])
43+
index1=range(2)
44+
pd.MultiIndex.from_arrays([index1, index1])
45+
46+
You can change the cutoff point for when all values are shown in the outputs
47+
by changing :attr:`options.display.max_seq_items` (default is 100).
1848

1949
.. _whatsnew_0231.deprecations:
2050

pandas/core/indexes/multi.py

+22-5
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
import numpy as np
88
from pandas._libs import algos as libalgos, index as libindex, lib, Timestamp
99

10-
from pandas.compat import range, zip, lrange, lzip, map
10+
from pandas.compat import range, zip, lrange, lzip, map, u
1111
from pandas.compat.numpy import function as nv
1212
from pandas import compat
1313

@@ -609,11 +609,28 @@ def _format_attrs(self):
609609
"""
610610
Return a list of tuples of the (attr,formatted_value)
611611
"""
612+
def to_string_helper(obj, attr_name):
613+
"""converts obj.attr_name to a string.
614+
"""
615+
indices = getattr(obj, attr_name)
616+
if attr_name == 'labels':
617+
# self.labels is a list of FrozenNDArray, Index._format_data
618+
# expects a pd.Index
619+
indices = [Index(i) for i in indices]
620+
621+
_name = u("{}({}=").format(obj.__class__.__name__, attr_name)
622+
attr_string = [idx._format_data(name=_name)
623+
for idx in indices]
624+
attr_string = u("").join(attr_string)
625+
if attr_string.endswith(u(", ")): # else [1, 2, ], want [1, 2]
626+
attr_string = attr_string[:-2]
627+
628+
return u("[{}]").format(attr_string)
629+
612630
attrs = [
613-
('levels', ibase.default_pprint(self._levels,
614-
max_seq_items=False)),
615-
('labels', ibase.default_pprint(self._labels,
616-
max_seq_items=False))]
631+
('levels', to_string_helper(self, attr_name='levels')),
632+
('labels', to_string_helper(self, attr_name='labels')),
633+
]
617634
if com._any_not_none(*self.names):
618635
attrs.append(('names', ibase.default_pprint(self.names)))
619636
if self.sortorder is not None:

pandas/tests/indexes/test_multi.py

+75
Original file line numberDiff line numberDiff line change
@@ -3279,3 +3279,78 @@ def test_duplicate_multiindex_labels(self):
32793279
with pytest.raises(ValueError):
32803280
ind.set_levels([['A', 'B', 'A', 'A', 'B'], [2, 1, 3, -2, 5]],
32813281
inplace=True)
3282+
3283+
def test_repr(self):
3284+
# GH21145
3285+
3286+
# no items
3287+
idx1, idx2 = range(0), []
3288+
idx = pd.MultiIndex.from_arrays([idx1, idx2])
3289+
expected = """\
3290+
MultiIndex(levels=[[], []],
3291+
labels=[[], []])"""
3292+
assert repr(idx) == expected
3293+
3294+
# two items
3295+
idx1, idx2 = range(2), ['a', 'b']
3296+
idx = MultiIndex.from_arrays([idx1, idx2])
3297+
expected = """\
3298+
MultiIndex(levels=[[0, 1], ['a', 'b']],
3299+
labels=[[0, 1], [0, 1]])"""
3300+
assert repr(idx) == expected
3301+
3302+
# 100 items
3303+
idx1, idx2 = range(100), range(100)
3304+
idx = pd.MultiIndex.from_arrays([idx1, idx2])
3305+
expected = """\
3306+
MultiIndex(levels=[[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
3307+
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
3308+
30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44,
3309+
45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
3310+
60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74,
3311+
75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89,
3312+
90, 91, 92, 93, 94, 95, 96, 97, 98, 99],
3313+
[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
3314+
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
3315+
30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44,
3316+
45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
3317+
60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74,
3318+
75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89,
3319+
90, 91, 92, 93, 94, 95, 96, 97, 98, 99],
3320+
],
3321+
labels=[[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
3322+
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
3323+
30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44,
3324+
45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
3325+
60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74,
3326+
75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89,
3327+
90, 91, 92, 93, 94, 95, 96, 97, 98, 99],
3328+
[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
3329+
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
3330+
30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44,
3331+
45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
3332+
60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74,
3333+
75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89,
3334+
90, 91, 92, 93, 94, 95, 96, 97, 98, 99],
3335+
])"""
3336+
assert repr(idx) == expected
3337+
3338+
# 1000 items
3339+
idx1, idx2 = range(1000), range(1000)
3340+
idx = pd.MultiIndex.from_arrays([idx1, idx2])
3341+
expected = """\
3342+
MultiIndex(levels=[[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
3343+
...
3344+
990, 991, 992, 993, 994, 995, 996, 997, 998, 999],
3345+
[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
3346+
...
3347+
990, 991, 992, 993, 994, 995, 996, 997, 998, 999],
3348+
],
3349+
labels=[[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
3350+
...
3351+
990, 991, 992, 993, 994, 995, 996, 997, 998, 999],
3352+
[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
3353+
...
3354+
990, 991, 992, 993, 994, 995, 996, 997, 998, 999],
3355+
])"""
3356+
assert repr(idx) == expected

0 commit comments

Comments
 (0)