Skip to content

BUG: Display precision doesn't affect complex float numbers #25514 #25745

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

Merged
merged 8 commits into from
Apr 12, 2019
1 change: 1 addition & 0 deletions doc/source/whatsnew/v0.25.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,7 @@ Numeric

- Bug in :meth:`to_numeric` in which large negative numbers were being improperly handled (:issue:`24910`)
- Bug in :meth:`to_numeric` in which numbers were being coerced to float, even though ``errors`` was not ``coerce`` (:issue:`24910`)
- Bug in :class:`format` in which floating point complex numbers were not being formatted to proper display precision and trimming (:issue:`25514`)
- Bug in error messages in :meth:`DataFrame.corr` and :meth:`Series.corr`. Added the possibility of using a callable. (:issue:`25729`)
- Bug in :meth:`Series.divmod` and :meth:`Series.rdivmod` which would raise an (incorrect) ``ValueError`` rather than return a pair of :class:`Series` objects as result (:issue:`25557`)
- Raises a helpful exception when a non-numeric index is sent to :meth:`interpolate` with methods which require numeric index. (:issue:`21662`)
Expand Down
12 changes: 6 additions & 6 deletions pandas/core/frame.py
Original file line number Diff line number Diff line change
Expand Up @@ -2497,12 +2497,12 @@ def memory_usage(self, index=True, deep=False):
... for t in dtypes])
>>> df = pd.DataFrame(data)
>>> df.head()
int64 float64 complex128 object bool
0 1 1.0 (1+0j) 1 True
1 1 1.0 (1+0j) 1 True
2 1 1.0 (1+0j) 1 True
3 1 1.0 (1+0j) 1 True
4 1 1.0 (1+0j) 1 True
int64 float64 complex128 object bool
0 1 1.0 1.0+0.0j 1 True
1 1 1.0 1.0+0.0j 1 True
2 1 1.0 1.0+0.0j 1 True
3 1 1.0 1.0+0.0j 1 True
4 1 1.0 1.0+0.0j 1 True

>>> df.memory_usage()
Index 80
Expand Down
31 changes: 25 additions & 6 deletions pandas/io/formats/format.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@
from pandas.compat import lzip

from pandas.core.dtypes.common import (
is_categorical_dtype, is_datetime64_dtype, is_datetime64tz_dtype,
is_extension_array_dtype, is_float, is_float_dtype, is_integer,
is_integer_dtype, is_list_like, is_numeric_dtype, is_scalar,
is_categorical_dtype, is_complex_dtype, is_datetime64_dtype,
is_datetime64tz_dtype, is_extension_array_dtype, is_float, is_float_dtype,
is_integer, is_integer_dtype, is_list_like, is_numeric_dtype, is_scalar,
is_timedelta64_dtype)
from pandas.core.dtypes.generic import (
ABCIndexClass, ABCMultiIndex, ABCSeries, ABCSparseArray)
Expand Down Expand Up @@ -892,7 +892,7 @@ def format_array(values, formatter, float_format=None, na_rep='NaN',
fmt_klass = Timedelta64Formatter
elif is_extension_array_dtype(values.dtype):
fmt_klass = ExtensionArrayFormatter
elif is_float_dtype(values.dtype):
elif is_float_dtype(values.dtype) or is_complex_dtype(values.dtype):
fmt_klass = FloatArrayFormatter
elif is_integer_dtype(values.dtype):
fmt_klass = IntArrayFormatter
Expand Down Expand Up @@ -1084,6 +1084,7 @@ def format_values_with(float_format):

# separate the wheat from the chaff
values = self.values
is_complex = is_complex_dtype(values)
mask = isna(values)
if hasattr(values, 'to_dense'): # sparse numpy ndarray
values = values.to_dense()
Expand All @@ -1094,7 +1095,10 @@ def format_values_with(float_format):
for val in values.ravel()[imask]])

if self.fixed_width:
return _trim_zeros(values, na_rep)
if is_complex:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can do the type check right here instead of above

Copy link
Contributor Author

@sakarpanta sakarpanta Apr 11, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The problem with that is at that point the values object has been reassigned as values = np.array(values, dtype='object') and is no longer a complex type but an array with the complex numbers (or floats) as strings.

return _trim_zeros_complex(values, na_rep)
else:
return _trim_zeros_float(values, na_rep)

return values

Expand Down Expand Up @@ -1424,7 +1428,22 @@ def just(x):
return result


def _trim_zeros(str_floats, na_rep='NaN'):
def _trim_zeros_complex(str_complexes, na_rep='NaN'):
"""
Separates the real and imaginary parts from the complex number, and
executes the _trim_zeros_float method on each of those.
"""
def separate_and_trim(str_complex, na_rep):
num_arr = str_complex.split('+')
return (_trim_zeros_float([num_arr[0]], na_rep) +
['+'] +
_trim_zeros_float([num_arr[1][:-1]], na_rep) +
['j'])

return [''.join(separate_and_trim(x, na_rep)) for x in str_complexes]


def _trim_zeros_float(str_floats, na_rep='NaN'):
"""
Trims zeros, leaving just one before the decimal points if need be.
"""
Expand Down
13 changes: 13 additions & 0 deletions pandas/tests/io/formats/test_format.py
Original file line number Diff line number Diff line change
Expand Up @@ -1370,6 +1370,19 @@ def test_to_string_float_index(self):
'5.0 4')
assert result == expected

def test_to_string_complex_float_formatting(self):
# GH #25514
with pd.option_context('display.precision', 5):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you add the gh issue number as a comment

df = DataFrame({'x': [
(0.4467846931321966 + 0.0715185102060818j),
(0.2739442392974528 + 0.23515228785438969j),
(0.26974928742135185 + 0.3250604054898979j)]})
result = df.to_string()
expected = (' x\n0 0.44678+0.07152j\n'
'1 0.27394+0.23515j\n'
'2 0.26975+0.32506j')
assert result == expected

def test_to_string_ascii_error(self):
data = [('0 ', ' .gitignore ', ' 5 ',
' \xe2\x80\xa2\xe2\x80\xa2\xe2\x80'
Expand Down