Show Index Headers on DataFrames with Style
State: closed

Partial solution for https://github.com/pydata/pandas/issues/11655 (**Conditional HTML styling hides MultiIndex structure**) and https://github.com/pydata/pandas/issues/11610 (**Followup to Conditional HTML Styling**).

The Style API is inconsistent with `DataFrame.to_html()` when printing index names. Currently the style API doesn't print any index names but `to_html` and the standard notebook repr functions do.

This PR adds a row for index headings in the `Styler._translate` method. This PR does not cause multi-index rownames to span multiple rows, but I can work on adding that if people want. 
## Reproducing Output:

``` python
import pandas as pd
import numpy as np

np.random.seed(24)
df = pd.DataFrame({'A': np.linspace(1, 10, 10)})
df = pd.concat([df, pd.DataFrame(np.random.randn(10, 4),
                                 columns=list('BCDE'))],
               axis=1)
```

``` python
df.set_index(['A', 'B']).style
```
##### Current Output

<img width="506" alt="screen shot 2016-01-19 at 10 19 08 am" src="https://cloud.githubusercontent.com/assets/3064019/12422922/32254fb2-be97-11e5-8096-fcadbd902daa.png">
##### Patched Output:

<img width="441" alt="screen shot 2016-01-19 at 10 19 19 am" src="https://cloud.githubusercontent.com/assets/3064019/12422947/46affb6c-be97-11e5-83c7-acd276bdb88f.png">
## TODO:
- [X] Add Tests


Labels:
name: Output-Formatting
description: __repr__ of pandas objects, to_string
name: IO HTML
description: read_html, to_html, Styler.apply, Styler.applymap
name: MultiIndex
name: Styler
description: conditional formatting using DataFrame.style

Comments:
tests pls

@jreback tests added. Do you think I need to add more tests?

Just gave a quick look, and the changes look good to me. Could you add a release note in `doc/source/whatsnew/v0.18.0.txt` under the bug fixes section?

Slightly off topic, but I saw your PrettyPandas the other day, looks great! Feel free to bug me with anything that's causing you difficulty with developing that. I've been busy with other types of work, so I haven't had time to actually use `.style` yet. e.g. I think pandas could have a decorator that makes it easier to hook into our lazy style evaluation so that you can export the styles more easily.

@HHammond some small comments. otherwise looks good.

can you run `git diff master | flake8 --diff` on this as well (and if anything comes up, pls fix). we are trying to fix PEP across the code base.

@TomAugspurger Thanks, I'm glad you like PrettyPandas. I'll try and explore the limits of what `style` can do and keep you in the loop if anything comes up.

It's been added to the what's new page, I've added the issue to the tests, and flake8 is happy with my patch. Anything else you guys need?

@jreback is this good to merge?

pls squash. http://pandas.pydata.org/pandas-docs/stable/contributing.html#combining-commits

@TomAugspurger ball in your court

Squashed

@HHammond thanks!

Please use the patch tool next time!

Sorry, I remembered that seconds after merging, old habits :)

No problem, but there's no need to ask people to squash any more either if you use that tool (unless there is some messy commit history or merge commits, of course). 

Still mismatches with normal `to_html` which skips if index name is `None`.

![2016-02-06 14 28 00](https://cloud.githubusercontent.com/assets/1696302/12864867/254ba020-ccde-11e5-9fe3-a20c83c83890.png)

@HHammond Appreciated if you can work.

I can take a look at that on Sunday or Monday. 

@TomAugspurger I have a patch for @sinhrks request, is it something that belongs in https://github.com/pydata/pandas/pull/12162 or would you prefer I create a new PR for that?

##### Patch:

```
diff --git a/pandas/core/style.py b/pandas/core/style.py
index a5a42c2..45e9dfc 100644
--- a/pandas/core/style.py
+++ b/pandas/core/style.py
@@ -206,7 +206,7 @@ class Styler(object):
                                "class": " ".join(cs)})
             head.append(row_es)

-        if self.data.index.names:
+        if self.data.index.names and self.data.index.names != [None]:
             index_header_row = []

             for c, name in enumerate(self.data.index.names):
```

You can do it as a separate PR if you have a chance. You might want to base it off https://github.com/pydata/pandas/pull/12162 to avoid merge conflicts.

PR: https://github.com/pydata/pandas/pull/12260