Repository: pandas-dev/pandas

Issue:
BUG: Empty DataFrame.style.render raises IndexError
#### Code Sample, a copy-pastable example if possible

```python
In [6]: pd.DataFrame().style.render()
---------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
<ipython-input-6-345e1b37074e> in <module>()
----> 1 pd.DataFrame().style.render()

/Users/taugspurger/Envs/dask-dev/lib/python3.6/site-packages/pandas/formats/style.py in render(self)
    416         """
    417         self._compute()
--> 418         d = self._translate()
    419         # filter out empty styles, every cell will have a class
    420         # but the list of props may just be [['', '']].

/Users/taugspurger/Envs/dask-dev/lib/python3.6/site-packages/pandas/formats/style.py in _translate(self)
    252                            "is_visible": True})
    253
--> 254             for c in range(len(clabels[0])):
    255                 cs = [COL_HEADING_CLASS, "level%s" % r, "col%s" % c]
    256                 cs.extend(cell_context.get(

IndexError: list index out of range
```
#### Problem description

We assume that there's at least one column (and probably row)

#### Expected Output

Should match the output of an empty DataFrame in the notebook


Discussion:
I'll take a stab at this (I'm at PyCon sprint).

Resolving patch:
diff --git a/pandas/io/formats/style.py b/pandas/io/formats/style.py
--- a/pandas/io/formats/style.py
+++ b/pandas/io/formats/style.py
@@ -238,24 +238,25 @@ def format_attr(pair):
                            "class": " ".join(cs),
                            "is_visible": True})
 
-            for c, value in enumerate(clabels[r]):
-                cs = [COL_HEADING_CLASS, "level%s" % r, "col%s" % c]
-                cs.extend(cell_context.get(
-                    "col_headings", {}).get(r, {}).get(c, []))
-                es = {
-                    "type": "th",
-                    "value": value,
-                    "display_value": value,
-                    "class": " ".join(cs),
-                    "is_visible": _is_visible(c, r, col_lengths),
-                }
-                colspan = col_lengths.get((r, c), 0)
-                if colspan > 1:
-                    es["attributes"] = [
-                        format_attr({"key": "colspan", "value": colspan})
-                    ]
-                row_es.append(es)
-            head.append(row_es)
+            if clabels:
+                for c, value in enumerate(clabels[r]):
+                    cs = [COL_HEADING_CLASS, "level%s" % r, "col%s" % c]
+                    cs.extend(cell_context.get(
+                        "col_headings", {}).get(r, {}).get(c, []))
+                    es = {
+                        "type": "th",
+                        "value": value,
+                        "display_value": value,
+                        "class": " ".join(cs),
+                        "is_visible": _is_visible(c, r, col_lengths),
+                    }
+                    colspan = col_lengths.get((r, c), 0)
+                    if colspan > 1:
+                        es["attributes"] = [
+                            format_attr({"key": "colspan", "value": colspan})
+                        ]
+                    row_es.append(es)
+                head.append(row_es)
 
         if self.data.index.names and not all(x is None
                                              for x in self.data.index.names):


Test patch:
diff --git a/pandas/tests/io/formats/test_style.py b/pandas/tests/io/formats/test_style.py
--- a/pandas/tests/io/formats/test_style.py
+++ b/pandas/tests/io/formats/test_style.py
@@ -103,6 +103,16 @@ def test_render(self):
         s.render()
         # it worked?
 
+    def test_render_empty_dfs(self):
+        empty_df = DataFrame()
+        es = Styler(empty_df)
+        es.render()
+        # An index but no columns
+        DataFrame(columns=['a']).style.render()
+        # A column but no index
+        DataFrame(index=['a']).style.render()
+        # No IndexError raised?
+
     def test_render_double(self):
         df = pd.DataFrame({"A": [0, 1]})
         style = lambda x: pd.Series(["color: red; border: 1px",