Skip to content

BUG: to_string ignoring formatter for FloatingArray #50333

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 1 commit into from
Dec 19, 2022
Merged
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
3 changes: 2 additions & 1 deletion doc/source/whatsnew/v2.0.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -877,7 +877,8 @@ I/O
- Bug in :func:`read_sql_query` ignoring ``dtype`` argument when ``chunksize`` is specified and result is empty (:issue:`50245`)
- Bug in :func:`read_csv` for a single-line csv with fewer columns than ``names`` raised :class:`.errors.ParserError` with ``engine="c"`` (:issue:`47566`)
- Bug in displaying ``string`` dtypes not showing storage option (:issue:`50099`)
- Bug in :func:`DataFrame.to_string` with ``header=False`` that printed the index name on the same line as the first row of the data (:issue:`49230`)
- Bug in :meth:`DataFrame.to_string` with ``header=False`` that printed the index name on the same line as the first row of the data (:issue:`49230`)
- Bug in :meth:`DataFrame.to_string` ignoring float formatter for extension arrays (:issue:`39336`)
- Fixed memory leak which stemmed from the initialization of the internal JSON module (:issue:`49222`)
- Fixed issue where :func:`json_normalize` would incorrectly remove leading characters from column names that matched the ``sep`` argument (:issue:`49861`)
-
Expand Down
13 changes: 11 additions & 2 deletions pandas/io/formats/format.py
Original file line number Diff line number Diff line change
Expand Up @@ -1259,6 +1259,7 @@ def format_array(
decimal: str = ".",
leading_space: bool | None = True,
quoting: int | None = None,
fallback_formatter: Callable | None = None,
) -> list[str]:
"""
Format an array for printing.
Expand All @@ -1281,6 +1282,7 @@ def format_array(
When formatting an Index subclass
(e.g. IntervalIndex._format_native_types), we don't want the
leading space since it should be left-aligned.
fallback_formatter

Returns
-------
Expand Down Expand Up @@ -1322,6 +1324,7 @@ def format_array(
decimal=decimal,
leading_space=leading_space,
quoting=quoting,
fallback_formatter=fallback_formatter,
)

return fmt_obj.get_result()
Expand All @@ -1341,6 +1344,7 @@ def __init__(
quoting: int | None = None,
fixed_width: bool = True,
leading_space: bool | None = True,
fallback_formatter: Callable | None = None,
) -> None:
self.values = values
self.digits = digits
Expand All @@ -1353,6 +1357,7 @@ def __init__(
self.quoting = quoting
self.fixed_width = fixed_width
self.leading_space = leading_space
self.fallback_formatter = fallback_formatter

def get_result(self) -> list[str]:
fmt_values = self._format_strings()
Expand All @@ -1371,6 +1376,8 @@ def _format_strings(self) -> list[str]:

if self.formatter is not None:
formatter = self.formatter
elif self.fallback_formatter is not None:
formatter = self.fallback_formatter
else:
quote_strings = self.quoting is not None and self.quoting != QUOTE_NONE
formatter = partial(
Expand Down Expand Up @@ -1419,7 +1426,7 @@ def _format(x):

fmt_values = []
for i, v in enumerate(vals):
if not is_float_type[i] and leading_space:
if not is_float_type[i] and leading_space or self.formatter is not None:
fmt_values.append(f" {_format(v)}")
elif is_float_type[i]:
fmt_values.append(float_format(v))
Expand Down Expand Up @@ -1651,8 +1658,9 @@ def _format_strings(self) -> list[str]:
values = extract_array(self.values, extract_numpy=True)

formatter = self.formatter
fallback_formatter = None
if formatter is None:
formatter = values._formatter(boxed=True)
fallback_formatter = values._formatter(boxed=True)

if isinstance(values, Categorical):
# Categorical is special for now, so that we can preserve tzinfo
Expand All @@ -1671,6 +1679,7 @@ def _format_strings(self) -> list[str]:
decimal=self.decimal,
leading_space=self.leading_space,
quoting=self.quoting,
fallback_formatter=fallback_formatter,
)
return fmt_values

Expand Down
14 changes: 14 additions & 0 deletions pandas/tests/frame/test_repr_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -365,3 +365,17 @@ def test_datetime64tz_slice_non_truncate(self):
df = df.iloc[:, :5]
result = repr(df)
assert result == expected

def test_masked_ea_with_formatter(self):
# GH#39336
df = DataFrame(
{
"a": Series([0.123456789, 1.123456789], dtype="Float64"),
"b": Series([1, 2], dtype="Int64"),
}
)
result = df.to_string(formatters=["{:.2f}".format, "{:.2f}".format])
expected = """ a b
0 0.12 1.00
1 1.12 2.00"""
assert result == expected