Skip to content

Commit 439fd18

Browse files
merge master
1 parent 03a0948 commit 439fd18

File tree

5 files changed

+92
-30
lines changed

5 files changed

+92
-30
lines changed

doc/source/whatsnew/v0.25.0.rst

+2
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,7 @@ I/O
349349

350350
- Bug in :func:`DataFrame.to_html()` where values were truncated using display options instead of outputting the full content (:issue:`17004`)
351351
- Fixed bug in missing text when using :meth:`to_clipboard` if copying utf-16 characters in Python 3 on Windows (:issue:`25040`)
352+
- Bug in :meth:`Series.to_string` adding a leading space when ``index=False`` (:issue:`24980`)
352353
- Bug in :func:`read_json` for ``orient='table'`` when it tries to infer dtypes by default, which is not applicable as dtypes are already defined in the JSON schema (:issue:`21345`)
353354
- Bug in :func:`read_json` for ``orient='table'`` and float index, as it infers index dtype by default, which is not applicable because index dtype is already defined in the JSON schema (:issue:`25433`)
354355
- Bug in :func:`read_json` for ``orient='table'`` and string of float column names, as it makes a column name type conversion to Timestamp, which is not applicable because column names are already defined in the JSON schema (:issue:`25435`)
@@ -364,6 +365,7 @@ I/O
364365
- Improved :meth:`pandas.read_stata` and :class:`pandas.io.stata.StataReader` to read incorrectly formatted 118 format files saved by Stata (:issue:`25960`)
365366
- Fixed bug in loading objects from S3 that contain ``#`` characters in the URL (:issue:`25945`)
366367

368+
367369
Plotting
368370
^^^^^^^^
369371

pandas/core/generic.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -2880,9 +2880,9 @@ def to_latex(self, buf=None, columns=None, col_space=None, header=True,
28802880
... 'mask': ['red', 'purple'],
28812881
... 'weapon': ['sai', 'bo staff']})
28822882
>>> df.to_latex(index=False) # doctest: +NORMALIZE_WHITESPACE
2883-
'\\begin{tabular}{lll}\n\\toprule\n name & mask & weapon
2884-
\\\\\n\\midrule\n Raphael & red & sai \\\\\n Donatello &
2885-
purple & bo staff \\\\\n\\bottomrule\n\\end{tabular}\n'
2883+
'\\begin{tabular}{lll}\n\\toprule\n name & mask & weapon
2884+
\\\\\n\\midrule\n Raphael & red & sai \\\\\nDonatello &
2885+
purple & bo staff \\\\\n\\bottomrule\n\\end{tabular}\n'
28862886
"""
28872887
# Get defaults from the pandas config
28882888
if self.ndim == 1:

pandas/io/formats/format.py

+35-9
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
@@ -717,9 +724,15 @@ def _format_col(self, i):
717724
frame = self.tr_frame
718725
formatter = self._get_formatter(i)
719726
values_to_format = frame.iloc[:, i]._formatting_values()
727+
728+
if self.index:
729+
leading_space = 'compat'
730+
else:
731+
leading_space = False
720732
return format_array(values_to_format, formatter,
721733
float_format=self.float_format, na_rep=self.na_rep,
722-
space=self.col_space, decimal=self.decimal)
734+
space=self.col_space, decimal=self.decimal,
735+
leading_space=leading_space)
723736

724737
def to_html(self, classes=None, notebook=False, border=None):
725738
"""
@@ -856,7 +869,7 @@ def _get_column_name_list(self):
856869

