Repository: pandas-dev/pandas

Issue:
ENH: DataFrame.style option for hiding the index
#### Code Sample, a copy-pastable example if possible

``` python
df = pd.DataFrame(np.random.randn(10, 2))
df.style.set_include_index(False)  # name TBD
```
#### Expected Output

Same output, but without the index

Would maybe want a way to hide the columns too.

---

Current workaround

``` python
df = pd.DataFrame(np.random.randn(10, 2))
df.style.set_table_styles([
    {'selector': '.row_heading, .blank', 'props': [('display', 'none;')]}
])
```

This doesn't work if there's a `df.index.name` and almost surely doesn't work with MultiIndexes.



Discussion:

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
@@ -133,6 +133,9 @@ def __init__(self, data, precision=None, table_styles=None, uuid=None,
             precision = get_option('display.precision')
         self.precision = precision
         self.table_attributes = table_attributes
+        self.hidden_index = False
+        self.hidden_columns = []
+
         # display_funcs maps (row, col) -> formatting function
 
         def default_display_func(x):
@@ -180,6 +183,8 @@ def _translate(self):
         caption = self.caption
         ctx = self.ctx
         precision = self.precision
+        hidden_index = self.hidden_index
+        hidden_columns = self.hidden_columns
         uuid = self.uuid or str(uuid1()).replace("-", "_")
         ROW_HEADING_CLASS = "row_heading"
         COL_HEADING_CLASS = "col_heading"
@@ -194,7 +199,7 @@ def format_attr(pair):
 
         # for sparsifying a MultiIndex
         idx_lengths = _get_level_lengths(self.index)
-        col_lengths = _get_level_lengths(self.columns)
+        col_lengths = _get_level_lengths(self.columns, hidden_columns)
 
         cell_context = dict()
 
@@ -217,7 +222,7 @@ def format_attr(pair):
             row_es = [{"type": "th",
                        "value": BLANK_VALUE,
                        "display_value": BLANK_VALUE,
-                       "is_visible": True,
+                       "is_visible": not hidden_index,
                        "class": " ".join([BLANK_CLASS])}] * (n_rlvls - 1)
 
             # ... except maybe the last for columns.names
@@ -229,7 +234,7 @@ def format_attr(pair):
                            "value": name,
                            "display_value": name,
                            "class": " ".join(cs),
-                           "is_visible": True})
+                           "is_visible": not hidden_index})
 
             if clabels:
                 for c, value in enumerate(clabels[r]):
@@ -252,7 +257,8 @@ def format_attr(pair):
                     row_es.append(es)
                 head.append(row_es)
 
-        if self.data.index.names and _any_not_none(*self.data.index.names):
+        if (self.data.index.names and _any_not_none(*self.data.index.names) and
+                not hidden_index):
             index_header_row = []
 
             for c, name in enumerate(self.data.index.names):
@@ -266,7 +272,7 @@ def format_attr(pair):
                 [{"type": "th",
                   "value": BLANK_VALUE,
                   "class": " ".join([BLANK_CLASS])
-                  }] * len(clabels[0]))
+                  }] * (len(clabels[0]) - len(hidden_columns)))
 
             head.append(index_header_row)
 
@@ -278,7 +284,8 @@ def format_attr(pair):
                        "row{row}".format(row=r)]
                 es = {
                     "type": "th",
-                    "is_visible": _is_visible(r, c, idx_lengths),
+                    "is_visible": (_is_visible(r, c, idx_lengths) and
+                                   not hidden_index),
                     "value": value,
                     "display_value": value,
                     "id": "_".join(rid[1:]),
@@ -302,7 +309,8 @@ def format_attr(pair):
                     "value": value,
                     "class": " ".join(cs),
                     "id": "_".join(cs[1:]),
-                    "display_value": formatter(value)
+                    "display_value": formatter(value),
+                    "is_visible": (c not in hidden_columns)
                 })
                 props = []
                 for x in ctx[r, c]:
