Skip to content

Commit 5a90aa2

Browse files
attack68feefladder
authored andcommitted
ENH: Styler.bar height control (pandas-dev#42483)
1 parent f9b71b0 commit 5a90aa2

File tree

3 files changed

+38
-3
lines changed

3 files changed

+38
-3
lines changed

doc/source/whatsnew/v1.4.0.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ Other enhancements
3131
^^^^^^^^^^^^^^^^^^
3232
- Add support for assigning values to ``by`` argument in :meth:`DataFrame.plot.hist` and :meth:`DataFrame.plot.box` (:issue:`15079`)
3333
- :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`)
34-
- Additional options added to :meth:`.Styler.bar` to control alignment and display (:issue:`26070`)
34+
- Additional options added to :meth:`.Styler.bar` to control alignment and display, with keyword only arguments (:issue:`26070`, :issue:`36419`)
3535
- :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 <window.overview>` for performance and functional benefits (:issue:`42273`)
3636
-
3737

pandas/io/formats/style.py

+21-2
Original file line numberDiff line numberDiff line change
@@ -2046,8 +2046,10 @@ def bar(
20462046
self,
20472047
subset: Subset | None = None,
20482048
axis: Axis | None = 0,
2049+
*,
20492050
color="#d65f5f",
20502051
width: float = 100,
2052+
height: float = 100,
20512053
align: str | float | int | Callable = "mid",
20522054
vmin: float | None = None,
20532055
vmax: float | None = None,
@@ -2056,6 +2058,8 @@ def bar(
20562058
"""
20572059
Draw bar chart in the cell backgrounds.
20582060
2061+
.. versionchanged:: 1.4.0
2062+
20592063
Parameters
20602064
----------
20612065
subset : label, array-like, IndexSlice, optional
@@ -2074,6 +2078,10 @@ def bar(
20742078
width : float, default 100
20752079
The percentage of the cell, measured from the left, in which to draw the
20762080
bars, in [0, 100].
2081+
height : float, default 100
2082+
The percentage height of the bar in the cell, centrally aligned, in [0,100].
2083+
2084+
.. versionadded:: 1.4.0
20772085
align : str, int, float, callable, default 'mid'
20782086
How to align the bars within the cells relative to a width adjusted center.
20792087
If string must be one of:
@@ -2131,6 +2139,7 @@ def bar(
21312139
align=align,
21322140
colors=color,
21332141
width=width / 100,
2142+
height=height / 100,
21342143
vmin=vmin,
21352144
vmax=vmax,
21362145
base_css=props,
@@ -2791,6 +2800,7 @@ def _bar(
27912800
align: str | float | int | Callable,
27922801
colors: list[str],
27932802
width: float,
2803+
height: float,
27942804
vmin: float | None,
27952805
vmax: float | None,
27962806
base_css: str,
@@ -2808,6 +2818,9 @@ def _bar(
28082818
Two listed colors as string in valid CSS.
28092819
width : float in [0,1]
28102820
The percentage of the cell, measured from left, where drawn bars will reside.
2821+
height : float in [0,1]
2822+
The percentage of the cell's height where drawn bars will reside, centrally
2823+
aligned.
28112824
vmin : float, optional
28122825
Overwrite the minimum value of the window.
28132826
vmax : float, optional
@@ -2873,7 +2886,7 @@ def css_calc(x, left: float, right: float, align: str):
28732886
28742887
Notes
28752888
-----
2876-
Uses ``colors`` and ``width`` from outer scope.
2889+
Uses ``colors``, ``width`` and ``height`` from outer scope.
28772890
"""
28782891
if pd.isna(x):
28792892
return base_css
@@ -2911,7 +2924,13 @@ def css_calc(x, left: float, right: float, align: str):
29112924
else:
29122925
start, end = z_frac, (x - left) / (right - left)
29132926

2914-
return css_bar(start * width, end * width, color)
2927+
ret = css_bar(start * width, end * width, color)
2928+
if height < 1 and "background: linear-gradient(" in ret:
2929+
return (
2930+
ret + f" no-repeat center; background-size: 100% {height * 100:.1f}%;"
2931+
)
2932+
else:
2933+
return ret
29152934

29162935
values = data.to_numpy()
29172936
left = np.nanmin(values) if vmin is None else vmin

pandas/tests/io/formats/style/test_bar.py

+16
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,22 @@ def test_colors_mixed(align, exp):
275275
assert result == {(0, 0): exp[0], (1, 0): exp[1]}
276276

277277

278+
def test_bar_align_height():
279+
# test when keyword height is used 'no-repeat center' and 'background-size' present
280+
data = DataFrame([[1], [2]])
281+
result = data.style.bar(align="left", height=50)._compute().ctx
282+
bg_s = "linear-gradient(90deg, #d65f5f 100.0%, transparent 100.0%) no-repeat center"
283+
expected = {
284+
(0, 0): [("width", "10em")],
285+
(1, 0): [
286+
("width", "10em"),
287+
("background", bg_s),
288+
("background-size", "100% 50.0%"),
289+
],
290+
}
291+
assert result == expected
292+
293+
278294
def test_bar_bad_align_raises():
279295
df = DataFrame({"A": [-100, -60, -30, -20]})
280296
msg = "`align` should be in {'left', 'right', 'mid', 'mean', 'zero'} or"

0 commit comments

Comments
 (0)