Skip to content

Commit ac6f1fc

Browse files
resumbit
1 parent 659e0ca commit ac6f1fc

File tree

6 files changed

+93
-34
lines changed

6 files changed

+93
-34
lines changed

doc/source/whatsnew/v0.24.2.rst

-1
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,6 @@ Bug Fixes
5858
- Bug in reading a HDF5 table-format ``DataFrame`` created in Python 2, in Python 3 (:issue:`24925`)
5959
- Bug in reading a JSON with ``orient='table'`` generated by :meth:`DataFrame.to_json` with ``index=False`` (:issue:`25170`)
6060
- Bug where float indexes could have misaligned values when printing (:issue:`25061`)
61-
-
6261

6362
**Categorical**
6463

doc/source/whatsnew/v0.25.0.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ I/O
158158
^^^
159159

160160
- Fixed bug in missing text when using :meth:`to_clipboard` if copying utf-16 characters in Python 3 on Windows (:issue:`25040`)
161-
-
161+
- Bug in :meth:`Series.to_string` adding a leading space when ``index=False`` (:issue:`24980`)
162162
-
163163
-
164164

pandas/core/generic.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -2843,9 +2843,9 @@ def to_latex(self, buf=None, columns=None, col_space=None, header=True,
28432843
... 'mask': ['red', 'purple'],
28442844
... 'weapon': ['sai', 'bo staff']})
28452845
>>> df.to_latex(index=False) # doctest: +NORMALIZE_WHITESPACE
2846-
'\\begin{tabular}{lll}\n\\toprule\n name & mask & weapon
2847-
\\\\\n\\midrule\n Raphael & red & sai \\\\\n Donatello &
2848-
purple & bo staff \\\\\n\\bottomrule\n\\end{tabular}\n'
2846+
'\\begin{tabular}{lll}\n\\toprule\n name & mask & weapon
2847+
\\\\\n\\midrule\n Raphael & red & sai \\\\\nDonatello &
2848+
purple & bo staff \\\\\n\\bottomrule\n\\end{tabular}\n'
28492849
"""
28502850
# Get defaults from the pandas config
28512851
if self.ndim == 1:

pandas/io/formats/format.py

+36-10
Original file line numberDiff line numberDiff line change
@@ -252,8 +252,15 @@ def _get_formatted_index(self):
252252

253253
def _get_formatted_values(self):
254254
values_to_format = self.tr_series._formatting_values()
255+
256+
if self.index:
257+
leading_space = 'compat'
258+
else:
259+
leading_space = False
255260
return format_array(values_to_format, None,
256-
float_format=self.float_format, na_rep=self.na_rep)
261+
float_format=self.float_format,
262+
na_rep=self.na_rep,
263+
leading_space=leading_space)
257264

258265
def to_string(self):
259266
series = self.tr_series
@@ -703,9 +710,15 @@ def _format_col(self, i):
703710
frame = self.tr_frame
704711
formatter = self._get_formatter(i)
705712
values_to_format = frame.iloc[:, i]._formatting_values()
713+
714+
if self.index:
715+
leading_space = 'compat'
716+
else:
717+
leading_space = False
706718
return format_array(values_to_format, formatter,
707719
float_format=self.float_format, na_rep=self.na_rep,
708-
space=self.col_space, decimal=self.decimal)
720+
space=self.col_space, decimal=self.decimal,
721+
leading_space=leading_space)
709722

710723
def to_html(self, classes=None, notebook=False, border=None):
711724
"""
@@ -847,7 +860,7 @@ def _get_column_name_list(self):
847860