@@ -742,7 +750,7 @@ def set_uuid(self, uuid):
 
     def set_caption(self, caption):
         """
-        Se the caption on a Styler
+        Set the caption on a Styler
 
         Parameters
         ----------
@@ -784,6 +792,40 @@ def set_table_styles(self, table_styles):
         self.table_styles = table_styles
         return self
 
+    def hide_index(self):
+        """
+        Hide any indices from rendering.
+
+        .. versionadded:: 0.22.0
+
+        Returns
+        -------
+        self : Styler
+        """
+        self.hidden_index = True
+        return self
+
+    def hide_columns(self, subset):
+        """
+        Hide columns from rendering.
+
+        .. versionadded:: 0.22.0
+
+        Parameters
+        ----------
+        subset: IndexSlice
+            An argument to ``DataFrame.loc`` that identifies which columns
+            are hidden.
+
+        Returns
+        -------
+        self : Styler
+        """
+        subset = _non_reducing_slice(subset)
+        hidden_df = self.data.loc[subset]
+        self.hidden_columns = self.columns.get_indexer_for(hidden_df.columns)
+        return self
+
     # -----------------------------------------------------------------------
     # A collection of "builtin" styles
     # -----------------------------------------------------------------------
@@ -1158,31 +1200,48 @@ def _is_visible(idx_row, idx_col, lengths):
     return (idx_col, idx_row) in lengths
 
 
-def _get_level_lengths(index):
+def _get_level_lengths(index, hidden_elements=None):
     """
     Given an index, find the level lenght for each element.
