Skip to content

ENH: formatting integers in FloatIndex as floats #12207

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

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions doc/source/whatsnew/v0.18.0.txt
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,48 @@ In addition, ``.round()``, ``.floor()`` and ``.ceil()`` will be available thru t
s
s.dt.round('D')


Formatting of integer in FloatIndex
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Integers in ``FloatIndex``, e.g. 1., are now formatted with a decimal point
and a ``0`` digit, e.g. ``1.0`` (:issue:`11713`)

This change affects the display in jupyter, but also the output of IO methods
like ``.to_csv`` or ``.to_html``

Previous Behavior:

.. code-block:: python

In [2]: s = Series([1,2,3], index=np.arange(3.))

In [3]: s
Out[3]:
0 1
1 2
2 3
dtype: int64

In [4]: s.index
Out[4]: Float64Index([0.0, 1.0, 2.0], dtype='float64')

In [5]: print(s.to_csv(path=None))
0,1
1,2
2,3


New Behavior:

.. ipython:: python

s = Series([1,2,3], index=np.arange(3.))
s
s.index
print(s.to_csv(path=None))


.. _whatsnew_0180.enhancements.other:

Other enhancements
Expand Down
10 changes: 6 additions & 4 deletions pandas/core/format.py
Original file line number Diff line number Diff line change
Expand Up @@ -2115,7 +2115,9 @@ def _format_strings(self):
abs_vals = np.abs(self.values)

# this is pretty arbitrary for now
has_large_values = (abs_vals > 1e8).any()
# large values: more that 8 characters including decimal symbol
# and first digit, hence > 1e6
has_large_values = (abs_vals > 1e6).any()
has_small_values = ((abs_vals < 10**(-self.digits)) &
(abs_vals > 0)).any()

Expand Down Expand Up @@ -2367,7 +2369,7 @@ def just(x):

def _trim_zeros(str_floats, na_rep='NaN'):
"""
Trims zeros and decimal points.
Trims zeros, leaving just one before the decimal points if need be.
"""
trimmed = str_floats

Expand All @@ -2379,8 +2381,8 @@ def _cond(values):
while _cond(trimmed):
trimmed = [x[:-1] if x != na_rep else x for x in trimmed]

# trim decimal points
return [x[:-1] if x.endswith('.') and x != na_rep else x for x in trimmed]
# leave one 0 after the decimal points if need be.
return [x + "0" if x.endswith('.') and x != na_rep else x for x in trimmed]


def single_column_table(column, align=None, style=None):
Expand Down
30 changes: 15 additions & 15 deletions pandas/tests/test_format.py
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ def test_repr_chop_threshold(self):
self.assertEqual(repr(df), ' 0 1\n0 0.0 0.5\n1 0.5 0.0')

with option_context("display.chop_threshold", 0.6):
self.assertEqual(repr(df), ' 0 1\n0 0 0\n1 0 0')
self.assertEqual(repr(df), ' 0 1\n0 0.0 0.0\n1 0.0 0.0')

with option_context("display.chop_threshold", None):
self.assertEqual(repr(df), ' 0 1\n0 0.1 0.5\n1 0.5 -0.1')
Expand Down Expand Up @@ -753,7 +753,7 @@ def test_to_html_with_empty_string_label(self):

