From b5f72b710d7ebdcefd2b5dddae38c2048ffd2382 Mon Sep 17 00:00:00 2001 From: Marshall Crumiller Date: Thu, 25 Jul 2024 13:31:27 -0400 Subject: [PATCH 1/2] Add header align logic --- py-polars/polars/dataframe/frame.py | 1 + py-polars/polars/io/spreadsheet/_write_utils.py | 15 +++++++++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/py-polars/polars/dataframe/frame.py b/py-polars/polars/dataframe/frame.py index cf23828c420b..2e3803446e42 100644 --- a/py-polars/polars/dataframe/frame.py +++ b/py-polars/polars/dataframe/frame.py @@ -3190,6 +3190,7 @@ def write_excel( row_totals=row_totals, sparklines=sparklines, formulas=formulas, + autofilter=autofilter, ) # normalise cell refs (eg: "B3" => (2,1)) and establish table start/finish, diff --git a/py-polars/polars/io/spreadsheet/_write_utils.py b/py-polars/polars/io/spreadsheet/_write_utils.py index 6509eaa54390..73ae79c9eba4 100644 --- a/py-polars/polars/io/spreadsheet/_write_utils.py +++ b/py-polars/polars/io/spreadsheet/_write_utils.py @@ -330,6 +330,7 @@ def _xl_setup_table_columns( row_totals: RowTotalsDefinition | None = None, float_precision: int = 3, table_style: dict[str, Any] | str | None = None, + autofilter: bool = True, # noqa: FBT001 ) -> tuple[list[dict[str, Any]], dict[str | tuple[str, ...], str], DataFrame]: """Setup and unify all column-related formatting/defaults.""" @@ -450,14 +451,23 @@ def _map_str(s: Series) -> Series: dtype_formats[tp] = fmt # associate formats/functions with specific columns + header_dict = header_format or {} + add_align = "align" not in header_dict + header_alignment = {"align": "right"} | ({"indent": 2} if autofilter else {}) + col_header_format = {} for col, tp in df.schema.items(): base_type = tp.base_type() + header_fmt = header_format if base_type in dtype_formats: fmt = dtype_formats.get(tp, dtype_formats[base_type]) column_formats.setdefault(col, fmt) + if add_align and base_type in [*FLOAT_DTYPES, *INTEGER_DTYPES]: + header_fmt = header_dict | header_alignment if col not in column_formats: column_formats[col] = fmt_default + col_header_format[col] = format_cache.get(header_fmt) if header_fmt else None + # ensure externally supplied formats are made available for col, fmt in column_formats.items(): # type: ignore[assignment] if isinstance(fmt, str): @@ -473,9 +483,6 @@ def _map_str(s: Series) -> Series: fmt["valign"] = "vcenter" column_formats[col] = format_cache.get(fmt) - # optional custom header format - col_header_format = format_cache.get(header_format) if header_format else None - # assemble table columns table_columns = [ { @@ -483,7 +490,7 @@ def _map_str(s: Series) -> Series: for k, v in { "header": col, "format": column_formats[col], - "header_format": col_header_format, + "header_format": col_header_format.get(col), "total_function": column_total_funcs.get(col), "formula": ( row_total_funcs.get(col) From c7cc745af2f0643d70d5d91d9c2122eb3b1a9c2c Mon Sep 17 00:00:00 2001 From: Marshall Crumiller Date: Thu, 25 Jul 2024 13:51:53 -0400 Subject: [PATCH 2/2] No dict union for 3.8 --- py-polars/polars/io/spreadsheet/_write_utils.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/py-polars/polars/io/spreadsheet/_write_utils.py b/py-polars/polars/io/spreadsheet/_write_utils.py index 73ae79c9eba4..c659329d36cc 100644 --- a/py-polars/polars/io/spreadsheet/_write_utils.py +++ b/py-polars/polars/io/spreadsheet/_write_utils.py @@ -453,7 +453,9 @@ def _map_str(s: Series) -> Series: # associate formats/functions with specific columns header_dict = header_format or {} add_align = "align" not in header_dict - header_alignment = {"align": "right"} | ({"indent": 2} if autofilter else {}) + header_alignment = {"align": "right"} + if autofilter: + header_alignment["indent"] = 2 # type: ignore[assignment] col_header_format = {} for col, tp in df.schema.items(): base_type = tp.base_type() @@ -462,7 +464,7 @@ def _map_str(s: Series) -> Series: fmt = dtype_formats.get(tp, dtype_formats[base_type]) column_formats.setdefault(col, fmt) if add_align and base_type in [*FLOAT_DTYPES, *INTEGER_DTYPES]: - header_fmt = header_dict | header_alignment + header_fmt = {**header_dict, **header_alignment} if col not in column_formats: column_formats[col] = fmt_default