+    Optional argument is a list of index positions which
+    should not be visible.
 
     Result is a dictionary of (level, inital_position): span
     """
     sentinel = sentinel_factory()
     levels = index.format(sparsify=sentinel, adjoin=False, names=False)
 
-    if index.nlevels == 1:
-        return {(0, i): 1 for i, value in enumerate(levels)}
+    if hidden_elements is None:
+        hidden_elements = []
 
     lengths = {}
+    if index.nlevels == 1:
+        for i, value in enumerate(levels):
+            if(i not in hidden_elements):
+                lengths[(0, i)] = 1
+        return lengths
 
     for i, lvl in enumerate(levels):
         for j, row in enumerate(lvl):
             if not get_option('display.multi_sparse'):
                 lengths[(i, j)] = 1
-            elif row != sentinel:
+            elif (row != sentinel) and (j not in hidden_elements):
                 last_label = j
                 lengths[(i, last_label)] = 1
-            else:
+            elif (row != sentinel):
+                # even if its hidden, keep track of it in case
+                # length >1 and later elemens are visible
+                last_label = j
+                lengths[(i, last_label)] = 0
+            elif(j not in hidden_elements):
                 lengths[(i, last_label)] += 1
 
-    return lengths
+    non_zero_lengths = {}
+    for element, length in lengths.items():
+        if(length >= 1):
+            non_zero_lengths[element] = length
+
+    return non_zero_lengths
 
 
 def _maybe_wrap_formatter(formatter):


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
@@ -891,6 +891,120 @@ def test_mi_sparse_column_names(self):
         ]
         assert head == expected
 
+    def test_hide_single_index(self):
+        # GH 14194
+        # single unnamed index
+        ctx = self.df.style._translate()
+        assert ctx['body'][0][0]['is_visible']
+        assert ctx['head'][0][0]['is_visible']
+        ctx2 = self.df.style.hide_index()._translate()
+        assert not ctx2['body'][0][0]['is_visible']
+        assert not ctx2['head'][0][0]['is_visible']
+
+        # single named index
+        ctx3 = self.df.set_index('A').style._translate()
+        assert ctx3['body'][0][0]['is_visible']
+        assert len(ctx3['head']) == 2  # 2 header levels
+        assert ctx3['head'][0][0]['is_visible']
+
+        ctx4 = self.df.set_index('A').style.hide_index()._translate()
+        assert not ctx4['body'][0][0]['is_visible']
+        assert len(ctx4['head']) == 1  # only 1 header levels
+        assert not ctx4['head'][0][0]['is_visible']
+
+    def test_hide_multiindex(self):
+        # GH 14194
+        df = pd.DataFrame({'A': [1, 2]}, index=pd.MultiIndex.from_arrays(
+            [['a', 'a'], [0, 1]],
+            names=['idx_level_0', 'idx_level_1'])
+        )
+        ctx1 = df.style._translate()
+        # tests for 'a' and '0'
+        assert ctx1['body'][0][0]['is_visible']
+        assert ctx1['body'][0][1]['is_visible']
+        # check for blank header rows
+        assert ctx1['head'][0][0]['is_visible']
+        assert ctx1['head'][0][1]['is_visible']
+
+        ctx2 = df.style.hide_index()._translate()
+        # tests for 'a' and '0'
+        assert not ctx2['body'][0][0]['is_visible']
+        assert not ctx2['body'][0][1]['is_visible']
+        # check for blank header rows
+        assert not ctx2['head'][0][0]['is_visible']
+        assert not ctx2['head'][0][1]['is_visible']
+
+    def test_hide_columns_single_level(self):
+        # GH 14194
+        # test hiding single column
+        ctx = self.df.style._translate()
+        assert ctx['head'][0][1]['is_visible']
+        assert ctx['head'][0][1]['display_value'] == 'A'
+        assert ctx['head'][0][2]['is_visible']
+        assert ctx['head'][0][2]['display_value'] == 'B'
+        assert ctx['body'][0][1]['is_visible']  # col A, row 1
+        assert ctx['body'][1][2]['is_visible']  # col B, row 1
+
+        ctx = self.df.style.hide_columns('A')._translate()
+        assert not ctx['head'][0][1]['is_visible']
+        assert not ctx['body'][0][1]['is_visible']  # col A, row 1
+        assert ctx['body'][1][2]['is_visible']  # col B, row 1
+
+        # test hiding mulitiple columns
+        ctx = self.df.style.hide_columns(['A', 'B'])._translate()
+        assert not ctx['head'][0][1]['is_visible']
+        assert not ctx['head'][0][2]['is_visible']
+        assert not ctx['body'][0][1]['is_visible']  # col A, row 1
+        assert not ctx['body'][1][2]['is_visible']  # col B, row 1
+
+    def test_hide_columns_mult_levels(self):
+        # GH 14194
+        # setup dataframe with multiple column levels and indices
+        i1 = pd.MultiIndex.from_arrays([['a', 'a'], [0, 1]],
+                                       names=['idx_level_0',
+                                              'idx_level_1'])
+        i2 = pd.MultiIndex.from_arrays([['b', 'b'], [0, 1]],
+                                       names=['col_level_0',
+                                              'col_level_1'])
+        df = pd.DataFrame([[1, 2], [3, 4]], index=i1, columns=i2)
+        ctx = df.style._translate()
+        # column headers
+        assert ctx['head'][0][2]['is_visible']
+        assert ctx['head'][1][2]['is_visible']
+        assert ctx['head'][1][3]['display_value'] == 1
+        # indices
+        assert ctx['body'][0][0]['is_visible']
+        # data
+        assert ctx['body'][1][2]['is_visible']
+        assert ctx['body'][1][2]['display_value'] == 3
+        assert ctx['body'][1][3]['is_visible']
+        assert ctx['body'][1][3]['display_value'] == 4
+
+        # hide top column level, which hides both columns
+        ctx = df.style.hide_columns('b')._translate()
+        assert not ctx['head'][0][2]['is_visible']  # b
+        assert not ctx['head'][1][2]['is_visible']  # 0
+        assert not ctx['body'][1][2]['is_visible']  # 3
+        assert ctx['body'][0][0]['is_visible']  # index
+
+        # hide first column only
+        ctx = df.style.hide_columns([('b', 0)])._translate()
+        assert ctx['head'][0][2]['is_visible']  # b
+        assert not ctx['head'][1][2]['is_visible']  # 0
+        assert not ctx['body'][1][2]['is_visible']  # 3
+        assert ctx['body'][1][3]['is_visible']
+        assert ctx['body'][1][3]['display_value'] == 4
+
+        # hide second column and index
+        ctx = df.style.hide_columns([('b', 1)]).hide_index()._translate()
+        assert not ctx['body'][0][0]['is_visible']  # index
+        assert ctx['head'][0][2]['is_visible']  # b
+        assert ctx['head'][1][2]['is_visible']  # 0
+        assert not ctx['head'][1][3]['is_visible']  # 1
+        assert not ctx['body'][1][3]['is_visible']  # 4
+        assert ctx['body'][1][2]['is_visible']
+        assert ctx['body'][1][2]['display_value'] == 3
+
 
 class TestStylerMatplotlibDep(object):