Skip to content

Commit 2a9d84f

Browse files
committed
Add excel export
1 parent bea5bdb commit 2a9d84f

13 files changed

Lines changed: 3232 additions & 150 deletions

File tree

README.md

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ Returns a `PivotTableResult` dict containing the current `config` state.
102102
| `on_config_change` | `Callable[[], None] \| None` | `None` | Called when the user changes the pivot config interactively, including toolbar and header-menu actions. |
103103
| `enable_drilldown` | `bool` | `True` | Show an inline drill-down panel with source records when a cell is clicked. |
104104
| `locked` | `bool` | `False` | Viewer mode with exploration enabled. Toolbar config controls are read-only, viewer-safe actions like data export and group expand/collapse remain available, and header-menu sorting/filtering/`Show Values As` plus drill-down still work. |
105-
| `export_filename` | `str \| None` | `None` | Base filename (without extension) for exported files. Date and extension are appended automatically. Defaults to `"pivot-table"`. |
105+
| `export_filename` | `str \| None` | `None` | Base filename (without extension) for exported files (.xlsx, .csv, .tsv). Date and extension are appended automatically. Defaults to `"pivot-table"`. |
106106

107107
> **Frontend-only interactions:** Column resize (drag header edges) and fullscreen mode (toolbar expand icon) are available automatically when `interactive=True`. No additional Python parameters are needed.
108108
@@ -431,11 +431,13 @@ Hover over a parent column header to reveal the collapse toggle.
431431

432432
### Data Export
433433

434-
Export the pivot table as CSV, TSV, or copy to clipboard. Available via the toolbar utility menu (download icon) whenever the interactive toolbar is shown, including locked viewer mode.
434+
Export the pivot table as Excel, CSV, TSV, or copy to clipboard. Available via the toolbar utility menu (download icon) whenever the interactive toolbar is shown, including locked viewer mode.
435435

436-
- **Format**: CSV, TSV, or Clipboard (tab-separated for pasting into spreadsheets)
436+
- **Format**: Excel (.xlsx), CSV, TSV, or Clipboard (tab-separated for pasting into spreadsheets)
437437
- **Content**: Formatted (display values with currency, percentages, etc.) or Raw (unformatted numbers)
438-
- **Filename**: Customizable via `export_filename`. The date (`YYYY-MM-DD`) and file extension are appended automatically. Defaults to `"pivot-table"` (e.g. `pivot-table_2026-03-09.csv`).
438+
- **Filename**: Customizable via `export_filename`. The date (`YYYY-MM-DD`) and file extension are appended automatically. Defaults to `"pivot-table"` (e.g. `pivot-table_2026-03-09.xlsx`).
439+
440+
Excel export produces a professionally styled workbook with merged column headers, bold totals/subtotals, number formatting, banded rows, frozen panes (headers stay visible when scrolling), and row dimension merging that matches the rendered table layout. Sort order, active filters, and show-values-as percentages are all preserved.
439441

440442
Export always outputs the full expanded table regardless of any collapsed row/column groups.
441443

@@ -513,7 +515,7 @@ When `interactive=True`, hovering over the top-right of the toolbar reveals util
513515
| **Swap** | Transposes row and column dimensions |
514516
| **Copy Config** | Copies the current config as JSON to clipboard |
515517
| **Import Config** | Paste a JSON config to apply |
516-
| **Export Data** | Open the export popover (CSV / TSV / Clipboard). Use `export_filename` to customize the download filename. |
518+
| **Export Data** | Open the export popover (Excel / CSV / TSV / Clipboard). Use `export_filename` to customize the download filename. |
517519
| **Fullscreen** (expand icon) | Toggles fullscreen mode — the table fills the entire viewport. Press Escape or click the collapse icon to exit. |
518520
| **Settings** (gear icon) | Opens a popover with display toggles: Row Totals, Column Totals, Subtotals, Repeat Labels, Sticky Headers, and Expand/Collapse All group controls |
519521

e2e_playwright/pivot_table_data_test.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ def test_export_data_panel_opens(page_at_app: Page):
133133
panel = page.get_by_test_id("toolbar-export-data-panel")
134134
expect(panel).to_be_visible(timeout=5000)
135135

136+
expect(panel.get_by_test_id("export-format-xlsx")).to_be_visible()
136137
expect(panel.get_by_test_id("export-format-csv")).to_be_visible()
137138
expect(panel.get_by_test_id("export-format-tsv")).to_be_visible()
138139
expect(panel.get_by_test_id("export-content-formatted")).to_be_visible()
@@ -312,6 +313,33 @@ def test_csv_download_content(page_at_app: Page):
312313
assert len(content.strip().splitlines()) > 1, "CSV should have data rows"
313314

