Skip to content

Commit e67fdf6

Browse files
authored
DOC+BUG: Styler.to_excel pseudo css number-format (#46239)
1 parent 9b11a62 commit e67fdf6

File tree

5 files changed

+42
-1
lines changed

5 files changed

+42
-1
lines changed
32.4 KB
Loading

doc/source/whatsnew/v1.4.2.rst

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ Fixed regressions
1616
~~~~~~~~~~~~~~~~~
1717
- Fixed regression in :meth:`DataFrame.drop` and :meth:`Series.drop` when :class:`Index` had extension dtype and duplicates (:issue:`45860`)
1818
- Fixed memory performance regression in :meth:`Series.fillna` when called on a :class:`DataFrame` column with ``inplace=True`` (:issue:`46149`)
19+
- Provided an alternative solution for passing custom Excel formats in :meth:`.Styler.to_excel`, which was a regression based on stricter CSS validation. Examples available in the documentation for :meth:`.Styler.format` (:issue:`46152`)
1920
-
2021

2122
.. ---------------------------------------------------------------------------

pandas/io/formats/excel.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -316,7 +316,9 @@ def build_fill(self, props: Mapping[str, str]):
316316
return {"fgColor": self.color_to_excel(fill_color), "patternType": "solid"}
317317

318318
def build_number_format(self, props: Mapping[str, str]) -> dict[str, str | None]:
319-
return {"format_code": props.get("number-format")}
319+
fc = props.get("number-format")
320+
fc = fc.replace("§", ";") if isinstance(fc, str) else fc
321+
return {"format_code": fc}
320322

321323
def build_font(
322324
self, props: Mapping[str, str]

pandas/io/formats/style_render.py

+34
Original file line numberDiff line numberDiff line change
@@ -992,6 +992,10 @@ def format(
992992
-------
993993
self : Styler
994994
995+
See Also
996+
--------
997+
Styler.format_index: Format the text display value of index labels.
998+
995999
Notes
9961000
-----
9971001
This method assigns a formatting function, ``formatter``, to each cell in the
@@ -1027,6 +1031,12 @@ def format(
10271031
- ``styler.format.thousands``: default None.
10281032
- ``styler.format.escape``: default None.
10291033
1034+
.. warning::
1035+
`Styler.format` is ignored when using the output format `Styler.to_excel`,
1036+
since Excel and Python have inherrently different formatting structures.
1037+
However, it is possible to use the `number-format` pseudo CSS attribute
1038+
to force Excel permissible formatting. See examples.
1039+
10301040
Examples
10311041
--------
10321042
Using ``na_rep`` and ``precision`` with the default ``formatter``
@@ -1094,6 +1104,19 @@ def format(
10941104
1 & \textbf{\textasciitilde \space \textasciicircum } \\
10951105
2 & \textbf{\$\%\#} \\
10961106
\end{tabular}
1107+
1108+
Pandas defines a `number-format` pseudo CSS attribute instead of the `.format`
1109+
method to create `to_excel` permissible formatting. Note that semi-colons are
1110+
CSS protected characters but used as separators in Excel's format string.
1111+
Replace semi-colons with the section separator character (ASCII-245) when
1112+
defining the formatting here.
1113+
1114+
>>> df = pd.DataFrame({"A": [1, 0, -1]})
1115+
>>> pseudo_css = "number-format: 0§[Red](0)§-§@;"
1116+
>>> df.style.applymap(lambda v: css).to_excel("formatted_file.xlsx")
1117+
... # doctest: +SKIP
1118+
1119+
.. figure:: ../../_static/style/format_excel_css.png
10971120
"""
10981121
if all(
10991122
(
@@ -1185,6 +1208,10 @@ def format_index(
11851208
-------
11861209
self : Styler
11871210
1211+
See Also
1212+
--------
1213+
Styler.format: Format the text display value of data cells.
1214+
11881215
Notes
11891216
-----
11901217
This method assigns a formatting function, ``formatter``, to each level label
@@ -1211,6 +1238,13 @@ def format_index(
12111238
When using a ``formatter`` string the dtypes must be compatible, otherwise a
12121239
`ValueError` will be raised.
12131240
1241+
.. warning::
1242+
`Styler.format_index` is ignored when using the output format
1243+
`Styler.to_excel`, since Excel and Python have inherrently different
1244+
formatting structures.
1245+
However, it is possible to use the `number-format` pseudo CSS attribute
1246+
to force Excel permissible formatting. See documentation for `Styler.format`.
1247+
12141248
Examples
12151249
--------
12161250
Using ``na_rep`` and ``precision`` with the default ``formatter``

pandas/tests/io/formats/test_to_excel.py

+4
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,10 @@
210210
("white-space: normal", {"alignment": {"wrap_text": True}}),
211211
# NUMBER FORMAT
212212
("number-format: 0%", {"number_format": {"format_code": "0%"}}),
213+
(
214+
"number-format: 0§[Red](0)§-§@;",
215+
{"number_format": {"format_code": "0;[red](0);-;@"}}, # GH 46152
216+
),
213217
],
214218
)
215219
def test_css_to_excel(css, expected):

0 commit comments

Comments
 (0)