857870
def format_array(values, formatter, float_format=None, na_rep='NaN',
858871
digits=None, space=None, justify='right', decimal='.',
859-
leading_space=None):
872+
leading_space='compat'):
860873
"""
861874
Format an array for printing.
862875
@@ -870,7 +883,7 @@ def format_array(values, formatter, float_format=None, na_rep='NaN',
870883
space
871884
justify
872885
decimal
873-
leading_space : bool, optional
886+
leading_space : bool, default is 'compat'
874887
Whether the array should be formatted with a leading space.
875888
When an array as a column of a Series or DataFrame, we do want
876889
the leading space to pad between columns.
@@ -920,7 +933,7 @@ class GenericArrayFormatter(object):
920933

921934
def __init__(self, values, digits=7, formatter=None, na_rep='NaN',
922935
space=12, float_format=None, justify='right', decimal='.',
923-
quoting=None, fixed_width=True, leading_space=None):
936+
quoting=None, fixed_width=True, leading_space='compat'):
924937
self.values = values
925938
self.digits = digits
926939
self.na_rep = na_rep
@@ -978,7 +991,7 @@ def _format(x):
978991

979992
is_float_type = lib.map_infer(vals, is_float) & notna(vals)
980993
leading_space = self.leading_space
981-
if leading_space is None:
994+
if leading_space == 'compat':
982995
leading_space = is_float_type.any()
983996

984997
fmt_values = []
@@ -1102,7 +1115,11 @@ def format_values_with(float_format):
11021115
# The default is otherwise to use str instead of a formatting string
11031116
if self.float_format is None:
11041117
if self.fixed_width:
1105-
float_format = partial('{value: .{digits:d}f}'.format,
1118+
if self.leading_space is not False:
1119+
fmt_str = '{value: .{digits:d}f}'
1120+
else:
1121+
fmt_str = '{value:.{digits:d}f}'
1122+
float_format = partial(fmt_str.format,
11061123
digits=self.digits)
11071124
else:
11081125
float_format = self.float_format
@@ -1134,7 +1151,11 @@ def format_values_with(float_format):
11341151
(abs_vals > 0)).any()
11351152

11361153
if has_small_values or (too_long and has_large_values):
1137-
float_format = partial('{value: .{digits:d}e}'.format,
1154+
if self.leading_space is not False:
1155+
fmt_str = '{value: .{digits:d}e}'
1156+
else:
1157+
fmt_str = '{value:.{digits:d}e}'
1158+
float_format = partial(fmt_str.format,
11381159
digits=self.digits)
11391160
formatted_values = format_values_with(float_format)
11401161

@@ -1151,7 +1172,12 @@ def _format_strings(self):
11511172
class IntArrayFormatter(GenericArrayFormatter):
11521173

11531174
def _format_strings(self):
1154-
formatter = self.formatter or (lambda x: '{x: d}'.format(x=x))
1175+
if self.leading_space is False:
1176+
fmt_str = '{x:d}'
1177+
else:
1178+
fmt_str = '{x: d}'
1179+
formatter = self.formatter or (lambda x: fmt_str.format(x=x))
1180+
# formatter = self.formatter or (lambda x: '{x: d}'.format(x=x))
11551181
fmt_values = [formatter(x) for x in self.values]
11561182
return fmt_values
11571183

pandas/tests/io/formats/test_format.py

+41-7
Original file line numberDiff line numberDiff line change
@@ -1245,15 +1245,15 @@ def test_to_string_no_index(self):
12451245

12461246
df_s = df.to_string(index=False)
12471247
# Leading space is expected for positive numbers.
1248-
expected = (" x y z\n"
1249-
" 11 33 AAA\n"
1250-
" 22 -44 ")
1248+
expected = (" x y z\n"
1249+
"11 33 AAA\n"
1250+
"22 -44 ")
12511251
assert df_s == expected
12521252

12531253
df_s = df[['y', 'x', 'z']].to_string(index=False)
1254-
expected = (" y x z\n"
1255-
" 33 11 AAA\n"
1256-
"-44 22 ")
1254+
expected = (" y x z\n"
1255+
" 33 11 AAA\n"
1256+
"-44 22 ")
12571257
assert df_s == expected
12581258

12591259
def test_to_string_line_width_no_index(self):
@@ -1268,7 +1268,7 @@ def test_to_string_line_width_no_index(self):
12681268
df = DataFrame({'x': [11, 22, 33], 'y': [4, 5, 6]})
12691269

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

12731273
assert df_s == expected
12741274

@@ -2329,6 +2329,15 @@ def test_to_string_header(self):
23292329
exp = '0 0\n ..\n9 9'
23302330
assert res == exp
23312331

2332+
@pytest.mark.parametrize("inputs, expected", [
2333+
([' a', ' b'], ' a\n b'),
2334+
(['.1', '1'], '.1\n 1'),
2335+
(['10', '-10'], ' 10\n-10')
2336+
])
2337+
def test_to_string_index_false_corner_case(self, inputs, expected):
2338+
s = pd.Series(inputs).to_string(index=False)
2339+
assert s == expected
2340+
23322341
def test_to_string_multindex_header(self):
23332342
# GH 16718
23342343
df = (pd.DataFrame({'a': [0], 'b': [1], 'c': [2], 'd': [3]})
@@ -2737,6 +2746,31 @@ def test_format_percentiles():
27372746
fmt.format_percentiles([0.1, 0.5, 'a'])
27382747

27392748

2749+
@pytest.mark.parametrize("input_array, expected", [
2750+
("a", "a"),
2751+
(["a", "b"], "a\nb"),
2752+
([1, "a"], "1\na"),
2753+
(1, "1"),
2754+
([0, -1], " 0\n-1"),
2755+
(1.0, '1.0')
2756+
])
2757+
def test_format_remove_leading_space_series(input_array, expected):
2758+
# GH: 24980
2759+
s = pd.Series(input_array).to_string(index=False)
2760+
assert s == expected
2761+
2762+
2763+
@pytest.mark.parametrize("input_array, expected", [
2764+
({"A": ["a"]}, "A\na"),
2765+
({"A": ["a", "b"], "B": ["c", "dd"]}, "A B\na c\nb dd"),
2766+
({"A": ["a", 1], "B": ["aa", 1]}, "A B\na aa\n1 1")
2767+
])
2768+
def test_format_remove_leading_space_dataframe(input_array, expected):
2769+
# GH: 24980
2770+
df = pd.DataFrame(input_array).to_string(index=False)
2771+
assert df == expected
2772+
2773+
27402774
def test_repr_html_ipython_config(ip):
27412775
code = textwrap.dedent("""\
27422776
import pandas as pd