848861
def format_array(values, formatter, float_format=None, na_rep='NaN',
849862
digits=None, space=None, justify='right', decimal='.',
850-
leading_space=None):
863+
leading_space='compat'):
851864
"""
852865
Format an array for printing.
853866
@@ -861,7 +874,7 @@ def format_array(values, formatter, float_format=None, na_rep='NaN',
861874
space
862875
justify
863876
decimal
864-
leading_space : bool, optional
877+
leading_space : bool, default is 'compat'
865878
Whether the array should be formatted with a leading space.
866879
When an array as a column of a Series or DataFrame, we do want
867880
the leading space to pad between columns.
@@ -911,7 +924,7 @@ class GenericArrayFormatter(object):
911924

912925
def __init__(self, values, digits=7, formatter=None, na_rep='NaN',
913926
space=12, float_format=None, justify='right', decimal='.',
914-
quoting=None, fixed_width=True, leading_space=None):
927+
quoting=None, fixed_width=True, leading_space='compat'):
915928
self.values = values
916929
self.digits = digits
917930
self.na_rep = na_rep
@@ -963,12 +976,12 @@ def _format(x):
963976

964977
is_float_type = lib.map_infer(vals, is_float) & notna(vals)
965978
leading_space = self.leading_space
966-
if leading_space is None:
979+
if leading_space == 'compat':
967980
leading_space = is_float_type.any()
968981

969982
fmt_values = []
970983
for i, v in enumerate(vals):
971-
if not is_float_type[i] and leading_space:
984+
if not is_float_type[i] and leading_space is True:
972985
fmt_values.append(u' {v}'.format(v=_format(v)))
973986
elif is_float_type[i]:
974987
fmt_values.append(float_format(v))
@@ -1087,7 +1100,11 @@ def format_values_with(float_format):
10871100
# The default is otherwise to use str instead of a formatting string
10881101
if self.float_format is None:
10891102
if self.fixed_width:
1090-
float_format = partial('{value: .{digits:d}f}'.format,
1103+
if self.leading_space is not False:
1104+
fmt_str = '{value: .{digits:d}f}'
1105+
else:
1106+
fmt_str = '{value:.{digits:d}f}'
1107+
float_format = partial(fmt_str.format,
10911108
digits=self.digits)
10921109
else:
10931110
float_format = self.float_format
@@ -1119,7 +1136,11 @@ def format_values_with(float_format):
11191136
(abs_vals > 0)).any()
11201137

11211138
if has_small_values or (too_long and has_large_values):
1122-
float_format = partial('{value: .{digits:d}e}'.format,
1139+
if self.leading_space is not False:
1140+
fmt_str = '{value: .{digits:d}e}'
1141+
else:
1142+
fmt_str = '{value:.{digits:d}e}'
1143+
float_format = partial(fmt_str.format,
11231144
digits=self.digits)
11241145
formatted_values = format_values_with(float_format)
11251146

@@ -1136,7 +1157,12 @@ def _format_strings(self):
11361157
class IntArrayFormatter(GenericArrayFormatter):
11371158

11381159
def _format_strings(self):
1139-
formatter = self.formatter or (lambda x: '{x: d}'.format(x=x))
1160+
if self.leading_space is False:
1161+
fmt_str = '{x:d}'
1162+
else:
1163+
fmt_str = '{x: d}'
1164+
formatter = self.formatter or (lambda x: fmt_str.format(x=x))
1165+
# formatter = self.formatter or (lambda x: '{x: d}'.format(x=x))
11401166
fmt_values = [formatter(x) for x in self.values]
11411167
return fmt_values
11421168

pandas/tests/io/formats/test_format.py

+42-8
Original file line numberDiff line numberDiff line change
@@ -1292,15 +1292,15 @@ def test_to_string_no_index(self):
12921292

12931293
df_s = df.to_string(index=False)
12941294
# Leading space is expected for positive numbers.
1295-
expected = (" x y z\n"
1296-
" 11 33 AAA\n"
1297-
" 22 -44 ")
1295+
expected = (" x y z\n"
1296+
"11 33 AAA\n"
1297+
"22 -44 ")
12981298
assert df_s == expected
12991299

13001300
df_s = df[['y', 'x', 'z']].to_string(index=False)
1301-
expected = (" y x z\n"
1302-
" 33 11 AAA\n"
1303-
"-44 22 ")
1301+
expected = (" y x z\n"
1302+
" 33 11 AAA\n"
1303+
"-44 22 ")
13041304
assert df_s == expected
13051305

13061306
def test_to_string_line_width_no_index(self):
@@ -1315,7 +1315,7 @@ def test_to_string_line_width_no_index(self):
13151315
df = DataFrame({'x': [11, 22, 33], 'y': [4, 5, 6]})
13161316

13171317
df_s = df.to_string(line_width=1, index=False)
1318-
expected = " x \\\n 11 \n 22 \n 33 \n\n y \n 4 \n 5 \n 6 "
1318+
expected = " x \\\n11 \n22 \n33 \n\n y \n 4 \n 5 \n 6 "
13191319

13201320
assert df_s == expected
13211321

@@ -1888,7 +1888,7 @@ def test_to_string_without_index(self):
18881888
# GH 11729 Test index=False option
18891889
s = Series([1, 2, 3, 4])
18901890
result = s.to_string(index=False)
1891-
expected = (u(' 1\n') + ' 2\n' + ' 3\n' + ' 4')
1891+
expected = (u('1\n') + '2\n' + '3\n' + '4')
18921892
assert result == expected
18931893

18941894
def test_unicode_name_in_footer(self):
@@ -2380,6 +2380,15 @@ def test_to_string_header(self):
23802380
exp = '0 0\n ..\n9 9'
23812381
assert res == exp
23822382

2383+
@pytest.mark.parametrize("inputs, expected", [
2384+
([' a', ' b'], ' a\n b'),
2385+
(['.1', '1'], '.1\n 1'),
2386+
(['10', '-10'], ' 10\n-10')
2387+
])
2388+
def test_to_string_index_false_corner_case(self, inputs, expected):
2389+
s = pd.Series(inputs).to_string(index=False)
2390+
assert s == expected
2391+
23832392

23842393
def _three_digit_exp():
23852394
return '{x:.4g}'.format(x=1.7e8) == '1.7e+008'
@@ -2780,6 +2789,31 @@ def test_format_percentiles():
27802789
fmt.format_percentiles([0.1, 0.5, 'a'])
27812790

27822791

2792+
@pytest.mark.parametrize("input_array, expected", [
2793+
("a", "a"),
2794+
(["a", "b"], "a\nb"),
2795+
([1, "a"], "1\na"),
2796+
(1, "1"),
2797+
([0, -1], " 0\n-1"),
2798+
(1.0, '1.0')
2799+
])
2800+
def test_format_remove_leading_space_series(input_array, expected):
2801+
# GH: 24980
2802+
s = pd.Series(input_array).to_string(index=False)
2803+
assert s == expected
2804+
2805+
2806+
@pytest.mark.parametrize("input_array, expected", [
2807+
({"A": ["a"]}, "A\na"),
2808+
({"A": ["a", "b"], "B": ["c", "dd"]}, "A B\na c\nb dd"),
2809+
({"A": ["a", 1], "B": ["aa", 1]}, "A B\na aa\n1 1")
2810+
])
2811+
def test_format_remove_leading_space_dataframe(input_array, expected):
2812+
# GH: 24980
2813+
df = pd.DataFrame(input_array).to_string(index=False)
2814+
assert df == expected
2815+
2816+
27832817
def test_repr_html_ipython_config(ip):
27842818
code = textwrap.dedent("""\
27852819
import pandas as pd

