From b06cff6de9154ab8a615e301f8506115c5a73579 Mon Sep 17 00:00:00 2001 From: Mark Sikora Date: Sat, 21 Jul 2018 16:17:14 -0400 Subject: [PATCH 1/2] ENH: Number formatting support for excel styles --- doc/source/style.ipynb | 5 ++++- doc/source/whatsnew/v0.24.0.txt | 1 + pandas/io/formats/excel.py | 5 ++++- pandas/tests/io/formats/test_to_excel.py | 3 +++ pandas/tests/io/test_excel.py | 14 +++++++++----- 5 files changed, 21 insertions(+), 7 deletions(-) diff --git a/doc/source/style.ipynb b/doc/source/style.ipynb index 152ca90049bf1..6f66c1a9bf7f9 100644 --- a/doc/source/style.ipynb +++ b/doc/source/style.ipynb @@ -985,7 +985,10 @@ "- `vertical-align`\n", "- `white-space: nowrap`\n", "\n", - "Only CSS2 named colors and hex colors of the form `#rgb` or `#rrggbb` are currently supported." + "Only CSS2 named colors and hex colors of the form `#rgb` or `#rrggbb` are currently supported.\n", + "\n", + "The following pseudo CSS properties are also available to set excel specific style properties:\n", + "- `number-format`\n" ] }, { diff --git a/doc/source/whatsnew/v0.24.0.txt b/doc/source/whatsnew/v0.24.0.txt index 973b75f0e1451..38d5c5cf8c199 100644 --- a/doc/source/whatsnew/v0.24.0.txt +++ b/doc/source/whatsnew/v0.24.0.txt @@ -372,6 +372,7 @@ Other API Changes - Trying to reindex a ``DataFrame`` with a non unique ``MultiIndex`` now raises a ``ValueError`` instead of an ``Exception`` (:issue:`21770`) - :meth:`PeriodIndex.tz_convert` and :meth:`PeriodIndex.tz_localize` have been removed (:issue:`21781`) - :class:`Index` subtraction will attempt to operate element-wise instead of raising ``TypeError`` (:issue:`19369`) +- :class:`pandas.io.formats.style.Styler` supports a ``number-format`` property when using :meth:`~pandas.io.formats.style.Styler.to_excel` .. _whatsnew_0240.deprecations: diff --git a/pandas/io/formats/excel.py b/pandas/io/formats/excel.py index ec95ce7a970ad..0bc268bc18b95 100644 --- a/pandas/io/formats/excel.py +++ b/pandas/io/formats/excel.py @@ -98,8 +98,8 @@ def build_xlstyle(self, props): 'border': self.build_border(props), 'fill': self.build_fill(props), 'font': self.build_font(props), + 'number_format': self.build_number_format(props), } - # TODO: support number format # TODO: handle cell width and height: needs support in pandas.io.excel def remove_none(d): @@ -314,6 +314,9 @@ def color_to_excel(self, val): warnings.warn('Unhandled color format: {val!r}'.format(val=val), CSSWarning) + def build_number_format(self, props): + return {'format_code': props.get('number-format')} + class ExcelFormatter(object): """ diff --git a/pandas/tests/io/formats/test_to_excel.py b/pandas/tests/io/formats/test_to_excel.py index 2d691bf2c5d8e..9fc16c43f5c1d 100644 --- a/pandas/tests/io/formats/test_to_excel.py +++ b/pandas/tests/io/formats/test_to_excel.py @@ -172,6 +172,9 @@ {'alignment': {'wrap_text': False}}), ('white-space: normal', {'alignment': {'wrap_text': True}}), + # NUMBER FORMAT + ('number-format: 0%', + {'number_format': {'format_code': '0%'}}), ]) def test_css_to_excel(css, expected): convert = CSSToExcelConverter() diff --git a/pandas/tests/io/test_excel.py b/pandas/tests/io/test_excel.py index d1eab16e7c22c..e51780891534f 100644 --- a/pandas/tests/io/test_excel.py +++ b/pandas/tests/io/test_excel.py @@ -2241,6 +2241,7 @@ def style(df): ['', 'font-style: italic', ''], ['', '', 'text-align: right'], ['background-color: red', '', ''], + ['number-format: 0%', '', ''], ['', '', ''], ['', '', ''], ['', '', '']], @@ -2266,7 +2267,7 @@ def custom_converter(css): # Prepare spreadsheets - df = DataFrame(np.random.randn(10, 3)) + df = DataFrame(np.random.randn(11, 3)) with ensure_clean('.xlsx' if engine != 'xlwt' else '.xls') as path: writer = ExcelWriter(path, engine=engine) df.to_excel(writer, sheet_name='frame') @@ -2294,7 +2295,7 @@ def custom_converter(css): n_cells += 1 # ensure iteration actually happened: - assert n_cells == (10 + 1) * (3 + 1) + assert n_cells == (11 + 1) * (3 + 1) # (2) check styling with default converter @@ -2344,13 +2345,16 @@ def custom_converter(css): assert cell1.fill.patternType != cell2.fill.patternType assert cell2.fill.fgColor.rgb == alpha + 'FF0000' assert cell2.fill.patternType == 'solid' + elif ref == 'B9': + assert cell1.number_format == 'General' + assert cell2.number_format == '0%' else: assert_equal_style(cell1, cell2) assert cell1.value == cell2.value n_cells += 1 - assert n_cells == (10 + 1) * (3 + 1) + assert n_cells == (11 + 1) * (3 + 1) # (3) check styling with custom converter n_cells = 0 @@ -2359,7 +2363,7 @@ def custom_converter(css): assert len(col1) == len(col2) for cell1, cell2 in zip(col1, col2): ref = '%s%d' % (cell2.column, cell2.row) - if ref in ('B2', 'C3', 'D4', 'B5', 'C6', 'D7', 'B8'): + if ref in ('B2', 'C3', 'D4', 'B5', 'C6', 'D7', 'B8', 'B9'): assert not cell1.font.bold assert cell2.font.bold else: @@ -2368,7 +2372,7 @@ def custom_converter(css): assert cell1.value == cell2.value n_cells += 1 - assert n_cells == (10 + 1) * (3 + 1) + assert n_cells == (11 + 1) * (3 + 1) @td.skip_if_no('openpyxl') From 4c28407bdb661c901d78c922508b82e4bc0f24d3 Mon Sep 17 00:00:00 2001 From: Tom Augspurger Date: Tue, 24 Jul 2018 08:10:24 -0500 Subject: [PATCH 2/2] Fixup whatsnew --- doc/source/whatsnew/v0.24.0.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/whatsnew/v0.24.0.txt b/doc/source/whatsnew/v0.24.0.txt index 38d5c5cf8c199..137fd5aafe5bd 100644 --- a/doc/source/whatsnew/v0.24.0.txt +++ b/doc/source/whatsnew/v0.24.0.txt @@ -372,7 +372,7 @@ Other API Changes - Trying to reindex a ``DataFrame`` with a non unique ``MultiIndex`` now raises a ``ValueError`` instead of an ``Exception`` (:issue:`21770`) - :meth:`PeriodIndex.tz_convert` and :meth:`PeriodIndex.tz_localize` have been removed (:issue:`21781`) - :class:`Index` subtraction will attempt to operate element-wise instead of raising ``TypeError`` (:issue:`19369`) -- :class:`pandas.io.formats.style.Styler` supports a ``number-format`` property when using :meth:`~pandas.io.formats.style.Styler.to_excel` +- :class:`pandas.io.formats.style.Styler` supports a ``number-format`` property when using :meth:`~pandas.io.formats.style.Styler.to_excel` (:issue:`22015`) .. _whatsnew_0240.deprecations: