From 1eb6dc776704e543a612a1363580c502bf99269b Mon Sep 17 00:00:00 2001 From: JHM Darbyshire <24256554+attack68@users.noreply.github.com> Date: Sun, 6 Mar 2022 17:33:45 +0100 Subject: [PATCH] Backport PR #46239: DOC+BUG: `Styler.to_excel` pseudo css `number-format` --- doc/source/_static/style/format_excel_css.png | Bin 0 -> 33222 bytes doc/source/whatsnew/v1.4.2.rst | 1 + pandas/io/formats/excel.py | 4 ++- pandas/io/formats/style_render.py | 34 ++++++++++++++++++ pandas/tests/io/formats/test_to_excel.py | 4 +++ 5 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 doc/source/_static/style/format_excel_css.png diff --git a/doc/source/_static/style/format_excel_css.png b/doc/source/_static/style/format_excel_css.png new file mode 100644 index 0000000000000000000000000000000000000000..0bd4662c3f2d029d194ffbf94770068e0ace3f6c GIT binary patch literal 33222 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 O0000 dict[str, str | None]: - return {"format_code": props.get("number-format")} + fc = props.get("number-format") + fc = fc.replace("§", ";") if isinstance(fc, str) else fc + return {"format_code": fc} def build_font( self, props: Mapping[str, str] diff --git a/pandas/io/formats/style_render.py b/pandas/io/formats/style_render.py index 2ff0a994ebb01..e15387b1e2bae 100644 --- a/pandas/io/formats/style_render.py +++ b/pandas/io/formats/style_render.py @@ -891,6 +891,10 @@ def format( ------- self : Styler + See Also + -------- + Styler.format_index: Format the text display value of index labels. + Notes ----- This method assigns a formatting function, ``formatter``, to each cell in the @@ -926,6 +930,12 @@ def format( - ``styler.format.thousands``: default None. - ``styler.format.escape``: default None. + .. warning:: + `Styler.format` is ignored when using the output format `Styler.to_excel`, + since Excel and Python have inherrently different formatting structures. + However, it is possible to use the `number-format` pseudo CSS attribute + to force Excel permissible formatting. See examples. + Examples -------- Using ``na_rep`` and ``precision`` with the default ``formatter`` @@ -993,6 +1003,19 @@ def format( 1 & \textbf{\textasciitilde \space \textasciicircum } \\ 2 & \textbf{\$\%\#} \\ \end{tabular} + + Pandas defines a `number-format` pseudo CSS attribute instead of the `.format` + method to create `to_excel` permissible formatting. Note that semi-colons are + CSS protected characters but used as separators in Excel's format string. + Replace semi-colons with the section separator character (ASCII-245) when + defining the formatting here. + + >>> df = pd.DataFrame({"A": [1, 0, -1]}) + >>> pseudo_css = "number-format: 0§[Red](0)§-§@;" + >>> df.style.applymap(lambda v: css).to_excel("formatted_file.xlsx") + ... # doctest: +SKIP + + .. figure:: ../../_static/style/format_excel_css.png """ if all( ( @@ -1084,6 +1107,10 @@ def format_index( ------- self : Styler + See Also + -------- + Styler.format: Format the text display value of data cells. + Notes ----- This method assigns a formatting function, ``formatter``, to each level label @@ -1110,6 +1137,13 @@ def format_index( When using a ``formatter`` string the dtypes must be compatible, otherwise a `ValueError` will be raised. + .. warning:: + `Styler.format_index` is ignored when using the output format + `Styler.to_excel`, since Excel and Python have inherrently different + formatting structures. + However, it is possible to use the `number-format` pseudo CSS attribute + to force Excel permissible formatting. See documentation for `Styler.format`. + Examples -------- Using ``na_rep`` and ``precision`` with the default ``formatter`` diff --git a/pandas/tests/io/formats/test_to_excel.py b/pandas/tests/io/formats/test_to_excel.py index 968ad63eaceef..81fb66d55938a 100644 --- a/pandas/tests/io/formats/test_to_excel.py +++ b/pandas/tests/io/formats/test_to_excel.py @@ -206,6 +206,10 @@ ("white-space: normal", {"alignment": {"wrap_text": True}}), # NUMBER FORMAT ("number-format: 0%", {"number_format": {"format_code": "0%"}}), + ( + "number-format: 0§[Red](0)§-§@;", + {"number_format": {"format_code": "0;[red](0);-;@"}}, # GH 46152 + ), ], ) def test_css_to_excel(css, expected):