def test_to_html_unicode(self):
df = DataFrame({u('\u03c3'): np.arange(10.)})
expected = u'<table border="1" class="dataframe">\n <thead>\n <tr style="text-align: right;">\n <th></th>\n <th>\u03c3</th>\n </tr>\n </thead>\n <tbody>\n <tr>\n <th>0</th>\n <td>0</td>\n </tr>\n <tr>\n <th>1</th>\n <td>1</td>\n </tr>\n <tr>\n <th>2</th>\n <td>2</td>\n </tr>\n <tr>\n <th>3</th>\n <td>3</td>\n </tr>\n <tr>\n <th>4</th>\n <td>4</td>\n </tr>\n <tr>\n <th>5</th>\n <td>5</td>\n </tr>\n <tr>\n <th>6</th>\n <td>6</td>\n </tr>\n <tr>\n <th>7</th>\n <td>7</td>\n </tr>\n <tr>\n <th>8</th>\n <td>8</td>\n </tr>\n <tr>\n <th>9</th>\n <td>9</td>\n </tr>\n </tbody>\n</table>'
expected = u'<table border="1" class="dataframe">\n <thead>\n <tr style="text-align: right;">\n <th></th>\n <th>\u03c3</th>\n </tr>\n </thead>\n <tbody>\n <tr>\n <th>0</th>\n <td>0.0</td>\n </tr>\n <tr>\n <th>1</th>\n <td>1.0</td>\n </tr>\n <tr>\n <th>2</th>\n <td>2.0</td>\n </tr>\n <tr>\n <th>3</th>\n <td>3.0</td>\n </tr>\n <tr>\n <th>4</th>\n <td>4.0</td>\n </tr>\n <tr>\n <th>5</th>\n <td>5.0</td>\n </tr>\n <tr>\n <th>6</th>\n <td>6.0</td>\n </tr>\n <tr>\n <th>7</th>\n <td>7.0</td>\n </tr>\n <tr>\n <th>8</th>\n <td>8.0</td>\n </tr>\n <tr>\n <th>9</th>\n <td>9.0</td>\n </tr>\n </tbody>\n</table>'
self.assertEqual(df.to_html(), expected)
df = DataFrame({'A': [u('\u03c3')]})
expected = u'<table border="1" class="dataframe">\n <thead>\n <tr style="text-align: right;">\n <th></th>\n <th>A</th>\n </tr>\n </thead>\n <tbody>\n <tr>\n <th>0</th>\n <td>\u03c3</td>\n </tr>\n </tbody>\n</table>'
Expand Down Expand Up @@ -1916,12 +1916,12 @@ def test_to_string_format_na(self):
'B': [np.nan, 'foo', 'foooo', 'fooooo', 'bar']})
result = df.to_string()

expected = (' A B\n'
'0 NaN NaN\n'
'1 -1 foo\n'
'2 -2 foooo\n'
'3 3 fooooo\n'
'4 4 bar')
expected = (' A B\n'
'0 NaN NaN\n'
'1 -1.0 foo\n'
'2 -2.0 foooo\n'
'3 3.0 fooooo\n'
'4 4.0 bar')
self.assertEqual(result, expected)

def test_to_string_line_width(self):
Expand Down Expand Up @@ -3760,8 +3760,8 @@ def test_misc(self):
def test_format(self):
obj = fmt.FloatArrayFormatter(np.array([12, 0], dtype=np.float64))
result = obj.get_result()
self.assertEqual(result[0], " 12")
self.assertEqual(result[1], " 0")
self.assertEqual(result[0], " 12.0")
self.assertEqual(result[1], " 0.0")

def test_output_significant_digits(self):
# Issue #9764
Expand Down Expand Up @@ -3793,15 +3793,15 @@ def test_output_significant_digits(self):
def test_too_long(self):
# GH 10451
with pd.option_context('display.precision', 4):
# need both a number > 1e8 and something that normally formats to
# need both a number > 1e6 and something that normally formats to
# having length > display.precision + 6
df = pd.DataFrame(dict(x=[12345.6789]))
self.assertEqual(str(df), ' x\n0 12345.6789')
df = pd.DataFrame(dict(x=[2e8]))
self.assertEqual(str(df), ' x\n0 200000000')
df = pd.DataFrame(dict(x=[12345.6789, 2e8]))
df = pd.DataFrame(dict(x=[2e6]))
self.assertEqual(str(df), ' x\n0 2000000.0')
df = pd.DataFrame(dict(x=[12345.6789, 2e6]))
self.assertEqual(
str(df), ' x\n0 1.2346e+04\n1 2.0000e+08')
str(df), ' x\n0 1.2346e+04\n1 2.0000e+06')


class TestRepr_timedelta64(tm.TestCase):
Expand Down