Repository: pandas-dev/pandas (python)

Issue:
DOC: Improve DataFrame.equals docstring comparing index & column with extension dtypes
### Pandas version checks

- [X] I have checked that this issue has not already been reported.

- [X] I have confirmed this bug exists on the [latest version](https://pandas.pydata.org/docs/whatsnew/index.html) of pandas.

- [X] I have confirmed this bug exists on the main branch of pandas.


### Reproducible Example

```python
pd.__version__
Out[27]: '1.3.5'

df = pd.DataFrame({"i": pd.Series([1, 2, 2], dtype=pd.Int64Dtype())})
df2 = pd.DataFrame({"i": pd.Series([1, 2, 2], dtype="int64")})
df.equals(df2)
Out[10]: False
df.dtypes
Out[11]: 
i    Int64
dtype: object
df2.dtypes
Out[12]: 
i    int64
dtype: object
df.index.dtype
Out[13]: dtype('int64')
df2.index.dtype
Out[14]: dtype('int64')

df = pd.DataFrame({"i": pd.Series([1, 2, 2], dtype=pd.Int64Dtype())}).set_index("i")
df2 = pd.DataFrame({"i": pd.Series([1, 2, 2], dtype="int64")}).set_index("i")
df.equals(df2)
Out[15]: True    # <<< df's are equal now
df.dtypes
Out[16]: Series([], dtype: object)
df2.dtypes
Out[17]: Series([], dtype: object)
df.index.dtype
Out[18]: dtype('O')
df2.index.dtype
Out[19]: dtype('int64')




pd.__version__
Out[70]: '1.4.1'

df = pd.DataFrame({"i": pd.Series([1, 2, 2], dtype=pd.Int64Dtype())})
df2 = pd.DataFrame({"i": pd.Series([1, 2, 2], dtype="int64")})
df.equals(df2)
Out[71]: False
df.dtypes
Out[72]: 
i    Int64
dtype: object
df2.dtypes
Out[73]: 
i    int64
dtype: object
df.index.dtype
Out[74]: dtype('int64')
df2.index.dtype
Out[75]: dtype('int64')

df = pd.DataFrame({"i": pd.Series([1, 2, 2], dtype=pd.Int64Dtype())}).set_index("i")
df2 = pd.DataFrame({"i": pd.Series([1, 2, 2], dtype="int64")}).set_index("i")
df.equals(df2)
Out[76]: False    # <<< df's are no longer equal
df.dtypes
Out[77]: Series([], dtype: object)
df2.dtypes
Out[78]: Series([], dtype: object)
df.index.dtype
Out[79]: Int64Dtype()
df2.index.dtype
Out[80]: dtype('int64')
```


### Issue Description

There is a difference between df.equals in 1.3.5 & 1.4.1 and it looks related to the use of extension vs non-extension types in indexes. Please see the example.

I found similar issues but they all seem to touch only what seems a very specific part or what looks like a bigger change, like: #46164 is only about equality between EA's.

There is no clear statement about this change in changelog so opening an issue. 

For reference, in my library I am writing the data into the storage, and when reading it back, the data frame that I read is no longer equal to the one I wrote.

### Expected Behavior

I expect equality to not change unless it's stated in the changelog. 

### Installed Versions

1.3.5
------------------
commit           : 66e3805b8cabe977f40c05259cc3fcf7ead5687d
python           : 3.8.8.final.0
python-bits      : 64
OS               : Darwin
OS-release       : 21.1.0
Version          : Darwin Kernel Version 21.1.0: Wed Oct 13 17:33:23 PDT 2021; root:xnu-8019.41.5~1/RELEASE_X86_64
machine          : x86_64
processor        : i386
byteorder        : little
LC_ALL           : None
LANG             : None
LOCALE           : en_GB.UTF-8
pandas           : 1.3.5
numpy            : 1.22.3
pytz             : 2021.3
dateutil         : 2.8.2
pip              : 21.3.1
setuptools       : 58.3.0
Cython           : 0.29.28
pytest           : 7.1.1
hypothesis       : None
sphinx           : 4.4.0
blosc            : None
feather          : None
xlsxwriter       : None
lxml.etree       : 4.8.0
html5lib         : None
pymysql          : 1.0.2
psycopg2         : None
jinja2           : 3.1.0
IPython          : 7.32.0
pandas_datareader: None
bs4              : 4.10.0
bottleneck       : None
fsspec           : 2022.02.0
fastparquet      : None
gcsfs            : None
matplotlib       : None
numexpr          : None
odfpy            : None
openpyxl         : 3.0.9
pandas_gbq       : None
pyarrow          : 6.0.1
pyxlsb           : None
s3fs             : 0.4.2
scipy            : None
sqlalchemy       : None
tables           : None
tabulate         : None
xarray           : None
xlrd             : None
xlwt             : None
numba            : None



1.4.1
------------------
commit           : 06d230151e6f18fdb8139d09abf539867a8cd481
python           : 3.8.8.final.0
python-bits      : 64
OS               : Darwin
OS-release       : 21.1.0
Version          : Darwin Kernel Version 21.1.0: Wed Oct 13 17:33:23 PDT 2021; root:xnu-8019.41.5~1/RELEASE_X86_64
machine          : x86_64
processor        : i386
byteorder        : little
LC_ALL           : None
LANG             : None
LOCALE           : en_GB.UTF-8
pandas           : 1.4.1
numpy            : 1.22.3
pytz             : 2021.3
dateutil         : 2.8.2
pip              : 21.3.1
setuptools       : 58.3.0
Cython           : 0.29.28
pytest           : 7.1.1
hypothesis       : None
sphinx           : 4.4.0
blosc            : None
feather          : None
xlsxwriter       : None
lxml.etree       : 4.8.0
html5lib         : None
pymysql          : 1.0.2
psycopg2         : None
jinja2           : 3.1.0
IPython          : 7.32.0
pandas_datareader: None
bs4              : 4.10.0
bottleneck       : None
fastparquet      : None
fsspec           : 2022.02.0
gcsfs            : None
matplotlib       : None
numba            : None
numexpr          : None
odfpy            : None
openpyxl         : 3.0.9
pandas_gbq       : None
pyarrow          : 6.0.1
pyreadstat       : None
pyxlsb           : None
s3fs             : 0.4.2
scipy            : None
sqlalchemy       : None
tables           : None
tabulate         : None
xarray           : None
xlrd             : None
xlwt             : None
zstandard        : None

Pull request:
DOC: Improve ``df.equals()`` docstring
- [x] closes #46507

Patch:
diff --git a/pandas/core/generic.py b/pandas/core/generic.py
index ef10958ac1..e46a0aa044 100644
--- a/pandas/core/generic.py
+++ b/pandas/core/generic.py
@@ -1451,8 +1451,8 @@ class NDFrame(PandasObject, indexing.IndexingMixin):
         the same location are considered equal.
 
         The row/column index do not need to have the same type, as long
-        as the values are considered equal. Corresponding columns must be of
-        the same dtype.
+        as the values are considered equal. Corresponding columns and
+        index must be of the same dtype.
 
         Parameters
         ----------
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