Skip to content

Commit

Permalink
ENH: better MultiIndex.__repr__ (#22511)
Browse files Browse the repository at this point in the history
  • Loading branch information
topper-123 authored and jreback committed Jun 19, 2019
1 parent 376a05e commit d47947a
Show file tree
Hide file tree
Showing 9 changed files with 451 additions and 146 deletions.
9 changes: 5 additions & 4 deletions doc/source/user_guide/advanced.rst
Original file line number Diff line number Diff line change
Expand Up @@ -182,15 +182,15 @@ on a deeper level.
Defined Levels
~~~~~~~~~~~~~~

The repr of a ``MultiIndex`` shows all the defined levels of an index, even
The :class:`MultiIndex` keeps all the defined levels of an index, even
if they are not actually used. When slicing an index, you may notice this.
For example:

.. ipython:: python
  df.columns # original MultiIndex
  df.columns.levels # original MultiIndex
df[['foo','qux']].columns # sliced
df[['foo','qux']].columns.levels # sliced
This is done to avoid a recomputation of the levels in order to make slicing
highly performant. If you want to see only the used levels, you can use the
Expand All @@ -210,7 +210,8 @@ To reconstruct the ``MultiIndex`` with only the used levels, the

.. ipython:: python
df[['foo', 'qux']].columns.remove_unused_levels()
new_mi = df[['foo', 'qux']].columns.remove_unused_levels()
new_mi.levels
Data alignment and using ``reindex``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Expand Down
32 changes: 32 additions & 0 deletions doc/source/whatsnew/v0.25.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,38 @@ a dict to a Series groupby aggregation (:ref:`whatsnew_0200.api_breaking.depreca

See :ref:`groupby.aggregate.named` for more.


.. _whatsnew_0250.enhancements.multi_index_repr:

Better repr for MultiIndex
^^^^^^^^^^^^^^^^^^^^^^^^^^

Printing of :class:`MultiIndex` instances now shows tuples of each row and ensures
that the tuple items are vertically aligned, so it's now easier to understand
the structure of the ``MultiIndex``. (:issue:`13480`):

The repr now looks like this:

.. ipython:: python
pd.MultiIndex.from_product([['a', 'abc'], range(500)])
Previously, outputting a :class:`MultiIndex` printed all the ``levels`` and
``codes`` of the ``MultiIndex``, which was visually unappealing and made
the output more difficult to navigate. For example (limiting the range to 5):

.. code-block:: ipython
In [1]: pd.MultiIndex.from_product([['a', 'abc'], range(5)])
Out[1]: MultiIndex(levels=[['a', 'abc'], [0, 1, 2, 3]],
...: codes=[[0, 0, 0, 0, 1, 1, 1, 1], [0, 1, 2, 3, 0, 1, 2, 3]])
In the new repr, all values will be shown, if the number of rows is smaller
than :attr:`options.display.max_seq_items` (default: 100 items). Horizontally,
the output will truncate, if it's wider than :attr:`options.display.width`
(default: 80 characters).


.. _whatsnew_0250.enhancements.other:

Other Enhancements
Expand Down
41 changes: 27 additions & 14 deletions pandas/core/indexes/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -1332,16 +1332,23 @@ def set_names(self, names, level=None, inplace=False):
>>> idx = pd.MultiIndex.from_product([['python', 'cobra'],
... [2018, 2019]])
>>> idx
MultiIndex(levels=[['cobra', 'python'], [2018, 2019]],
codes=[[1, 1, 0, 0], [0, 1, 0, 1]])
MultiIndex([('python', 2018),
('python', 2019),
( 'cobra', 2018),
( 'cobra', 2019)],
)
>>> idx.set_names(['kind', 'year'], inplace=True)
>>> idx
MultiIndex(levels=[['cobra', 'python'], [2018, 2019]],
codes=[[1, 1, 0, 0], [0, 1, 0, 1]],
MultiIndex([('python', 2018),
('python', 2019),
( 'cobra', 2018),
( 'cobra', 2019)],
names=['kind', 'year'])
>>> idx.set_names('species', level=0)
MultiIndex(levels=[['cobra', 'python'], [2018, 2019]],
codes=[[1, 1, 0, 0], [0, 1, 0, 1]],
MultiIndex([('python', 2018),
('python', 2019),
( 'cobra', 2018),
( 'cobra', 2019)],
names=['species', 'year'])
"""

Expand Down Expand Up @@ -1403,12 +1410,16 @@ def rename(self, name, inplace=False):
... [2018, 2019]],
... names=['kind', 'year'])
>>> idx
MultiIndex(levels=[['cobra', 'python'], [2018, 2019]],
codes=[[1, 1, 0, 0], [0, 1, 0, 1]],
MultiIndex([('python', 2018),
('python', 2019),
( 'cobra', 2018),
( 'cobra', 2019)],
names=['kind', 'year'])
>>> idx.rename(['species', 'year'])
MultiIndex(levels=[['cobra', 'python'], [2018, 2019]],
codes=[[1, 1, 0, 0], [0, 1, 0, 1]],
MultiIndex([('python', 2018),
('python', 2019),
( 'cobra', 2018),
( 'cobra', 2019)],
names=['species', 'year'])
>>> idx.rename('species')
Traceback (most recent call last):
Expand Down Expand Up @@ -5442,8 +5453,8 @@ def ensure_index_from_sequences(sequences, names=None):
>>> ensure_index_from_sequences([['a', 'a'], ['a', 'b']],
names=['L1', 'L2'])
MultiIndex(levels=[['a'], ['a', 'b']],
codes=[[0, 0], [0, 1]],
MultiIndex([('a', 'a'),
('a', 'b')],
names=['L1', 'L2'])
See Also
Expand Down Expand Up @@ -5483,8 +5494,10 @@ def ensure_index(index_like, copy=False):
Index([('a', 'a'), ('b', 'c')], dtype='object')
>>> ensure_index([['a', 'a'], ['b', 'c']])
MultiIndex(levels=[['a'], ['b', 'c']],
codes=[[0, 0], [0, 1]])
MultiIndex([('a', 'b'),
('a', 'c')],
dtype='object')
)
See Also
--------
Expand Down
Loading

0 comments on commit d47947a

Please sign in to comment.