Repository: pandas-dev/pandas

Issue:
to_latex with float_format doesn't work like expected 
#### Code Sample

```python
import pandas as pd
df = pd.DataFrame([[0.19999]])
print(df.to_latex(float_format='%.3f'))
# returns:
# \begin{tabular}{lr}
# \toprule
# {} &   0 \\
# \midrule
# 0 & 0.2 \\
# \bottomrule
# \end{tabular}
```
#### Problem description

The float format doesn't seem to be respected in the example above. In contrast:
```python
'%.3f' % df.values[0][0]
# returns
# '0.200'
```
I would expect the number to be rendered as `0.200` instead of `0.2`.

Issue #6052 is possibly related, but the problem description is different.

#### Expected Output

```
\begin{tabular}{lr}
\toprule
{} &   0 \\
\midrule
0 & 0.200 \\
\bottomrule
\end{tabular}
```

#### Output of ``pd.show_versions()``

<details>
Using Anaconda Python 3.6.5 with recent pandas 0.23.1.

```
INSTALLED VERSIONS
------------------
commit: None
python: 3.6.5.final.0
python-bits: 64
OS: Linux
OS-release: 4.4.0-128-generic
machine: x86_64
processor: x86_64
byteorder: little
LC_ALL: None
LANG: en_US.UTF-8
LOCALE: en_US.UTF-8

pandas: 0.23.1
pytest: None
pip: 10.0.1
setuptools: 39.2.0
Cython: None
numpy: 1.14.5
scipy: None
pyarrow: None
xarray: None
IPython: 6.4.0
sphinx: None
patsy: None
dateutil: 2.7.3
pytz: 2018.4
blosc: None
bottleneck: None
tables: None
numexpr: None
feather: None
matplotlib: None
openpyxl: None
xlrd: None
xlwt: None
xlsxwriter: None
lxml: None
bs4: None
html5lib: None
sqlalchemy: None
pymysql: None
psycopg2: None
jinja2: None
s3fs: None
fastparquet: None
pandas_gbq: None
pandas_datareader: None

```
</details>



Discussion:
Thanks for the report - investigation and PRs are always welcome!
`float_format` takes a function rather than a string so if you do:
```python
import pandas as pd
df = pd.DataFrame([[0.19999]])
print(df.to_latex(float_format=lambda x: '%.3f' % x))
```
you'll get what you want. It isn't just `to_latex` that is affected by this, `to_string` and `to_html` have the same behaviour. One problem is that the `to_latex` docstring isn't inheriting the docstring from `to_string` (which it probably should), so this information is hidden away.

`to_csv` on the otherhand, does seem to accept a string, according to the docstring.
Oops, I wasn't aware it is expecting a function! Thanks a lot, this way it works! From my perspective, issue can be closed... Thanks again!
`float_format` accepts a string for the other `to_...` functions and it should here, so this is still a bug if anyone wants to work it
I think the problem is that trailing zeros are being "trimmed" away. Presuming `float_format` should override this behaviour then a potential fix is 79b5acb5929333f0d0cd602b5ac206b29cc589a6. If that sounds like the right logic then I'll open a PR (when time permits). 

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
@@ -960,6 +960,8 @@ def __init__(self, *args, **kwargs):
         # float_format is expected to be a string
         # formatter should be used to pass a function
         if self.float_format is not None and self.formatter is None:
+            # GH21625, GH22270
+            self.fixed_width = False
             if callable(self.float_format):
                 self.formatter = self.float_format
                 self.float_format = None


Test patch:
diff --git a/pandas/tests/io/formats/data/gh21625_expected_output.html b/pandas/tests/io/formats/data/gh21625_expected_output.html
new file mode 100644
--- /dev/null
+++ b/pandas/tests/io/formats/data/gh21625_expected_output.html
@@ -0,0 +1,14 @@
+<table border="1" class="dataframe">
+  <thead>
+    <tr style="text-align: right;">
+      <th></th>
+      <th>x</th>
+    </tr>
+  </thead>
+  <tbody>
+    <tr>
+      <th>0</th>
+      <td>0.200</td>
+    </tr>
+  </tbody>
+</table>
\ No newline at end of file
diff --git a/pandas/tests/io/formats/data/gh22270_expected_output.html b/pandas/tests/io/formats/data/gh22270_expected_output.html
new file mode 100644
--- /dev/null
+++ b/pandas/tests/io/formats/data/gh22270_expected_output.html
@@ -0,0 +1,14 @@
+<table border="1" class="dataframe">
+  <thead>
+    <tr style="text-align: right;">
+      <th></th>
+      <th>x</th>
+    </tr>
+  </thead>
+  <tbody>
+    <tr>
+      <th>0</th>
+      <td>100</td>
+    </tr>
+  </tbody>
+</table>
\ No newline at end of file
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
@@ -1359,6 +1359,18 @@ def test_to_string_float_formatting(self):
                         '1  2.512000e-01')
         assert df_s == expected
 
+    def test_to_string_float_format_no_fixed_width(self):
+
+        # GH 21625
+        df = DataFrame({'x': [0.19999]})
+        expected = '      x\n0 0.200'
+        assert df.to_string(float_format='%.3f') == expected
+
+        # GH 22270
+        df = DataFrame({'x': [100.0]})
+        expected = '    x\n0 100'
+        assert df.to_string(float_format='%.0f') == expected
+
     def test_to_string_small_float_values(self):
         df = DataFrame({'a': [1.5, 1e-17, -5.5e-7]})
 
diff --git a/pandas/tests/io/formats/test_to_html.py b/pandas/tests/io/formats/test_to_html.py
--- a/pandas/tests/io/formats/test_to_html.py
+++ b/pandas/tests/io/formats/test_to_html.py
@@ -465,3 +465,15 @@ def test_to_html_with_id(self):
                                                   name='myindexname'))
         result = df.to_html(index_names=False, table_id="TEST_ID")
         assert ' id="TEST_ID"' in result
+
+    def test_to_html_float_format_no_fixed_width(self, datapath):
+
+        # GH 21625
+        df = DataFrame({'x': [0.19999]})
+        expected = expected_html(datapath, 'gh21625_expected_output')
+        assert df.to_html(float_format='%.3f') == expected
+
+        # GH 22270
+        df = DataFrame({'x': [100.0]})
+        expected = expected_html(datapath, 'gh22270_expected_output')
+        assert df.to_html(float_format='%.0f') == expected
diff --git a/pandas/tests/io/formats/test_to_latex.py b/pandas/tests/io/formats/test_to_latex.py
--- a/pandas/tests/io/formats/test_to_latex.py
+++ b/pandas/tests/io/formats/test_to_latex.py
@@ -708,3 +708,29 @@ def test_to_latex_multiindex_empty_name(self):
 \end{tabular}
 """
         assert observed == expected
+
+    def test_to_latex_float_format_no_fixed_width(self):
+
+        # GH 21625
+        df = DataFrame({'x': [0.19999]})
+        expected = r"""\begin{tabular}{lr}
+\toprule
+{} &     x \\
+\midrule
+0 & 0.200 \\
+\bottomrule
+\end{tabular}
+"""
+        assert df.to_latex(float_format='%.3f') == expected
+
+        # GH 22270
+        df = DataFrame({'x': [100.0]})
+        expected = r"""\begin{tabular}{lr}
+\toprule
+{} &   x \\
+\midrule
+0 & 100 \\
+\bottomrule
+\end{tabular}
+"""
+        assert df.to_latex(float_format='%.0f') == expected