Repository: pandas-dev/pandas

Issue:
Justification is broken with to_string(index=False) 
With 0.17.1, justification is handled correctly:

```
In [3]: df = pd.DataFrame(np.random.randn(3, 3), columns=['one', 'two', 'three'])

In [4]: print df.to_string(index=False)
      one       two     three
 0.096065 -0.529437 -2.058535
 0.588013  0.221911 -2.400129
 0.848234 -0.093931  1.221708
```

But in 0.18.0, it's broken:

```
In [4]: print df.to_string(index=False)
one       two     three
1.164170 -0.027236 -0.114962
-1.405931  0.019395  0.743320
0.598321  0.655802 -1.061834
```

This is caused by PR #11942. The issue it was meant to fix (#11833) is actually caused by using the format string "% d" for formatting integers, which produces a leading space if the integer is positive (where the minus sign would go for a negative integer). My preferred solution would be to change the formatter to "%d" (and to revert #11942), which would have the added bonus of eliminating double spaces between some columns (see the first `to_string` output in #11833, for example). A bunch of formatting tests would have to be adjusted, though. Is there anyone who prefers the extra space?



Discussion:
yeah looks like the prior fix only dealt with integers. a more comprehensive fix would be ok.

The formatting issue seems more broad to me. This example demonstrates:

```
import pandas as pd

NAMES = ['Short', 'Longer', 'Much Longer name to the Max -----------']
VALUES = [1, 9374518, 32432]

d = pd.DataFrame({'Name': NAMES, 'Value': VALUES})

print("With index")
print(d.to_string())

print("\n\nWithout index")
print(d.to_string(index=False))

```

Produces this:

```
With index
                                      Name    Value
0                                    Short        1
1                                   Longer  9374518
2  Much Longer name to the Max -----------    32432

Without index
Name    Value
                                  Short        1
                                 Longer  9374518
Much Longer name to the Max -----------    32432

```

Might affect this.

```
display.max_colwidth : int
    The maximum width in characters of a column in the repr of
    a pandas data structure. When the column overflows, a "..."
    placeholder is embedded in the output.
    [default: 50] [currently: 50]
```

Note that only the header line is shifted incorrectly.

My current workaround is this (data is the DataFrame):

```
# Find longest index string
longest = max([len(str(s)) for s in data.index]) + 1

# Print to lines and manually remove 'index' from each line
lines = data.to_string().split('\n')
lines = [l[longest:] for l in lines]
print('\n'.join(lines))
```

@hawkeyej certainly love for a PR to fix! just write up a test of the correct results, and use your fix; see what else breaks :) 

Initial work in https://github.com/pandas-dev/pandas/pull/14196, can possibly be used as a basis (it needs tests)

Ping. Annoying bug, can I help? Though I'm not a pandas expert...

Resolving patch:
diff --git a/pandas/io/formats/format.py b/pandas/io/formats/format.py
--- a/pandas/io/formats/format.py
+++ b/pandas/io/formats/format.py
@@ -288,8 +288,7 @@ def to_string(self):
         if self.index:
             result = self.adj.adjoin(3, *[fmt_index[1:], fmt_values])
         else:
-            result = self.adj.adjoin(3, fmt_values).replace('\n ',
-                                                            '\n').strip()
+            result = self.adj.adjoin(3, fmt_values)
 
         if self.header and have_header:
             result = fmt_index[0] + '\n' + result
@@ -650,8 +649,6 @@ def to_string(self):
                 self._chk_truncate()
                 strcols = self._to_str_columns()
                 text = self.adj.adjoin(1, *strcols)
-        if not self.index:
-            text = text.replace('\n ', '\n').strip()
         self.buf.writelines(text)
 
         if self.should_show_dimensions:


Test patch:
diff --git a/pandas/tests/io/formats/test_format.py b/pandas/tests/io/formats/test_format.py
--- a/pandas/tests/io/formats/test_format.py
+++ b/pandas/tests/io/formats/test_format.py
@@ -1269,18 +1269,42 @@ def test_to_string_specified_header(self):
             df.to_string(header=['X'])
 
     def test_to_string_no_index(self):
-        df = DataFrame({'x': [1, 2, 3], 'y': [4, 5, 6]})
+        # GH 16839, GH 13032
+        df = DataFrame({'x': [11, 22], 'y': [33, -44], 'z': ['AAA', '   ']})
 
         df_s = df.to_string(index=False)
-        expected = "x  y\n1  4\n2  5\n3  6"
+        # Leading space is expected for positive numbers.
+        expected = ("  x   y    z\n"
+                    " 11  33  AAA\n"
+                    " 22 -44     ")
+        assert df_s == expected
 
+        df_s = df[['y', 'x', 'z']].to_string(index=False)
+        expected = ("  y   x    z\n"
+                    " 33  11  AAA\n"
+                    "-44  22     ")
         assert df_s == expected
 
     def test_to_string_line_width_no_index(self):
+        # GH 13998, GH 22505
         df = DataFrame({'x': [1, 2, 3], 'y': [4, 5, 6]})
 
         df_s = df.to_string(line_width=1, index=False)
-        expected = "x  \\\n1   \n2   \n3   \n\ny  \n4  \n5  \n6"
+        expected = " x  \\\n 1   \n 2   \n 3   \n\n y  \n 4  \n 5  \n 6  "
+
+        assert df_s == expected
+
+        df = DataFrame({'x': [11, 22, 33], 'y': [4, 5, 6]})
+
+        df_s = df.to_string(line_width=1, index=False)
+        expected = "  x  \\\n 11   \n 22   \n 33   \n\n y  \n 4  \n 5  \n 6  "
+
+        assert df_s == expected
+
+        df = DataFrame({'x': [11, 22, -33], 'y': [4, 5, -6]})
+
+        df_s = df.to_string(line_width=1, index=False)
+        expected = "  x  \\\n 11   \n 22   \n-33   \n\n y  \n 4  \n 5  \n-6  "
 
         assert df_s == expected
 
@@ -1793,7 +1817,7 @@ def test_to_string_without_index(self):
         # GH 11729 Test index=False option
         s = Series([1, 2, 3, 4])
         result = s.to_string(index=False)
-        expected = (u('1\n') + '2\n' + '3\n' + '4')
+        expected = (u(' 1\n') + ' 2\n' + ' 3\n' + ' 4')
         assert result == expected
 
     def test_unicode_name_in_footer(self):