Skip to content

Commit

Permalink
ENH 14194: add style option for hiding index and columns (#16141)
Browse files Browse the repository at this point in the history
  • Loading branch information
nchmura4 authored and jreback committed Nov 19, 2017
1 parent b315e7d commit b00e62c
Show file tree
Hide file tree
Showing 4 changed files with 258 additions and 27 deletions.
81 changes: 69 additions & 12 deletions doc/source/style.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -674,13 +674,14 @@
"- precision\n",
"- captions\n",
"- table-wide styles\n",
"- hiding the index or columns\n",
"\n",
"Each of these can be specified in two ways:\n",
"\n",
"- A keyword argument to `Styler.__init__`\n",
"- A call to one of the `.set_` methods, e.g. `.set_caption`\n",
"- A call to one of the `.set_` or `.hide_` methods, e.g. `.set_caption` or `.hide_columns`\n",
"\n",
"The best method to use depends on the context. Use the `Styler` constructor when building many styled DataFrames that should all share the same properties. For interactive use, the`.set_` methods are more convenient."
"The best method to use depends on the context. Use the `Styler` constructor when building many styled DataFrames that should all share the same properties. For interactive use, the`.set_` and `.hide_` methods are more convenient."
]
},
{
Expand Down Expand Up @@ -814,6 +815,38 @@
"We hope to collect some useful ones either in pandas, or preferable in a new package that [builds on top](#Extensibility) the tools here."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Hiding the Index or Columns"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The index can be hidden from rendering by calling `Styler.hide_index`. Columns can be hidden from rendering by calling `Styler.hide_columns` and passing in the name of a column, or a slice of columns."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"df.style.hide_index()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"df.style.hide_columns(['C','D'])"
]
},
{
"cell_type": "markdown",
"metadata": {},
Expand Down Expand Up @@ -875,7 +908,9 @@
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"from IPython.html import widgets\n",
Expand Down Expand Up @@ -911,7 +946,9 @@
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"np.random.seed(25)\n",
Expand Down Expand Up @@ -1010,7 +1047,9 @@
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"%mkdir templates"
Expand All @@ -1027,7 +1066,9 @@
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"%%file templates/myhtml.tpl\n",
Expand Down Expand Up @@ -1078,7 +1119,9 @@
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"MyStyler(df)"
Expand All @@ -1094,7 +1137,9 @@
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"HTML(MyStyler(df).render(table_title=\"Extending Example\"))"
Expand All @@ -1110,7 +1155,9 @@
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"EasyStyler = Styler.from_custom_template(\"templates\", \"myhtml.tpl\")\n",
Expand All @@ -1127,7 +1174,9 @@
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"with open(\"template_structure.html\") as f:\n",
Expand All @@ -1147,6 +1196,7 @@
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true,
"nbsphinx": "hidden"
},
"outputs": [],
Expand All @@ -1163,7 +1213,7 @@
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"display_name": "Python [default]",
"language": "python",
"name": "python3"
},
Expand All @@ -1177,7 +1227,14 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.6.1"
"version": "3.5.3"
},
"widgets": {
"application/vnd.jupyter.widget-state+json": {
"state": {},
"version_major": 1,
"version_minor": 0
}
}
},
"nbformat": 4,
Expand Down
3 changes: 2 additions & 1 deletion doc/source/whatsnew/v0.22.0.txt
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ Other Enhancements

- Better support for :func:`Dataframe.style.to_excel` output with the ``xlsxwriter`` engine. (:issue:`16149`)
- :func:`pandas.tseries.frequencies.to_offset` now accepts leading '+' signs e.g. '+1h'. (:issue:`18171`)
-
- :class:`pandas.io.formats.style.Styler` now has method ``hide_index()`` to determine whether the index will be rendered in ouptut (:issue:`14194`)
- :class:`pandas.io.formats.style.Styler` now has method ``hide_columns()`` to determine whether columns will be hidden in output (:issue:`14194`)

.. _whatsnew_0220.api_breaking:

Expand Down
87 changes: 73 additions & 14 deletions pandas/io/formats/style.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down Expand Up @@ -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"
Expand All @@ -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()

Expand All @@ -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
Expand All @@ -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]):
Expand All @@ -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):
Expand All @@ -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)

Expand All @@ -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:]),
Expand All @@ -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]:
Expand Down Expand Up @@ -741,7 +749,7 @@ def set_uuid(self, uuid):

def set_caption(self, caption):
"""
Se the caption on a Styler
Set the caption on a Styler
Parameters
----------
Expand Down Expand Up @@ -783,6 +791,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
# -----------------------------------------------------------------------
Expand Down Expand Up @@ -1157,31 +1199,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):
Expand Down
Loading

0 comments on commit b00e62c

Please sign in to comment.