Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ENH: better MultiIndex.__repr__ #22511

Merged
merged 12 commits into from
Jun 19, 2019
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 @@ -1322,16 +1322,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 @@ -1393,12 +1400,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 @@ -5420,8 +5431,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 @@ -5461,8 +5472,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