Repository: pandas-dev/pandas

Issue:
to_html(col_space=<int>) does not set min-width style correctly.
#### Code Sample, a copy-pastable example if possible

```python
import pandas as pd
import pandas.util.testing as tm
df = pd.DataFrame(index = tm.makeMultiIndex())
print(df.to_html(col_space=100))
```

```
<table border="1" class="dataframe">
  <thead>
    <tr style="text-align: right;">
      <th style="min-width: 100;"></th>
      <th style="min-width: 100;"></th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th rowspan="2" valign="top"style="min-width: 100;">foo</th>
      <th style="min-width: 100;">1</th>
    </tr>
    <tr>
      <th style="min-width: 100;">2</th>
    </tr>
    <tr>
      <th rowspan="2" valign="top"style="min-width: 100;">bar</th>
      <th style="min-width: 100;">1</th>
    </tr>
    <tr>
      <th style="min-width: 100;">2</th>
    </tr>
  </tbody>
</table>
```

#### Problem description

The `col_space` parameter expects an int..

https://github.com/pandas-dev/pandas/blob/cb89bc0c012a3154fae394a7299e72ec75956c9b/pandas/io/formats/format.py#L47-L48

it should be either px of % for HTML but this raises an error if you try.
```
print(df.to_html(col_space='100px'))
```
gives `TypeError: '>' not supported between instances of 'str' and 'int'`

The `<th style="min-width: 100;">` is also applied needlessly to the `<th>` tags within `<tbody>`

#### Expected Output
```
<table border="1" class="dataframe">
  <thead>
    <tr style="text-align: right;">
      <th style="min-width: 100px;"></th>
      <th style="min-width: 100px;"></th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th rowspan="2" valign="top">foo</th>
      <th>1</th>
    </tr>
    <tr>
      <th>2</th>
    </tr>
    <tr>
      <th rowspan="2" valign="top">bar</th>
      <th>1</th>
    </tr>
    <tr>
      <th>2</th>
    </tr>
  </tbody>
</table>
```
#### Output of ``pd.show_versions()``

<details>

[paste the output of ``pd.show_versions()`` here below this line]

</details>



Discussion:

Resolving patch:
diff --git a/pandas/core/frame.py b/pandas/core/frame.py
--- a/pandas/core/frame.py
+++ b/pandas/core/frame.py
@@ -663,7 +663,9 @@ def _repr_html_(self):
 
     @Substitution(header='Write out the column names. If a list of strings '
                          'is given, it is assumed to be aliases for the '
-                         'column names')
+                         'column names',
+                  col_space_type='int',
+                  col_space='The minimum width of each column')
     @Substitution(shared_params=fmt.common_docstring,
                   returns=fmt.return_docstring)
     def to_string(self, buf=None, columns=None, col_space=None, header=True,
@@ -2149,7 +2151,12 @@ def to_parquet(self, fname, engine='auto', compression='snappy',
                    compression=compression, index=index,
                    partition_cols=partition_cols, **kwargs)
 
-    @Substitution(header='Whether to print column labels, default True')
+    @Substitution(header='Whether to print column labels, default True',
+                  col_space_type='str or int',
+                  col_space='The minimum width of each column in CSS length '
+                            'units.  An int is assumed to be px units.\n\n'
+                            '            .. versionadded:: 0.25.0\n'
+                            '                Abillity to use str')
     @Substitution(shared_params=fmt.common_docstring,
                   returns=fmt.return_docstring)
     def to_html(self, buf=None, columns=None, col_space=None, header=True,
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
@@ -45,8 +45,8 @@
             Buffer to write to.
         columns : sequence, optional, default None
             The subset of columns to write. Writes all columns by default.
-        col_space : int, optional
-            The minimum width of each column.
+        col_space : %(col_space_type)s, optional
+            %(col_space)s.
         header : bool, optional
             %(header)s.
         index : bool, optional, default True
diff --git a/pandas/io/formats/html.py b/pandas/io/formats/html.py
--- a/pandas/io/formats/html.py
+++ b/pandas/io/formats/html.py
@@ -46,6 +46,9 @@ def __init__(self, formatter, classes=None, border=None):
         self.border = border
         self.table_id = self.fmt.table_id
         self.render_links = self.fmt.render_links
+        if isinstance(self.fmt.col_space, int):
+            self.fmt.col_space = ('{colspace}px'
+                                  .format(colspace=self.fmt.col_space))
 
     @property
     def show_row_idx_names(self):
@@ -85,8 +88,30 @@ def write(self, s, indent=0):
         rs = pprint_thing(s)
         self.elements.append(' ' * indent + rs)
 
-    def write_th(self, s, indent=0, tags=None):
-        if self.fmt.col_space is not None and self.fmt.col_space > 0:
+    def write_th(self, s, header=False, indent=0, tags=None):
+        """
+        Method for writting a formatted <th> cell.
+
+        If col_space is set on the formatter then that is used for
+        the value of min-width.
+
+        Parameters
+        ----------
+        s : object
+            The data to be written inside the cell.
+        header : boolean, default False
+            Set to True if the <th> is for use inside <thead>.  This will
+            cause min-width to be set if there is one.
+        indent : int, default 0
+            The indentation level of the cell.
+        tags : string, default None
+            Tags to include in the cell.
+
+        Returns
+        -------
+        A written <th> cell.
+        """
+        if header and self.fmt.col_space is not None:
             tags = (tags or "")
             tags += ('style="min-width: {colspace};"'
                      .format(colspace=self.fmt.col_space))
@@ -137,7 +162,7 @@ def write_tr(self, line, indent=0, indent_delta=0, header=False,
         for i, s in enumerate(line):
             val_tag = tags.get(i, None)
             if header or (self.bold_rows and i < nindex_levels):
-                self.write_th(s, indent, tags=val_tag)
+                self.write_th(s, indent=indent, header=header, tags=val_tag)
             else:
                 self.write_td(s, indent, tags=val_tag)
 


Test patch:
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
@@ -643,3 +643,17 @@ def test_to_html_round_column_headers():
         notebook = df.to_html(notebook=True)
     assert "0.55555" in html
     assert "0.556" in notebook
+
+
+@pytest.mark.parametrize("unit", ['100px', '10%', '5em', 150])
+def test_to_html_with_col_space_units(unit):
+    # GH 25941
+    df = DataFrame(np.random.random(size=(1, 3)))
+    result = df.to_html(col_space=unit)
+    result = result.split('tbody')[0]
+    hdrs = [x for x in result.split("\n") if re.search(r"<th[>\s]", x)]
+    if isinstance(unit, int):
+        unit = str(unit) + 'px'
+    for h in hdrs:
+        expected = '<th style="min-width: {unit};">'.format(unit=unit)
+        assert expected in h