pandas/tests/io/formats/test_to_latex.py

+11-11
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,10 @@ def test_to_latex(self, frame):
5656
withoutindex_result = df.to_latex(index=False)
5757
withoutindex_expected = r"""\begin{tabular}{rl}
5858
\toprule
59-
a & b \\
59+
a & b \\
6060
\midrule
61-
1 & b1 \\
62-
2 & b2 \\
61+
1 & b1 \\
62+
2 & b2 \\
6363
\bottomrule
6464
\end{tabular}
6565
"""
@@ -415,7 +415,7 @@ def test_to_latex_longtable(self, frame):
415415
withoutindex_result = df.to_latex(index=False, longtable=True)
416416
withoutindex_expected = r"""\begin{longtable}{rl}
417417
\toprule
418-
a & b \\
418+
a & b \\
419419
\midrule
420420
\endhead
421421
\midrule
@@ -425,8 +425,8 @@ def test_to_latex_longtable(self, frame):
425425
426426
\bottomrule
427427
\endlastfoot
428-
1 & b1 \\
429-
2 & b2 \\
428+
1 & b1 \\
429+
2 & b2 \\
430430
\end{longtable}
431431
"""
432432

@@ -482,8 +482,8 @@ def test_to_latex_no_header(self):
482482
withoutindex_result = df.to_latex(index=False, header=False)
483483
withoutindex_expected = r"""\begin{tabular}{rl}
484484
\toprule
485-
1 & b1 \\
486-
2 & b2 \\
485+
1 & b1 \\
486+
2 & b2 \\
487487
\bottomrule
488488
\end{tabular}
489489
"""
@@ -509,10 +509,10 @@ def test_to_latex_specified_header(self):
509509
withoutindex_result = df.to_latex(header=['AA', 'BB'], index=False)
510510
withoutindex_expected = r"""\begin{tabular}{rl}
511511
\toprule
512-
AA & BB \\
512+
AA & BB \\
513513
\midrule
514-
1 & b1 \\
515-
2 & b2 \\
514+
1 & b1 \\
515+
2 & b2 \\
516516
\bottomrule
517517
\end{tabular}
518518
"""

0 commit comments

Comments
 (0)