314315

316+
def test_excel_download_content(page_at_app: Page):
317+
"""Downloading Excel produces a .xlsx file with the expected filename."""
318+
page = page_at_app
319+
container = get_pivot(page, "test_pivot")
320+
expect(container.get_by_test_id("pivot-toolbar")).to_be_visible(timeout=15000)
321+
322+
container.get_by_test_id("toolbar-export-data").evaluate("el => el.click()")
323+
panel = page.get_by_test_id("toolbar-export-data-panel")
324+
expect(panel).to_be_visible(timeout=5000)
325+
326+
# Excel is the default format; just select raw content
327+
panel.get_by_test_id("export-content-raw").click()
328+
329+
with page.expect_download() as dl_info:
330+
panel.get_by_test_id("toolbar-export-data-action").click()
331+
332+
download = dl_info.value
333+
suggested = download.suggested_filename
334+
assert suggested.endswith(".xlsx"), f"Expected .xlsx extension, got: {suggested}"
335+
336+
path = download.path()
337+
assert path is not None
338+
339+
file_size = Path(path).stat().st_size
340+
assert file_size > 100, f"Excel file too small ({file_size} bytes), likely empty"
341+
342+
315343
def test_sticky_headers_during_scroll(page_at_app: Page):
316344
"""Sticky headers remain visible during vertical scroll."""
317345
page = page_at_app

streamlit_app.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@
6060
- **Swap** (↔) — transposes row and column dimensions.
6161
- **Copy Config** — copies the current config as JSON to your clipboard.
6262
- **Import Config** — paste a JSON config to apply it.
63-
- **Export Data** (↓) — export the table as CSV, TSV, or copy to clipboard
63+
- **Export Data** (↓) — export the table as Excel, CSV, TSV, or copy to clipboard
6464
(see Section 11 for details).
6565
- **Settings** (⚙) — opens a popover with display toggles (e.g. Row Totals,
6666
Column Totals). More options appear here as you add features — see
@@ -812,13 +812,17 @@
812812

813813
st.markdown(
814814
"""
815-
Export the pivot table data as **CSV**, **TSV**, or copy to **clipboard** for
816-
pasting into Excel or Google Sheets.
815+
Export the pivot table data as **Excel** (.xlsx), **CSV**, **TSV**, or copy to
816+
**clipboard** for pasting into spreadsheets.
817+
818+
Excel export produces a professionally styled workbook with merged column
819+
headers, bold totals/subtotals, number formatting, banded rows, and frozen
820+
panes — matching the quality you'd expect from BI tools like Sigma.
817821
818822
**Try it:**
819823
- Use the top-right utility menu in the toolbar.
820824
- Click the **Download** icon (↓) to open the export popover.
821-
- Choose a **Format**: CSV, TSV, or Clipboard.
825+
- Choose a **Format**: Excel, CSV, TSV, or Clipboard.
822826
- Choose **Content**: Formatted (display values including currency, percentages)
823827
or Raw (unformatted aggregated numbers).
824828
- Click **Export** (downloads a file) or **Copy** (copies to clipboard as
@@ -828,7 +832,7 @@
828832
- Export is always available when the toolbar is visible (``interactive=True``).
829833
- Use ``export_filename`` to customize the downloaded file name. The date
830834
(``YYYY-MM-DD``) and file extension are appended automatically.
831-
Defaults to ``"pivot-table"`` (e.g. ``pivot-table_2026-03-09.csv``).
835+
Defaults to ``"pivot-table"`` (e.g. ``pivot-table_2026-03-09.xlsx``).
832836
- This demo sets `export_filename="sales-export-demo"` so you can see the custom
833837
filename behavior in the downloaded file.
834838
"""

streamlit_pivot/__init__.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -729,9 +729,9 @@ def st_pivot_table(
729729
drill-down panel below the pivot table showing the
730730
contributing source records. Set to False to disable.
731731
export_filename : str or None
732-
Base filename (without extension) used when exporting data.
733-
The date and file extension are appended automatically.
734-
Defaults to ``"pivot-table"`` when not set.
732+
Base filename (without extension) used when exporting data
733+
(.xlsx, .csv, .tsv). The date and file extension are appended
734+
automatically. Defaults to ``"pivot-table"`` when not set.
735735
execution_mode : str
736736
Performance execution mode. ``"auto"`` (default) keeps the client-side
737737
path unless the dataset is large enough to trigger the threshold_hybrid

0 commit comments

Comments
 (0)