Files
wehub-resource-sync 8cb1f9f479
Publish SDK (PyPI) / publish (push) Waiting to run
Publish SDK (npm) / publish (@aionui/officecli-sdk) (push) Waiting to run
Publish SDK (npm) / publish (@officecli/officecli-sdk) (push) Waiting to run
Publish SDK (npm) / publish (@officecli/sdk) (push) Waiting to run
Publish SDK (npm) / publish (officecli-sdk) (push) Waiting to run
SDK smoke / smoke (windows-latest) (push) Waiting to run
SDK smoke / smoke (macos-latest) (push) Waiting to run
SDK smoke / smoke (ubuntu-latest) (push) Waiting to run
Skill parity / diff (push) Waiting to run
chore: import upstream snapshot with attribution
2026-07-13 13:09:29 +08:00

185 lines
7.6 KiB
Python

#!/usr/bin/env python3
"""
Slicer Showcase — generates slicers.xlsx with a PivotTable and 3 slicers.
Slicers are the interactive button panels that filter a PivotTable. In OOXML a
slicer is NOT free-standing: it is anchored to a *pivot cache field*, so it
always binds to an existing PivotTable via `pivotTable=` + `field=`. This
script builds the prerequisites first (source data → PivotTable), then adds
several slicers on different fields of that pivot.
SDK twin of slicers.sh (officecli CLI). Both produce an equivalent slicers.xlsx.
This one drives the **officecli Python SDK** (`pip install officecli-sdk`): one
resident is started, the source-data cell writes ship in a single `doc.batch(...)`
round-trip, and each pivot/slicer is one `add` item shipped over the named pipe.
Each item is the same `{"command","parent","type","props"}` dict you'd put in an
`officecli batch` list.
See slicers.md for a per-slicer guide.
Usage:
pip install officecli-sdk # plus the `officecli` binary on PATH
python3 slicers.py
"""
import os
import sys
# --- locate the SDK: prefer an installed `officecli-sdk`, else the in-repo copy
try:
import officecli # pip install officecli-sdk
except ImportError:
sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)),
"..", "..", "sdk", "python"))
import officecli
FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)), "slicers.xlsx")
def slicer(sheet, **props):
"""One `add slicer` item in batch-shape, anchored on the given sheet."""
return {"command": "add", "parent": f"/{sheet}", "type": "slicer", "props": props}
print(f"Building {FILE} ...")
with officecli.create(FILE, "--force") as doc:
# ==========================================================================
# Source data — a realistic sales table: Region / Product / Quarter / Sales.
# batch is used here only for speed (many cell writes in one round-trip).
# ==========================================================================
print("\n--- Populating source data ---")
data_items = []
for j, h in enumerate(["Region", "Product", "Quarter", "Sales"]):
data_items.append({"command": "set", "path": f"/Sheet1/{'ABCD'[j]}1",
"props": {"text": h}})
rows = [
("North", "Laptop", "Q1", 12500),
("North", "Phone", "Q2", 8900),
("North", "Tablet", "Q3", 6200),
("South", "Laptop", "Q1", 22000),
("South", "Phone", "Q2", 18500),
("South", "Tablet", "Q4", 7800),
("East", "Laptop", "Q2", 19500),
("East", "Phone", "Q3", 13800),
("East", "Tablet", "Q1", 5400),
("West", "Laptop", "Q4", 25000),
("West", "Phone", "Q2", 16800),
("West", "Tablet", "Q3", 8900),
]
for i, row in enumerate(rows):
for j, val in enumerate(row):
data_items.append({"command": "set", "path": f"/Sheet1/{'ABCD'[j]}{i+2}",
"props": {"text": str(val)}})
doc.batch(data_items)
# ==========================================================================
# The slicer SOURCE — a PivotTable. Slicers anchor to this pivot's cache
# fields.
#
# officecli add slicers.xlsx /Dashboard --type pivottable \
# --prop source=Sheet1!A1:D13 \
# --prop rows=Region \
# --prop cols=Quarter \
# --prop values=Sales:sum \
# --prop layout=outline \
# --prop grandtotals=both \
# --prop name=SalesPivot \
# --prop style=PivotStyleMedium9
# ==========================================================================
print("\n--- Dashboard PivotTable (slicer source) ---")
doc.send({"command": "add", "parent": "/", "type": "sheet",
"props": {"name": "Dashboard"}})
doc.send({"command": "add", "parent": "/Dashboard", "type": "pivottable",
"props": {"source": "Sheet1!A1:D13", "rows": "Region",
"cols": "Quarter", "values": "Sales:sum",
"layout": "outline", "grandtotals": "both",
"name": "SalesPivot", "style": "PivotStyleMedium9"}})
# ==========================================================================
# Slicers — each binds to SalesPivot via a different cache field.
# ==========================================================================
# --------------------------------------------------------------------------
# Slicer 1: Region
#
# officecli add slicers.xlsx /Dashboard --type slicer \
# --prop pivotTable=/Dashboard/pivottable[1] \
# --prop field=Region \
# --prop caption='Filter by Region' \
# --prop columnCount=2 \
# --prop rowHeight=250000 \
# --prop name=RegionSlicer
#
# Features: pivotTable= (full path reference), field=Region, custom caption,
# columnCount=2 (two-column button grid), rowHeight in EMU, explicit name
# --------------------------------------------------------------------------
print("\n--- Slicer: Region ---")
doc.send(slicer("Dashboard",
pivotTable="/Dashboard/pivottable[1]",
field="Region",
caption="Filter by Region",
columnCount="2",
rowHeight="250000",
name="RegionSlicer"))
# --------------------------------------------------------------------------
# Slicer 2: Product
#
# officecli add slicers.xlsx /Dashboard --type slicer \
# --prop pivotTable=SalesPivot \
# --prop field=Product \
# --prop caption='Filter by Product' \
# --prop columnCount=3 \
# --prop name=ProductSlicer
#
# Features: pivotTable= by BARE NAME (resolves against the host sheet's
# pivots), columnCount=3 (wide grid)
# --------------------------------------------------------------------------
print("\n--- Slicer: Product ---")
doc.send(slicer("Dashboard",
pivotTable="SalesPivot",
field="Product",
caption="Filter by Product",
columnCount="3",
name="ProductSlicer"))
# --------------------------------------------------------------------------
# Slicer 3: Quarter
#
# officecli add slicers.xlsx /Dashboard --type slicer \
# --prop pivotTable=SalesPivot \
# --prop field=Quarter \
# --prop columnCount=1 \
# --prop name=QuarterSlicer
#
# Features: caption OMITTED — defaults to the field name ("Quarter");
# rowHeight OMITTED — defaults to 225425 EMU (~17.5pt). Minimal slicer.
# --------------------------------------------------------------------------
print("\n--- Slicer: Quarter ---")
doc.send(slicer("Dashboard",
pivotTable="SalesPivot",
field="Quarter",
columnCount="1",
name="QuarterSlicer"))
# ==========================================================================
# Modify an existing slicer with `set` (caption + columnCount are settable;
# `field` is add-time only and Set intentionally ignores it).
#
# officecli set slicers.xlsx /Dashboard/slicer[1] \
# --prop caption=Region --prop columnCount=1
# ==========================================================================
print("\n--- Set: slicer[1] caption + columnCount ---")
doc.send({"command": "set", "path": "/Dashboard/slicer[1]",
"props": {"caption": "Region", "columnCount": "1"}})
doc.send({"command": "save"})
print(f"\nDone! Generated: {FILE}")
print(" Sheet1 (source data) + Dashboard (1 PivotTable + 3 slicers)")