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
185 lines
7.6 KiB
Python
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)")
|