Repository: pandas-dev/pandas (python)

Issue:
improve explanation of linear interpolation in `quantile`
Currently explained like
https://github.com/pandas-dev/pandas/blob/2e218d10984e9919f0296931d92ea851c6a6faf5/pandas/core/series.py#L2647-L2648

The phrase "the fractional part of the index surrounded by `i` and `j`" is not easy to parse and has no clear meaning.

Pull request:
DOC: Improve ``quantile`` docstring
- [x] closes #51745 and #52181


Patch:
diff --git a/pandas/core/series.py b/pandas/core/series.py
index e4dca97bc6..626fcd4776 100644
--- a/pandas/core/series.py
+++ b/pandas/core/series.py
@@ -2820,8 +2820,8 @@ class Series(base.IndexOpsMixin, NDFrame):  # type: ignore[misc]
             This optional parameter specifies the interpolation method to use,
             when the desired quantile lies between two data points `i` and `j`:
 
-                * linear: `i + (j - i) * fraction`, where `fraction` is the
-                  fractional part of the index surrounded by `i` and `j`.
+                * linear: `i + (j - i) * (x-i)/(j-i)`, where `(x-i)/(j-i)` is
+                  the fractional part of the index surrounded by `i > j`.
                 * lower: `i`.
                 * higher: `j`.
                 * nearest: `i` or `j` whichever is nearest.
diff --git a/pandas/io/formats/style.py b/pandas/io/formats/style.py
index 39d5b45862..7d5c354aef 100644
--- a/pandas/io/formats/style.py
+++ b/pandas/io/formats/style.py
@@ -4082,8 +4082,9 @@ def _bar(
             return ret
 
     values = data.to_numpy()
-    left = np.nanmin(values) if vmin is None else vmin
-    right = np.nanmax(values) if vmax is None else vmax
+    # A tricky way to address the issue where np.nanmin/np.nanmax fail to handle pd.NA.
+    left = np.nanmin(data.min(skipna=True)) if vmin is None else vmin
+    right = np.nanmax(data.max(skipna=True)) if vmax is None else vmax
     z: float = 0  # adjustment to translate data
 
     if align == "mid":


Test patch:
diff --git a/pandas/tests/io/formats/style/test_bar.py b/pandas/tests/io/formats/style/test_bar.py
index 19884aaac8..b0e4712e8b 100644
--- a/pandas/tests/io/formats/style/test_bar.py
+++ b/pandas/tests/io/formats/style/test_bar.py
@@ -1,7 +1,13 @@
+import io
+
 import numpy as np
 import pytest
 
-from pandas import DataFrame
+from pandas import (
+    NA,
+    DataFrame,
+    read_csv,
+)
 
 pytest.importorskip("jinja2")
 
@@ -305,3 +311,48 @@ def test_bar_value_error_raises():
     msg = r"`height` must be a value in \[0, 100\]"
     with pytest.raises(ValueError, match=msg):
         df.style.bar(height=200).to_html()
+
+
+def test_bar_color_and_cmap_error_raises():
+    df = DataFrame({"A": [1, 2, 3, 4]})
+    msg = "`color` and `cmap` cannot both be given"
+    # Test that providing both color and cmap raises a ValueError
+    with pytest.raises(ValueError, match=msg):
+        df.style.bar(color="#d65f5f", cmap="viridis").to_html()
+
+
+def test_bar_invalid_color_type_error_raises():
+    df = DataFrame({"A": [1, 2, 3, 4]})
+    msg = (
+        r"`color` must be string or list or tuple of 2 strings,"
+        r"\(eg: color=\['#d65f5f', '#5fba7d'\]\)"
+    )
+    # Test that providing an invalid color type raises a ValueError
+    with pytest.raises(ValueError, match=msg):
+        df.style.bar(color=123).to_html()
+
+    # Test that providing a color list with more than two elements raises a ValueError
+    with pytest.raises(ValueError, match=msg):
+        df.style.bar(color=["#d65f5f", "#5fba7d", "#abcdef"]).to_html()
+
+
+def test_styler_bar_with_NA_values():
+    df1 = DataFrame({"A": [1, 2, NA, 4]})
+    df2 = DataFrame([[NA, NA], [NA, NA]])
+    expected_substring = "style type="
+    html_output1 = df1.style.bar(subset="A").to_html()
+    html_output2 = df2.style.bar(align="left", axis=None).to_html()
+    assert expected_substring in html_output1
+    assert expected_substring in html_output2
+
+
+def test_style_bar_with_pyarrow_NA_values():
+    data = """name,age,test1,test2,teacher
+        Adam,15,95.0,80,Ashby
+        Bob,16,81.0,82,Ashby
+        Dave,16,89.0,84,Jones
+        Fred,15,,88,Jones"""
+    df = read_csv(io.StringIO(data), dtype_backend="pyarrow")
+    expected_substring = "style type="
+    html_output = df.style.bar(subset="test1").to_html()
+    assert expected_substring in html_output