From a69e853eaec110b516efd300d37582f71988c124 Mon Sep 17 00:00:00 2001 From: "JHM Darbyshire (iMac)" Date: Sun, 11 Jul 2021 14:54:44 +0200 Subject: [PATCH 1/5] add arg to control bar height in styler.bar --- pandas/io/formats/style.py | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/pandas/io/formats/style.py b/pandas/io/formats/style.py index d1e61e12a5dd3..a1a23d00d41c0 100644 --- a/pandas/io/formats/style.py +++ b/pandas/io/formats/style.py @@ -2052,6 +2052,7 @@ def bar( vmin: float | None = None, vmax: float | None = None, props: str = "width: 10em;", + height: float = 100, ) -> Styler: """ Draw bar chart in the cell backgrounds. @@ -2100,6 +2101,11 @@ def bar( Maximum bar value, defining the right hand limit of the bar drawing range, higher values are clipped to `vmax`. When None (default): the maximum value of the data will be used. + height : float, default 100 + The percentage height of the bar in the cell, centrally aligned, in [0,100]. + + .. versionadded:: 1.4.0 + props : str, optional The base CSS of the cell that is extended to add the bar chart. Defaults to `"width: 10em;"` @@ -2131,6 +2137,7 @@ def bar( align=align, colors=color, width=width / 100, + height=height / 100, vmin=vmin, vmax=vmax, base_css=props, @@ -2791,6 +2798,7 @@ def _bar( align: str | float | int | Callable, colors: list[str], width: float, + height: float, vmin: float | None, vmax: float | None, base_css: str, @@ -2808,6 +2816,9 @@ def _bar( Two listed colors as string in valid CSS. width : float in [0,1] The percentage of the cell, measured from left, where drawn bars will reside. + height : float in [0,1] + The percentage of the cell's height where drawn bars will reside, centrally + aligned. vmin : float, optional Overwrite the minimum value of the window. vmax : float, optional @@ -2873,7 +2884,7 @@ def css_calc(x, left: float, right: float, align: str): Notes ----- - Uses ``colors`` and ``width`` from outer scope. + Uses ``colors``, ``width`` and ``height`` from outer scope. """ if pd.isna(x): return base_css @@ -2911,7 +2922,13 @@ def css_calc(x, left: float, right: float, align: str): else: start, end = z_frac, (x - left) / (right - left) - return css_bar(start * width, end * width, color) + if height < 1: + return ( + css_bar(start * width, end * width, color) + + f" no-repeat center; background-size: 100% {height * 100:.1f}%;" + ) + else: + return css_bar(start * width, end * width, color) values = data.to_numpy() left = np.nanmin(values) if vmin is None else vmin From b7193831f0671d5583b3a8743e827b50c395425d Mon Sep 17 00:00:00 2001 From: "JHM Darbyshire (iMac)" Date: Sun, 11 Jul 2021 17:19:35 +0200 Subject: [PATCH 2/5] add arg to control bar height in styler.bar --- pandas/io/formats/style.py | 8 ++++---- pandas/tests/io/formats/style/test_align.py | 16 ++++++++++++++++ 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/pandas/io/formats/style.py b/pandas/io/formats/style.py index a1a23d00d41c0..c037f128adc95 100644 --- a/pandas/io/formats/style.py +++ b/pandas/io/formats/style.py @@ -2922,13 +2922,13 @@ def css_calc(x, left: float, right: float, align: str): else: start, end = z_frac, (x - left) / (right - left) - if height < 1: + ret = css_bar(start * width, end * width, color) + if height < 1 and "background: linear-gradient(" in ret: return ( - css_bar(start * width, end * width, color) - + f" no-repeat center; background-size: 100% {height * 100:.1f}%;" + ret + f" no-repeat center; background-size: 100% {height * 100:.1f}%;" ) else: - return css_bar(start * width, end * width, color) + return ret values = data.to_numpy() left = np.nanmin(values) if vmin is None else vmin diff --git a/pandas/tests/io/formats/style/test_align.py b/pandas/tests/io/formats/style/test_align.py index be7d2fc3be518..3516defc56af6 100644 --- a/pandas/tests/io/formats/style/test_align.py +++ b/pandas/tests/io/formats/style/test_align.py @@ -484,3 +484,19 @@ def test_bar_align_mixed_cases(align, exp): result = data.style.bar(align=align)._compute().ctx expected = {(0, 0): exp[0], (1, 0): exp[1], (2, 0): exp[2]} assert result == expected + + +def test_bar_align_height(): + # test when keyword height is used 'no-repeat center' and 'background-size' present + data = DataFrame([[1], [2]]) + result = data.style.bar(align="left", height=50)._compute().ctx + bg_s = "linear-gradient(90deg, #d65f5f 100.0%, transparent 100.0%) no-repeat center" + expected = { + (0, 0): [("width", "10em")], + (1, 0): [ + ("width", "10em"), + ("background", bg_s), + ("background-size", "100% 50.0%"), + ], + } + assert result == expected From e0459ae7a63e4a3f97e00698801d47e7621b002f Mon Sep 17 00:00:00 2001 From: "JHM Darbyshire (iMac)" Date: Sun, 11 Jul 2021 17:28:25 +0200 Subject: [PATCH 3/5] whats new --- doc/source/whatsnew/v1.4.0.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/whatsnew/v1.4.0.rst b/doc/source/whatsnew/v1.4.0.rst index d114f26788f00..7570f9c8fe983 100644 --- a/doc/source/whatsnew/v1.4.0.rst +++ b/doc/source/whatsnew/v1.4.0.rst @@ -30,7 +30,7 @@ enhancement2 Other enhancements ^^^^^^^^^^^^^^^^^^ - :meth:`Series.sample`, :meth:`DataFrame.sample`, and :meth:`.GroupBy.sample` now accept a ``np.random.Generator`` as input to ``random_state``. A generator will be more performant, especially with ``replace=False`` (:issue:`38100`) -- Additional options added to :meth:`.Styler.bar` to control alignment and display (:issue:`26070`) +- Additional options added to :meth:`.Styler.bar` to control alignment and display (:issue:`26070`, :issue:`36419`) - :meth:`Series.ewm`, :meth:`DataFrame.ewm`, now support a ``method`` argument with a ``'table'`` option that performs the windowing operation over an entire :class:`DataFrame`. See :ref:`Window Overview ` for performance and functional benefits (:issue:`42273`) - From 9cb59c9877b927abb7f4efa9a1615511dd50bf68 Mon Sep 17 00:00:00 2001 From: "JHM Darbyshire (iMac)" Date: Tue, 13 Jul 2021 07:43:46 +0200 Subject: [PATCH 4/5] makes args kw only after subset axis/ --- pandas/io/formats/style.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/pandas/io/formats/style.py b/pandas/io/formats/style.py index 89d832689b1ca..0e89f21fe2431 100644 --- a/pandas/io/formats/style.py +++ b/pandas/io/formats/style.py @@ -2046,17 +2046,20 @@ def bar( self, subset: Subset | None = None, axis: Axis | None = 0, + *, color="#d65f5f", width: float = 100, + height: float = 100, align: str | float | int | Callable = "mid", vmin: float | None = None, vmax: float | None = None, props: str = "width: 10em;", - height: float = 100, ) -> Styler: """ Draw bar chart in the cell backgrounds. + .. versionchanged:: 1.4.0 + Parameters ---------- subset : label, array-like, IndexSlice, optional @@ -2075,6 +2078,10 @@ def bar( width : float, default 100 The percentage of the cell, measured from the left, in which to draw the bars, in [0, 100]. + height : float, default 100 + The percentage height of the bar in the cell, centrally aligned, in [0,100]. + + .. versionadded:: 1.4.0 align : str, int, float, callable, default 'mid' How to align the bars within the cells relative to a width adjusted center. If string must be one of: @@ -2101,11 +2108,6 @@ def bar( Maximum bar value, defining the right hand limit of the bar drawing range, higher values are clipped to `vmax`. When None (default): the maximum value of the data will be used. - height : float, default 100 - The percentage height of the bar in the cell, centrally aligned, in [0,100]. - - .. versionadded:: 1.4.0 - props : str, optional The base CSS of the cell that is extended to add the bar chart. Defaults to `"width: 10em;"` From f81c8f688d3a62736087edf49321eca6ff974890 Mon Sep 17 00:00:00 2001 From: "JHM Darbyshire (iMac)" Date: Tue, 13 Jul 2021 07:45:04 +0200 Subject: [PATCH 5/5] makes args kw only after subset axis/ --- doc/source/whatsnew/v1.4.0.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/whatsnew/v1.4.0.rst b/doc/source/whatsnew/v1.4.0.rst index e93b0429129ef..cb2a59860783f 100644 --- a/doc/source/whatsnew/v1.4.0.rst +++ b/doc/source/whatsnew/v1.4.0.rst @@ -31,7 +31,7 @@ Other enhancements ^^^^^^^^^^^^^^^^^^ - Add support for assigning values to ``by`` argument in :meth:`DataFrame.plot.hist` and :meth:`DataFrame.plot.box` (:issue:`15079`) - :meth:`Series.sample`, :meth:`DataFrame.sample`, and :meth:`.GroupBy.sample` now accept a ``np.random.Generator`` as input to ``random_state``. A generator will be more performant, especially with ``replace=False`` (:issue:`38100`) -- Additional options added to :meth:`.Styler.bar` to control alignment and display (:issue:`26070`, :issue:`36419`) +- Additional options added to :meth:`.Styler.bar` to control alignment and display, with keyword only arguments (:issue:`26070`, :issue:`36419`) - :meth:`Series.ewm`, :meth:`DataFrame.ewm`, now support a ``method`` argument with a ``'table'`` option that performs the windowing operation over an entire :class:`DataFrame`. See :ref:`Window Overview ` for performance and functional benefits (:issue:`42273`) -