diff --git a/doc/source/whatsnew/v2.0.0.rst b/doc/source/whatsnew/v2.0.0.rst
index 7fc856be374e9..e9e06044eba0a 100644
--- a/doc/source/whatsnew/v2.0.0.rst
+++ b/doc/source/whatsnew/v2.0.0.rst
@@ -1322,6 +1322,7 @@ I/O
- Bug in :func:`read_csv` unnecessarily overflowing for extension array dtype when containing ``NA`` (:issue:`32134`)
- Bug in :meth:`DataFrame.to_dict` not converting ``NA`` to ``None`` (:issue:`50795`)
- Bug in :meth:`DataFrame.to_json` where it would segfault when failing to encode a string (:issue:`50307`)
+- Bug in :meth:`DataFrame.to_html` with ``na_rep`` set when the :class:`DataFrame` contains non-scalar data (:issue:`47103`)
- Bug in :func:`read_xml` where file-like objects failed when iterparse is used (:issue:`50641`)
- Bug in :func:`read_xml` ignored repeated elements when iterparse is used (:issue:`51183`)
diff --git a/pandas/io/formats/style_render.py b/pandas/io/formats/style_render.py
index 6ae9c528e4772..141b9a70023b6 100644
--- a/pandas/io/formats/style_render.py
+++ b/pandas/io/formats/style_render.py
@@ -1814,7 +1814,7 @@ def _maybe_wrap_formatter(
if na_rep is None:
return func_3
else:
- return lambda x: na_rep if isna(x) else func_3(x)
+ return lambda x: na_rep if (isna(x) is True) else func_3(x)
def non_reducing_slice(slice_: Subset):
diff --git a/pandas/tests/io/formats/data/html/gh47103_expected_output.html b/pandas/tests/io/formats/data/html/gh47103_expected_output.html
new file mode 100644
index 0000000000000..f8c54cb85c815
--- /dev/null
+++ b/pandas/tests/io/formats/data/html/gh47103_expected_output.html
@@ -0,0 +1,16 @@
+
+
+
+ |
+ a |
+ b |
+
+
+
+
+ 0 |
+ 1 |
+ [1, 2, 3] |
+
+
+
diff --git a/pandas/tests/io/formats/style/test_html.py b/pandas/tests/io/formats/style/test_html.py
index d878d82f55e51..1867260fbc4b4 100644
--- a/pandas/tests/io/formats/style/test_html.py
+++ b/pandas/tests/io/formats/style/test_html.py
@@ -976,3 +976,32 @@ def html_lines(foot_prefix: str):
)
)
assert expected_css + expected_table == result
+
+
+def test_to_html_na_rep_non_scalar_data(datapath):
+ # GH47103
+ df = DataFrame([dict(a=1, b=[1, 2, 3], c=np.nan)])
+ result = df.style.format(na_rep="-").to_html(table_uuid="test")
+ expected = """\
+
+
+
+
+ |
+ a |
+ b |
+ c |
+
+
+
+
+ 0 |
+ 1 |
+ [1, 2, 3] |
+ - |
+
+
+
+"""
+ assert result == expected
diff --git a/pandas/tests/io/formats/test_to_html.py b/pandas/tests/io/formats/test_to_html.py
index 3059efef09095..a66858d3f983e 100644
--- a/pandas/tests/io/formats/test_to_html.py
+++ b/pandas/tests/io/formats/test_to_html.py
@@ -882,6 +882,14 @@ def test_to_html_na_rep_and_float_format(na_rep, datapath):
assert result == expected
+def test_to_html_na_rep_non_scalar_data(datapath):
+ # GH47103
+ df = DataFrame([dict(a=1, b=[1, 2, 3])])
+ result = df.to_html(na_rep="-")
+ expected = expected_html(datapath, "gh47103_expected_output")
+ assert result == expected
+
+
def test_to_html_float_format_object_col(datapath):
# GH#40024
df = DataFrame(data={"x": [1000.0, "test"]})