-
-
Notifications
You must be signed in to change notification settings - Fork 18.4k
ENH 14194: add style option for hiding index and columns #16141
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 6 commits
39dfbd5
33d5e5d
72f0bc0
650f3f7
4556057
a5c4e9e
cb779ec
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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. | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. how does subset make sense here? does it make sense to hide some columns? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The idea is that you may have columns that are needed for formatting -- determining the color of a row, for example -- but you may not want to display them. For example, lets say you had a dataframe with columns City and AvgTemp. Avg Temp was used by Styler to color each row. But in the final rendering, you only want to display city (colored appropriately). AFAIK there is no way to do that right now, but with this change you could do df.style.hide_columns(['AvgTemp']). You only want to hide AvgTemp. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this is a bit unusual for pandas, but I think it's fine here. It's kind of like There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. maybe we should support |
||
.. 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): | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hide_cols -> hide_columns
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
didn't we eliminate the paramaters as user facing and only use the methods? (which i think is better anyhow)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jreback yes, thanks, i should have caught that. fixed!