Skip to content

Commit 1c34755

Browse files
committed
ENH: Styler.bar: properly support NaNs
1 parent 6b4e2c2 commit 1c34755

File tree

3 files changed

+50
-3
lines changed

3 files changed

+50
-3
lines changed

doc/source/whatsnew/v0.24.0.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -728,7 +728,7 @@ Other
728728
- :meth:`~pandas.io.formats.style.Styler.background_gradient` now takes a ``text_color_threshold`` parameter to automatically lighten the text color based on the luminance of the background color. This improves readability with dark background colors without the need to limit the background colormap range. (:issue:`21258`)
729729
- Require at least 0.28.2 version of ``cython`` to support read-only memoryviews (:issue:`21688`)
730730
- :meth:`~pandas.io.formats.style.Styler.background_gradient` now also supports tablewise application (in addition to rowwise and columnwise) with ``axis=None`` (:issue:`15204`)
731-
- :meth:`~pandas.io.formats.style.Styler.bar` now also supports tablewise application (in addition to rowwise and columnwise) with ``axis=None`` and setting clipping range with ``vmin`` and ``vmax`` (:issue:`21548` and :issue:`21526`)
731+
- :meth:`~pandas.io.formats.style.Styler.bar` now also supports tablewise application (in addition to rowwise and columnwise) with ``axis=None`` and setting clipping range with ``vmin`` and ``vmax`` (:issue:`21548` and :issue:`21526`). ``NaN`` values are also handled properly.
732732
-
733733
-
734734
-

pandas/io/formats/style.py

+10-2
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@
3030
import pandas.core.common as com
3131
from pandas.core.indexing import _maybe_numeric_slice, _non_reducing_slice
3232
from pandas.util._decorators import Appender
33+
from pandas.core.dtypes.generic import ABCSeries
34+
3335
try:
3436
import matplotlib.pyplot as plt
3537
from matplotlib import colors
@@ -997,8 +999,12 @@ def _bar(s, align, colors, width=100, vmin=None, vmax=None):
997999
"""Draw bar chart in dataframe cells"""
9981000

9991001
# Get input value range.
1000-
smin = s.values.min() if vmin is None else vmin
1001-
smax = s.values.max() if vmax is None else vmax
1002+
smin = s.min() if vmin is None else vmin
1003+
if isinstance(smin, ABCSeries):
1004+
smin = smin.min()
1005+
smax = s.max() if vmax is None else vmax
1006+
if isinstance(smax, ABCSeries):
1007+
smax = smax.max()
10021008
if align == 'mid':
10031009
smin = min(0, smin)
10041010
smax = max(0, smax)
@@ -1025,6 +1031,8 @@ def css_bar(start, end, color):
10251031
return css
10261032

10271033
def css(x):
1034+
if pd.isna(x):
1035+
return ''
10281036
if align == 'left':
10291037
return css_bar(0, x, colors[x > zero])
10301038
else:

pandas/tests/io/formats/test_style.py

+39
Original file line numberDiff line numberDiff line change
@@ -651,6 +651,45 @@ def test_bar_align_mid_vmin_vmax_clipping(self):
651651
}
652652
assert result == expected
653653

654+
def test_bar_align_mid_nans(self):
655+
df = pd.DataFrame({'A': [1, None], 'B': [-1, 3]})
656+
result = df.style.bar(align='mid', axis=None)._compute().ctx
657+
expected = {
658+
(0, 0): ['width: 10em', ' height: 80%',
659+
'background: linear-gradient(90deg, '
660+
'transparent 25.0%, #d65f5f 25.0%, '
661+
'#d65f5f 50.0%, transparent 50.0%)'],
662+
(1, 0): [''],
663+
(0, 1): ['width: 10em', ' height: 80%',
664+
'background: linear-gradient(90deg,'
665+
'#d65f5f 25.0%, transparent 25.0%)'],
666+
(1, 1): ['width: 10em', ' height: 80%',
667+
'background: linear-gradient(90deg, '
668+
'transparent 25.0%, #d65f5f 25.0%, '
669+
'#d65f5f 100.0%, transparent 100.0%)']
670+
}
671+
assert result == expected
672+
673+
def test_bar_align_zero_nans(self):
674+
df = pd.DataFrame({'A': [1, None], 'B': [-1, 2]})
675+
result = df.style.bar(align='zero', axis=None)._compute().ctx
676+
expected = {
677+
(0, 0): ['width: 10em', ' height: 80%',
678+
'background: linear-gradient(90deg, '
679+
'transparent 50.0%, #d65f5f 50.0%, '
680+
'#d65f5f 75.0%, transparent 75.0%)'],
681+
(1, 0): [''],
682+
(0, 1): ['width: 10em', ' height: 80%',
683+
'background: linear-gradient(90deg, '
684+
'transparent 25.0%, #d65f5f 25.0%, '
685+
'#d65f5f 50.0%, transparent 50.0%)'],
686+
(1, 1): ['width: 10em', ' height: 80%',
687+
'background: linear-gradient(90deg, '
688+
'transparent 50.0%, #d65f5f 50.0%, '
689+
'#d65f5f 100.0%, transparent 100.0%)']
690+
}
691+
assert result == expected
692+
654693
def test_bar_bad_align_raises(self):
655694
df = pd.DataFrame({'A': [-100, -60, -30, -20]})
656695
with pytest.raises(ValueError):

0 commit comments

Comments
 (0)