diff --git a/doc/source/reference/style.rst b/doc/source/reference/style.rst index a739993e4d376..8ba0aa8282608 100644 --- a/doc/source/reference/style.rst +++ b/doc/source/reference/style.rst @@ -41,6 +41,7 @@ Style application Styler.format Styler.format_index Styler.hide + Styler.show Styler.set_td_classes Styler.set_table_styles Styler.set_table_attributes diff --git a/doc/source/whatsnew/v1.4.0.rst b/doc/source/whatsnew/v1.4.0.rst index 3ee34a158902b..466aa78a41cb1 100644 --- a/doc/source/whatsnew/v1.4.0.rst +++ b/doc/source/whatsnew/v1.4.0.rst @@ -87,6 +87,7 @@ Styler - Styling and formatting of indexes has been added, with :meth:`.Styler.apply_index`, :meth:`.Styler.applymap_index` and :meth:`.Styler.format_index`. These mirror the signature of the methods already used to style and format data values, and work with both HTML, LaTeX and Excel format (:issue:`41893`, :issue:`43101`, :issue:`41993`, :issue:`41995`) - The new method :meth:`.Styler.hide` deprecates :meth:`.Styler.hide_index` and :meth:`.Styler.hide_columns` (:issue:`43758`) + - The new method :meth:`.Styler.show` provides a convenient refactorisation of :meth:`.Styler.hide` for specific rows and column labels, including ``head`` and ``tail`` options (:issue:`?????`) - The keyword arguments ``level`` and ``names`` have been added to :meth:`.Styler.hide` (and implicitly to the deprecated methods :meth:`.Styler.hide_index` and :meth:`.Styler.hide_columns`) for additional control of visibility of MultiIndexes and of index names (:issue:`25475`, :issue:`43404`, :issue:`43346`) - The :meth:`.Styler.export` and :meth:`.Styler.use` have been updated to address all of the added functionality from v1.2.0 and v1.3.0 (:issue:`40675`) - Global options under the category ``pd.options.styler`` have been extended to configure default ``Styler`` properties which address formatting, encoding, and HTML and LaTeX rendering. Note that formerly ``Styler`` relied on ``display.html.use_mathjax``, which has now been replaced by ``styler.html.mathjax``. (:issue:`41395`) diff --git a/pandas/io/formats/style.py b/pandas/io/formats/style.py index 29c1e35dbb546..63ec72131fc65 100644 --- a/pandas/io/formats/style.py +++ b/pandas/io/formats/style.py @@ -2401,6 +2401,10 @@ def hide( ------- self : Styler + See Also + -------- + Styler.show: Show specific rows / columns. + Notes ----- This method has multiple functionality depending upon the combination @@ -2557,6 +2561,93 @@ def hide( setattr(self, f"hide_{obj}_names", True) return self + def show( + self, + subset: Subset | None = None, + axis: Axis = 0, + head: int | None = None, + tail: int | None = None, + ) -> Styler: + """ + Show specific rows / columns in the display. + + .. versionadded:: 1.4.0 + + Parameters + ---------- + subset : label, array-like, IndexSlice, optional + A valid 1d input or single key along the axis within + `DataFrame.loc[, :]` or `DataFrame.loc[:, ]` depending + upon ``axis``, to limit ``data`` to select specific rows / columns. + axis : {"index", 0, "columns", 1} + Apply to the index or columns. + head : int, optional + The number of rows / columns at the start of the axis-index to show. + tail : int, optional + The number of rows / columns at the end of the axis-index to show. + + Returns + ------- + self : Styler + + See Also + -------- + Styler.hide: Hide the entire index / columns, or specific rows / columns. + + Notes + ----- + This is a simplified wrapper of :meth:`Styler.hide`, where the inputs are + internally restructured to a call to `Styler.hide`. It is recommended to + use `Styler.show` exclusively, and with only one call per axis, as a form of + convenient data exploration. For more specific control of removing items from + the display it is recommended to use `Styler.hide`, with as many successive + calls as is required. + + The technical explanation for this recommendation is that at instantiation + `Styler` is configured to display all datapoints and all aspects of the + index and column headers of a DataFrame, + but `Styler.hide` can be called to selectively, and successively, remove + items from that default display. + + For example, given an index of `[0, 1, 2, 3]`, calling: + + .. code-block:: python + + styler.hide([0, 1]).hide([2, 3]) + + will first hide the first 2 index labels and then, subsequently, also hide the + final 2 labels, resulting in hiding all of the rows and displaying none. + + In this case `styler.show([0, 1])` is refactored as the call + `styler.hide([v for v in styler.index if v not in [0, 1]])` which is + equivalently `styler.hide([2, 3])` so performing: + + .. code-block:: python + + styler.hide([0, 1]).show([0, 1]) + + is effectively the same as the above and will also result in all rows hidden. + + `Styler.hide` will always only add items to the set that is considered hidden. + It never removes items, that have been previously added, from that set to make + them visible again. This is done to provide consistent method chaining. + """ + axis = self.data._get_axis_number(axis) + obj = "index" if axis == 0 else "columns" + + visible = [] + if head is not None: + visible.extend(getattr(self, obj)[:head]) + if tail is not None: + visible.extend(getattr(self, obj)[-tail:]) + if subset is not None: + subset_ = IndexSlice[subset, :] if axis == 0 else IndexSlice[:, subset] + visible.extend(getattr(self.data.loc[non_reducing_slice(subset_)], obj)) + + return self.hide( + subset=[v for v in getattr(self, obj) if v not in visible], axis=axis + ) + # ----------------------------------------------------------------------- # A collection of "builtin" styles # ----------------------------------------------------------------------- diff --git a/pandas/tests/io/formats/style/test_style.py b/pandas/tests/io/formats/style/test_style.py index cb01cc39250b5..99a0cdf442d59 100644 --- a/pandas/tests/io/formats/style/test_style.py +++ b/pandas/tests/io/formats/style/test_style.py @@ -1548,3 +1548,25 @@ def test_col_trimming_hide_columns(): assert ctx["head"][0][c + 2]["is_visible"] == vals[1] assert len(ctx["body"][0]) == 6 # index + 2 hidden + 2 visible + trimming col + + +@pytest.mark.parametrize( + "kwargs, exp", + [ + ({"head": 2}, [3, 4]), + ({"tail": 2}, [1, 2]), + ({"subset": [2, 3]}, [1, 4]), + ({"head": 1, "tail": 1}, [2, 3]), + ({"head": 2, "subset": [2, 3]}, [4]), + ({"tail": 2, "subset": [2, 3]}, [1]), + ({"tail": 1, "subset": [2, 3], "head": 1}, []), + ], +) +@pytest.mark.parametrize("axis", ["index", "columns"]) +def test_show(kwargs, exp, axis): + df = DataFrame(np.random.randn(4, 4), index=[1, 2, 3, 4], columns=[1, 2, 3, 4]) + styler = Styler(df, uuid_len=0) + result = styler.show(axis=axis, **kwargs)._translate(True, True) + styler2 = Styler(df, uuid_len=0) + expected = styler2.hide(subset=exp, axis=axis)._translate(True, True) + assert result == expected