pandas/tests/io/formats/test_to_latex.py

+11-11
Original file line numberDiff line numberDiff line change
@@ -64,10 +64,10 @@ def test_to_latex(self, frame):
6464
withoutindex_result = df.to_latex(index=False)
6565
withoutindex_expected = r"""\begin{tabular}{rl}
6666
\toprule
67-
a & b \\
67+
a & b \\
6868
\midrule
69-
1 & b1 \\
70-
2 & b2 \\
69+
1 & b1 \\
70+
2 & b2 \\
7171
\bottomrule
7272
\end{tabular}
7373
"""
@@ -423,7 +423,7 @@ def test_to_latex_longtable(self, frame):
423423
withoutindex_result = df.to_latex(index=False, longtable=True)
424424
withoutindex_expected = r"""\begin{longtable}{rl}
425425
\toprule
426-
a & b \\
426+
a & b \\
427427
\midrule
428428
\endhead
429429
\midrule
@@ -433,8 +433,8 @@ def test_to_latex_longtable(self, frame):
433433
434434
\bottomrule
435435
\endlastfoot
436-
1 & b1 \\
437-
2 & b2 \\
436+
1 & b1 \\
437+
2 & b2 \\
438438
\end{longtable}
439439
"""
440440

@@ -490,8 +490,8 @@ def test_to_latex_no_header(self):
490490
withoutindex_result = df.to_latex(index=False, header=False)
491491
withoutindex_expected = r"""\begin{tabular}{rl}
492492
\toprule
493-
1 & b1 \\
494-
2 & b2 \\
493+
1 & b1 \\
494+
2 & b2 \\
495495
\bottomrule
496496
\end{tabular}
497497
"""
@@ -517,10 +517,10 @@ def test_to_latex_specified_header(self):
517517
withoutindex_result = df.to_latex(header=['AA', 'BB'], index=False)
518518
withoutindex_expected = r"""\begin{tabular}{rl}
519519
\toprule
520-
AA & BB \\
520+
AA & BB \\
521521
\midrule
522-
1 & b1 \\
523-
2 & b2 \\
522+
1 & b1 \\
523+
2 & b2 \\
524524
\bottomrule
525525
\end{tabular}
526526
"""

0 commit comments

Comments
 (0)