Skip to content

Commit c13fcd1

Browse files
jorisvandenbosschePingviinituutti
authored andcommitted
Fix repr of DataFrame with IntervalIndex (pandas-dev#24134)
1 parent f8cbafc commit c13fcd1

File tree

5 files changed

+83
-11
lines changed

5 files changed

+83
-11
lines changed

pandas/core/indexes/interval.py

+5-4
Original file line numberDiff line numberDiff line change
@@ -1015,10 +1015,11 @@ def _format_with_header(self, header, **kwargs):
10151015

10161016
def _format_native_types(self, na_rep='', quoting=None, **kwargs):
10171017
""" actually format my specific types """
1018-
from pandas.io.formats.format import IntervalArrayFormatter
1019-
return IntervalArrayFormatter(values=self,
1020-
na_rep=na_rep,
1021-
justify='all').get_result()
1018+
from pandas.io.formats.format import ExtensionArrayFormatter
1019+
return ExtensionArrayFormatter(values=self,
1020+
na_rep=na_rep,
1021+
justify='all',
1022+
leading_space=False).get_result()
10221023

10231024
def _format_data(self, name=None):
10241025

pandas/io/formats/format.py

+44-6
Original file line numberDiff line numberDiff line change
@@ -840,7 +840,34 @@ def _get_column_name_list(self):
840840

841841

842842
def format_array(values, formatter, float_format=None, na_rep='NaN',
843-
digits=None, space=None, justify='right', decimal='.'):
843+
digits=None, space=None, justify='right', decimal='.',
844+
leading_space=None):
845+
"""
846+
Format an array for printing.
847+
848+
Parameters
849+
----------
850+
values
851+
formatter
852+
float_format
853+
na_rep
854+
digits
855+
space
856+
justify
857+
decimal
858+
leading_space : bool, optional
859+
Whether the array should be formatted with a leading space.
860+
When an array as a column of a Series or DataFrame, we do want
861+
the leading space to pad between columns.
862+
863+
When formatting an Index subclass
864+
(e.g. IntervalIndex._format_native_types), we don't want the
865+
leading space since it should be left-aligned.
866+
867+
Returns
868+
-------
869+
List[str]
870+
"""
844871

845872
if is_datetime64_dtype(values.dtype):
846873
fmt_klass = Datetime64Formatter
@@ -868,7 +895,8 @@ def format_array(values, formatter, float_format=None, na_rep='NaN',
868895

869896
fmt_obj = fmt_klass(values, digits=digits, na_rep=na_rep,
870897
float_format=float_format, formatter=formatter,
871-
space=space, justify=justify, decimal=decimal)
898+
space=space, justify=justify, decimal=decimal,
899+
leading_space=leading_space)
872900

873901
return fmt_obj.get_result()
874902

@@ -877,7 +905,7 @@ class GenericArrayFormatter(object):
877905

878906
def __init__(self, values, digits=7, formatter=None, na_rep='NaN',
879907
space=12, float_format=None, justify='right', decimal='.',
880-
quoting=None, fixed_width=True):
908+
quoting=None, fixed_width=True, leading_space=None):
881909
self.values = values
882910
self.digits = digits
883911
self.na_rep = na_rep
@@ -888,6 +916,7 @@ def __init__(self, values, digits=7, formatter=None, na_rep='NaN',
888916
self.decimal = decimal
889917
self.quoting = quoting
890918
self.fixed_width = fixed_width
919+
self.leading_space = leading_space
891920

892921
def get_result(self):
893922
fmt_values = self._format_strings()
@@ -927,7 +956,9 @@ def _format(x):
927956
vals = vals.values
928957

929958
is_float_type = lib.map_infer(vals, is_float) & notna(vals)
930-
leading_space = is_float_type.any()
959+
leading_space = self.leading_space
960+
if leading_space is None:
961+
leading_space = is_float_type.any()
931962

932963
fmt_values = []
933964
for i, v in enumerate(vals):
@@ -936,7 +967,13 @@ def _format(x):
936967
elif is_float_type[i]:
937968
fmt_values.append(float_format(v))
938969
else:
939-
fmt_values.append(u' {v}'.format(v=_format(v)))
970+
if leading_space is False:
971+
# False specifically, so that the default is
972+
# to include a space if we get here.
973+
tpl = u'{v}'
974+
else:
975+
tpl = u' {v}'
976+
fmt_values.append(tpl.format(v=_format(v)))
940977

941978
return fmt_values
942979

@@ -1135,7 +1172,8 @@ def _format_strings(self):
11351172
formatter,
11361173
float_format=self.float_format,
11371174
na_rep=self.na_rep, digits=self.digits,
1138-
space=self.space, justify=self.justify)
1175+
space=self.space, justify=self.justify,
1176+
leading_space=self.leading_space)
11391177
return fmt_values
11401178

11411179

pandas/tests/indexes/interval/test_interval.py

+15-1
Original file line numberDiff line numberDiff line change
@@ -377,7 +377,21 @@ def test_repr_max_seq_item_setting(self):
377377
def test_repr_roundtrip(self):
378378
super(TestIntervalIndex, self).test_repr_roundtrip()
379379

380-
# TODO: check this behavior is consistent with test_interval_new.py
380+
def test_frame_repr(self):
381+
# https://github.com/pandas-dev/pandas/pull/24134/files
382+
df = pd.DataFrame({'A': [1, 2, 3, 4]},
383+
index=pd.IntervalIndex.from_breaks([0, 1, 2, 3, 4]))
384+
result = repr(df)
385+
expected = (
386+
' A\n'
387+
'(0, 1] 1\n'
388+
'(1, 2] 2\n'
389+
'(2, 3] 3\n'
390+
'(3, 4] 4'
391+
)
392+
assert result == expected
393+
394+
# TODO: check this behavior is consistent with test_interval_new.py
381395
def test_get_item(self, closed):
382396
i = IntervalIndex.from_arrays((0, 1, np.nan), (1, 2, np.nan),
383397
closed=closed)

pandas/tests/indexes/period/test_formats.py

+12
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,18 @@ def test_to_native_types():
4949

5050

5151
class TestPeriodIndexRendering(object):
52+
53+
def test_frame_repr(self):
54+
df = pd.DataFrame({"A": [1, 2, 3]},
55+
index=pd.date_range('2000', periods=3))
56+
result = repr(df)
57+
expected = (
58+
' A\n'
59+
'2000-01-01 1\n'
60+
'2000-01-02 2\n'
61+
'2000-01-03 3')
62+
assert result == expected
63+
5264
@pytest.mark.parametrize('method', ['__repr__', '__unicode__', '__str__'])
5365
def test_representation(self, method):
5466
# GH#7601

pandas/tests/indexes/test_category.py

+7
Original file line numberDiff line numberDiff line change
@@ -812,6 +812,13 @@ def test_equals_categoridcal_unordered(self):
812812
assert not a.equals(c)
813813
assert not b.equals(c)
814814

815+
def test_frame_repr(self):
816+
df = pd.DataFrame({"A": [1, 2, 3]},
817+
index=pd.CategoricalIndex(['a', 'b', 'c']))
818+
result = repr(df)
819+
expected = ' A\na 1\nb 2\nc 3'
820+
assert result == expected
821+
815822
def test_string_categorical_index_repr(self):
816823
# short
817824
idx = pd.CategoricalIndex(['a', 'bb', 'ccc'])

0 commit comments

Comments
 (0)