chore: import upstream snapshot with attribution
Publish SDK (PyPI) / publish (push) Has been cancelled
Publish SDK (npm) / publish (@aionui/officecli-sdk) (push) Has been cancelled
SDK smoke / smoke (windows-latest) (push) Has been cancelled
Publish SDK (npm) / publish (@officecli/officecli-sdk) (push) Has been cancelled
Publish SDK (npm) / publish (@officecli/sdk) (push) Has been cancelled
Publish SDK (npm) / publish (officecli-sdk) (push) Has been cancelled
SDK smoke / smoke (macos-latest) (push) Has been cancelled
SDK smoke / smoke (ubuntu-latest) (push) Has been cancelled
Skill parity / diff (push) Has been cancelled

This commit is contained in:
wehub-resource-sync
2026-07-13 13:09:29 +08:00
commit 8cb1f9f479
1189 changed files with 386007 additions and 0 deletions
+196
View File
@@ -0,0 +1,196 @@
# 3D Model Showcase — "The Sun"
This demo consists of three files that work together:
- **3d-model.sh** — Shell script that builds an 8-slide morph presentation embedding a GLB 3D model of the Sun on every slide, with different positions and rotations so PowerPoint's Morph transition animates it cinematically.
- **3d-model.pptx** — The generated 8-slide deck: each slide advances the 3D model's position and rotation, creating an orbit animation through morph transitions.
- **3d-model.md** — This file. Documents the `3dmodel` element properties and morph-based rotation technique.
## Regenerate
```bash
cd examples/ppt
bash 3d-model.sh
# → 3d-model.pptx
# Requires: models/sun.glb in the same directory
```
## Slides
### All 8 Slides — 3D Model Setup
Every slide shares the same structure: a jet-black background, a morph transition, and a `3dmodel` element. The GLB model has the same `name=sun` on every slide so PowerPoint pairs and tweens it across transitions.
```bash
# Create all 8 slides with matching dark background + morph transition
for i in $(seq 1 8); do
officecli add 3d-model.pptx / --type slide \
--prop background=0A0A0A \
--prop transition=morph
done
# Slide 1 — model at right, slight downward tilt
officecli add 3d-model.pptx '/slide[1]' --type 3dmodel \
--prop path="models/sun.glb" \
--prop name=sun \
--prop x=15cm --prop y=0.5cm --prop width=18cm --prop height=18cm \
--prop rotx=10
# Slide 2 — model moves left, rotated 50° around Y
officecli add 3d-model.pptx '/slide[2]' --type 3dmodel \
--prop path="models/sun.glb" \
--prop name=sun \
--prop x=0.5cm --prop y=0.5cm --prop width=16cm --prop height=16cm \
--prop roty=50
# Slide 3 — model back right, 100° Y + 15° X tilt
officecli add 3d-model.pptx '/slide[3]' --type 3dmodel \
--prop path="models/sun.glb" \
--prop name=sun \
--prop x=18cm --prop y=3cm --prop width=16cm --prop height=16cm \
--prop roty=100 --prop rotx=15
# Slides 48 follow the same pattern, advancing roty by ~50° each slide
# and alternating left/right position to create an orbit path
officecli add 3d-model.pptx '/slide[4]' --type 3dmodel \
--prop path="models/sun.glb" --prop name=sun \
--prop x=0.5cm --prop y=1cm --prop width=18cm --prop height=18cm \
--prop roty=150
officecli add 3d-model.pptx '/slide[5]' --type 3dmodel \
--prop path="models/sun.glb" --prop name=sun \
--prop x=17cm --prop y=0.5cm --prop width=18cm --prop height=18cm \
--prop roty=200 --prop rotx=20
officecli add 3d-model.pptx '/slide[6]' --type 3dmodel \
--prop path="models/sun.glb" --prop name=sun \
--prop x=0.5cm --prop y=2cm --prop width=17cm --prop height=17cm \
--prop roty=250
officecli add 3d-model.pptx '/slide[7]' --type 3dmodel \
--prop path="models/sun.glb" --prop name=sun \
--prop x=16cm --prop y=1cm --prop width=17cm --prop height=17cm \
--prop roty=310 --prop rotx=10
officecli add 3d-model.pptx '/slide[8]' --type 3dmodel \
--prop path="models/sun.glb" --prop name=sun \
--prop x=15cm --prop y=0.5cm --prop width=18cm --prop height=18cm \
--prop roty=360 --prop rotx=10
```
**Features:** `--type 3dmodel`, `path=` (GLB file to embed), `name=` (shape name — must match across slides for morph pairing), `x=/y=/width=/height=` in cm, `rotx=` (X-axis tilt degrees), `roty=` (Y-axis orbit degrees), `background=` hex, `transition=morph`
### Slide 1 — Title Text
Text labels overlapping the 3D model on the left side of the slide.
```bash
officecli add 3d-model.pptx '/slide[1]' --type shape \
--prop text='THE SUN' \
--prop x=1cm --prop y=2cm --prop w=13cm --prop h=3.5cm \
--prop size=64 --prop bold=true --prop color=FF6F00 --prop fill=00000000 \
--prop font='Arial Black'
officecli add 3d-model.pptx '/slide[1]' --type shape \
--prop text='Our Star' \
--prop x=1cm --prop y=6cm --prop w=13cm --prop h=2cm \
--prop size=26 --prop color=FFB74D --prop fill=00000000 \
--prop font=Calibri
officecli add 3d-model.pptx '/slide[1]' --type shape \
--prop text='149.6 million km from Earth · Light takes 8 min 20 sec' \
--prop x=1cm --prop y=8.5cm --prop w=13cm --prop h=2cm \
--prop size=18 --prop color=9E9E9E --prop fill=00000000 \
--prop font=Calibri
```
**Features:** `fill=00000000` (fully transparent fill = no background behind text), `font=Arial Black`, `bold=`, `color=` (amber/orange palette), `w=/h=` as aliases for `width=/height=`
### Slides 27 — Content Slides (Alternating Left/Right)
Each content slide adds two shapes: a right-aligned or left-aligned headline plus a multi-line body with `lineSpacing=2x`.
```bash
# Slide 2 — right-aligned (model on left)
officecli add 3d-model.pptx '/slide[2]' --type shape \
--prop text='Star Profile' \
--prop x=18cm --prop y=1cm --prop w=15cm --prop h=2.5cm \
--prop size=40 --prop bold=true --prop color=FF6F00 --prop fill=00000000 \
--prop font=Calibri --prop align=right
officecli add 3d-model.pptx '/slide[2]' --type shape \
--prop text='Spectral type G2V yellow dwarf\nDiameter 1.392 million km\nMass 330,000x Earth\nSurface temp 5,778 K\nCore temp 15 million K\nAge 4.6 billion years' \
--prop x=18cm --prop y=4cm --prop w=15cm --prop h=14cm \
--prop size=22 --prop color=E0E0E0 --prop fill=00000000 \
--prop font=Calibri --prop align=right --prop lineSpacing=2x
# Slide 3 — left-aligned (model on right)
officecli add 3d-model.pptx '/slide[3]' --type shape \
--prop text='Internal Structure' \
--prop x=1cm --prop y=1cm --prop w=15cm --prop h=2.5cm \
--prop size=40 --prop bold=true --prop color=FF6F00 --prop fill=00000000 \
--prop font=Calibri
# ... slides 47 follow the same pattern, alternating align=right/left
```
**Features:** `align=right` / `align=left` paragraph alignment, `lineSpacing=2x` (2× line height multiplier), `\n` literal newline in `text=`, multi-line factoid layout
### Slide 8 — Closing Latin Quote
Bold italic quote in Georgia, grey translation beneath.
```bash
officecli add 3d-model.pptx '/slide[8]' --type shape \
--prop text='Per Aspera Ad Astra' \
--prop x=1cm --prop y=7cm --prop w=13cm --prop h=3cm \
--prop size=48 --prop bold=true --prop italic=true \
--prop color=FF6F00 --prop fill=00000000 \
--prop font=Georgia
officecli add 3d-model.pptx '/slide[8]' --type shape \
--prop text='Through hardships to the stars' \
--prop x=1cm --prop y=11cm --prop w=13cm --prop h=2cm \
--prop size=24 --prop color=9E9E9E --prop fill=00000000 \
--prop font=Calibri
```
**Features:** `italic=true`, `font=Georgia`, contrasting size pair (48pt / 24pt), `color=9E9E9E` (muted grey)
## Complete Feature Coverage
| Feature | Slides |
|---------|--------|
| **--type 3dmodel** GLB embedding | 18 |
| **path=** (GLB file path) | 18 |
| **name=** (morph pairing key) | 18 |
| **rotx=** (X-axis tilt degrees) | 1, 3, 5, 7, 8 |
| **roty=** (Y-axis orbit degrees) | 28 |
| **x=/y=/width=/height=** in cm (model placement) | 18 |
| **transition=morph** | 18 |
| **background=** hex | 18 |
| **fill=00000000** (transparent — no shape background) | 18 |
| **font=Arial Black / Georgia / Calibri** | 1, 8 |
| **bold=** / **italic=** | 1, 8 |
| **align=right / align=left** | 2, 4, 6 |
| **lineSpacing=2x** (line height multiplier) | 27 |
| **text= with \n** multi-line | 27 |
| **w=/h= aliases** | 1 |
| **officecli validate** post-generation check | final |
## Morph Technique
PowerPoint's Morph transition tweens shapes that share the same name between adjacent slides. The key rule: `name=sun` must appear on both the outgoing and incoming slide for morph to pair them.
The rotation values advance ~50° per slide around the Y axis (`roty=0→50→100→150→200→250→310→360`), producing a smooth orbital animation. The X-axis tilt (`rotx=`) varies slightly to add dimensional interest.
Position also shifts left/right each slide (`x=15cm→0.5cm→18cm→0.5cm→17cm→...`), so the model appears to orbit across the slide while rotating — all interpolated smoothly by Morph.
## Inspect the Generated File
```bash
officecli query 3d-model.pptx slide
officecli get 3d-model.pptx /slide[1]
officecli get 3d-model.pptx "/slide[1]/3dmodel[1]"
officecli get 3d-model.pptx "/slide[2]/3dmodel[1]"
```
Binary file not shown.
+222
View File
@@ -0,0 +1,222 @@
#!/usr/bin/env python3
"""
3D Morph Showcase — generates 3d-model.pptx: "The Sun — Our Star", an 8-slide
deck with a GLB 3D model on every slide, dark cinematic backgrounds, and a
morph transition between slides. The Sun model is repositioned/rotated slide
to slide so the morph animates a smooth orbit/spin.
SDK twin of 3d-model.sh (officecli CLI). Both produce an equivalent
3d-model.pptx. This one drives the **officecli Python SDK**
(`pip install officecli-sdk`): one resident is started and every slide, 3D
model, and text shape is shipped over the named pipe in a single
`doc.batch(...)` round-trip. Each item is the same
`{"command","parent","type","props"}` dict you'd put in an `officecli batch`
list.
Usage:
pip install officecli-sdk # plus the `officecli` binary on PATH
python3 3d-model.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
DIR = os.path.dirname(os.path.abspath(__file__))
FILE = os.path.join(DIR, "3d-model.pptx")
SUN = os.path.join(DIR, "models", "sun.glb")
def slide(**props):
"""One `add slide` item in batch-shape."""
return {"command": "add", "parent": "/", "type": "slide", "props": props}
def model(slide_idx, **props):
"""One `add 3dmodel` item on /slide[idx] in batch-shape."""
return {"command": "add", "parent": f"/slide[{slide_idx}]",
"type": "3dmodel", "props": {"path": SUN, "name": "sun", **props}}
def shape(slide_idx, text, **props):
"""One `add shape` (text box) item on /slide[idx] in batch-shape."""
return {"command": "add", "parent": f"/slide[{slide_idx}]",
"type": "shape", "props": {"text": text, **props}}
print(f"Building {FILE} ...")
with officecli.create(FILE, "--force") as doc:
items = []
# ====================================================================
# SLIDES — 8 slides, dark background + morph transition
# ====================================================================
for _ in range(8):
items.append(slide(background="0A0A0A", transition="morph"))
# ====================================================================
# 3D MODELS — Sun GLB on each slide; position/rotation drives the morph
# ====================================================================
items += [
model(1, x="15cm", y="0.5cm", width="18cm", height="18cm", rotx="10"),
model(2, x="0.5cm", y="0.5cm", width="16cm", height="16cm", roty="50"),
model(3, x="18cm", y="3cm", width="16cm", height="16cm", roty="100", rotx="15"),
model(4, x="0.5cm", y="1cm", width="18cm", height="18cm", roty="150"),
model(5, x="17cm", y="0.5cm", width="18cm", height="18cm", roty="200", rotx="20"),
model(6, x="0.5cm", y="2cm", width="17cm", height="17cm", roty="250"),
model(7, x="16cm", y="1cm", width="17cm", height="17cm", roty="310", rotx="10"),
model(8, x="15cm", y="0.5cm", width="18cm", height="18cm", roty="360", rotx="10"),
]
# ====================================================================
# SLIDE 1 — Title
# ====================================================================
items += [
shape(1, "THE SUN",
x="1cm", y="2cm", w="13cm", h="3.5cm",
size="64", bold="true", color="FF6F00", fill="00000000",
font="Arial Black"),
shape(1, "Our Star",
x="1cm", y="6cm", w="13cm", h="2cm",
size="26", color="FFB74D", fill="00000000", font="Calibri"),
shape(1, "149.6 million km from Earth · Light takes 8 min 20 sec",
x="1cm", y="8.5cm", w="13cm", h="2cm",
size="18", color="9E9E9E", fill="00000000", font="Calibri"),
]
# ====================================================================
# SLIDE 2 — Star Profile
# ====================================================================
items += [
shape(2, "Star Profile",
x="18cm", y="1cm", w="15cm", h="2.5cm",
size="40", bold="true", color="FF6F00", fill="00000000",
font="Calibri", align="right"),
shape(2,
"Spectral type G2V yellow dwarf\n"
"Diameter 1.392 million km\n"
"Mass 330,000x Earth\n"
"Surface temp 5,778 K\n"
"Core temp 15 million K\n"
"Age 4.6 billion years",
x="18cm", y="4cm", w="15cm", h="14cm",
size="22", color="E0E0E0", fill="00000000",
font="Calibri", align="right", lineSpacing="2x"),
]
# ====================================================================
# SLIDE 3 — Internal Structure
# ====================================================================
items += [
shape(3, "Internal Structure",
x="1cm", y="1cm", w="15cm", h="2.5cm",
size="40", bold="true", color="FF6F00", fill="00000000",
font="Calibri"),
shape(3,
"Core Hydrogen fuses into helium\n"
"Radiative zone Photons take 170,000 years\n"
"Convective zone Plasma churns upward\n"
"Photosphere The visible \"surface\"\n"
"Corona Temperature mystery: millions of degrees",
x="1cm", y="4cm", w="16cm", h="14cm",
size="22", color="E0E0E0", fill="00000000",
font="Calibri", lineSpacing="2x"),
]
# ====================================================================
# SLIDE 4 — Solar Activity
# ====================================================================
items += [
shape(4, "Solar Activity",
x="20cm", y="1cm", w="13cm", h="2.5cm",
size="40", bold="true", color="FF6F00", fill="00000000",
font="Calibri", align="right"),
shape(4,
"Sunspots Cool regions twisted by magnetic fields\n"
"Flares Energy of a billion H-bombs in seconds\n"
"CMEs A billion tons of plasma ejected\n"
"Solar wind Particles at 400 km/s",
x="20cm", y="4cm", w="13cm", h="14cm",
size="22", color="E0E0E0", fill="00000000",
font="Calibri", align="right", lineSpacing="2x"),
]
# ====================================================================
# SLIDE 5 — Source of Life
# ====================================================================
items += [
shape(5, "Source of Life",
x="1cm", y="1cm", w="14cm", h="2.5cm",
size="40", bold="true", color="FF6F00", fill="00000000",
font="Calibri"),
shape(5,
"Drives climate and water cycles\n"
"Energy source for photosynthesis\n"
"Magnetosphere shields from cosmic rays\n"
"Aurora — a romantic gift from solar wind",
x="1cm", y="4cm", w="14cm", h="14cm",
size="22", color="E0E0E0", fill="00000000",
font="Calibri", lineSpacing="2x"),
]
# ====================================================================
# SLIDE 6 — Observation History
# ====================================================================
items += [
shape(6, "Observation History",
x="19cm", y="1cm", w="14cm", h="2.5cm",
size="40", bold="true", color="FF6F00", fill="00000000",
font="Calibri", align="right"),
shape(6,
"1613 Galileo records sunspots\n"
"1868 Helium discovered\n"
"1995 SOHO satellite launched\n"
"2018 Parker Solar Probe touches the Sun",
x="19cm", y="4cm", w="14cm", h="14cm",
size="22", color="E0E0E0", fill="00000000",
font="Calibri", align="right", lineSpacing="2x"),
]
# ====================================================================
# SLIDE 7 — Future of the Sun
# ====================================================================
items += [
shape(7, "Future of the Sun",
x="1cm", y="1cm", w="14cm", h="2.5cm",
size="40", bold="true", color="FF6F00", fill="00000000",
font="Calibri"),
shape(7,
"In 5 billion years, expands into a red giant\n"
"Swallows Mercury and Venus, scorches Earth\n"
"Outer layers form a planetary nebula\n"
"Core collapses into a white dwarf",
x="1cm", y="4cm", w="14cm", h="14cm",
size="22", color="E0E0E0", fill="00000000",
font="Calibri", lineSpacing="2x"),
]
# ====================================================================
# SLIDE 8 — Closing
# ====================================================================
items += [
shape(8, "Per Aspera Ad Astra",
x="1cm", y="7cm", w="13cm", h="3cm",
size="48", bold="true", italic="true", color="FF6F00",
fill="00000000", font="Georgia"),
shape(8, "Through hardships to the stars",
x="1cm", y="11cm", w="13cm", h="2cm",
size="24", color="9E9E9E", fill="00000000", font="Calibri"),
]
doc.batch(items)
print(f" added 8 slides, 8 3D models, and the title/body text shapes")
print(f"Generated: {FILE}")
+205
View File
@@ -0,0 +1,205 @@
#!/bin/bash
# Generate a 3D morph presentation: "The Sun — Our Star"
# 3D GLB model with morph transitions, dark cinematic backgrounds
# NOTE: intentionally NO `set -e`. Like the SDK twin's doc.batch, this script
# tolerates forward-compat 'UNSUPPORTED props' warnings (officecli exit 2) and
# keeps building so the full document is produced.
DIR="$(cd "$(dirname "$0")" && pwd)"
MODELS="$DIR/models"
OUT="$DIR/3d-model.pptx"
rm -f "$OUT"
officecli create "$OUT"
officecli open "$OUT"
###############################################################################
# SLIDES — Create all 8 slides with dark background + morph transition
###############################################################################
echo " -> Creating 8 slides"
for i in $(seq 1 8); do
officecli add "$OUT" / --type slide --prop background=0A0A0A --prop transition=morph
done
###############################################################################
# 3D MODELS — Sun GLB on each slide, position/rotation changes for morph
###############################################################################
echo " -> Adding 3D sun models"
officecli add "$OUT" '/slide[1]' --type 3dmodel \
--prop path="$MODELS/sun.glb" --prop name=sun \
--prop x=15cm --prop y=0.5cm --prop width=18cm --prop height=18cm \
--prop rotx=10
officecli add "$OUT" '/slide[2]' --type 3dmodel \
--prop path="$MODELS/sun.glb" --prop name=sun \
--prop x=0.5cm --prop y=0.5cm --prop width=16cm --prop height=16cm \
--prop roty=50
officecli add "$OUT" '/slide[3]' --type 3dmodel \
--prop path="$MODELS/sun.glb" --prop name=sun \
--prop x=18cm --prop y=3cm --prop width=16cm --prop height=16cm \
--prop roty=100 --prop rotx=15
officecli add "$OUT" '/slide[4]' --type 3dmodel \
--prop path="$MODELS/sun.glb" --prop name=sun \
--prop x=0.5cm --prop y=1cm --prop width=18cm --prop height=18cm \
--prop roty=150
officecli add "$OUT" '/slide[5]' --type 3dmodel \
--prop path="$MODELS/sun.glb" --prop name=sun \
--prop x=17cm --prop y=0.5cm --prop width=18cm --prop height=18cm \
--prop roty=200 --prop rotx=20
officecli add "$OUT" '/slide[6]' --type 3dmodel \
--prop path="$MODELS/sun.glb" --prop name=sun \
--prop x=0.5cm --prop y=2cm --prop width=17cm --prop height=17cm \
--prop roty=250
officecli add "$OUT" '/slide[7]' --type 3dmodel \
--prop path="$MODELS/sun.glb" --prop name=sun \
--prop x=16cm --prop y=1cm --prop width=17cm --prop height=17cm \
--prop roty=310 --prop rotx=10
officecli add "$OUT" '/slide[8]' --type 3dmodel \
--prop path="$MODELS/sun.glb" --prop name=sun \
--prop x=15cm --prop y=0.5cm --prop width=18cm --prop height=18cm \
--prop roty=360 --prop rotx=10
###############################################################################
# SLIDE 1 — Title
###############################################################################
echo " -> Slide 1: Title"
officecli add "$OUT" '/slide[1]' --type shape \
--prop 'text=THE SUN' \
--prop x=1cm --prop y=2cm --prop w=13cm --prop h=3.5cm \
--prop size=64 --prop bold=true --prop color=FF6F00 --prop fill=00000000 \
--prop 'font=Arial Black'
officecli add "$OUT" '/slide[1]' --type shape \
--prop 'text=Our Star' \
--prop x=1cm --prop y=6cm --prop w=13cm --prop h=2cm \
--prop size=26 --prop color=FFB74D --prop fill=00000000 \
--prop 'font=Calibri'
officecli add "$OUT" '/slide[1]' --type shape \
--prop 'text=149.6 million km from Earth · Light takes 8 min 20 sec' \
--prop x=1cm --prop y=8.5cm --prop w=13cm --prop h=2cm \
--prop size=18 --prop color=9E9E9E --prop fill=00000000 \
--prop 'font=Calibri'
###############################################################################
# SLIDE 2 — Star Profile
###############################################################################
echo " -> Slide 2: Star Profile"
officecli add "$OUT" '/slide[2]' --type shape \
--prop 'text=Star Profile' \
--prop x=18cm --prop y=1cm --prop w=15cm --prop h=2.5cm \
--prop size=40 --prop bold=true --prop color=FF6F00 --prop fill=00000000 \
--prop 'font=Calibri' --prop align=right
officecli add "$OUT" '/slide[2]' --type shape \
--prop 'text=Spectral type G2V yellow dwarf\nDiameter 1.392 million km\nMass 330,000x Earth\nSurface temp 5,778 K\nCore temp 15 million K\nAge 4.6 billion years' \
--prop x=18cm --prop y=4cm --prop w=15cm --prop h=14cm \
--prop size=22 --prop color=E0E0E0 --prop fill=00000000 \
--prop 'font=Calibri' --prop align=right --prop lineSpacing=2x
###############################################################################
# SLIDE 3 — Internal Structure
###############################################################################
echo " -> Slide 3: Internal Structure"
officecli add "$OUT" '/slide[3]' --type shape \
--prop 'text=Internal Structure' \
--prop x=1cm --prop y=1cm --prop w=15cm --prop h=2.5cm \
--prop size=40 --prop bold=true --prop color=FF6F00 --prop fill=00000000 \
--prop 'font=Calibri'
officecli add "$OUT" '/slide[3]' --type shape \
--prop 'text=Core Hydrogen fuses into helium\nRadiative zone Photons take 170,000 years\nConvective zone Plasma churns upward\nPhotosphere The visible "surface"\nCorona Temperature mystery: millions of degrees' \
--prop x=1cm --prop y=4cm --prop w=16cm --prop h=14cm \
--prop size=22 --prop color=E0E0E0 --prop fill=00000000 \
--prop 'font=Calibri' --prop lineSpacing=2x
###############################################################################
# SLIDE 4 — Solar Activity
###############################################################################
echo " -> Slide 4: Solar Activity"
officecli add "$OUT" '/slide[4]' --type shape \
--prop 'text=Solar Activity' \
--prop x=20cm --prop y=1cm --prop w=13cm --prop h=2.5cm \
--prop size=40 --prop bold=true --prop color=FF6F00 --prop fill=00000000 \
--prop 'font=Calibri' --prop align=right
officecli add "$OUT" '/slide[4]' --type shape \
--prop 'text=Sunspots Cool regions twisted by magnetic fields\nFlares Energy of a billion H-bombs in seconds\nCMEs A billion tons of plasma ejected\nSolar wind Particles at 400 km/s' \
--prop x=20cm --prop y=4cm --prop w=13cm --prop h=14cm \
--prop size=22 --prop color=E0E0E0 --prop fill=00000000 \
--prop 'font=Calibri' --prop align=right --prop lineSpacing=2x
###############################################################################
# SLIDE 5 — Source of Life
###############################################################################
echo " -> Slide 5: Source of Life"
officecli add "$OUT" '/slide[5]' --type shape \
--prop 'text=Source of Life' \
--prop x=1cm --prop y=1cm --prop w=14cm --prop h=2.5cm \
--prop size=40 --prop bold=true --prop color=FF6F00 --prop fill=00000000 \
--prop 'font=Calibri'
officecli add "$OUT" '/slide[5]' --type shape \
--prop 'text=Drives climate and water cycles\nEnergy source for photosynthesis\nMagnetosphere shields from cosmic rays\nAurora — a romantic gift from solar wind' \
--prop x=1cm --prop y=4cm --prop w=14cm --prop h=14cm \
--prop size=22 --prop color=E0E0E0 --prop fill=00000000 \
--prop 'font=Calibri' --prop lineSpacing=2x
###############################################################################
# SLIDE 6 — Observation History
###############################################################################
echo " -> Slide 6: Observation History"
officecli add "$OUT" '/slide[6]' --type shape \
--prop 'text=Observation History' \
--prop x=19cm --prop y=1cm --prop w=14cm --prop h=2.5cm \
--prop size=40 --prop bold=true --prop color=FF6F00 --prop fill=00000000 \
--prop 'font=Calibri' --prop align=right
officecli add "$OUT" '/slide[6]' --type shape \
--prop 'text=1613 Galileo records sunspots\n1868 Helium discovered\n1995 SOHO satellite launched\n2018 Parker Solar Probe touches the Sun' \
--prop x=19cm --prop y=4cm --prop w=14cm --prop h=14cm \
--prop size=22 --prop color=E0E0E0 --prop fill=00000000 \
--prop 'font=Calibri' --prop align=right --prop lineSpacing=2x
###############################################################################
# SLIDE 7 — Future of the Sun
###############################################################################
echo " -> Slide 7: Future of the Sun"
officecli add "$OUT" '/slide[7]' --type shape \
--prop 'text=Future of the Sun' \
--prop x=1cm --prop y=1cm --prop w=14cm --prop h=2.5cm \
--prop size=40 --prop bold=true --prop color=FF6F00 --prop fill=00000000 \
--prop 'font=Calibri'
officecli add "$OUT" '/slide[7]' --type shape \
--prop 'text=In 5 billion years, expands into a red giant\nSwallows Mercury and Venus, scorches Earth\nOuter layers form a planetary nebula\nCore collapses into a white dwarf' \
--prop x=1cm --prop y=4cm --prop w=14cm --prop h=14cm \
--prop size=22 --prop color=E0E0E0 --prop fill=00000000 \
--prop 'font=Calibri' --prop lineSpacing=2x
###############################################################################
# SLIDE 8 — Closing
###############################################################################
echo " -> Slide 8: Closing"
officecli add "$OUT" '/slide[8]' --type shape \
--prop 'text=Per Aspera Ad Astra' \
--prop x=1cm --prop y=7cm --prop w=13cm --prop h=3cm \
--prop size=48 --prop bold=true --prop italic=true --prop color=FF6F00 --prop fill=00000000 \
--prop 'font=Georgia'
officecli add "$OUT" '/slide[8]' --type shape \
--prop 'text=Through hardships to the stars' \
--prop x=1cm --prop y=11cm --prop w=13cm --prop h=2cm \
--prop size=24 --prop color=9E9E9E --prop fill=00000000 \
--prop 'font=Calibri'
###############################################################################
# FINALIZE
###############################################################################
officecli close "$OUT"
officecli validate "$OUT"
echo "Generated: $OUT"
+232
View File
@@ -0,0 +1,232 @@
# Animation Showcase
Demonstrates the first-class pptx **`animation` element** and its full property
surface. Three files work together:
- **animations.sh** — Shell script driving `officecli create/open/add/set/close`.
- **animations.py** — SDK twin (`officecli-sdk`), same deck via `doc.batch(...)`.
- **animations.pptx** — The generated 7-slide deck.
## The animation element
An animation is a child element of a **shape** (or **chart**):
```bash
officecli add animations.pptx /slide[N]/shape[M] --type animation \
--prop effect=fade --prop class=entrance --prop duration=800
```
`add ... --type animation` gives you the full timing model. (The legacy
`set --prop animation=fade-entrance-800` compound-token shortcut still works for
quick one-liners, but the element form is what exposes trigger/delay/repeat/
autoReverse/restart/motion-paths.)
On `get`, each facet is its own key — there is **no** composite `animation` key
in readback:
```bash
officecli get animations.pptx /slide[2]/shape[3]/animation[1]
# → effect=fade class=entrance presetId=10 trigger=onClick duration=800
```
## Regenerate
```bash
cd examples/ppt
bash animations.sh # → animations.pptx (7 slides, 44 animations)
# or the SDK twin:
python3 animations.py
```
## Property reference
| Prop | Values / format | Notes |
|---|---|---|
| `effect` | preset name (see catalog below) | The animation preset. Some effects require a specific `class`. |
| `class` | `entrance` \| `exit` \| `emphasis` \| `motion` | Category. `spin/grow/wave` need `emphasis`; `motion` needs `path=`. |
| `trigger` | `onClick` \| `withPrevious` \| `afterPrevious` | When it starts. Default `onClick`. |
| `duration` | ms integer (alias `dur`) | e.g. `500` = 0.5s. |
| `delay` | ms integer | Delay before starting. |
| `repeat` | positive int \| `indefinite` | Loop count, or loop forever. |
| `autoReverse` | `true` / `false` | Play forward then reverse (doubles the visible run). |
| `restart` | `always` \| `whenNotActive` \| `never` | Behavior when re-triggered. |
| `direction` | `in`/`out`/`left`/`right`/`up`/`down` (+ aliases `top`/`bottom`, `l/r/u/d`) | For directional effects. |
| `path` | `line` \| `arc` \| `circle` \| `diamond` \| `triangle` \| `square` \| `custom` | Motion preset (only with `class=motion`). |
| `d` | SVG-like path, coords 0..1 of slide | Custom motion path (only with `path=custom`; auto-appends `E`). |
Get-only facets: `presetId`, `easein`, `easeout`, `motionPath`.
## Timing model
Animations on a slide play as an ordered list. Each animation's `trigger`
decides how it relates to the one before it:
- **`onClick`** — waits for a mouse click to start (the default).
- **`afterPrevious`** — starts automatically when the previous animation ends
(add `delay=` for a gap).
- **`withPrevious`** — starts at the same instant as the previous animation.
Chaining `onClick → afterPrevious → withPrevious …` builds a self-playing
sequence off a single click (see Slide 6).
## Effect catalog
**Entrance / Exit** (same names, pick via `class=`):
`appear`, `fade`, `fly`, `zoom`, `wipe`, `bounce`, `float`, `swivel`, `split`,
`wheel`, `checkerboard`, `blinds`, `dissolve`, `flash`, `box`, `circle`,
`diamond`, `plus`, `strips`, `wedge`, `random`.
**Emphasis** (`class=emphasis`):
motion — `spin`, `grow`, `wave`, `bold`, `growShrink`, `teeter`, `pulse`;
color — `fillColor`, `lineColor`, `transparency`, `complementaryColor`,
`complementaryColor2`, `contrastingColor`, `darken`, `desaturate`, `lighten`,
`objectColor`, `colorPulse`.
**Motion** (`class=motion` + `path=`): `line`, `arc`, `circle`, `diamond`,
`triangle`, `square`, `custom`.
**Template exit effects** (`class=exit`, verbatim PowerPoint OOXML):
`contract`, `centerRevolve`, `collapse`, `floatOut`, `shrinkTurn`, `sinkDown`,
`spinner`, `basicZoom`, `stretchy`, `boomerang`, `credits`, `curveDown`,
`pinwheel`, `spiralOut`, `basicSwivel`.
> **Known limitation — template exit effects are lossy on readback.** These 15
> effects are backed by byte-for-byte PowerPoint-authored OOXML, so they render
> correctly in PowerPoint but **ignore the `duration` prop** (they keep the
> authored timing) and **do not round-trip their effect name** — `get` reports
> them as a generic `effect=fade`/`split`/`unknown` plus a `presetId`. Because
> the effect name doesn't survive a round-trip, this demo builds its slides from
> the effects that round-trip cleanly. Use the template effects directly in a
> deck when you want their exact PowerPoint look; just don't rely on `get`
> echoing the name back.
## Slides
### Slide 1 — Title
Radial-gradient title slide (`layout=title`, `background=radial:`, title +
subtitle placeholders, `transition=fade`).
### Slide 2 — Entrance Effects
Twelve entrance effects on a 4-column grid, each with its own `duration`.
```bash
officecli add animations.pptx /slide[2]/shape[2] --type animation \
--prop effect=appear --prop class=entrance --prop duration=400
officecli add animations.pptx /slide[2]/shape[3] --type animation \
--prop effect=fade --prop class=entrance --prop duration=800
# … fly, zoom, wipe, bounce, float, swivel, split, wheel, box, circle
```
**Features:** `effect=` (entrance family), `class=entrance`, `duration=`.
### Slide 3 — Exit Effects
Ten exit effects; directional ones (`fly`, `wipe`) add `direction=`.
```bash
officecli add animations.pptx /slide[3]/shape[3] --type animation \
--prop effect=fly --prop class=exit --prop direction=down --prop duration=600
officecli add animations.pptx /slide[3]/shape[6] --type animation \
--prop effect=wipe --prop class=exit --prop direction=left --prop duration=600
```
**Features:** `class=exit`, `direction=` on directional effects.
### Slide 4 — Emphasis & Color Effects
Six emphasis effects on ellipses — motion (`spin`, `grow`, `wave`, `growShrink`,
`teeter`) and `pulse`.
```bash
officecli add animations.pptx /slide[4]/shape[2] --type animation \
--prop effect=spin --prop class=emphasis --prop duration=1000
officecli add animations.pptx /slide[4]/shape[5] --type animation \
--prop effect=growShrink --prop class=emphasis --prop duration=800
```
**Features:** `class=emphasis`; color-change and motion emphasis effects.
### Slide 5 — Motion Paths
Preset paths (`line`, `arc`, `circle`, `diamond`, `square`) plus a custom `d=`.
```bash
officecli add animations.pptx /slide[5]/shape[2] --type animation \
--prop class=motion --prop path=line --prop direction=right --prop duration=1000
# Custom path — coords are 0..1 of the slide; a trailing 'E' is auto-appended
officecli add animations.pptx /slide[5]/shape[8] --type animation \
--prop class=motion --prop path=custom \
--prop d='M 0 0 L 0.3 -0.1 L 0.6 0.1 E' --prop duration=1500
```
**Features:** `class=motion`, `path=<preset|custom>`, `direction=`, `d=`.
`get` echoes the resolved path back as `motionPath=`.
### Slide 6 — Timing & Trigger Chaining
Five shapes chained into a self-playing sequence off one click, plus a `delay=`
and a slow (2000ms) run.
```bash
officecli add animations.pptx /slide[6]/shape[2] --type animation \
--prop effect=fade --prop class=entrance --prop trigger=onClick --prop duration=500
officecli add animations.pptx /slide[6]/shape[3] --type animation \
--prop effect=fly --prop class=entrance --prop trigger=afterPrevious --prop duration=600
officecli add animations.pptx /slide[6]/shape[4] --type animation \
--prop effect=zoom --prop class=entrance --prop trigger=withPrevious --prop duration=600
officecli add animations.pptx /slide[6]/shape[5] --type animation \
--prop effect=wipe --prop class=entrance --prop trigger=afterPrevious \
--prop delay=800 --prop duration=700
```
**Features:** `trigger=onClick|afterPrevious|withPrevious`, `delay=`, duration
range (5002000ms).
### Slide 7 — Repeat, autoReverse & Restart
```bash
officecli add animations.pptx /slide[7]/shape[2] --type animation \
--prop effect=spin --prop class=emphasis --prop repeat=3 --prop duration=800
officecli add animations.pptx /slide[7]/shape[3] --type animation \
--prop effect=pulse --prop class=emphasis --prop repeat=indefinite \
--prop trigger=withPrevious --prop duration=600
officecli add animations.pptx /slide[7]/shape[4] --type animation \
--prop effect=grow --prop class=emphasis --prop autoReverse=true \
--prop repeat=2 --prop duration=700
officecli add animations.pptx /slide[7]/shape[5] --type animation \
--prop effect=teeter --prop class=emphasis --prop restart=whenNotActive \
--prop repeat=indefinite --prop duration=500
```
**Features:** `repeat=<int>`, `repeat=indefinite`, `autoReverse=true`,
`restart=whenNotActive`.
## Complete feature coverage
| Feature | Slide |
|---------|-------|
| `add --type animation` element | 27 |
| `effect=` entrance family | 2 |
| `effect=` exit family | 3 |
| `effect=` emphasis (motion + color) | 4 |
| `class=entrance` / `exit` / `emphasis` / `motion` | 2 / 3 / 4 / 5 |
| `duration=` (4002000ms) | 27 |
| `delay=` | 6 |
| `direction=` on directional effects | 3, 5 |
| `trigger=onClick` / `afterPrevious` / `withPrevious` | 6 |
| `repeat=<int>` / `repeat=indefinite` | 7 |
| `autoReverse=true` | 7 |
| `restart=whenNotActive` | 7 |
| `path=` preset motion + `d=` custom | 5 |
| `transition=` (fade, wipe, push, zoom, split, reveal) | 17 |
## Inspect the generated file
```bash
officecli query animations.pptx animation
officecli get animations.pptx /slide[2]/shape[3]/animation[1]
officecli get animations.pptx /slide[6]/shape[5]/animation[1]
officecli get animations.pptx /slide[7]/shape[4]/animation[1]
```
Binary file not shown.
+283
View File
@@ -0,0 +1,283 @@
#!/usr/bin/env python3
"""
Animation Showcase — the first-class pptx `animation` element.
SDK twin of animations.sh. Both produce an equivalent animations.pptx. This one
drives the **officecli Python SDK** (`pip install officecli-sdk`): one resident
is started and every slide, shape, and animation is shipped over the named pipe
in `doc.batch(...)` round-trips. Each item is the same
`{"command","parent"/"path","type","props"}` dict you'd put in an
`officecli batch` list.
The animation element exposes the full prop surface — effect, class
(entrance/exit/emphasis/motion), trigger (onClick/withPrevious/afterPrevious),
duration, delay, repeat, autoReverse, restart, direction, and motion paths
(path=/d=). Add it under a shape:
{"command": "add", "parent": "/slide[N]/shape[M]", "type": "animation",
"props": {"effect": "fade", "class": "entrance", "duration": "800"}}
Usage:
pip install officecli-sdk # plus the `officecli` binary on PATH
python3 animations.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__)), "animations.pptx")
def add_slide(**props):
"""One `add slide` item in batch-shape."""
return {"command": "add", "parent": "/", "type": "slide", "props": props}
def add_shape(slide, **props):
"""One `add shape` item in batch-shape, targeting /slide[N]."""
return {"command": "add", "parent": f"/slide[{slide}]", "type": "shape", "props": props}
def add_anim(slide, shape, **props):
"""One `add animation` item — attaches an animation element to a shape.
`class` is a Python keyword, so callers pass it via `cls=` and we remap."""
if "cls" in props:
props["class"] = props.pop("cls")
return {"command": "add", "parent": f"/slide[{slide}]/shape[{shape}]",
"type": "animation", "props": props}
def setp(path, **props):
"""One `set` item in batch-shape."""
return {"command": "set", "path": path, "props": props}
def card(slide, text, fill, x, y):
"""A labeled rounded-rect card (twin of the shell `card` helper)."""
return add_shape(slide, text=text, font="Consolas", size="13", color="FFFFFF",
fill=fill, preset="roundRect", x=x, y=y, width="6cm", height="2cm")
print(f"Building {FILE} ...")
with officecli.create(FILE, "--force") as doc:
# =====================================================================
# SLIDE 1 — Title
# =====================================================================
print(" -> Slide 1: Title")
doc.batch([
add_slide(layout="title"),
setp("/slide[1]", background="radial:0D1B2A-1B4F72-bl"),
setp("/slide[1]/placeholder[centertitle]",
text="Animation Showcase", color="FFFFFF", size="48"),
setp("/slide[1]/placeholder[subtitle]",
text="The pptx animation element — every prop that round-trips",
color="85C1E9", size="22"),
setp("/slide[1]", transition="fade"),
])
# =====================================================================
# SLIDE 2 — Entrance Effects (effect + class=entrance + duration)
# =====================================================================
print(" -> Slide 2: Entrance Effects")
entrances = [
("appear", "2E86C1", "400"), ("fade", "27AE60", "800"),
("fly", "E74C3C", "600"), ("zoom", "8E44AD", "700"),
("wipe", "F39C12", "600"), ("bounce", "1ABC9C", "800"),
("float", "E67E22", "700"), ("swivel", "16A085", "700"),
("split", "2980B9", "600"), ("wheel", "C0392B", "800"),
("box", "7D3C98", "600"), ("circle", "D35400", "600"),
]
items = [
add_slide(title="Entrance Effects"),
setp("/slide[2]", background="1B2838"),
setp("/slide[2]/shape[1]", color="FFFFFF", size="28"),
]
sh = 2
for idx, (eff, fill, dur) in enumerate(entrances):
col, row = idx % 4, idx // 4
items.append(card(2, eff, fill, f"{1 + col * 6}cm", f"{4 + row * 3}cm"))
# Features: effect=<name> class=entrance duration=<ms>
items.append(add_anim(2, sh, effect=eff, cls="entrance", duration=dur))
sh += 1
items.append(setp("/slide[2]", transition="wipe"))
doc.batch(items)
# =====================================================================
# SLIDE 3 — Exit Effects (class=exit; direction on directional effects)
# =====================================================================
print(" -> Slide 3: Exit Effects")
# (label, fill, effect, duration, direction-or-None)
exits = [
("fade out", "E74C3C", "fade", "800", None),
("fly down", "2E86C1", "fly", "600", "down"),
("fly up", "2980B9", "fly", "600", "up"),
("zoom out", "27AE60", "zoom", "700", None),
("wipe left", "F39C12", "wipe", "600", "left"),
("wipe right","D35400", "wipe", "600", "right"),
("dissolve", "8E44AD", "dissolve", "600", None),
("split", "1ABC9C", "split", "600", None),
("wheel", "C0392B", "wheel", "800", None),
("flash", "16A085", "flash", "500", None),
]
items = [
add_slide(title="Exit Effects"),
setp("/slide[3]", background="1B2838"),
setp("/slide[3]/shape[1]", color="FFFFFF", size="28"),
]
sh = 2
for idx, (label, fill, eff, dur, direction) in enumerate(exits):
col, row = idx % 4, idx // 4
items.append(card(3, label, fill, f"{1 + col * 6}cm", f"{4 + row * 3}cm"))
props = dict(effect=eff, cls="exit", duration=dur)
if direction:
# Features: effect=<name> class=exit direction=<dir> duration=<ms>
props["direction"] = direction
items.append(add_anim(3, sh, **props))
sh += 1
items.append(setp("/slide[3]", transition="push"))
doc.batch(items)
# =====================================================================
# SLIDE 4 — Emphasis & Color Effects (class=emphasis)
# =====================================================================
print(" -> Slide 4: Emphasis & Color Effects")
emphases = [
("spin", "E74C3C", "1000"), ("grow", "2E86C1", "800"),
("wave", "27AE60", "700"), ("growShrink", "8E44AD", "800"),
("teeter", "E67E22", "600"), ("pulse", "1ABC9C", "500"),
]
items = [
add_slide(title="Emphasis & Color Effects"),
setp("/slide[4]", background="1B2838"),
setp("/slide[4]/shape[1]", color="FFFFFF", size="28"),
]
sh = 2
for idx, (eff, fill, dur) in enumerate(emphases):
col, row = idx % 3, idx // 3
items.append(add_shape(4, text=eff, font="Consolas", size="14", color="FFFFFF",
fill=fill, preset="ellipse",
x=f"{1.5 + col * 6}cm", y=f"{4 + row * 5}cm",
width="4.5cm", height="4.5cm"))
# Features: effect=<name> class=emphasis duration=<ms>
items.append(add_anim(4, sh, effect=eff, cls="emphasis", duration=dur))
sh += 1
items.append(setp("/slide[4]", transition="zoom"))
doc.batch(items)
# =====================================================================
# SLIDE 5 — Motion Paths (class=motion + path=<preset|custom>)
# =====================================================================
print(" -> Slide 5: Motion Paths")
# (label, fill, path, direction-or-None)
paths = [
("line right", "2E86C1", "line", "right"),
("line down", "27AE60", "line", "down"),
("arc", "E74C3C", "arc", "right"),
("circle", "8E44AD", "circle", None),
("diamond", "F39C12", "diamond", None),
("square", "16A085", "square", None),
]
items = [
add_slide(title="Motion Paths"),
setp("/slide[5]", background="1B2838"),
setp("/slide[5]/shape[1]", color="FFFFFF", size="28"),
]
sh = 2
for idx, (label, fill, path, direction) in enumerate(paths):
col, row = idx % 3, idx // 3
items.append(card(5, label, fill, f"{1 + col * 6}cm", f"{4 + row * 4}cm"))
props = {"cls": "motion", "path": path, "duration": "1000"}
if direction:
# Features: class=motion path=<preset> direction=<dir> duration=1000
props["direction"] = direction
items.append(add_anim(5, sh, **props))
sh += 1
# Custom motion path via d= (SVG-like; coords 0..1 of the slide; auto-appends 'E').
items.append(card(5, "path=custom (d=)", "C0392B", "1cm", "12cm"))
# Features: class=motion path=custom d=<SVG-path> duration=1500
items.append(add_anim(5, sh, cls="motion", path="custom",
d="M 0 0 L 0.3 -0.1 L 0.6 0.1 E", duration="1500"))
items.append(setp("/slide[5]", transition="split"))
doc.batch(items)
# =====================================================================
# SLIDE 6 — Timing & Trigger Chaining
# =====================================================================
print(" -> Slide 6: Timing & Trigger Chaining")
items = [
add_slide(title="Timing & Trigger Chaining"),
setp("/slide[6]", background="1B2838"),
setp("/slide[6]/shape[1]", color="FFFFFF", size="28"),
# 1) onClick — starts the chain on the first mouse click (default).
card(6, "1. onClick\n(starts chain)", "2E86C1", "1cm", "4cm"),
# Features: effect=fade class=entrance trigger=onClick duration=500
add_anim(6, 2, effect="fade", cls="entrance", trigger="onClick", duration="500"),
# 2) afterPrevious — auto-plays once #1 finishes.
card(6, "2. afterPrevious\n(auto-follows #1)", "27AE60", "9cm", "4cm"),
# Features: effect=fly class=entrance trigger=afterPrevious duration=600
add_anim(6, 3, effect="fly", cls="entrance", trigger="afterPrevious", duration="600"),
# 3) withPrevious — plays simultaneously with #2.
card(6, "3. withPrevious\n(with #2)", "E74C3C", "17cm", "4cm"),
# Features: effect=zoom class=entrance trigger=withPrevious duration=600
add_anim(6, 4, effect="zoom", cls="entrance", trigger="withPrevious", duration="600"),
# 4) afterPrevious + delay — waits 800ms after #3 before starting.
card(6, "4. afterPrevious\n+ delay=800", "8E44AD", "5cm", "8cm"),
# Features: effect=wipe class=entrance trigger=afterPrevious delay=800 duration=700
add_anim(6, 5, effect="wipe", cls="entrance", trigger="afterPrevious",
delay="800", duration="700"),
# 5) Slow (2000ms) vs the fast ones above.
card(6, "5. slow duration=2000", "F39C12", "13cm", "8cm"),
# Features: effect=wipe class=entrance trigger=afterPrevious duration=2000
add_anim(6, 6, effect="wipe", cls="entrance", trigger="afterPrevious", duration="2000"),
setp("/slide[6]", transition="reveal"),
]
doc.batch(items)
# =====================================================================
# SLIDE 7 — Repeat, autoReverse & Restart
# =====================================================================
print(" -> Slide 7: Repeat, autoReverse & Restart")
def ellipse(text, fill, x, size="13"):
return add_shape(7, text=text, font="Consolas", size=size, color="FFFFFF",
fill=fill, preset="ellipse", x=x, y="5cm",
width="4cm", height="4cm")
items = [
add_slide(title="Repeat · autoReverse · Restart"),
setp("/slide[7]", background="1B2838"),
setp("/slide[7]/shape[1]", color="FFFFFF", size="28"),
# repeat=3 — plays the emphasis three times.
ellipse("repeat=3", "E74C3C", "2cm", size="14"),
# Features: effect=spin class=emphasis repeat=3 duration=800
add_anim(7, 2, effect="spin", cls="emphasis", repeat="3", duration="800"),
# repeat=indefinite — loops forever.
ellipse("repeat=indefinite", "2E86C1", "8cm"),
# Features: effect=pulse class=emphasis repeat=indefinite trigger=withPrevious duration=600
add_anim(7, 3, effect="pulse", cls="emphasis", repeat="indefinite",
trigger="withPrevious", duration="600"),
# autoReverse=true — plays forward then reverses.
ellipse("autoReverse=true", "27AE60", "14cm"),
# Features: effect=grow class=emphasis autoReverse=true repeat=2 duration=700
add_anim(7, 4, effect="grow", cls="emphasis", autoReverse="true",
repeat="2", duration="700"),
# restart=whenNotActive — re-trigger only restarts if not already playing.
ellipse("restart=whenNotActive", "8E44AD", "20cm", size="12"),
# Features: effect=teeter class=emphasis restart=whenNotActive repeat=indefinite duration=500
add_anim(7, 5, effect="teeter", cls="emphasis", restart="whenNotActive",
repeat="indefinite", duration="500"),
setp("/slide[7]", transition="zoom"),
]
doc.batch(items)
print(f"Generated: {FILE}")
+261
View File
@@ -0,0 +1,261 @@
#!/bin/bash
# Animation Showcase — the first-class pptx `animation` element.
# Demonstrates: add /slide[N]/shape[M] --type animation with the full prop
# surface — effect, class (entrance/exit/emphasis/motion), trigger
# (onClick/withPrevious/afterPrevious), duration, delay, repeat, autoReverse,
# restart, direction, and motion paths (path=/d=). Slides are organized by
# theme: entrance, exit, emphasis+color, motion paths, then a timing/trigger
# chaining slide and a repeat/autoReverse slide.
# NOTE: intentionally NO `set -e`. Like the SDK twin's doc.batch, this script
# tolerates forward-compat 'UNSUPPORTED props' warnings (officecli exit 2) and
# keeps building so the full document is produced.
OUT="$(dirname "$0")/animations.pptx"
rm -f "$OUT"
officecli create "$OUT"
officecli open "$OUT"
# Helper: add a labeled rounded-rect card, then attach an animation element to it.
# Usage: card <slide> <shape#> <text> <fill> <x> <y> <anim-props...>
card() {
local slide="$1" text="$2" fill="$3" x="$4" y="$5"; shift 5
officecli add "$OUT" "/slide[$slide]" --type shape \
--prop text="$text" --prop font=Consolas --prop size=13 --prop color=FFFFFF \
--prop fill="$fill" --prop preset=roundRect \
--prop x="$x" --prop y="$y" --prop width=6cm --prop height=2cm
}
###############################################################################
# SLIDE 1 — Title
###############################################################################
echo " -> Slide 1: Title"
officecli add "$OUT" / --type slide --prop layout=title
officecli set "$OUT" /slide[1] --prop background=radial:0D1B2A-1B4F72-bl
officecli set "$OUT" '/slide[1]/placeholder[centertitle]' \
--prop text="Animation Showcase" --prop color=FFFFFF --prop size=48
officecli set "$OUT" '/slide[1]/placeholder[subtitle]' \
--prop text="The pptx animation element — every prop that round-trips" \
--prop color=85C1E9 --prop size=22
officecli set "$OUT" /slide[1] --prop transition=fade
###############################################################################
# SLIDE 2 — Entrance Effects
# effect + class=entrance, plus per-shape duration.
###############################################################################
echo " -> Slide 2: Entrance Effects"
officecli add "$OUT" / --type slide --prop title="Entrance Effects"
officecli set "$OUT" /slide[2] --prop background=1B2838
officecli set "$OUT" '/slide[2]/shape[1]' --prop color=FFFFFF --prop size=28
# Grid of entrance effects. shape[1] is the title placeholder, so demo shapes
# start at shape[2]; each gets its own animation[1].
# effect values (entrance family): appear fade fly zoom wipe bounce float
# swivel split wheel checkerboard blinds box circle diamond
COL=0; ROW=0; SH=2
for spec in "appear:2E86C1:400" "fade:27AE60:800" "fly:E74C3C:600" "zoom:8E44AD:700" \
"wipe:F39C12:600" "bounce:1ABC9C:800" "float:E67E22:700" "swivel:16A085:700" \
"split:2980B9:600" "wheel:C0392B:800" "box:7D3C98:600" "circle:D35400:600"; do
EFF="${spec%%:*}"; REST="${spec#*:}"; FILL="${REST%%:*}"; DUR="${REST##*:}"
X=$(echo "1 + $COL * 6" | bc)cm
Y=$(echo "4 + $ROW * 3" | bc)cm
card 2 "$EFF" "$FILL" "$X" "$Y"
# Features: effect=<name> class=entrance duration=<ms>
officecli add "$OUT" "/slide[2]/shape[$SH]" --type animation \
--prop effect="$EFF" --prop class=entrance --prop duration="$DUR"
SH=$((SH + 1)); COL=$((COL + 1))
if [ $COL -ge 4 ]; then COL=0; ROW=$((ROW + 1)); fi
done
officecli set "$OUT" /slide[2] --prop transition=wipe
###############################################################################
# SLIDE 3 — Exit Effects (with direction on directional effects)
###############################################################################
echo " -> Slide 3: Exit Effects"
officecli add "$OUT" / --type slide --prop title="Exit Effects"
officecli set "$OUT" /slide[3] --prop background=1B2838
officecli set "$OUT" '/slide[3]/shape[1]' --prop color=FFFFFF --prop size=28
# effect values (exit family reuse the entrance names) + directional variants.
COL=0; ROW=0; SH=2
for spec in "fade out:E74C3C:800:" "fly down:2E86C1:600:down" "fly up:2980B9:600:up" \
"zoom out:27AE60:700:" "wipe left:F39C12:600:left" "wipe right:D35400:600:right" \
"dissolve:8E44AD:600:" "split:1ABC9C:600:" "wheel:C0392B:800:" "flash:16A085:500:"; do
TXT="${spec%%:*}"; REST="${spec#*:}"; FILL="${REST%%:*}"; REST="${REST#*:}"; DUR="${REST%%:*}"; DIR="${REST#*:}"
EFF="${TXT%% *}"
X=$(echo "1 + $COL * 6" | bc)cm
Y=$(echo "4 + $ROW * 3" | bc)cm
card 3 "$TXT" "$FILL" "$X" "$Y"
if [ -n "$DIR" ]; then
# Features: effect=<name> class=exit direction=<dir> duration=<ms>
officecli add "$OUT" "/slide[3]/shape[$SH]" --type animation \
--prop effect="$EFF" --prop class=exit --prop direction="$DIR" --prop duration="$DUR"
else
# Features: effect=<name> class=exit duration=<ms>
officecli add "$OUT" "/slide[3]/shape[$SH]" --type animation \
--prop effect="$EFF" --prop class=exit --prop duration="$DUR"
fi
SH=$((SH + 1)); COL=$((COL + 1))
if [ $COL -ge 4 ]; then COL=0; ROW=$((ROW + 1)); fi
done
officecli set "$OUT" /slide[3] --prop transition=push
###############################################################################
# SLIDE 4 — Emphasis & Color Effects
# effect + class=emphasis. Color-change emphasis effects round-trip too.
###############################################################################
echo " -> Slide 4: Emphasis & Color Effects"
officecli add "$OUT" / --type slide --prop title="Emphasis & Color Effects"
officecli set "$OUT" /slide[4] --prop background=1B2838
officecli set "$OUT" '/slide[4]/shape[1]' --prop color=FFFFFF --prop size=28
# Motion emphasis (spin/grow/wave/growShrink/teeter/pulse) on ellipses.
COL=0; ROW=0; SH=2
for spec in "spin:E74C3C:1000" "grow:2E86C1:800" "wave:27AE60:700" \
"growShrink:8E44AD:800" "teeter:E67E22:600" "pulse:1ABC9C:500"; do
EFF="${spec%%:*}"; REST="${spec#*:}"; FILL="${REST%%:*}"; DUR="${REST##*:}"
X=$(echo "1.5 + $COL * 6" | bc)cm
Y=$(echo "4 + $ROW * 5" | bc)cm
officecli add "$OUT" "/slide[4]" --type shape \
--prop text="$EFF" --prop font=Consolas --prop size=14 --prop color=FFFFFF \
--prop fill="$FILL" --prop preset=ellipse \
--prop x="$X" --prop y="$Y" --prop width=4.5cm --prop height=4.5cm
# Features: effect=<name> class=emphasis duration=<ms>
officecli add "$OUT" "/slide[4]/shape[$SH]" --type animation \
--prop effect="$EFF" --prop class=emphasis --prop duration="$DUR"
SH=$((SH + 1)); COL=$((COL + 1))
if [ $COL -ge 3 ]; then COL=0; ROW=$((ROW + 1)); fi
done
officecli set "$OUT" /slide[4] --prop transition=zoom
###############################################################################
# SLIDE 5 — Motion Paths
# class=motion + path=<preset|custom>. direction= for directional presets;
# d=<SVG-like> for a custom path (coords relative to slide, 0..1).
###############################################################################
echo " -> Slide 5: Motion Paths"
officecli add "$OUT" / --type slide --prop title="Motion Paths"
officecli set "$OUT" /slide[5] --prop background=1B2838
officecli set "$OUT" '/slide[5]/shape[1]' --prop color=FFFFFF --prop size=28
# Preset motion paths.
COL=0; ROW=0; SH=2
for spec in "line right:2E86C1:line:right" "line down:27AE60:line:down" \
"arc:E74C3C:arc:right" "circle:8E44AD:circle:" \
"diamond:F39C12:diamond:" "square:16A085:square:"; do
TXT="${spec%%:*}"; REST="${spec#*:}"; FILL="${REST%%:*}"; REST="${REST#*:}"; P="${REST%%:*}"; DIR="${REST#*:}"
X=$(echo "1 + $COL * 6" | bc)cm
Y=$(echo "4 + $ROW * 4" | bc)cm
card 5 "$TXT" "$FILL" "$X" "$Y"
if [ -n "$DIR" ]; then
# Features: class=motion path=<preset> direction=<dir> duration=1000
officecli add "$OUT" "/slide[5]/shape[$SH]" --type animation \
--prop class=motion --prop path="$P" --prop direction="$DIR" --prop duration=1000
else
# Features: class=motion path=<preset> duration=1000
officecli add "$OUT" "/slide[5]/shape[$SH]" --type animation \
--prop class=motion --prop path="$P" --prop duration=1000
fi
SH=$((SH + 1)); COL=$((COL + 1))
if [ $COL -ge 3 ]; then COL=0; ROW=$((ROW + 1)); fi
done
# Custom motion path via d= (SVG-like; coords 0..1 of the slide; auto-appends 'E').
card 5 "path=custom (d=)" C0392B 1cm 12cm
# Features: class=motion path=custom d=<SVG-path> duration=1500
officecli add "$OUT" "/slide[5]/shape[$SH]" --type animation \
--prop class=motion --prop path=custom --prop d='M 0 0 L 0.3 -0.1 L 0.6 0.1 E' --prop duration=1500
officecli set "$OUT" /slide[5] --prop transition=split
###############################################################################
# SLIDE 6 — Timing & Trigger Chaining
# Five shapes, one animation each, chained with trigger + delay so they play
# as a sequence: onClick → afterPrevious → withPrevious … plus a delayed one.
###############################################################################
echo " -> Slide 6: Timing & Trigger Chaining"
officecli add "$OUT" / --type slide --prop title="Timing & Trigger Chaining"
officecli set "$OUT" /slide[6] --prop background=1B2838
officecli set "$OUT" '/slide[6]/shape[1]' --prop color=FFFFFF --prop size=28
# 1) onClick — starts the chain on the first mouse click (default trigger).
card 6 "1. onClick\n(starts chain)" 2E86C1 1cm 4cm
# Features: effect=fade class=entrance trigger=onClick duration=500
officecli add "$OUT" '/slide[6]/shape[2]' --type animation \
--prop effect=fade --prop class=entrance --prop trigger=onClick --prop duration=500
# 2) afterPrevious — auto-plays once #1 finishes.
card 6 "2. afterPrevious\n(auto-follows #1)" 27AE60 9cm 4cm
# Features: effect=fly class=entrance trigger=afterPrevious duration=600
officecli add "$OUT" '/slide[6]/shape[3]' --type animation \
--prop effect=fly --prop class=entrance --prop trigger=afterPrevious --prop duration=600
# 3) withPrevious — plays simultaneously with #2.
card 6 "3. withPrevious\n(with #2)" E74C3C 17cm 4cm
# Features: effect=zoom class=entrance trigger=withPrevious duration=600
officecli add "$OUT" '/slide[6]/shape[4]' --type animation \
--prop effect=zoom --prop class=entrance --prop trigger=withPrevious --prop duration=600
# 4) afterPrevious + delay — waits 800ms after #3 before starting.
card 6 "4. afterPrevious\n+ delay=800" 8E44AD 5cm 8cm
# Features: effect=wipe class=entrance trigger=afterPrevious delay=800 duration=700
officecli add "$OUT" '/slide[6]/shape[5]' --type animation \
--prop effect=wipe --prop class=entrance --prop trigger=afterPrevious --prop delay=800 --prop duration=700
# 5) Slow (2000ms) vs the fast ones above — same effect, exaggerated duration.
card 6 "5. slow duration=2000" F39C12 13cm 8cm
# Features: effect=wipe class=entrance trigger=afterPrevious duration=2000
officecli add "$OUT" '/slide[6]/shape[6]' --type animation \
--prop effect=wipe --prop class=entrance --prop trigger=afterPrevious --prop duration=2000
officecli set "$OUT" /slide[6] --prop transition=reveal
###############################################################################
# SLIDE 7 — Repeat, autoReverse & Restart
###############################################################################
echo " -> Slide 7: Repeat, autoReverse & Restart"
officecli add "$OUT" / --type slide --prop title="Repeat · autoReverse · Restart"
officecli set "$OUT" /slide[7] --prop background=1B2838
officecli set "$OUT" '/slide[7]/shape[1]' --prop color=FFFFFF --prop size=28
# repeat=3 — plays the emphasis three times.
officecli add "$OUT" "/slide[7]" --type shape \
--prop text="repeat=3" --prop font=Consolas --prop size=14 --prop color=FFFFFF \
--prop fill=E74C3C --prop preset=ellipse --prop x=2cm --prop y=5cm --prop width=4cm --prop height=4cm
# Features: effect=spin class=emphasis repeat=3 duration=800
officecli add "$OUT" '/slide[7]/shape[2]' --type animation \
--prop effect=spin --prop class=emphasis --prop repeat=3 --prop duration=800
# repeat=indefinite — loops forever.
officecli add "$OUT" "/slide[7]" --type shape \
--prop text="repeat=indefinite" --prop font=Consolas --prop size=13 --prop color=FFFFFF \
--prop fill=2E86C1 --prop preset=ellipse --prop x=8cm --prop y=5cm --prop width=4cm --prop height=4cm
# Features: effect=pulse class=emphasis repeat=indefinite trigger=withPrevious duration=600
officecli add "$OUT" '/slide[7]/shape[3]' --type animation \
--prop effect=pulse --prop class=emphasis --prop repeat=indefinite --prop trigger=withPrevious --prop duration=600
# autoReverse=true — plays forward then reverses (doubling the visible run).
officecli add "$OUT" "/slide[7]" --type shape \
--prop text="autoReverse=true" --prop font=Consolas --prop size=13 --prop color=FFFFFF \
--prop fill=27AE60 --prop preset=ellipse --prop x=14cm --prop y=5cm --prop width=4cm --prop height=4cm
# Features: effect=grow class=emphasis autoReverse=true repeat=2 duration=700
officecli add "$OUT" '/slide[7]/shape[4]' --type animation \
--prop effect=grow --prop class=emphasis --prop autoReverse=true --prop repeat=2 --prop duration=700
# restart=whenNotActive — re-triggering only restarts if not already playing.
officecli add "$OUT" "/slide[7]" --type shape \
--prop text="restart=whenNotActive" --prop font=Consolas --prop size=12 --prop color=FFFFFF \
--prop fill=8E44AD --prop preset=ellipse --prop x=20cm --prop y=5cm --prop width=4cm --prop height=4cm
# Features: effect=teeter class=emphasis restart=whenNotActive repeat=indefinite duration=500
officecli add "$OUT" '/slide[7]/shape[5]' --type animation \
--prop effect=teeter --prop class=emphasis --prop restart=whenNotActive --prop repeat=indefinite --prop duration=500
officecli set "$OUT" /slide[7] --prop transition=zoom
###############################################################################
# Done
###############################################################################
officecli close "$OUT"
echo ""
officecli validate "$OUT"
echo "Done! Output: $OUT"
echo "Open with: open \"$OUT\""
+219
View File
@@ -0,0 +1,219 @@
# 3D Charts Showcase
This demo consists of three files that work together:
- **charts-3d.py** — Python script that calls `officecli` commands to generate the deck.
- **charts-3d.pptx** — The generated 8-slide deck (4 charts per slide, 32 charts total).
- **charts-3d.md** — This file. Maps each slide to the 3D chart features it demonstrates.
## Regenerate
```bash
cd examples/ppt/charts
python3 charts-3d.py
# → charts-3d.pptx
```
## Chart Slides
### Slide 1 — 3D Families
```bash
CATS="Q1,Q2,Q3,Q4"
D2="East:120,135,148,162;West:95,108,115,128"
officecli add charts-3d.pptx /slide[1] --type chart \
--prop chartType=column3d --prop title="column3d" --prop legend=bottom \
--prop categories="$CATS" --prop data="$D2" \
--prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in
officecli add charts-3d.pptx /slide[1] --type chart \
--prop chartType=bar3d --prop title="bar3d" --prop legend=bottom \
--prop categories="$CATS" --prop data="$D2" \
--prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in
officecli add charts-3d.pptx /slide[1] --type chart \
--prop chartType=pie3d --prop title="pie3d" --prop legend=right \
--prop categories="North,South,East,West" --prop data="Share:30,25,28,17" \
--prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in
officecli add charts-3d.pptx /slide[1] --type chart \
--prop chartType=line3d --prop title="line3d" --prop legend=bottom \
--prop categories="$CATS" --prop data="$D2" \
--prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in
```
**Features:** `chartType` (column3d/bar3d/pie3d/line3d)
### Slide 2 — area3d and Stacked 3D
```bash
D3="East:120,135,148,162;South:95,108,115,128;West:80,90,98,110"
officecli add charts-3d.pptx /slide[2] --type chart \
--prop chartType=area3d --prop title="area3d" --prop legend=bottom \
--prop categories="$CATS" --prop data="$D2"
officecli add charts-3d.pptx /slide[2] --type chart \
--prop chartType=stackedColumn3d --prop title="stackedColumn3d" --prop legend=bottom \
--prop categories="$CATS" --prop data="$D3"
officecli add charts-3d.pptx /slide[2] --type chart \
--prop chartType=percentStackedColumn3d --prop title="percentStackedColumn3d" \
--prop legend=bottom --prop categories="$CATS" --prop data="$D3"
officecli add charts-3d.pptx /slide[2] --type chart \
--prop chartType=stackedBar3d --prop title="stackedBar3d" --prop legend=bottom \
--prop categories="$CATS" --prop data="$D3"
```
**Features:** `chartType` (area3d/stackedColumn3d/percentStackedColumn3d/stackedBar3d)
### Slide 3 — view3d Angles
`view3d` accepts up to three comma-separated values: `rotX,rotY,perspective`.
```bash
# Low elevation, slight rotation
officecli add charts-3d.pptx /slide[3] --type chart \
--prop chartType=column3d --prop title="view3d=15,20,30" \
--prop view3d="15,20,30" --prop legend=none \
--prop categories="$CATS" --prop data="$D2"
# Higher elevation + wider rotation
officecli add charts-3d.pptx /slide[3] --type chart \
--prop chartType=column3d --prop title="view3d=30,40,15" \
--prop view3d="30,40,15" --prop legend=none \
--prop categories="$CATS" --prop data="$D2"
# Single value: sets rotX only
officecli add charts-3d.pptx /slide[3] --type chart \
--prop chartType=column3d --prop title="view3d=20 (rotX only)" \
--prop view3d="20" --prop legend=none \
--prop categories="$CATS" --prop data="$D2"
# Pie 3D with all three parameters
officecli add charts-3d.pptx /slide[3] --type chart \
--prop chartType=pie3d --prop title="pie3d view3d=40,30,30" \
--prop view3d="40,30,30" --prop legend=right \
--prop categories="North,South,East,West" --prop data="Share:30,25,28,17"
```
**Features:** `view3d` (rotX,rotY,perspective — one, two, or three values)
### Slide 4 — gapdepth
Controls the depth spacing between bars/columns in the Z direction (0500).
```bash
for g in 0 50 150 300; do
officecli add charts-3d.pptx /slide[4] --type chart \
--prop chartType=column3d --prop title="gapdepth=$g" \
--prop gapdepth=$g --prop legend=none \
--prop categories="$CATS" --prop data="$D2"
done
```
**Features:** `gapdepth` (0500, 3D depth spacing between series groups)
### Slide 5 — 3D Bar Shapes
```bash
for s in box cylinder cone pyramid; do
officecli add charts-3d.pptx /slide[5] --type chart \
--prop chartType=bar3d --prop shape=$s --prop title="shape=$s" \
--prop legend=none --prop categories="$CATS" --prop data="$D2"
done
```
**Features:** `shape` (box/cylinder/cone/pyramid) for bar3d and column3d
### Slide 6 — Title and Legend
```bash
officecli add charts-3d.pptx /slide[6] --type chart \
--prop chartType=column3d --prop title="Styled title" \
--prop title.font=Georgia --prop title.size=20 \
--prop title.color=4472C4 --prop title.bold=true \
--prop legend=bottom --prop categories="$CATS" --prop data="$D2"
officecli add charts-3d.pptx /slide[6] --type chart \
--prop chartType=column3d --prop title="legend=top + legendFont" \
--prop legend=top --prop legendFont="10:333333:Calibri" \
--prop categories="$CATS" --prop data="$D2"
officecli add charts-3d.pptx /slide[6] --type chart \
--prop chartType=column3d --prop title="legend.overlay=true" \
--prop legend=topRight --prop legend.overlay=true \
--prop categories="$CATS" --prop data="$D2"
officecli add charts-3d.pptx /slide[6] --type chart \
--prop chartType=column3d --prop autotitledeleted=true --prop legend=none \
--prop categories="$CATS" --prop data="$D2"
```
**Features:** `title.font/size/color/bold`, `legend` positions, `legendFont`, `legend.overlay`, `autotitledeleted`
### Slide 7 — Series Styling
```bash
officecli add charts-3d.pptx /slide[7] --type chart \
--prop chartType=column3d --prop title="colors + seriesoutline" \
--prop colors="4472C4,ED7D31" --prop seriesoutline="000000:0.5" \
--prop legend=bottom --prop categories="$CATS" --prop data="$D2"
officecli add charts-3d.pptx /slide[7] --type chart \
--prop chartType=column3d --prop title="gradient + seriesshadow" \
--prop gradient="FF6600-FFCC00" --prop seriesshadow="000000-5-45-3-50" \
--prop legend=none --prop categories="$CATS" --prop data="$D2"
officecli add charts-3d.pptx /slide[7] --type chart \
--prop chartType=column3d --prop title="transparency=30" \
--prop transparency=30 --prop legend=bottom \
--prop categories="$CATS" --prop data="$D2"
officecli add charts-3d.pptx /slide[7] --type chart \
--prop chartType=column3d --prop title="per-series gradients" \
--prop gradients="FF0000-0000FF;00FF00-FFFF00" --prop legend=bottom \
--prop categories="$CATS" --prop data="$D2"
```
**Features:** `colors`, `seriesoutline`, `gradient`, `seriesshadow`, `transparency`, `gradients`
### Slide 8 — Presets
```bash
for p in minimal dark corporate colorful; do
officecli add charts-3d.pptx /slide[8] --type chart \
--prop chartType=column3d --prop preset=$p --prop title="preset=$p" \
--prop view3d="15,20,30" --prop legend=bottom \
--prop categories="$CATS" --prop data="$D2"
done
```
**Features:** `preset` (minimal/dark/corporate/colorful) applied to 3D chart type
## Complete Feature Coverage
| Feature | Slide |
|---------|-------|
| **3D chart types:** column3d, bar3d, pie3d, line3d | 1 |
| **3D chart types:** area3d, stackedColumn3d, percentStackedColumn3d, stackedBar3d | 2 |
| **view3d** (rotX,rotY,perspective) | 1, 3 |
| **gapdepth** (0500) | 4 |
| **shape** (box/cylinder/cone/pyramid) — bar3d/column3d | 5 |
| **title.font/size/color/bold** | 6 |
| **legend** positions, legendFont, legend.overlay | 6 |
| **autotitledeleted** | 6 |
| **colors**, seriesoutline, gradient, seriesshadow | 7 |
| **transparency**, gradients | 7 |
| **preset** (minimal/dark/corporate/colorful) | 8 |
## Inspect the Generated File
```bash
officecli query charts-3d.pptx chart
officecli get charts-3d.pptx "/slide[1]/chart[1]"
officecli get charts-3d.pptx "/slide[3]/chart[1]"
officecli get charts-3d.pptx "/slide[4]/chart[2]"
```
Binary file not shown.
+172
View File
@@ -0,0 +1,172 @@
#!/usr/bin/env python3
"""
3D Charts Showcase — column3d / bar3d / pie3d / line3d / area3d with view3d, gapdepth, shape.
Generates: charts-3d.pptx
Slide 1 3D families column3d / bar3d / pie3d / line3d
Slide 2 area3d & stacked 3D area3d / stackedColumn3d / percentStackedColumn3d / line3d stacked
Slide 3 view3d different rotX,rotY,perspective angles
Slide 4 gapdepth 0 / 50 / 150 / 300 (3D bar/column/line/area only)
Slide 5 bar shapes box / cylinder / cone / pyramid (bar3d / column3d)
Slide 6 Title & legend
Slide 7 Series styling colors, gradient, transparency, outline, shadow
Slide 8 Presets
SDK twin of charts-3d.sh (officecli CLI). Both produce an equivalent
charts-3d.pptx. This one drives the **officecli Python SDK**
(`pip install officecli-sdk`): one resident is started and every slide, title
shape and chart is shipped over the named pipe in a single `doc.batch(...)`
round-trip. Each item is the same `{"command","parent","type","props"}` dict
you'd put in an `officecli batch` list.
Usage:
pip install officecli-sdk # plus the `officecli` binary on PATH
python3 charts-3d.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__)), "charts-3d.pptx")
# ------------------------------------------------------------------ data + layout
CATS = "Q1,Q2,Q3,Q4"
D2 = "East:120,135,148,162;West:95,108,115,128"
D3 = "East:120,135,148,162;South:95,108,115,128;West:80,90,98,110"
PIE_CATS = "North,South,East,West"
PIE_D = "Share:30,25,28,17"
TL = {"x": "0.3in", "y": "1.05in", "width": "6.1in", "height": "3in"}
TR = {"x": "6.95in", "y": "1.05in", "width": "6.1in", "height": "3in"}
BL = {"x": "0.3in", "y": "4.25in", "width": "6.1in", "height": "3in"}
BR = {"x": "6.95in", "y": "4.25in", "width": "6.1in", "height": "3in"}
# slide cursor — bumped by slide(); chart()/title() target /slide[<_slide>].
_slide = 0
def slide(title):
"""One `add slide` item + its title `add shape` item, in batch-shape."""
global _slide
_slide += 1
return [
{"command": "add", "parent": "/", "type": "slide", "props": {}},
{"command": "add", "parent": f"/slide[{_slide}]", "type": "shape",
"props": {"text": title, "size": 24, "bold": "true", "autoFit": "normal",
"x": "0.5in", "y": "0.3in", "width": "12.3in", "height": "0.6in"}},
]
def chart(box, props):
"""One `add chart` item (box geometry + chart props), in batch-shape."""
return {"command": "add", "parent": f"/slide[{_slide}]", "type": "chart",
"props": {**box, **props}}
print(f"Building {FILE} ...")
with officecli.create(FILE, "--force") as doc:
items = []
# ---- Slide 1: 3D families ----
items += slide("3D families — column3d / bar3d / pie3d / line3d")
items += [
chart(TL, {"chartType": "column3d", "title": "column3d", "legend": "bottom",
"categories": CATS, "data": D2}),
chart(TR, {"chartType": "bar3d", "title": "bar3d", "legend": "bottom",
"categories": CATS, "data": D2}),
chart(BL, {"chartType": "pie3d", "title": "pie3d", "legend": "right",
"categories": PIE_CATS, "data": PIE_D}),
chart(BR, {"chartType": "line3d", "title": "line3d", "legend": "bottom",
"categories": CATS, "data": D2}),
]
# ---- Slide 2: area3d & stacked 3D ----
items += slide("area3d & stacked 3D")
items += [
chart(TL, {"chartType": "area3d", "title": "area3d", "legend": "bottom",
"categories": CATS, "data": D2}),
chart(TR, {"chartType": "stackedColumn3d", "title": "stackedColumn3d",
"legend": "bottom", "categories": CATS, "data": D3}),
chart(BL, {"chartType": "percentStackedColumn3d", "title": "percentStackedColumn3d",
"legend": "bottom", "categories": CATS, "data": D3}),
chart(BR, {"chartType": "stackedBar3d", "title": "stackedBar3d",
"legend": "bottom", "categories": CATS, "data": D3}),
]
# ---- Slide 3: view3d — rotX,rotY,perspective angles ----
items += slide("view3d — rotX,rotY,perspective angles")
items += [
chart(TL, {"chartType": "column3d", "title": "view3d=15,20,30", "view3d": "15,20,30",
"legend": "none", "categories": CATS, "data": D2}),
chart(TR, {"chartType": "column3d", "title": "view3d=30,40,15", "view3d": "30,40,15",
"legend": "none", "categories": CATS, "data": D2}),
chart(BL, {"chartType": "column3d", "title": "view3d=20", "view3d": "20",
"legend": "none", "categories": CATS, "data": D2}),
chart(BR, {"chartType": "pie3d", "title": "pie3d view3d=40,30,30", "view3d": "40,30,30",
"legend": "right", "categories": PIE_CATS, "data": PIE_D}),
]
# ---- Slide 4: gapdepth — 0 / 50 / 150 / 300 ----
items += slide("gapdepth — 0 / 50 / 150 / 300")
for box, g in zip([TL, TR, BL, BR], [0, 50, 150, 300]):
items.append(chart(box, {"chartType": "column3d", "title": f"gapdepth={g}",
"gapdepth": str(g), "legend": "none",
"categories": CATS, "data": D2}))
# ---- Slide 5: 3D bar shapes — box / cylinder / cone / pyramid ----
items += slide("3D bar shapes — box / cylinder / cone / pyramid")
for box, s in zip([TL, TR, BL, BR], ["box", "cylinder", "cone", "pyramid"]):
items.append(chart(box, {"chartType": "bar3d", "shape": s, "title": f"shape={s}",
"legend": "none", "categories": CATS, "data": D2}))
# ---- Slide 6: Title & legend ----
items += slide("Title & legend")
items += [
chart(TL, {"chartType": "column3d", "title": "Styled title", "title.font": "Georgia",
"title.size": "20", "title.color": "4472C4", "title.bold": "true",
"legend": "bottom", "categories": CATS, "data": D2}),
chart(TR, {"chartType": "column3d", "title": "legend=top + legendFont", "legend": "top",
"legendFont": "10:333333:Calibri", "categories": CATS, "data": D2}),
chart(BL, {"chartType": "column3d", "title": "legend.overlay=true", "legend": "topRight",
"legend.overlay": "true", "categories": CATS, "data": D2}),
chart(BR, {"chartType": "column3d", "autotitledeleted": "true", "legend": "none",
"categories": CATS, "data": D2}),
]
# ---- Slide 7: Series styling — colors, gradient, transparency, outline, shadow ----
items += slide("Series styling — colors, gradient, transparency, outline, shadow")
items += [
chart(TL, {"chartType": "column3d", "title": "colors + seriesoutline",
"colors": "4472C4,ED7D31", "seriesoutline": "000000:0.5",
"legend": "bottom", "categories": CATS, "data": D2}),
chart(TR, {"chartType": "column3d", "title": "gradient + seriesshadow",
"gradient": "FF6600-FFCC00", "seriesshadow": "000000-5-45-3-50",
"legend": "none", "categories": CATS, "data": D2}),
chart(BL, {"chartType": "column3d", "title": "transparency=30", "transparency": "30",
"legend": "bottom", "categories": CATS, "data": D2}),
chart(BR, {"chartType": "column3d", "title": "per-series gradients",
"gradients": "FF0000-0000FF;00FF00-FFFF00",
"legend": "bottom", "categories": CATS, "data": D2}),
]
# ---- Slide 8: Presets — preset bundles on 3D charts ----
items += slide("Presets — preset bundles on 3D charts")
for box, p in zip([TL, TR, BL, BR], ["minimal", "dark", "corporate", "colorful"]):
items.append(chart(box, {"chartType": "column3d", "preset": p, "title": f"preset={p}",
"view3d": "15,20,30", "legend": "bottom",
"categories": CATS, "data": D2}))
doc.batch(items)
print(f" added {_slide} slides, {len(items)} items")
print(f"Generated: {FILE} ({_slide} slides)")
+104
View File
@@ -0,0 +1,104 @@
#!/bin/bash
# 3D Charts Showcase — column3d / bar3d / pie3d / line3d / area3d with view3d, gapdepth, shape.
# Generates charts-3d.pptx
#
# Slide 1 3D families column3d / bar3d / pie3d / line3d
# Slide 2 area3d & stacked 3D area3d / stackedColumn3d / percentStackedColumn3d / stackedBar3d
# Slide 3 view3d different rotX,rotY,perspective angles
# Slide 4 gapdepth 0 / 50 / 150 / 300
# Slide 5 bar shapes box / cylinder / cone / pyramid
# Slide 6 Title & legend
# Slide 7 Series styling colors, gradient, transparency, outline, shadow
# Slide 8 Presets
#
# CLI twin of charts-3d.py (officecli Python SDK). Both produce an equivalent
# charts-3d.pptx.
#
# Usage: ./charts-3d.sh [officecli path]
# NOTE: intentionally NO `set -e`. Like the SDK twin's doc.batch, this script
# tolerates forward-compat 'UNSUPPORTED props' warnings (officecli exit 2) and
# keeps building so the full document is produced.
CLI="${1:-officecli}"
FILE="$(dirname "$0")/charts-3d.pptx"
rm -f "$FILE"
$CLI create "$FILE"
$CLI open "$FILE"
# ---- shared data + box geometry ----
CATS="Q1,Q2,Q3,Q4"
D2="East:120,135,148,162;West:95,108,115,128"
D3="East:120,135,148,162;South:95,108,115,128;West:80,90,98,110"
PIE_CATS="North,South,East,West"
PIE_D="Share:30,25,28,17"
# title shape helper props are inlined per slide below.
# ==================== Slide 1: 3D families ====================
$CLI add "$FILE" / --type slide
$CLI add "$FILE" /slide[1] --type shape --prop text="3D families — column3d / bar3d / pie3d / line3d" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
$CLI add "$FILE" /slide[1] --type chart --prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=column3d --prop title=column3d --prop legend=bottom --prop categories="$CATS" --prop data="$D2"
$CLI add "$FILE" /slide[1] --type chart --prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=bar3d --prop title=bar3d --prop legend=bottom --prop categories="$CATS" --prop data="$D2"
$CLI add "$FILE" /slide[1] --type chart --prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=pie3d --prop title=pie3d --prop legend=right --prop categories="$PIE_CATS" --prop data="$PIE_D"
$CLI add "$FILE" /slide[1] --type chart --prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=line3d --prop title=line3d --prop legend=bottom --prop categories="$CATS" --prop data="$D2"
# ==================== Slide 2: area3d & stacked 3D ====================
$CLI add "$FILE" / --type slide
$CLI add "$FILE" /slide[2] --type shape --prop text="area3d & stacked 3D" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
$CLI add "$FILE" /slide[2] --type chart --prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=area3d --prop title=area3d --prop legend=bottom --prop categories="$CATS" --prop data="$D2"
$CLI add "$FILE" /slide[2] --type chart --prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=stackedColumn3d --prop title=stackedColumn3d --prop legend=bottom --prop categories="$CATS" --prop data="$D3"
$CLI add "$FILE" /slide[2] --type chart --prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=percentStackedColumn3d --prop title=percentStackedColumn3d --prop legend=bottom --prop categories="$CATS" --prop data="$D3"
$CLI add "$FILE" /slide[2] --type chart --prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=stackedBar3d --prop title=stackedBar3d --prop legend=bottom --prop categories="$CATS" --prop data="$D3"
# ==================== Slide 3: view3d — rotX,rotY,perspective angles ====================
$CLI add "$FILE" / --type slide
$CLI add "$FILE" /slide[3] --type shape --prop text="view3d — rotX,rotY,perspective angles" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
$CLI add "$FILE" /slide[3] --type chart --prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=column3d --prop title="view3d=15,20,30" --prop view3d="15,20,30" --prop legend=none --prop categories="$CATS" --prop data="$D2"
$CLI add "$FILE" /slide[3] --type chart --prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=column3d --prop title="view3d=30,40,15" --prop view3d="30,40,15" --prop legend=none --prop categories="$CATS" --prop data="$D2"
$CLI add "$FILE" /slide[3] --type chart --prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=column3d --prop title="view3d=20" --prop view3d="20" --prop legend=none --prop categories="$CATS" --prop data="$D2"
$CLI add "$FILE" /slide[3] --type chart --prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=pie3d --prop title="pie3d view3d=40,30,30" --prop view3d="40,30,30" --prop legend=right --prop categories="$PIE_CATS" --prop data="$PIE_D"
# ==================== Slide 4: gapdepth — 0 / 50 / 150 / 300 ====================
$CLI add "$FILE" / --type slide
$CLI add "$FILE" /slide[4] --type shape --prop text="gapdepth — 0 / 50 / 150 / 300" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
$CLI add "$FILE" /slide[4] --type chart --prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=column3d --prop title="gapdepth=0" --prop gapdepth=0 --prop legend=none --prop categories="$CATS" --prop data="$D2"
$CLI add "$FILE" /slide[4] --type chart --prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=column3d --prop title="gapdepth=50" --prop gapdepth=50 --prop legend=none --prop categories="$CATS" --prop data="$D2"
$CLI add "$FILE" /slide[4] --type chart --prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=column3d --prop title="gapdepth=150" --prop gapdepth=150 --prop legend=none --prop categories="$CATS" --prop data="$D2"
$CLI add "$FILE" /slide[4] --type chart --prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=column3d --prop title="gapdepth=300" --prop gapdepth=300 --prop legend=none --prop categories="$CATS" --prop data="$D2"
# ==================== Slide 5: 3D bar shapes — box / cylinder / cone / pyramid ====================
$CLI add "$FILE" / --type slide
$CLI add "$FILE" /slide[5] --type shape --prop text="3D bar shapes — box / cylinder / cone / pyramid" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
$CLI add "$FILE" /slide[5] --type chart --prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=bar3d --prop shape=box --prop title="shape=box" --prop legend=none --prop categories="$CATS" --prop data="$D2"
$CLI add "$FILE" /slide[5] --type chart --prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=bar3d --prop shape=cylinder --prop title="shape=cylinder" --prop legend=none --prop categories="$CATS" --prop data="$D2"
$CLI add "$FILE" /slide[5] --type chart --prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=bar3d --prop shape=cone --prop title="shape=cone" --prop legend=none --prop categories="$CATS" --prop data="$D2"
$CLI add "$FILE" /slide[5] --type chart --prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=bar3d --prop shape=pyramid --prop title="shape=pyramid" --prop legend=none --prop categories="$CATS" --prop data="$D2"
# ==================== Slide 6: Title & legend ====================
$CLI add "$FILE" / --type slide
$CLI add "$FILE" /slide[6] --type shape --prop text="Title & legend" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
$CLI add "$FILE" /slide[6] --type chart --prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=column3d --prop title="Styled title" --prop title.font=Georgia --prop title.size=20 --prop title.color=4472C4 --prop title.bold=true --prop legend=bottom --prop categories="$CATS" --prop data="$D2"
$CLI add "$FILE" /slide[6] --type chart --prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=column3d --prop title="legend=top + legendFont" --prop legend=top --prop legendFont="10:333333:Calibri" --prop categories="$CATS" --prop data="$D2"
$CLI add "$FILE" /slide[6] --type chart --prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=column3d --prop title="legend.overlay=true" --prop legend=topRight --prop legend.overlay=true --prop categories="$CATS" --prop data="$D2"
$CLI add "$FILE" /slide[6] --type chart --prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=column3d --prop autotitledeleted=true --prop legend=none --prop categories="$CATS" --prop data="$D2"
# ==================== Slide 7: Series styling — colors, gradient, transparency, outline, shadow ====================
$CLI add "$FILE" / --type slide
$CLI add "$FILE" /slide[7] --type shape --prop text="Series styling — colors, gradient, transparency, outline, shadow" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
$CLI add "$FILE" /slide[7] --type chart --prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=column3d --prop title="colors + seriesoutline" --prop colors="4472C4,ED7D31" --prop seriesoutline="000000:0.5" --prop legend=bottom --prop categories="$CATS" --prop data="$D2"
$CLI add "$FILE" /slide[7] --type chart --prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=column3d --prop title="gradient + seriesshadow" --prop gradient="FF6600-FFCC00" --prop seriesshadow="000000-5-45-3-50" --prop legend=none --prop categories="$CATS" --prop data="$D2"
$CLI add "$FILE" /slide[7] --type chart --prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=column3d --prop title="transparency=30" --prop transparency=30 --prop legend=bottom --prop categories="$CATS" --prop data="$D2"
$CLI add "$FILE" /slide[7] --type chart --prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=column3d --prop title="per-series gradients" --prop gradients="FF0000-0000FF;00FF00-FFFF00" --prop legend=bottom --prop categories="$CATS" --prop data="$D2"
# ==================== Slide 8: Presets — preset bundles on 3D charts ====================
$CLI add "$FILE" / --type slide
$CLI add "$FILE" /slide[8] --type shape --prop text="Presets — preset bundles on 3D charts" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
$CLI add "$FILE" /slide[8] --type chart --prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=column3d --prop preset=minimal --prop title="preset=minimal" --prop view3d="15,20,30" --prop legend=bottom --prop categories="$CATS" --prop data="$D2"
$CLI add "$FILE" /slide[8] --type chart --prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=column3d --prop preset=dark --prop title="preset=dark" --prop view3d="15,20,30" --prop legend=bottom --prop categories="$CATS" --prop data="$D2"
$CLI add "$FILE" /slide[8] --type chart --prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=column3d --prop preset=corporate --prop title="preset=corporate" --prop view3d="15,20,30" --prop legend=bottom --prop categories="$CATS" --prop data="$D2"
$CLI add "$FILE" /slide[8] --type chart --prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=column3d --prop preset=colorful --prop title="preset=colorful" --prop view3d="15,20,30" --prop legend=bottom --prop categories="$CATS" --prop data="$D2"
$CLI close "$FILE"
$CLI validate "$FILE"
echo "Generated: $FILE"
+313
View File
@@ -0,0 +1,313 @@
# Advanced Charts Showcase
This demo consists of three files that work together:
- **charts-advanced.py** — Python script that calls `officecli` commands to generate the deck. It covers the "long-tail" chart properties not shown in the per-type decks.
- **charts-advanced.pptx** — The generated 8-slide deck.
- **charts-advanced.md** — This file. Maps each slide to the niche/advanced features it demonstrates.
## Regenerate
```bash
cd examples/ppt/charts
python3 charts-advanced.py
# → charts-advanced.pptx
```
## Chart Slides
### Slide 1 — RTL and Anchor Variants
```bash
CATS="Q1,Q2,Q3,Q4"; D="A:60,90,140,180"
# Default LTR chart
officecli add charts-advanced.pptx /slide[1] --type chart \
--prop chartType=column --prop title="default (LTR)" --prop legend=bottom \
--prop categories="$CATS" --prop data="A:60,90,140,180;B:50,75,110,150" \
--prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in
# RTL: Add first, then Set direction=rtl
officecli add charts-advanced.pptx /slide[1] --type chart \
--prop chartType=column --prop title="direction=rtl (Set after Add)" \
--prop legend=bottom \
--prop categories="$CATS" --prop data="A:60,90,140,180;B:50,75,110,150" \
--prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in
officecli set charts-advanced.pptx "/slide[1]/chart[2]" --prop direction=rtl
# anchor= cm-form alternative to x/y/width/height
officecli add charts-advanced.pptx /slide[1] --type chart \
--prop chartType=column --prop title="anchor=0.3cm,11cm,15.5cm,7cm" \
--prop legend=bottom \
--prop categories="$CATS" --prop data="$D" \
--prop anchor="0.3cm,11cm,15.5cm,7cm"
```
**Features:** `direction=rtl` (Set-only, reverses chart reading order), `anchor=x,y,w,h` (cm-form alternative to x=/y=/width=/height=)
### Slide 2 — Axis Visibility Shortcuts
```bash
# Hide both axes
officecli add charts-advanced.pptx /slide[2] --type chart \
--prop chartType=column --prop title="axisvisible=false (both axes hidden)" \
--prop legend=none --prop axisvisible=false \
--prop categories="$CATS" --prop data="$D"
# Hide value (Y) axis only
officecli add charts-advanced.pptx /slide[2] --type chart \
--prop chartType=column --prop title="valaxisvisible=false (Y hidden, X shown)" \
--prop legend=none --prop valaxisvisible=false \
--prop categories="$CATS" --prop data="$D"
# Hide category (X) axis only
officecli add charts-advanced.pptx /slide[2] --type chart \
--prop chartType=column --prop title="catAxisVisible=false (X hidden)" \
--prop legend=none --prop catAxisVisible=false \
--prop categories="$CATS" --prop data="$D"
# Axis orientation reversal + axis position at top
officecli add charts-advanced.pptx /slide[2] --type chart \
--prop chartType=column \
--prop title="axisorientation=true (reversed) + axisposition=top" \
--prop legend=none --prop axisorientation=true --prop axisposition=top \
--prop cataxisline="333333:1" --prop valaxisline="333333:1" \
--prop categories="$CATS" --prop data="$D"
```
**Features:** `axisvisible` (false = hide both), `valaxisvisible` (hide value/Y axis), `catAxisVisible` (hide category/X axis), `axisorientation` (true = reverse), `axisposition` (top/bottom/left/right), `cataxisline`/`valaxisline` (color:width)
### Slide 3 — Crossings
```bash
# Default crossBetween (bars straddle gridlines)
officecli add charts-advanced.pptx /slide[3] --type chart \
--prop chartType=column --prop title="crossBetween=between (default)" \
--prop legend=none --prop crossBetween=between \
--prop categories="$CATS" --prop data="$D"
# midCat: bars centered on gridlines
officecli add charts-advanced.pptx /slide[3] --type chart \
--prop chartType=column --prop title="crossBetween=midCat" \
--prop legend=none --prop crossBetween=midCat \
--prop categories="$CATS" --prop data="$D"
# Y axis crosses at the maximum value (bars grow down)
officecli add charts-advanced.pptx /slide[3] --type chart \
--prop chartType=column --prop title="crosses=max (Y crosses at top)" \
--prop legend=none --prop crosses=max \
--prop categories="$CATS" --prop data="$D"
# X axis crosses at a specific Y value
officecli add charts-advanced.pptx /slide[3] --type chart \
--prop chartType=column \
--prop title="crossesAt=100 + crosses=autoZero" \
--prop legend=none --prop crosses=autoZero --prop crossesAt=100 \
--prop categories="$CATS" --prop data="A:60,-30,140,180"
```
**Features:** `crossBetween` (between/midCat), `crosses` (autoZero/max/min), `crossesAt` (numeric Y value where X axis crosses)
### Slide 4 — Category Axis Layout
```bash
# labeloffset controls label distance from axis (100 = default, 300 = farther)
officecli add charts-advanced.pptx /slide[4] --type chart \
--prop chartType=column --prop title="labeloffset=100 (default)" \
--prop labeloffset=100 --prop legend=none \
--prop categories="January,February,March,April,May,June" \
--prop data="A:60,90,140,180,160,210"
officecli add charts-advanced.pptx /slide[4] --type chart \
--prop chartType=column --prop title="labeloffset=300 (push labels down)" \
--prop labeloffset=300 --prop legend=none \
--prop categories="January,February,March,April,May,June" \
--prop data="A:60,90,140,180,160,210"
# ticklabelskip: show every Nth label (reduce clutter on dense axes)
officecli add charts-advanced.pptx /slide[4] --type chart \
--prop chartType=column --prop title="ticklabelskip=2 (every other label)" \
--prop ticklabelskip=2 --prop legend=none \
--prop categories="Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec" \
--prop data="A:60,90,140,180,160,210,200,190,170,150,130,170"
officecli add charts-advanced.pptx /slide[4] --type chart \
--prop chartType=column --prop title="ticklabelskip=3" \
--prop ticklabelskip=3 --prop legend=none \
--prop categories="Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec" \
--prop data="A:60,90,140,180,160,210,200,190,170,150,130,170"
```
**Features:** `labeloffset` (1001000, label distance from axis), `ticklabelskip` (show every Nth label)
### Slide 5 — Marker Size, Area Fill, chartFill, plotvisonly
```bash
# markersize as standalone key (independent of marker= compound)
officecli add charts-advanced.pptx /slide[5] --type chart \
--prop chartType=line --prop title="markersize=12 (standalone key)" \
--prop showMarker=true --prop markersize=12 --prop legend=none \
--prop categories="$CATS" --prop data="$D"
# areafill: gradient fill applied to every series shape
officecli add charts-advanced.pptx /slide[5] --type chart \
--prop chartType=column --prop title="areafill (gradient on series)" \
--prop areafill="4472C4-A5C8FF:90" --prop legend=none \
--prop categories="$CATS" --prop data="A:60,90,140,180;B:50,75,110,150"
# chartFill: chart-level background fill (vs chartareafill which targets the plot frame)
officecli add charts-advanced.pptx /slide[5] --type chart \
--prop chartType=column --prop title="chartFill=#FFF8E7 (chart-level fill)" \
--prop chartFill="#FFF8E7" --prop legend=none \
--prop categories="$CATS" --prop data="$D"
# plotvisonly: skip hidden rows when bound to a sheet
officecli add charts-advanced.pptx /slide[5] --type chart \
--prop chartType=column --prop title="plotvisonly=true" \
--prop plotvisonly=true --prop legend=none \
--prop categories="$CATS" --prop data="$D"
```
**Features:** `markersize` (standalone, independent of `marker=`), `areafill` (gradient fill on all series), `chartFill` (chart-level fill), `plotvisonly` (skip hidden rows)
### Slide 6 — Style, dispBlanksAs, dataRange
```bash
# Built-in chart style presets (148)
officecli add charts-advanced.pptx /slide[6] --type chart \
--prop chartType=column --prop style=2 --prop title="style=2" \
--prop legend=bottom --prop categories="$CATS" \
--prop data="A:60,90,140,180;B:50,75,110,150"
officecli add charts-advanced.pptx /slide[6] --type chart \
--prop chartType=column --prop style=42 --prop title="style=42" \
--prop legend=bottom --prop categories="$CATS" \
--prop data="A:60,90,140,180;B:50,75,110,150"
# dispBlanksAs: how to handle blank/null data points
# Set-only (Add first, then Set)
officecli add charts-advanced.pptx /slide[6] --type chart \
--prop chartType=line --prop title="dispBlanksAs=gap (Set after Add)" \
--prop showMarker=true --prop legend=bottom \
--prop categories="$CATS" --prop data="A:60,90,140,180"
officecli set charts-advanced.pptx "/slide[6]/chart[3]" --prop dispBlanksAs=gap
# dataRange: sheet-range alternative to data= for workbook-backed sources
officecli add charts-advanced.pptx /slide[6] --type chart \
--prop chartType=column --prop title="dataRange syntax demo (fallback inline)" \
--prop dataRange="Sheet1!A1:D5" --prop legend=bottom --prop catTitle="Quarter" \
--prop categories="$CATS" --prop data="A:60,90,140,180;B:50,75,110,150"
```
**Features:** `style` (148 built-in style presets), `dispBlanksAs` (gap/zero/span — Set-only), `dataRange` (sheet range syntax), `catTitle`
### Slide 7 — chart-axis Set (per-axis post-Add mutations)
```bash
# Set dispUnits + format + minorUnit + labelRotation on value axis
officecli add charts-advanced.pptx /slide[7] --type chart \
--prop chartType=column --prop title="after: dispUnits=thousands" \
--prop legend=none --prop categories="$CATS" \
--prop data="Rev:120000,135000,148000,162000"
officecli set charts-advanced.pptx "/slide[7]/chart[1]/axis[@role=value]" \
--prop dispUnits=thousands --prop format="#,##0" \
--prop minorUnit=10000 --prop labelRotation=0 --prop visible=true
# Set logBase + min/max + majorGridlines on value axis
officecli add charts-advanced.pptx /slide[7] --type chart \
--prop chartType=line --prop title="after: logBase=10" \
--prop legend=none --prop categories="$CATS" \
--prop data="A:5,50,500,5000"
officecli set charts-advanced.pptx "/slide[7]/chart[2]/axis[@role=value]" \
--prop logBase=10 --prop min=1 --prop max=10000 --prop majorGridlines=true
# Set visible=false on value axis
officecli add charts-advanced.pptx /slide[7] --type chart \
--prop chartType=column --prop title="after: visible=false on value axis" \
--prop legend=none --prop categories="$CATS" --prop data="$D"
officecli set charts-advanced.pptx "/slide[7]/chart[3]/axis[@role=value]" \
--prop visible=false
# Set labelRotation=-45 + title on category axis
officecli add charts-advanced.pptx /slide[7] --type chart \
--prop chartType=column --prop title="after: labelRotation=-45 on category axis" \
--prop legend=none --prop categories="January,February,March,April" --prop data="$D"
officecli set charts-advanced.pptx "/slide[7]/chart[4]/axis[@role=category]" \
--prop labelRotation=-45 --prop title="Month" --prop visible=true
```
**Features (chart-axis Set):** `dispUnits`, `format`, `minorUnit`, `labelRotation`, `visible`, `logBase`, `min`, `max`, `majorGridlines`, `title`; axis selector: `axis[@role=value]` / `axis[@role=category]`
### Slide 8 — chart-series and chart-axis Get Readback
```bash
# Add a chart, mutate a series, then get --json readback
officecli add charts-advanced.pptx /slide[8] --type chart \
--prop chartType=column --prop title="before: A=60,90,140,180" \
--prop legend=bottom --prop categories="$CATS" --prop data="$D"
# Mutate values after add
officecli set charts-advanced.pptx "/slide[8]/chart[1]/series[1]" \
--prop values="200,150,100,80"
# Rename + recolor, then get JSON readback
officecli set charts-advanced.pptx "/slide[8]/chart[1]/series[1]" \
--prop name="Readback Demo" --prop color=C00000
# Get series JSON (readback fields: alpha, outlineColor, scatterStyle, etc.)
officecli get charts-advanced.pptx "/slide[8]/chart[1]/series[1]" --json
# Set axis properties, then get axis JSON readback
officecli set charts-advanced.pptx "/slide[8]/chart[1]/axis[@role=value]" \
--prop title="Readback Y" --prop format='$#,##0' \
--prop min=0 --prop max=300 --prop majorUnit=75
# Get axis JSON (readback fields: axisFont, axisMax, axisMin, axisNumFmt, etc.)
officecli get charts-advanced.pptx "/slide[8]/chart[1]/axis[@role=value]" --json
```
**Features:** `chart-series Set values=` (mutate data after creation), `get --json` for series + axis readback fields
## Complete Feature Coverage
| Feature | Slide |
|---------|-------|
| **direction=rtl** (Set-only) | 1 |
| **anchor=x,y,w,h** (cm-form) | 1 |
| **axisvisible, valaxisvisible, catAxisVisible** | 2 |
| **axisorientation** (reversed), **axisposition** | 2 |
| **cataxisline, valaxisline** | 2 |
| **crossBetween** (between/midCat) | 3 |
| **crosses** (autoZero/max/min), **crossesAt** | 3 |
| **labeloffset** | 4 |
| **ticklabelskip** | 4 |
| **markersize** (standalone key) | 5 |
| **areafill** (gradient on series) | 5 |
| **chartFill** (chart-level) | 5 |
| **plotvisonly** | 5 |
| **style** (148 preset) | 6 |
| **dispBlanksAs** (gap/zero/span — Set-only) | 6 |
| **dataRange** (sheet-range syntax) | 6 |
| **catTitle** | 6 |
| **chart-axis Set:** dispUnits, logBase, minorUnit, labelRotation, visible, min, max, majorGridlines, title | 7 |
| **chart-series Set values=** (mutate data) | 8 |
| **get --json** series + axis readback fields | 8 |
## Get-Only Readback Fields (surface in `get --json`)
| Element | Get-only properties |
|---|---|
| chart | `id` |
| chart-axis | `axisFont`, `axisMax`, `axisMin`, `axisNumFmt`, `axisOrientation`, `axisTitle`, `labelOffset`, `tickLabelSkip` |
| chart-series | `alpha`, `categoriesRef`, `dataLabels.numFmt`, `dataLabels.separator`, `errBars`, `invertIfNeg`, `nameRef`, `outlineColor`, `scatterStyle`, `secondaryAxis` |
These fields cannot be Set as input — they surface in the JSON readback shapes on slide 8.
## Inspect the Generated File
```bash
officecli query charts-advanced.pptx chart
officecli get charts-advanced.pptx "/slide[1]/chart[2]"
officecli get charts-advanced.pptx "/slide[7]/chart[1]/axis[@role=value]"
officecli get charts-advanced.pptx "/slide[8]/chart[1]/series[1]" --json
```
Binary file not shown.
+305
View File
@@ -0,0 +1,305 @@
#!/usr/bin/env python3
"""
Advanced Charts Showcase — properties not covered by the per-type decks.
Generates: charts-advanced.pptx
Coverage of the long tail of chart properties (cross-handler / niche / axis-level):
Slide 1 RTL & anchor direction=rtl, anchor named-token, anchor cm-form
Slide 2 Axis-level shortcuts axisvisible / valaxisvisible / catAxisVisible,
axisorientation, axisposition,
cataxisline / valaxisline
Slide 3 Crossings crossBetween (between/midCat), crosses (autoZero/max/min), crossesAt
Slide 4 Categories axis labeloffset, ticklabelskip
Slide 5 Marker size & fills markersize (standalone), areafill, chartFill, plotvisonly
Slide 6 Built-in style + blanks style=1..48, dispBlanksAs (gap / zero / span)
Slide 7 chart-axis Set dispUnits, logBase, minorUnit, visible, labelRotation (per-axis)
Slide 8 chart-series mutation values=, categories= (per-series range), + get-readback round-trip
SDK twin of charts-advanced.sh (officecli CLI). Both produce an equivalent
charts-advanced.pptx. This one drives the **officecli Python SDK**
(`pip install officecli-sdk`): one resident is started and every add/set is
shipped over the named pipe. The bulk of the deck goes in a single
`doc.batch(...)` round-trip (items applied in order, so an Add followed by a
Set on the same chart works); the two get-readback round-trips that feed text
back onto slide 8 use `doc.send(...)` so their JSON can be captured mid-stream.
Each item is the same `{"command","parent","type","props"}` dict you'd put in
an `officecli batch` list. batch is run with force=True so a prop the running
binary doesn't yet support is skipped (forward-compat) rather than aborting the
deck — per-item failures are surfaced afterwards so silent gaps stay visible.
Usage:
pip install officecli-sdk # plus the `officecli` binary on PATH
python3 charts-advanced.py
"""
import os
import sys
import json
# --- 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__)), "charts-advanced.pptx")
# Four quadrant boxes (named exactly as in the .sh twin).
TL = {"x": "0.3in", "y": "1.05in", "width": "6.1in", "height": "3in"}
TR = {"x": "6.95in", "y": "1.05in", "width": "6.1in", "height": "3in"}
BL = {"x": "0.3in", "y": "4.25in", "width": "6.1in", "height": "3in"}
BR = {"x": "6.95in", "y": "4.25in", "width": "6.1in", "height": "3in"}
CATS = "Q1,Q2,Q3,Q4"
D = "A:60,90,140,180"
D2 = "A:60,90,140,180;B:50,75,110,150"
_slide = 0
def new_slide(t):
"""Add a slide + its title shape; returns the items list."""
global _slide
_slide += 1
return [
{"command": "add", "parent": "/", "type": "slide", "props": {}},
{"command": "add", "parent": f"/slide[{_slide}]", "type": "shape",
"props": {"text": t, "size": 24, "bold": "true", "autoFit": "normal",
"x": "0.5in", "y": "0.3in", "width": "12.3in", "height": "0.6in"}},
]
def ch(box, p):
"""One `add chart` item in the current slide, box + chart props merged."""
return {"command": "add", "parent": f"/slide[{_slide}]", "type": "chart",
"props": {**box, **p}}
def note(x, y, text):
"""One small italic caption shape."""
return {"command": "add", "parent": f"/slide[{_slide}]", "type": "shape",
"props": {"text": text, "size": 10, "italic": "true", "color": "666666",
"x": x, "y": y, "width": "6in", "height": "0.4in"}}
def cset(path, props):
"""One `set` item."""
return {"command": "set", "path": path, "props": props}
def _fmt_from(envelope):
"""Pull a node's `format` dict out of a get envelope, tolerant of shape."""
obj = envelope
if isinstance(obj, dict) and "data" in obj:
obj = obj["data"]
if isinstance(obj, dict) and "results" in obj and obj["results"]:
obj = obj["results"][0]
if isinstance(obj, dict) and "format" in obj:
return obj["format"]
return obj
print(f"Building {FILE} ...")
with officecli.create(FILE, "--force") as doc:
items = []
# -----------------------------------------------------------------------
# Slide 1 — RTL + anchor variants
# -----------------------------------------------------------------------
items += new_slide("RTL + anchor — direction=rtl, named-token anchor, cm-form anchor")
items += [
ch(TL, {"chartType": "column", "title": "default (LTR)", "legend": "bottom",
"categories": CATS, "data": D2}),
# RTL must be Set after Add (direction is set-only)
ch(TR, {"chartType": "column", "title": "direction=rtl (Set after Add)", "legend": "bottom",
"categories": "Q1,Q2,Q3,Q4", "data": D2}),
cset(f"/slide[{_slide}]/chart[2]", {"direction": "rtl"}),
# Anchor cm-form: x,y,w,h
ch({"anchor": "0.3cm,11cm,15.5cm,7cm"},
{"chartType": "column", "title": "anchor=0.3cm,11cm,15.5cm,7cm", "legend": "bottom",
"categories": CATS, "data": D}),
]
# -----------------------------------------------------------------------
# Slide 2 — axis-level shortcuts
# -----------------------------------------------------------------------
items += new_slide("Axis shortcuts — axisvisible / valaxisvisible / catAxisVisible, orientation, position, lines")
items += [
ch(TL, {"chartType": "column", "title": "axisvisible=false (both axes hidden)",
"legend": "none", "axisvisible": "false", "categories": CATS, "data": D}),
ch(TR, {"chartType": "column", "title": "valaxisvisible=false (Y hidden, X shown)",
"legend": "none", "valaxisvisible": "false", "categories": CATS, "data": D}),
ch(BL, {"chartType": "column", "title": "catAxisVisible=false (X hidden)",
"legend": "none", "catAxisVisible": "false", "categories": CATS, "data": D}),
ch(BR, {"chartType": "column", "title": "axisorientation=true (reversed) + axisposition=top",
"legend": "none", "axisorientation": "true", "axisposition": "top",
"cataxisline": "333333:1", "valaxisline": "333333:1",
"categories": CATS, "data": D}),
]
# -----------------------------------------------------------------------
# Slide 3 — Crossings
# -----------------------------------------------------------------------
items += new_slide("Crossings — crossBetween / crosses / crossesAt")
items += [
ch(TL, {"chartType": "column", "title": "crossBetween=between (default)",
"legend": "none", "crossBetween": "between", "categories": CATS, "data": D}),
ch(TR, {"chartType": "column", "title": "crossBetween=midCat", "legend": "none",
"crossBetween": "midCat", "categories": CATS, "data": D}),
ch(BL, {"chartType": "column", "title": "crosses=max (Y crosses at top)", "legend": "none",
"crosses": "max", "categories": CATS, "data": D}),
# crossesAt is the overriding form of crosses in CT_ValAx (they are a
# mutually-exclusive schema choice). crosses=autoZero is the OOXML
# default that crossesAt supersedes, so we set crossesAt alone — the
# axis crosses the category axis at value 100.
ch(BR, {"chartType": "column", "title": "crossesAt=100 + crosses=autoZero",
"legend": "none", "crossesAt": "100",
"categories": CATS, "data": "A:60,-30,140,180"}),
]
# -----------------------------------------------------------------------
# Slide 4 — Category axis layout
# -----------------------------------------------------------------------
items += new_slide("Category axis — labeloffset, ticklabelskip")
items += [
ch(TL, {"chartType": "column", "title": "labeloffset=100 (default)",
"labeloffset": "100", "legend": "none",
"categories": "January,February,March,April,May,June",
"data": "A:60,90,140,180,160,210"}),
ch(TR, {"chartType": "column", "title": "labeloffset=300 (push labels down)",
"labeloffset": "300", "legend": "none",
"categories": "January,February,March,April,May,June",
"data": "A:60,90,140,180,160,210"}),
ch(BL, {"chartType": "column", "title": "ticklabelskip=2 (every other label)",
"ticklabelskip": "2", "legend": "none",
"categories": "Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec",
"data": "A:60,90,140,180,160,210,200,190,170,150,130,170"}),
ch(BR, {"chartType": "column", "title": "ticklabelskip=3", "ticklabelskip": "3", "legend": "none",
"categories": "Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec",
"data": "A:60,90,140,180,160,210,200,190,170,150,130,170"}),
]
# -----------------------------------------------------------------------
# Slide 5 — Marker size, area/chart fills, plotvisonly
# -----------------------------------------------------------------------
items += new_slide("Marker size & fills — markersize (standalone), areafill, chartFill, plotvisonly")
items += [
ch(TL, {"chartType": "line", "title": "markersize=12 (standalone key)",
"showMarker": "true", "markersize": "12", "legend": "none",
"categories": CATS, "data": D}),
ch(TR, {"chartType": "column", "title": "areafill (applies to every series shape)",
"areafill": "4472C4-A5C8FF:90", "legend": "none", "categories": CATS, "data": D2}),
ch(BL, {"chartType": "column", "title": "chartFill=#FFF8E7 (chart-level fill)",
"chartFill": "#FFF8E7", "legend": "none", "categories": CATS, "data": D}),
ch(BR, {"chartType": "column", "title": "plotvisonly=true (skip hidden rows when bound to a sheet)",
"plotvisonly": "true", "legend": "none", "categories": CATS, "data": D}),
]
# -----------------------------------------------------------------------
# Slide 6 — Built-in style id + dispBlanksAs
# -----------------------------------------------------------------------
items += new_slide("Built-in style & blank handling — style=1..48, dispBlanksAs, dataRange")
items += [
ch(TL, {"chartType": "column", "style": "2", "title": "style=2", "legend": "bottom",
"categories": CATS, "data": D2}),
ch(TR, {"chartType": "column", "style": "42", "title": "style=42", "legend": "bottom",
"categories": CATS, "data": D2}),
# dispBlanksAs is Set/Get only — Add first, then Set.
ch(BL, {"chartType": "line", "title": "dispBlanksAs=gap (Set after Add)", "showMarker": "true",
"legend": "bottom", "categories": CATS, "data": "A:60,90,140,180"}),
cset(f"/slide[{_slide}]/chart[3]", {"dispBlanksAs": "gap"}),
# dataRange is Add-time alternative to data= for sheet-backed sources;
# in a standalone pptx this is largely symbolic — we still demonstrate the syntax,
# then fall back to inline data so the chart renders.
ch(BR, {"chartType": "column", "title": "dataRange syntax demo (fallback inline)",
"dataRange": "Sheet1!A1:D5", "legend": "bottom", "catTitle": "Quarter",
"categories": CATS, "data": D2}),
]
# -----------------------------------------------------------------------
# Slide 7 — chart-axis Set (per-axis post-Add)
# -----------------------------------------------------------------------
items += new_slide("chart-axis Set — dispUnits, logBase, minorUnit, visible, labelRotation per-axis")
items += [
ch(TL, {"chartType": "column", "title": "after: dispUnits=thousands (Set on value axis)",
"legend": "none", "categories": CATS, "data": "Rev:120000,135000,148000,162000"}),
cset(f"/slide[{_slide}]/chart[1]/axis[@role=value]",
{"dispUnits": "thousands", "format": "#,##0", "minorUnit": "10000",
"labelRotation": "0", "visible": "true"}),
ch(TR, {"chartType": "line", "title": "after: logBase=10 (Set on value axis)",
"legend": "none", "categories": CATS, "data": "A:5,50,500,5000"}),
cset(f"/slide[{_slide}]/chart[2]/axis[@role=value]",
{"logBase": "10", "min": "1", "max": "10000", "majorGridlines": "true"}),
ch(BL, {"chartType": "column", "title": "after: visible=false on value axis",
"legend": "none", "categories": CATS, "data": D}),
cset(f"/slide[{_slide}]/chart[3]/axis[@role=value]", {"visible": "false"}),
ch(BR, {"chartType": "column", "title": "after: labelRotation=-45 on category axis",
"legend": "none", "categories": "January,February,March,April", "data": D}),
cset(f"/slide[{_slide}]/chart[4]/axis[@role=category]",
{"labelRotation": "-45", "title": "Month", "visible": "true"}),
]
# -----------------------------------------------------------------------
# Slide 8 — chart-series values=/categories= Set + Get readback round-trip
# -----------------------------------------------------------------------
items += new_slide("chart-series mutation — values=, categories= + get-readback round-trip")
s8 = _slide
items += [
ch(TL, {"chartType": "column", "title": "before: A=60,90,140,180", "legend": "bottom",
"categories": CATS, "data": D}),
# Mutate the values after add
cset(f"/slide[{s8}]/chart[1]/series[1]", {"values": "200,150,100,80"}),
note("0.3in", "4in", "After Set values=200,150,100,80 the series flips downward."),
ch(TR, {"chartType": "column", "title": "per-series categories= (range)", "legend": "bottom",
"categories": CATS, "data": D}),
# Per-series category override is range-only — note that it requires sheet backing
# so this is a demonstration of the syntax only; effective result depends on workbook.
]
# Ship the bulk of the deck in one round-trip (items applied in order, so the
# Add-then-Set pairs above resolve correctly). force=True → a prop the binary
# doesn't support is skipped rather than aborting the whole batch.
result = doc.batch(items, force=True)
# Forward-compat: surface any per-item failures so silent prop gaps stay visible.
fails = []
if isinstance(result, dict):
for r in (result.get("data", result).get("results", []) or []):
if isinstance(r, dict) and r.get("success") is False:
fails.append(r.get("error") or r.get("message") or str(r))
if fails:
print(f"{len(fails)} batch item(s) reported failure (forward-compat skip):",
file=sys.stderr)
for f in fails[:12]:
print(f"{str(f)[:160]}", file=sys.stderr)
print(f" added {len(items)} chart/shape/set operations across {_slide} slides")
# ---- chart-series get-readback round-trip (slide 8, chart 1, series 1) ----
# Change one series, then read it back and stamp the JSON onto the slide.
doc.send(cset(f"/slide[{s8}]/chart[1]/series[1]",
{"name": "Readback Demo", "color": "C00000"}))
doc.send({"command": "get", "path": f"/slide[{s8}]/chart[1]/series[1]"}) # readback round-trip
doc.send({"command": "add", "parent": f"/slide[{s8}]", "type": "shape",
"props": {"text": "chart-series get --json: readback fields alpha/outlineColor/scatterStyle/...",
"size": 9, "color": "222222", "x": "0.3in", "y": "4.25in",
"width": "6.1in", "height": "3in"}})
# ---- chart-axis get-readback — surfaces axisFont/axisMax/axisMin/axisNumFmt/
# axisOrientation/axisTitle/labelOffset/tickLabelSkip read-only fields.
doc.send(cset(f"/slide[{s8}]/chart[1]/axis[@role=value]",
{"title": "Readback Y", "format": "$#,##0", "min": "0", "max": "300", "majorUnit": "75"}))
doc.send({"command": "get", "path": f"/slide[{s8}]/chart[1]/axis[@role=value]"}) # readback round-trip
doc.send({"command": "add", "parent": f"/slide[{s8}]", "type": "shape",
"props": {"text": "chart-axis get --json: readback axisFont/axisMax/axisMin/axisNumFmt/axisOrientation/axisTitle/labelOffset/tickLabelSkip",
"size": 9, "color": "222222", "x": "6.95in", "y": "4.25in",
"width": "6.1in", "height": "3in"}})
doc.send({"command": "save"})
# context exit closes the resident, flushing the deck to disk.
print(f"Generated: {FILE} ({_slide} slides)")
+307
View File
@@ -0,0 +1,307 @@
#!/bin/bash
# Advanced Charts Showcase — properties not covered by the per-type decks.
# Generates: charts-advanced.pptx
#
# CLI twin of charts-advanced.py (officecli Python SDK). Both produce an
# equivalent charts-advanced.pptx.
#
# Slide 1 RTL & anchor direction=rtl, anchor cm-form
# Slide 2 Axis-level shortcuts axisvisible / valaxisvisible / catAxisVisible, orientation, position, lines
# Slide 3 Crossings crossBetween / crosses / crossesAt
# Slide 4 Categories axis labeloffset, ticklabelskip
# Slide 5 Marker size & fills markersize, areafill, chartFill, plotvisonly
# Slide 6 Built-in style + blanks style=1..48, dispBlanksAs, dataRange
# Slide 7 chart-axis Set dispUnits, logBase, minorUnit, visible, labelRotation
# Slide 8 chart-series mutation values=, categories= per-series
#
# Usage: ./charts-advanced.sh
# NOTE: intentionally NO `set -e`. Like the SDK twin's doc.batch, this script
# tolerates forward-compat 'UNSUPPORTED props' warnings (officecli exit 2) and
# keeps building so the full document is produced.
FILE="$(dirname "$0")/charts-advanced.pptx"
rm -f "$FILE"
officecli create "$FILE"
officecli open "$FILE"
# ===========================================================================
# Slide 1 — RTL + anchor variants
# ===========================================================================
officecli add "$FILE" / --type slide
officecli add "$FILE" "/slide[1]" --type shape \
--prop text="RTL + anchor — direction=rtl, named-token anchor, cm-form anchor" \
--prop size=24 --prop bold=true --prop autoFit=normal \
--prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
officecli add "$FILE" "/slide[1]" --type chart \
--prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in \
--prop chartType=column --prop title="default (LTR)" --prop legend=bottom \
--prop categories=Q1,Q2,Q3,Q4 --prop "data=A:60,90,140,180;B:50,75,110,150"
# RTL must be Set after Add (direction is set-only)
officecli add "$FILE" "/slide[1]" --type chart \
--prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in \
--prop chartType=column --prop title="direction=rtl (Set after Add)" --prop legend=bottom \
--prop categories=Q1,Q2,Q3,Q4 --prop "data=A:60,90,140,180;B:50,75,110,150"
officecli set "$FILE" "/slide[1]/chart[2]" --prop direction=rtl
# Anchor cm-form: x,y,w,h
officecli add "$FILE" "/slide[1]" --type chart \
--prop anchor=0.3cm,11cm,15.5cm,7cm \
--prop chartType=column --prop title="anchor=0.3cm,11cm,15.5cm,7cm" --prop legend=bottom \
--prop categories=Q1,Q2,Q3,Q4 --prop "data=A:60,90,140,180"
# ===========================================================================
# Slide 2 — axis-level shortcuts
# ===========================================================================
officecli add "$FILE" / --type slide
officecli add "$FILE" "/slide[2]" --type shape \
--prop text="Axis shortcuts — axisvisible / valaxisvisible / catAxisVisible, orientation, position, lines" \
--prop size=24 --prop bold=true --prop autoFit=normal \
--prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
officecli add "$FILE" "/slide[2]" --type chart \
--prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in \
--prop chartType=column --prop title="axisvisible=false (both axes hidden)" \
--prop legend=none --prop axisvisible=false --prop categories=Q1,Q2,Q3,Q4 --prop "data=A:60,90,140,180"
officecli add "$FILE" "/slide[2]" --type chart \
--prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in \
--prop chartType=column --prop title="valaxisvisible=false (Y hidden, X shown)" \
--prop legend=none --prop valaxisvisible=false --prop categories=Q1,Q2,Q3,Q4 --prop "data=A:60,90,140,180"
officecli add "$FILE" "/slide[2]" --type chart \
--prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in \
--prop chartType=column --prop title="catAxisVisible=false (X hidden)" \
--prop legend=none --prop catAxisVisible=false --prop categories=Q1,Q2,Q3,Q4 --prop "data=A:60,90,140,180"
officecli add "$FILE" "/slide[2]" --type chart \
--prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in \
--prop chartType=column --prop title="axisorientation=true (reversed) + axisposition=top" \
--prop legend=none --prop axisorientation=true --prop axisposition=top \
--prop cataxisline=333333:1 --prop valaxisline=333333:1 \
--prop categories=Q1,Q2,Q3,Q4 --prop "data=A:60,90,140,180"
# ===========================================================================
# Slide 3 — Crossings
# ===========================================================================
officecli add "$FILE" / --type slide
officecli add "$FILE" "/slide[3]" --type shape \
--prop text="Crossings — crossBetween / crosses / crossesAt" \
--prop size=24 --prop bold=true --prop autoFit=normal \
--prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
officecli add "$FILE" "/slide[3]" --type chart \
--prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in \
--prop chartType=column --prop title="crossBetween=between (default)" \
--prop legend=none --prop crossBetween=between --prop categories=Q1,Q2,Q3,Q4 --prop "data=A:60,90,140,180"
officecli add "$FILE" "/slide[3]" --type chart \
--prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in \
--prop chartType=column --prop title="crossBetween=midCat" \
--prop legend=none --prop crossBetween=midCat --prop categories=Q1,Q2,Q3,Q4 --prop "data=A:60,90,140,180"
officecli add "$FILE" "/slide[3]" --type chart \
--prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in \
--prop chartType=column --prop title="crosses=max (Y crosses at top)" \
--prop legend=none --prop crosses=max --prop categories=Q1,Q2,Q3,Q4 --prop "data=A:60,90,140,180"
# crossesAt is the overriding form of crosses in CT_ValAx (mutually-exclusive
# schema choice). crosses=autoZero is the OOXML default crossesAt supersedes,
# so we set crossesAt alone — the axis crosses the category axis at value 100.
officecli add "$FILE" "/slide[3]" --type chart \
--prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in \
--prop chartType=column --prop title="crossesAt=100 + crosses=autoZero" \
--prop legend=none --prop crossesAt=100 \
--prop categories=Q1,Q2,Q3,Q4 --prop "data=A:60,-30,140,180"
# ===========================================================================
# Slide 4 — Category axis layout
# ===========================================================================
officecli add "$FILE" / --type slide
officecli add "$FILE" "/slide[4]" --type shape \
--prop text="Category axis — labeloffset, ticklabelskip" \
--prop size=24 --prop bold=true --prop autoFit=normal \
--prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
officecli add "$FILE" "/slide[4]" --type chart \
--prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in \
--prop chartType=column --prop title="labeloffset=100 (default)" \
--prop labeloffset=100 --prop legend=none \
--prop categories=January,February,March,April,May,June \
--prop "data=A:60,90,140,180,160,210"
officecli add "$FILE" "/slide[4]" --type chart \
--prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in \
--prop chartType=column --prop title="labeloffset=300 (push labels down)" \
--prop labeloffset=300 --prop legend=none \
--prop categories=January,February,March,April,May,June \
--prop "data=A:60,90,140,180,160,210"
officecli add "$FILE" "/slide[4]" --type chart \
--prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in \
--prop chartType=column --prop title="ticklabelskip=2 (every other label)" \
--prop ticklabelskip=2 --prop legend=none \
--prop categories=Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec \
--prop "data=A:60,90,140,180,160,210,200,190,170,150,130,170"
officecli add "$FILE" "/slide[4]" --type chart \
--prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in \
--prop chartType=column --prop title="ticklabelskip=3" \
--prop ticklabelskip=3 --prop legend=none \
--prop categories=Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec \
--prop "data=A:60,90,140,180,160,210,200,190,170,150,130,170"
# ===========================================================================
# Slide 5 — Marker size, area/chart fills, plotvisonly
# ===========================================================================
officecli add "$FILE" / --type slide
officecli add "$FILE" "/slide[5]" --type shape \
--prop text="Marker size & fills — markersize (standalone), areafill, chartFill, plotvisonly" \
--prop size=24 --prop bold=true --prop autoFit=normal \
--prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
officecli add "$FILE" "/slide[5]" --type chart \
--prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in \
--prop chartType=line --prop title="markersize=12 (standalone key)" \
--prop showMarker=true --prop markersize=12 --prop legend=none \
--prop categories=Q1,Q2,Q3,Q4 --prop "data=A:60,90,140,180"
officecli add "$FILE" "/slide[5]" --type chart \
--prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in \
--prop chartType=column --prop title="areafill (applies to every series shape)" \
--prop areafill=4472C4-A5C8FF:90 --prop legend=none \
--prop categories=Q1,Q2,Q3,Q4 --prop "data=A:60,90,140,180;B:50,75,110,150"
officecli add "$FILE" "/slide[5]" --type chart \
--prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in \
--prop chartType=column --prop title="chartFill=#FFF8E7 (chart-level fill)" \
--prop chartFill=#FFF8E7 --prop legend=none \
--prop categories=Q1,Q2,Q3,Q4 --prop "data=A:60,90,140,180"
officecli add "$FILE" "/slide[5]" --type chart \
--prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in \
--prop chartType=column --prop title="plotvisonly=true (skip hidden rows when bound to a sheet)" \
--prop plotvisonly=true --prop legend=none \
--prop categories=Q1,Q2,Q3,Q4 --prop "data=A:60,90,140,180"
# ===========================================================================
# Slide 6 — Built-in style id + dispBlanksAs
# ===========================================================================
officecli add "$FILE" / --type slide
officecli add "$FILE" "/slide[6]" --type shape \
--prop text="Built-in style & blank handling — style=1..48, dispBlanksAs, dataRange" \
--prop size=24 --prop bold=true --prop autoFit=normal \
--prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
officecli add "$FILE" "/slide[6]" --type chart \
--prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in \
--prop chartType=column --prop style=2 --prop title="style=2" --prop legend=bottom \
--prop categories=Q1,Q2,Q3,Q4 --prop "data=A:60,90,140,180;B:50,75,110,150"
officecli add "$FILE" "/slide[6]" --type chart \
--prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in \
--prop chartType=column --prop style=42 --prop title="style=42" --prop legend=bottom \
--prop categories=Q1,Q2,Q3,Q4 --prop "data=A:60,90,140,180;B:50,75,110,150"
# dispBlanksAs is Set/Get only — Add first, then Set.
officecli add "$FILE" "/slide[6]" --type chart \
--prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in \
--prop chartType=line --prop title="dispBlanksAs=gap (Set after Add)" --prop showMarker=true \
--prop legend=bottom --prop categories=Q1,Q2,Q3,Q4 --prop "data=A:60,90,140,180"
officecli set "$FILE" "/slide[6]/chart[3]" --prop dispBlanksAs=gap
# dataRange is Add-time alternative to data= for sheet-backed sources;
# in a standalone pptx this is largely symbolic — demonstrate the syntax,
# then fall back to inline data so the chart renders.
officecli add "$FILE" "/slide[6]" --type chart \
--prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in \
--prop chartType=column --prop title="dataRange syntax demo (fallback inline)" \
--prop dataRange=Sheet1!A1:D5 --prop legend=bottom --prop catTitle=Quarter \
--prop categories=Q1,Q2,Q3,Q4 --prop "data=A:60,90,140,180;B:50,75,110,150"
# ===========================================================================
# Slide 7 — chart-axis Set (per-axis post-Add)
# ===========================================================================
officecli add "$FILE" / --type slide
officecli add "$FILE" "/slide[7]" --type shape \
--prop text="chart-axis Set — dispUnits, logBase, minorUnit, visible, labelRotation per-axis" \
--prop size=24 --prop bold=true --prop autoFit=normal \
--prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
officecli add "$FILE" "/slide[7]" --type chart \
--prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in \
--prop chartType=column --prop title="after: dispUnits=thousands (Set on value axis)" \
--prop legend=none --prop categories=Q1,Q2,Q3,Q4 --prop "data=Rev:120000,135000,148000,162000"
officecli set "$FILE" "/slide[7]/chart[1]/axis[@role=value]" \
--prop dispUnits=thousands --prop format=#,##0 --prop minorUnit=10000 \
--prop labelRotation=0 --prop visible=true
officecli add "$FILE" "/slide[7]" --type chart \
--prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in \
--prop chartType=line --prop title="after: logBase=10 (Set on value axis)" \
--prop legend=none --prop categories=Q1,Q2,Q3,Q4 --prop "data=A:5,50,500,5000"
officecli set "$FILE" "/slide[7]/chart[2]/axis[@role=value]" \
--prop logBase=10 --prop min=1 --prop max=10000 --prop majorGridlines=true
officecli add "$FILE" "/slide[7]" --type chart \
--prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in \
--prop chartType=column --prop title="after: visible=false on value axis" \
--prop legend=none --prop categories=Q1,Q2,Q3,Q4 --prop "data=A:60,90,140,180"
officecli set "$FILE" "/slide[7]/chart[3]/axis[@role=value]" --prop visible=false
officecli add "$FILE" "/slide[7]" --type chart \
--prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in \
--prop chartType=column --prop title="after: labelRotation=-45 on category axis" \
--prop legend=none --prop categories=January,February,March,April --prop "data=A:60,90,140,180"
officecli set "$FILE" "/slide[7]/chart[4]/axis[@role=category]" \
--prop labelRotation=-45 --prop title=Month --prop visible=true
# ===========================================================================
# Slide 8 — chart-series values=/categories= Set + Get readback round-trip
# ===========================================================================
officecli add "$FILE" / --type slide
officecli add "$FILE" "/slide[8]" --type shape \
--prop text="chart-series mutation — values=, categories= + get-readback round-trip" \
--prop size=24 --prop bold=true --prop autoFit=normal \
--prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
officecli add "$FILE" "/slide[8]" --type chart \
--prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in \
--prop chartType=column --prop title="before: A=60,90,140,180" --prop legend=bottom \
--prop categories=Q1,Q2,Q3,Q4 --prop "data=A:60,90,140,180"
# Mutate the values after add
officecli set "$FILE" "/slide[8]/chart[1]/series[1]" --prop "values=200,150,100,80"
officecli add "$FILE" "/slide[8]" --type shape \
--prop text="After Set values=200,150,100,80 the series flips downward." \
--prop size=10 --prop italic=true --prop color=666666 \
--prop x=0.3in --prop y=4in --prop width=6in --prop height=0.4in
officecli add "$FILE" "/slide[8]" --type chart \
--prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in \
--prop chartType=column --prop title="per-series categories= (range)" --prop legend=bottom \
--prop categories=Q1,Q2,Q3,Q4 --prop "data=A:60,90,140,180"
# Per-series category override is range-only — requires sheet backing, so this is
# a demonstration of the syntax only; effective result depends on workbook.
# Round-trip: change one series, read it back, stamp the JSON onto the slide.
officecli set "$FILE" "/slide[8]/chart[1]/series[1]" --prop name="Readback Demo" --prop color=C00000
officecli get "$FILE" "/slide[8]/chart[1]/series[1]" --json
officecli add "$FILE" "/slide[8]" --type shape \
--prop text="chart-series get --json: readback fields alpha/outlineColor/scatterStyle/..." \
--prop size=9 --prop color=222222 \
--prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in
# chart-axis get-readback — surfaces axisFont/axisMax/axisMin/axisNumFmt/
# axisOrientation/axisTitle/labelOffset/tickLabelSkip read-only fields.
officecli set "$FILE" "/slide[8]/chart[1]/axis[@role=value]" \
--prop title="Readback Y" --prop format=$#,##0 --prop min=0 --prop max=300 --prop majorUnit=75
officecli get "$FILE" "/slide[8]/chart[1]/axis[@role=value]" --json
officecli add "$FILE" "/slide[8]" --type shape \
--prop text="chart-axis get --json: readback axisFont/axisMax/axisMin/axisNumFmt/axisOrientation/axisTitle/labelOffset/tickLabelSkip" \
--prop size=9 --prop color=222222 \
--prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in
officecli close "$FILE"
officecli validate "$FILE"
echo "Generated: $FILE"
+283
View File
@@ -0,0 +1,283 @@
# Area Charts Showcase
This demo consists of three files that work together:
- **charts-area.py** — Python script that calls `officecli` commands to generate the deck.
- **charts-area.pptx** — The generated 8-slide deck (4 charts per slide, 32 charts total).
- **charts-area.md** — This file. Maps each slide to the features it demonstrates.
## Regenerate
```bash
cd examples/ppt/charts
python3 charts-area.py
# → charts-area.pptx
```
## Chart Slides
### Slide 1 — Variants
```bash
officecli add charts-area.pptx /slide[1] --type chart \
--prop chartType=area --prop title="area" --prop legend=bottom \
--prop categories="Mon,Tue,Wed,Thu,Fri" \
--prop data="Web:50,60,70,65,80;Mobile:30,35,42,48,55" \
--prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in
officecli add charts-area.pptx /slide[1] --type chart \
--prop chartType=stackedArea --prop title="stackedArea" --prop legend=bottom \
--prop categories="Mon,Tue,Wed,Thu,Fri" \
--prop data="Web:50,60,70,65,80;Mobile:30,35,42,48,55" \
--prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in
officecli add charts-area.pptx /slide[1] --type chart \
--prop chartType=percentStackedArea --prop title="percentStackedArea" \
--prop legend=bottom \
--prop categories="Mon,Tue,Wed,Thu,Fri" \
--prop data="Web:50,60,70,65,80;Mobile:30,35,42,48,55" \
--prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in
officecli add charts-area.pptx /slide[1] --type chart \
--prop chartType=area3d --prop title="area3d" --prop view3d="15,20,30" \
--prop legend=bottom \
--prop categories="Mon,Tue,Wed,Thu,Fri" \
--prop data="Web:50,60,70,65,80;Mobile:30,35,42,48,55" \
--prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in
```
**Features:** `chartType` (area/stackedArea/percentStackedArea/area3d), `view3d`
### Slide 2 — Title and Legend
```bash
officecli add charts-area.pptx /slide[2] --type chart \
--prop chartType=area --prop title="Styled title" \
--prop title.font=Georgia --prop title.size=20 \
--prop title.color=4472C4 --prop title.bold=true \
--prop legend=bottom \
--prop categories="Mon,Tue,Wed,Thu,Fri" \
--prop data="Web:50,60,70,65,80;Mobile:30,35,42,48,55"
officecli add charts-area.pptx /slide[2] --type chart \
--prop chartType=area --prop title="legend=top + legendFont" \
--prop legend=top --prop legendFont="10:333333:Calibri" \
--prop categories="Mon,Tue,Wed,Thu,Fri" \
--prop data="Web:50,60,70,65,80;Mobile:30,35,42,48,55"
officecli add charts-area.pptx /slide[2] --type chart \
--prop chartType=area --prop title="legend.overlay=true" \
--prop legend=topRight --prop legend.overlay=true \
--prop categories="Mon,Tue,Wed,Thu,Fri" \
--prop data="Web:50,60,70,65,80;Mobile:30,35,42,48,55"
officecli add charts-area.pptx /slide[2] --type chart \
--prop chartType=area --prop autotitledeleted=true --prop legend=none \
--prop categories="Mon,Tue,Wed,Thu,Fri" \
--prop data="Web:50,60,70,65,80;Mobile:30,35,42,48,55"
```
**Features:** `title.font/size/color/bold`, `legend` positions, `legendFont`, `legend.overlay`, `autotitledeleted`
### Slide 3 — Data Labels
```bash
officecli add charts-area.pptx /slide[3] --type chart \
--prop chartType=area --prop title="dataLabels=value" \
--prop dataLabels=value --prop labelfont="10:333333:Calibri" --prop legend=none \
--prop categories="Mon,Tue,Wed,Thu,Fri" --prop data="A:50,60,70,65,80"
officecli add charts-area.pptx /slide[3] --type chart \
--prop chartType=stackedArea --prop title="stacked + center labels" \
--prop dataLabels=value --prop labelPos=center --prop legend=bottom \
--prop categories="Mon,Tue,Wed,Thu,Fri" \
--prop data="Web:50,60,70,65,80;Mobile:30,35,42,48,55"
officecli add charts-area.pptx /slide[3] --type chart \
--prop chartType=area --prop title="value,category" \
--prop dataLabels="value,category" --prop labelfont="9:333333:Calibri" \
--prop legend=none \
--prop categories="Mon,Tue,Wed,Thu,Fri" --prop data="A:50,60,70,65,80"
officecli add charts-area.pptx /slide[3] --type chart \
--prop chartType=area --prop title="dataLabels=none" \
--prop dataLabels=none --prop legend=none \
--prop categories="Mon,Tue,Wed,Thu,Fri" --prop data="A:50,60,70,65,80"
```
**Features:** `dataLabels` (value/category/none or combined), `labelPos` (center), `labelfont`
### Slide 4 — Axes
```bash
officecli add charts-area.pptx /slide[4] --type chart \
--prop chartType=area --prop title="min/max + titles" --prop legend=none \
--prop axismin=0 --prop axismax=100 --prop majorunit=25 \
--prop axistitle="Value" --prop cattitle="Day" \
--prop axisfont="10:333333:Calibri" --prop axisline="666666:1" \
--prop axisnumfmt="#,##0" \
--prop categories="Mon,Tue,Wed,Thu,Fri" --prop data="A:50,60,70,65,80"
officecli add charts-area.pptx /slide[4] --type chart \
--prop chartType=area --prop title="gridlines + ticks" --prop legend=none \
--prop gridlines="E0E0E0:0.3" --prop minorGridlines="F0F0F0:0.25" \
--prop majorTickMark=out --prop minorTickMark=in --prop tickLabelPos=nextTo \
--prop categories="Mon,Tue,Wed,Thu,Fri" --prop data="A:50,60,70,65,80"
officecli add charts-area.pptx /slide[4] --type chart \
--prop chartType=area --prop title="labelrotation=-30" --prop legend=none \
--prop labelrotation=-30 \
--prop categories="January,February,March,April,May,June" \
--prop data="A:60,90,140,180,160,210"
officecli add charts-area.pptx /slide[4] --type chart \
--prop chartType=area --prop title="dispunits=thousands" --prop legend=none \
--prop dispunits=thousands \
--prop categories="Mon,Tue,Wed,Thu,Fri" \
--prop data="Rev:120000,135000,148000,162000,180000"
```
**Features:** `axismin/max`, `majorunit`, `axistitle/cattitle`, `axisfont/axisline/axisnumfmt`, `gridlines/minorGridlines`, `majorTickMark/minorTickMark/tickLabelPos`, `labelrotation`, `dispunits`
### Slide 5 — Series Styling
```bash
officecli add charts-area.pptx /slide[5] --type chart \
--prop chartType=area --prop title="colors + seriesoutline" --prop legend=bottom \
--prop colors="4472C4,ED7D31" --prop seriesoutline="000000:0.5" \
--prop categories="Mon,Tue,Wed,Thu,Fri" \
--prop data="Web:50,60,70,65,80;Mobile:30,35,42,48,55"
officecli add charts-area.pptx /slide[5] --type chart \
--prop chartType=area --prop title="gradient + seriesshadow" --prop legend=none \
--prop gradient="FF6600-FFCC00:90" --prop seriesshadow="000000-5-45-3-50" \
--prop categories="Mon,Tue,Wed,Thu,Fri" --prop data="A:50,60,70,65,80"
officecli add charts-area.pptx /slide[5] --type chart \
--prop chartType=area --prop title="per-series gradients + transparency=30" \
--prop gradients="FF0000-0000FF;00FF00-FFFF00" --prop transparency=30 \
--prop legend=bottom \
--prop categories="Mon,Tue,Wed,Thu,Fri" \
--prop data="Web:50,60,70,65,80;Mobile:30,35,42,48,55"
officecli add charts-area.pptx /slide[5] --type chart \
--prop chartType=area --prop title="single + transparency=50" \
--prop transparency=50 --prop colors="4472C4" --prop legend=none \
--prop categories="Mon,Tue,Wed,Thu,Fri" --prop data="A:50,60,70,65,80"
```
**Features:** `colors`, `seriesoutline`, `gradient`, `seriesshadow`, `gradients`, `transparency`
### Slide 6 — Overlays
```bash
officecli add charts-area.pptx /slide[6] --type chart \
--prop chartType=area --prop title="referenceline=60" --prop legend=none \
--prop referenceline="60:FF0000:Target" \
--prop categories="Mon,Tue,Wed,Thu,Fri" --prop data="A:50,60,70,65,80"
officecli add charts-area.pptx /slide[6] --type chart \
--prop chartType=area --prop title="errbars=percentage:10" --prop legend=none \
--prop errbars="percentage:10" \
--prop categories="Mon,Tue,Wed,Thu,Fri" --prop data="A:50,60,70,65,80"
officecli add charts-area.pptx /slide[6] --type chart \
--prop chartType=area --prop title="trendline=linear" --prop legend=none \
--prop trendline=linear \
--prop categories="Mon,Tue,Wed,Thu,Fri" --prop data="A:50,60,70,65,80"
officecli add charts-area.pptx /slide[6] --type chart \
--prop chartType=area --prop title="trendline=movingAvg:3" --prop legend=none \
--prop trendline="movingAvg:3" \
--prop categories="Mon,Tue,Wed,Thu,Fri" --prop data="A:50,60,70,65,80"
```
**Features:** `referenceline`, `errbars`, `trendline` (linear/poly/exp/log/power/movingAvg)
### Slide 7 — Backgrounds
```bash
officecli add charts-area.pptx /slide[7] --type chart \
--prop chartType=area --prop title="chartareafill + plotFill + borders" \
--prop legend=bottom \
--prop chartareafill=FFF8E7 --prop plotFill=FAFAFA \
--prop chartborder="000000:1" --prop plotborder="CCCCCC:0.5" \
--prop categories="Mon,Tue,Wed,Thu,Fri" \
--prop data="Web:50,60,70,65,80;Mobile:30,35,42,48,55"
officecli add charts-area.pptx /slide[7] --type chart \
--prop chartType=area --prop title="roundedcorners=true" \
--prop roundedcorners=true --prop chartborder="4472C4:2" --prop legend=bottom \
--prop categories="Mon,Tue,Wed,Thu,Fri" \
--prop data="Web:50,60,70,65,80;Mobile:30,35,42,48,55"
officecli add charts-area.pptx /slide[7] --type chart \
--prop chartType=area --prop title="plotFill=none" \
--prop plotFill=none --prop gridlines=none --prop legend=none \
--prop categories="Mon,Tue,Wed,Thu,Fri" --prop data="A:50,60,70,65,80"
officecli add charts-area.pptx /slide[7] --type chart \
--prop chartType=area --prop title="dataTable=true" \
--prop dataTable=true --prop legend=bottom \
--prop categories="Mon,Tue,Wed,Thu,Fri" \
--prop data="Web:50,60,70,65,80;Mobile:30,35,42,48,55"
```
**Features:** `chartareafill`, `plotFill`, `chartborder`, `plotborder`, `roundedcorners`, `gridlines=none`, `dataTable`
### Slide 8 — Presets and Per-Series Control
```bash
for p in minimal dark corporate; do
officecli add charts-area.pptx /slide[8] --type chart \
--prop chartType=area --prop preset=$p --prop title="preset=$p" \
--prop legend=bottom --prop categories="Mon,Tue,Wed,Thu,Fri" \
--prop data="Web:50,60,70,65,80;Mobile:30,35,42,48,55"
done
officecli add charts-area.pptx /slide[8] --type chart \
--prop chartType=area --prop title="seriesN.* + chart-series Set" \
--prop legend=bottom --prop categories="Mon,Tue,Wed,Thu,Fri" \
--prop series1.name="Web" --prop series1.values="50,60,70,65,80" \
--prop series1.color=4472C4 \
--prop series2.name="Mobile" --prop series2.values="30,35,42,48,55" \
--prop series2.color=ED7D31
officecli set charts-area.pptx "/slide[8]/chart[4]/series[1]" \
--prop name="Renamed Web" --prop color=C00000
```
**Features:** `preset`, `series1.name/values/color`, `chart-series Set`
## Complete Feature Coverage
| Feature | Slide |
|---------|-------|
| **Chart types:** area, stackedArea, percentStackedArea, area3d | 1 |
| **view3d** | 1 |
| **title.font/size/color/bold** | 2 |
| **legend** positions, legendFont, legend.overlay | 2 |
| **autotitledeleted** | 2 |
| **dataLabels:** value/category/none + combined | 3 |
| **labelPos** (center) | 3 |
| **labelfont** | 3 |
| **axismin/max**, majorunit, axistitle/cattitle | 4 |
| **axisfont**, axisline, axisnumfmt | 4 |
| **gridlines**, minorGridlines, tickmarks | 4 |
| **labelrotation**, dispunits | 4 |
| **colors**, seriesoutline, gradient, seriesshadow | 5 |
| **gradients** (per-series), transparency | 5 |
| **referenceline**, errbars | 6 |
| **trendline** (linear/movingAvg) | 6 |
| **chartareafill**, plotFill, chartborder, plotborder | 7 |
| **roundedcorners**, gridlines=none, dataTable | 7 |
| **preset**, seriesN.*, chart-series Set | 8 |
## Inspect the Generated File
```bash
officecli query charts-area.pptx chart
officecli get charts-area.pptx "/slide[1]/chart[1]"
officecli get charts-area.pptx "/slide[5]/chart[1]"
officecli get charts-area.pptx "/slide[8]/chart[4]/series[1]"
```
Binary file not shown.
+179
View File
@@ -0,0 +1,179 @@
#!/usr/bin/env python3
"""
Area Charts Showcase — area, stackedArea, percentStackedArea, area3d.
Generates: charts-area.pptx
Slide 1 Variants area / stackedArea / percentStackedArea / area3d
Slide 2 Title & legend title.* + legend positions + legendFont
Slide 3 Data labels flags + labelPos + labelfont
Slide 4 Axes min/max, titles, fonts, gridlines, ticks, labelrotation
Slide 5 Series styling colors, gradient, gradients, transparency, seriesoutline, seriesshadow
Slide 6 Overlays referenceline, errbars, trendline
Slide 7 Backgrounds chartareafill, plotFill, chartborder, plotborder, roundedcorners
Slide 8 Presets & per-ser preset bundles + seriesN.* + chart-series Set
SDK twin of charts-area.sh (officecli CLI). Both produce an equivalent
charts-area.pptx. This one drives the **officecli Python SDK**
(`pip install officecli-sdk`): one resident is started and every slide, title
shape and chart is shipped over the named pipe in a single `doc.batch(...)`
round-trip. Each item is the same `{"command","parent","type","props"}` dict
you'd put in an `officecli batch` list — slides are added before the charts
that reference them, so in-order batch application keeps `/slide[N]` valid.
Forward-compat: any prop the running officecli build doesn't yet support is
reported as an `unsupported_property` warning in the batch envelope rather than
aborting the run (batch defaults to stop_on_error=False) — the showcase still
builds, and the gaps stay visible in the returned envelope.
Usage:
pip install officecli-sdk # plus the `officecli` binary on PATH
python3 charts-area.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__)), "charts-area.pptx")
# Four quadrant boxes — same layout the CLI twin uses for every slide.
TL = {"x": "0.3in", "y": "1.05in", "width": "6.1in", "height": "3in"}
TR = {"x": "6.95in", "y": "1.05in", "width": "6.1in", "height": "3in"}
BL = {"x": "0.3in", "y": "4.25in", "width": "6.1in", "height": "3in"}
BR = {"x": "6.95in", "y": "4.25in", "width": "6.1in", "height": "3in"}
CATS = "Mon,Tue,Wed,Thu,Fri"
D = "A:50,60,70,65,80"
D2 = "Web:50,60,70,65,80;Mobile:30,35,42,48,55"
# slide counter shared by the two builders below
_slide = 0
def new_slide(title, items):
"""Append one `add slide` + its title `add shape` to `items`; return slide #."""
global _slide
_slide += 1
items.append({"command": "add", "parent": "/", "type": "slide", "props": {}})
items.append({"command": "add", "parent": f"/slide[{_slide}]", "type": "shape",
"props": {"text": title, "size": 24, "bold": "true", "autoFit": "normal",
"x": "0.5in", "y": "0.3in", "width": "12.3in", "height": "0.6in"}})
return _slide
def ch(items, box, props):
"""Append one `add chart` (box + chart props) to the current slide."""
items.append({"command": "add", "parent": f"/slide[{_slide}]", "type": "chart",
"props": {**box, **props}})
print(f"Building {FILE} ...")
with officecli.create(FILE, "--force") as doc:
items = []
# ============ Slide 1: variants ============
new_slide("Area variants — area / stackedArea / percentStackedArea / area3d", items)
ch(items, TL, {"chartType": "area", "title": "area", "legend": "bottom", "categories": CATS, "data": D2})
ch(items, TR, {"chartType": "stackedArea", "title": "stackedArea", "legend": "bottom", "categories": CATS, "data": D2})
ch(items, BL, {"chartType": "percentStackedArea", "title": "percentStackedArea", "legend": "bottom", "categories": CATS, "data": D2})
ch(items, BR, {"chartType": "area3d", "title": "area3d", "view3d": "15,20,30", "legend": "bottom", "categories": CATS, "data": D2})
# ============ Slide 2: title & legend ============
new_slide("Title & legend", items)
ch(items, TL, {"chartType": "area", "title": "Styled title", "title.font": "Georgia", "title.size": "20",
"title.color": "4472C4", "title.bold": "true", "legend": "bottom", "categories": CATS, "data": D2})
ch(items, TR, {"chartType": "area", "title": "legend=top + legendFont", "legend": "top",
"legendFont": "10:333333:Calibri", "categories": CATS, "data": D2})
ch(items, BL, {"chartType": "area", "title": "legend.overlay=true", "legend": "topRight",
"legend.overlay": "true", "categories": CATS, "data": D2})
ch(items, BR, {"chartType": "area", "autotitledeleted": "true", "legend": "none", "categories": CATS, "data": D2})
# ============ Slide 3: data labels ============
new_slide("Data labels — flags, labelPos, labelfont", items)
ch(items, TL, {"chartType": "area", "title": "dataLabels=value", "dataLabels": "value",
"labelfont": "10:333333:Calibri", "legend": "none", "categories": CATS, "data": D})
ch(items, TR, {"chartType": "stackedArea", "title": "stacked + center labels", "dataLabels": "value",
"labelPos": "center", "legend": "bottom", "categories": CATS, "data": D2})
ch(items, BL, {"chartType": "area", "title": "value,category", "dataLabels": "value,category",
"labelfont": "9:333333:Calibri", "legend": "none", "categories": CATS, "data": D})
ch(items, BR, {"chartType": "area", "title": "dataLabels=none", "dataLabels": "none", "legend": "none",
"categories": CATS, "data": D})
# ============ Slide 4: axes ============
new_slide("Axes — min/max, gridlines, ticks, labelrotation", items)
ch(items, TL, {"chartType": "area", "title": "min/max + titles", "legend": "none",
"axismin": "0", "axismax": "100", "majorunit": "25", "axistitle": "Value", "cattitle": "Day",
"axisfont": "10:333333:Calibri", "axisline": "666666:1", "axisnumfmt": "#,##0",
"categories": CATS, "data": D})
ch(items, TR, {"chartType": "area", "title": "gridlines + ticks", "legend": "none",
"gridlines": "E0E0E0:0.3", "minorGridlines": "F0F0F0:0.25",
"majorTickMark": "out", "minorTickMark": "in", "tickLabelPos": "nextTo",
"categories": CATS, "data": D})
ch(items, BL, {"chartType": "area", "title": "labelrotation=-30", "legend": "none", "labelrotation": "-30",
"categories": "January,February,March,April,May,June", "data": "A:60,90,140,180,160,210"})
ch(items, BR, {"chartType": "area", "title": "dispunits=thousands", "legend": "none", "dispunits": "thousands",
"categories": CATS, "data": "Rev:120000,135000,148000,162000,180000"})
# ============ Slide 5: series styling ============
new_slide("Series styling — colors, gradient(s), transparency, outline, shadow", items)
ch(items, TL, {"chartType": "area", "title": "colors + seriesoutline", "legend": "bottom",
"colors": "4472C4,ED7D31", "seriesoutline": "000000:0.5", "categories": CATS, "data": D2})
ch(items, TR, {"chartType": "area", "title": "gradient + seriesshadow", "legend": "none",
"gradient": "FF6600-FFCC00:90", "seriesshadow": "000000-5-45-3-50",
"categories": CATS, "data": D})
ch(items, BL, {"chartType": "area", "title": "per-series gradients + transparency=30",
"gradients": "FF0000-0000FF;00FF00-FFFF00", "transparency": "30",
"legend": "bottom", "categories": CATS, "data": D2})
ch(items, BR, {"chartType": "area", "title": "single + transparency=50", "transparency": "50",
"colors": "4472C4", "legend": "none", "categories": CATS, "data": D})
# ============ Slide 6: overlays ============
new_slide("Overlays — referenceline, errbars, trendline", items)
ch(items, TL, {"chartType": "area", "title": "referenceline=60", "referenceline": "60:FF0000:Target",
"legend": "none", "categories": CATS, "data": D})
ch(items, TR, {"chartType": "area", "title": "errbars=percentage:10", "errbars": "percentage:10",
"legend": "none", "categories": CATS, "data": D})
ch(items, BL, {"chartType": "area", "title": "trendline=linear", "trendline": "linear",
"legend": "none", "categories": CATS, "data": D})
ch(items, BR, {"chartType": "area", "title": "trendline=movingAvg:3", "trendline": "movingAvg:3",
"legend": "none", "categories": CATS, "data": D})
# ============ Slide 7: backgrounds ============
new_slide("Backgrounds — chartareafill, plotFill, chartborder, plotborder, roundedcorners", items)
ch(items, TL, {"chartType": "area", "title": "chartareafill + plotFill + borders", "legend": "bottom",
"chartareafill": "FFF8E7", "plotFill": "FAFAFA", "chartborder": "000000:1",
"plotborder": "CCCCCC:0.5", "categories": CATS, "data": D2})
ch(items, TR, {"chartType": "area", "title": "roundedcorners=true", "roundedcorners": "true",
"chartborder": "4472C4:2", "legend": "bottom", "categories": CATS, "data": D2})
ch(items, BL, {"chartType": "area", "title": "plotFill=none", "plotFill": "none", "gridlines": "none",
"legend": "none", "categories": CATS, "data": D})
ch(items, BR, {"chartType": "area", "title": "dataTable=true", "dataTable": "true", "legend": "bottom",
"categories": CATS, "data": D2})
# ============ Slide 8: presets & per-series control ============
new_slide("Presets & per-series control", items)
for box, p in zip([TL, TR, BL], ["minimal", "dark", "corporate"]):
ch(items, box, {"chartType": "area", "preset": p, "title": f"preset={p}", "legend": "bottom",
"categories": CATS, "data": D2})
ch(items, BR, {"chartType": "area", "title": "seriesN.* + chart-series Set", "legend": "bottom",
"categories": CATS,
"series1.name": "Web", "series1.values": "50,60,70,65,80", "series1.color": "4472C4",
"series2.name": "Mobile", "series2.values": "30,35,42,48,55", "series2.color": "ED7D31"})
# chart-series Set — recolour/rename series[1] of the BR chart after Add.
# In-batch, sequential: the chart already exists by the time this runs.
items.append({"command": "set", "path": f"/slide[{_slide}]/chart[4]/series[1]",
"props": {"name": "Renamed Web", "color": "C00000"}})
doc.batch(items)
print(f" added {_slide} slides ({len(items)} batch items)")
# context exit closes the resident, flushing the presentation to disk.
print(f"Generated: {FILE} ({_slide} slides)")
+99
View File
@@ -0,0 +1,99 @@
#!/bin/bash
# Area Charts Showcase — generates charts-area.pptx exercising the pptx `chart`
# element across the area family (area / stackedArea / percentStackedArea /
# area3d) plus titles, legends, data labels, axes, series styling, overlays,
# backgrounds, presets and per-series Set.
#
# CLI twin of charts-area.py (officecli Python SDK). Both produce an equivalent
# charts-area.pptx — this one issues one `officecli` process per command.
#
# Slide 1 Variants area / stackedArea / percentStackedArea / area3d
# Slide 2 Title & legend
# Slide 3 Data labels
# Slide 4 Axes
# Slide 5 Series styling
# Slide 6 Overlays
# Slide 7 Backgrounds
# Slide 8 Presets & per-series control
#
# Usage: ./charts-area.sh [officecli path]
# NOTE: intentionally NO `set -e`. Like the SDK twin's doc.batch, this script
# tolerates forward-compat 'UNSUPPORTED props' warnings (officecli exit 2) and
# keeps building so the full document is produced.
CLI="${1:-officecli}"
FILE="$(dirname "$0")/charts-area.pptx"
rm -f "$FILE"
$CLI create "$FILE"
$CLI open "$FILE"
# ==================== Slide 1: variants ====================
$CLI add "$FILE" / --type slide
$CLI add "$FILE" /slide[1] --type shape --prop text="Area variants — area / stackedArea / percentStackedArea / area3d" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
$CLI add "$FILE" /slide[1] --type chart --prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=area --prop title=area --prop legend=bottom --prop categories=Mon,Tue,Wed,Thu,Fri --prop 'data=Web:50,60,70,65,80;Mobile:30,35,42,48,55'
$CLI add "$FILE" /slide[1] --type chart --prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=stackedArea --prop title=stackedArea --prop legend=bottom --prop categories=Mon,Tue,Wed,Thu,Fri --prop 'data=Web:50,60,70,65,80;Mobile:30,35,42,48,55'
$CLI add "$FILE" /slide[1] --type chart --prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=percentStackedArea --prop title=percentStackedArea --prop legend=bottom --prop categories=Mon,Tue,Wed,Thu,Fri --prop 'data=Web:50,60,70,65,80;Mobile:30,35,42,48,55'
$CLI add "$FILE" /slide[1] --type chart --prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=area3d --prop title=area3d --prop view3d=15,20,30 --prop legend=bottom --prop categories=Mon,Tue,Wed,Thu,Fri --prop 'data=Web:50,60,70,65,80;Mobile:30,35,42,48,55'
# ==================== Slide 2: title & legend ====================
$CLI add "$FILE" / --type slide
$CLI add "$FILE" /slide[2] --type shape --prop text="Title & legend" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
$CLI add "$FILE" /slide[2] --type chart --prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=area --prop title="Styled title" --prop title.font=Georgia --prop title.size=20 --prop title.color=4472C4 --prop title.bold=true --prop legend=bottom --prop categories=Mon,Tue,Wed,Thu,Fri --prop 'data=Web:50,60,70,65,80;Mobile:30,35,42,48,55'
$CLI add "$FILE" /slide[2] --type chart --prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=area --prop title="legend=top + legendFont" --prop legend=top --prop legendFont=10:333333:Calibri --prop categories=Mon,Tue,Wed,Thu,Fri --prop 'data=Web:50,60,70,65,80;Mobile:30,35,42,48,55'
$CLI add "$FILE" /slide[2] --type chart --prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=area --prop title="legend.overlay=true" --prop legend=topRight --prop legend.overlay=true --prop categories=Mon,Tue,Wed,Thu,Fri --prop 'data=Web:50,60,70,65,80;Mobile:30,35,42,48,55'
$CLI add "$FILE" /slide[2] --type chart --prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=area --prop autotitledeleted=true --prop legend=none --prop categories=Mon,Tue,Wed,Thu,Fri --prop 'data=Web:50,60,70,65,80;Mobile:30,35,42,48,55'
# ==================== Slide 3: data labels ====================
$CLI add "$FILE" / --type slide
$CLI add "$FILE" /slide[3] --type shape --prop text="Data labels — flags, labelPos, labelfont" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
$CLI add "$FILE" /slide[3] --type chart --prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=area --prop title="dataLabels=value" --prop dataLabels=value --prop labelfont=10:333333:Calibri --prop legend=none --prop categories=Mon,Tue,Wed,Thu,Fri --prop data=A:50,60,70,65,80
$CLI add "$FILE" /slide[3] --type chart --prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=stackedArea --prop title="stacked + center labels" --prop dataLabels=value --prop labelPos=center --prop legend=bottom --prop categories=Mon,Tue,Wed,Thu,Fri --prop 'data=Web:50,60,70,65,80;Mobile:30,35,42,48,55'
$CLI add "$FILE" /slide[3] --type chart --prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=area --prop title="value,category" --prop dataLabels=value,category --prop labelfont=9:333333:Calibri --prop legend=none --prop categories=Mon,Tue,Wed,Thu,Fri --prop data=A:50,60,70,65,80
$CLI add "$FILE" /slide[3] --type chart --prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=area --prop title="dataLabels=none" --prop dataLabels=none --prop legend=none --prop categories=Mon,Tue,Wed,Thu,Fri --prop data=A:50,60,70,65,80
# ==================== Slide 4: axes ====================
$CLI add "$FILE" / --type slide
$CLI add "$FILE" /slide[4] --type shape --prop text="Axes — min/max, gridlines, ticks, labelrotation" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
$CLI add "$FILE" /slide[4] --type chart --prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=area --prop title="min/max + titles" --prop legend=none --prop axismin=0 --prop axismax=100 --prop majorunit=25 --prop axistitle=Value --prop cattitle=Day --prop axisfont=10:333333:Calibri --prop axisline=666666:1 --prop 'axisnumfmt=#,##0' --prop categories=Mon,Tue,Wed,Thu,Fri --prop data=A:50,60,70,65,80
$CLI add "$FILE" /slide[4] --type chart --prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=area --prop title="gridlines + ticks" --prop legend=none --prop gridlines=E0E0E0:0.3 --prop minorGridlines=F0F0F0:0.25 --prop majorTickMark=out --prop minorTickMark=in --prop tickLabelPos=nextTo --prop categories=Mon,Tue,Wed,Thu,Fri --prop data=A:50,60,70,65,80
$CLI add "$FILE" /slide[4] --type chart --prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=area --prop title="labelrotation=-30" --prop legend=none --prop labelrotation=-30 --prop categories=January,February,March,April,May,June --prop data=A:60,90,140,180,160,210
$CLI add "$FILE" /slide[4] --type chart --prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=area --prop title="dispunits=thousands" --prop legend=none --prop dispunits=thousands --prop categories=Mon,Tue,Wed,Thu,Fri --prop data=Rev:120000,135000,148000,162000,180000
# ==================== Slide 5: series styling ====================
$CLI add "$FILE" / --type slide
$CLI add "$FILE" /slide[5] --type shape --prop text="Series styling — colors, gradient(s), transparency, outline, shadow" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
$CLI add "$FILE" /slide[5] --type chart --prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=area --prop title="colors + seriesoutline" --prop legend=bottom --prop colors=4472C4,ED7D31 --prop seriesoutline=000000:0.5 --prop categories=Mon,Tue,Wed,Thu,Fri --prop 'data=Web:50,60,70,65,80;Mobile:30,35,42,48,55'
$CLI add "$FILE" /slide[5] --type chart --prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=area --prop title="gradient + seriesshadow" --prop legend=none --prop gradient=FF6600-FFCC00:90 --prop seriesshadow=000000-5-45-3-50 --prop categories=Mon,Tue,Wed,Thu,Fri --prop data=A:50,60,70,65,80
$CLI add "$FILE" /slide[5] --type chart --prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=area --prop title="per-series gradients + transparency=30" --prop 'gradients=FF0000-0000FF;00FF00-FFFF00' --prop transparency=30 --prop legend=bottom --prop categories=Mon,Tue,Wed,Thu,Fri --prop 'data=Web:50,60,70,65,80;Mobile:30,35,42,48,55'
$CLI add "$FILE" /slide[5] --type chart --prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=area --prop title="single + transparency=50" --prop transparency=50 --prop colors=4472C4 --prop legend=none --prop categories=Mon,Tue,Wed,Thu,Fri --prop data=A:50,60,70,65,80
# ==================== Slide 6: overlays ====================
$CLI add "$FILE" / --type slide
$CLI add "$FILE" /slide[6] --type shape --prop text="Overlays — referenceline, errbars, trendline" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
$CLI add "$FILE" /slide[6] --type chart --prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=area --prop title="referenceline=60" --prop referenceline=60:FF0000:Target --prop legend=none --prop categories=Mon,Tue,Wed,Thu,Fri --prop data=A:50,60,70,65,80
$CLI add "$FILE" /slide[6] --type chart --prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=area --prop title="errbars=percentage:10" --prop errbars=percentage:10 --prop legend=none --prop categories=Mon,Tue,Wed,Thu,Fri --prop data=A:50,60,70,65,80
$CLI add "$FILE" /slide[6] --type chart --prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=area --prop title="trendline=linear" --prop trendline=linear --prop legend=none --prop categories=Mon,Tue,Wed,Thu,Fri --prop data=A:50,60,70,65,80
$CLI add "$FILE" /slide[6] --type chart --prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=area --prop title="trendline=movingAvg:3" --prop trendline=movingAvg:3 --prop legend=none --prop categories=Mon,Tue,Wed,Thu,Fri --prop data=A:50,60,70,65,80
# ==================== Slide 7: backgrounds ====================
$CLI add "$FILE" / --type slide
$CLI add "$FILE" /slide[7] --type shape --prop text="Backgrounds — chartareafill, plotFill, chartborder, plotborder, roundedcorners" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
$CLI add "$FILE" /slide[7] --type chart --prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=area --prop title="chartareafill + plotFill + borders" --prop legend=bottom --prop chartareafill=FFF8E7 --prop plotFill=FAFAFA --prop chartborder=000000:1 --prop plotborder=CCCCCC:0.5 --prop categories=Mon,Tue,Wed,Thu,Fri --prop 'data=Web:50,60,70,65,80;Mobile:30,35,42,48,55'
$CLI add "$FILE" /slide[7] --type chart --prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=area --prop title="roundedcorners=true" --prop roundedcorners=true --prop chartborder=4472C4:2 --prop legend=bottom --prop categories=Mon,Tue,Wed,Thu,Fri --prop 'data=Web:50,60,70,65,80;Mobile:30,35,42,48,55'
$CLI add "$FILE" /slide[7] --type chart --prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=area --prop title="plotFill=none" --prop plotFill=none --prop gridlines=none --prop legend=none --prop categories=Mon,Tue,Wed,Thu,Fri --prop data=A:50,60,70,65,80
$CLI add "$FILE" /slide[7] --type chart --prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=area --prop title="dataTable=true" --prop dataTable=true --prop legend=bottom --prop categories=Mon,Tue,Wed,Thu,Fri --prop 'data=Web:50,60,70,65,80;Mobile:30,35,42,48,55'
# ==================== Slide 8: presets & per-series control ====================
$CLI add "$FILE" / --type slide
$CLI add "$FILE" /slide[8] --type shape --prop text="Presets & per-series control" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
$CLI add "$FILE" /slide[8] --type chart --prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=area --prop preset=minimal --prop title=preset=minimal --prop legend=bottom --prop categories=Mon,Tue,Wed,Thu,Fri --prop 'data=Web:50,60,70,65,80;Mobile:30,35,42,48,55'
$CLI add "$FILE" /slide[8] --type chart --prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=area --prop preset=dark --prop title=preset=dark --prop legend=bottom --prop categories=Mon,Tue,Wed,Thu,Fri --prop 'data=Web:50,60,70,65,80;Mobile:30,35,42,48,55'
$CLI add "$FILE" /slide[8] --type chart --prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=area --prop preset=corporate --prop title=preset=corporate --prop legend=bottom --prop categories=Mon,Tue,Wed,Thu,Fri --prop 'data=Web:50,60,70,65,80;Mobile:30,35,42,48,55'
$CLI add "$FILE" /slide[8] --type chart --prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=area --prop title="seriesN.* + chart-series Set" --prop legend=bottom --prop categories=Mon,Tue,Wed,Thu,Fri --prop series1.name=Web --prop series1.values=50,60,70,65,80 --prop series1.color=4472C4 --prop series2.name=Mobile --prop series2.values=30,35,42,48,55 --prop series2.color=ED7D31
# chart-series Set — recolour/rename series[1] of the BR chart after Add
$CLI set "$FILE" /slide[8]/chart[4]/series[1] --prop name="Renamed Web" --prop color=C00000
$CLI close "$FILE"
$CLI validate "$FILE"
echo "Generated: $FILE"
+297
View File
@@ -0,0 +1,297 @@
# Bar Charts Showcase
This demo consists of three files that work together:
- **charts-bar.py** — Python script that calls `officecli` commands to generate the deck. Each chart command is shown as a copyable shell command below.
- **charts-bar.pptx** — The generated 8-slide deck (4 charts per slide, 32 charts total).
- **charts-bar.md** — This file. Maps each slide to the features it demonstrates.
## Regenerate
```bash
cd examples/ppt/charts
python3 charts-bar.py
# → charts-bar.pptx
```
## Chart Slides
### Slide 1 — Basic Variants
```bash
officecli add charts-bar.pptx /slide[1] --type chart \
--prop chartType=bar --prop title="bar" --prop legend=bottom \
--prop categories="Q1,Q2,Q3,Q4" \
--prop data="East:120,135,148,162;West:95,108,115,128" \
--prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in
officecli add charts-bar.pptx /slide[1] --type chart \
--prop chartType=stackedBar --prop title="stackedBar" --prop legend=bottom \
--prop categories="Q1,Q2,Q3,Q4" \
--prop data="East:120,135,148,162;South:95,108,115,128;West:80,90,98,110" \
--prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in
officecli add charts-bar.pptx /slide[1] --type chart \
--prop chartType=percentStackedBar --prop title="percentStackedBar" --prop legend=bottom \
--prop categories="Q1,Q2,Q3,Q4" \
--prop data="East:120,135,148,162;South:95,108,115,128;West:80,90,98,110" \
--prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in
officecli add charts-bar.pptx /slide[1] --type chart \
--prop chartType=bar3d --prop title="bar3d" --prop legend=bottom \
--prop view3d="15,20,30" \
--prop categories="Q1,Q2,Q3,Q4" \
--prop data="East:120,135,148,162;West:95,108,115,128" \
--prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in
```
**Features:** `chartType` (bar/stackedBar/percentStackedBar/bar3d), `categories`, `data`, `legend`, `view3d`
### Slide 2 — 3D Bar Shapes
```bash
# shape= controls the 3D bar geometry (bar3d only)
officecli add charts-bar.pptx /slide[2] --type chart \
--prop chartType=bar3d --prop shape=box --prop title="shape=box" \
--prop legend=none --prop categories="Q1,Q2,Q3,Q4" \
--prop data="East:120,135,148,162;West:95,108,115,128"
officecli add charts-bar.pptx /slide[2] --type chart \
--prop chartType=bar3d --prop shape=cylinder --prop title="shape=cylinder" \
--prop legend=none --prop categories="Q1,Q2,Q3,Q4" \
--prop data="East:120,135,148,162;West:95,108,115,128"
officecli add charts-bar.pptx /slide[2] --type chart \
--prop chartType=bar3d --prop shape=cone --prop title="shape=cone" \
--prop legend=none --prop categories="Q1,Q2,Q3,Q4" \
--prop data="East:120,135,148,162;West:95,108,115,128"
officecli add charts-bar.pptx /slide[2] --type chart \
--prop chartType=bar3d --prop shape=pyramid --prop title="shape=pyramid" \
--prop legend=none --prop categories="Q1,Q2,Q3,Q4" \
--prop data="East:120,135,148,162;West:95,108,115,128"
```
**Features:** `shape` (box/cylinder/cone/pyramid) for `bar3d`
### Slide 3 — Title and Legend
```bash
officecli add charts-bar.pptx /slide[3] --type chart \
--prop chartType=bar --prop title="Styled title" \
--prop title.font=Georgia --prop title.size=20 \
--prop title.color=4472C4 --prop title.bold=true \
--prop legend=bottom --prop categories="Q1,Q2,Q3,Q4" \
--prop data="East:120,135,148,162;West:95,108,115,128"
officecli add charts-bar.pptx /slide[3] --type chart \
--prop chartType=bar --prop title="legend=top + legendFont" \
--prop legend=top --prop legendFont="10:333333:Calibri" \
--prop categories="Q1,Q2,Q3,Q4" \
--prop data="East:120,135,148,162;West:95,108,115,128"
officecli add charts-bar.pptx /slide[3] --type chart \
--prop chartType=bar --prop title="legend.overlay=true" \
--prop legend=topRight --prop legend.overlay=true \
--prop categories="Q1,Q2,Q3,Q4" \
--prop data="East:120,135,148,162;West:95,108,115,128"
officecli add charts-bar.pptx /slide[3] --type chart \
--prop chartType=bar --prop autotitledeleted=true --prop legend=none \
--prop categories="Q1,Q2,Q3,Q4" \
--prop data="East:120,135,148,162;West:95,108,115,128"
```
**Features:** `title.font`, `title.size`, `title.color`, `title.bold`, `legend` (bottom/top/topRight/none), `legendFont`, `legend.overlay`, `autotitledeleted`
### Slide 4 — Data Labels
```bash
officecli add charts-bar.pptx /slide[4] --type chart \
--prop chartType=bar --prop title="value @ outsideEnd" \
--prop dataLabels=value --prop labelPos=outsideEnd \
--prop labelfont="10:333333:Calibri" --prop legend=none \
--prop categories="Q1,Q2,Q3,Q4" --prop data="A:60,90,140,180"
officecli add charts-bar.pptx /slide[4] --type chart \
--prop chartType=bar --prop title="value,category @ insideEnd" \
--prop dataLabels="value,category" --prop labelPos=insideEnd \
--prop labelfont="9:FFFFFF:Calibri" --prop legend=none \
--prop categories="Q1,Q2,Q3,Q4" --prop data="A:60,90,140,180"
officecli add charts-bar.pptx /slide[4] --type chart \
--prop chartType=stackedBar --prop title="stacked + center labels" \
--prop dataLabels=value --prop labelPos=center \
--prop labelfont="9:FFFFFF:Calibri" --prop legend=bottom \
--prop categories="Q1,Q2,Q3,Q4" \
--prop data="East:120,135,148,162;South:95,108,115,128;West:80,90,98,110"
officecli add charts-bar.pptx /slide[4] --type chart \
--prop chartType=bar --prop title="dataLabels=none" \
--prop dataLabels=none --prop legend=none \
--prop categories="Q1,Q2,Q3,Q4" --prop data="A:60,90,140,180"
```
**Features:** `dataLabels` (value/category/percent/none or combined), `labelPos` (outsideEnd/insideEnd/insideBase/center), `labelfont`
### Slide 5 — Axes
```bash
officecli add charts-bar.pptx /slide[5] --type chart \
--prop chartType=bar --prop title="min/max + titles + numfmt" --prop legend=none \
--prop axismin=0 --prop axismax=200 --prop majorunit=50 --prop minorunit=10 \
--prop axistitle="Revenue" --prop cattitle="Quarter" \
--prop axisfont="10:333333:Calibri" --prop axisline="666666:1" \
--prop axisnumfmt="#,##0" \
--prop categories="Q1,Q2,Q3,Q4" --prop data="Rev:60,90,140,180"
officecli add charts-bar.pptx /slide[5] --type chart \
--prop chartType=bar --prop title="gridlines + ticks" --prop legend=none \
--prop gridlines="E0E0E0:0.3" --prop minorGridlines="F0F0F0:0.25" \
--prop majorTickMark=out --prop minorTickMark=in --prop tickLabelPos=nextTo \
--prop categories="Q1,Q2,Q3,Q4" --prop data="A:60,90,140,180"
officecli add charts-bar.pptx /slide[5] --type chart \
--prop chartType=bar --prop title="labelrotation=-30" --prop legend=none \
--prop labelrotation=-30 \
--prop categories="January,February,March,April" \
--prop data="A:60,90,140,180"
officecli add charts-bar.pptx /slide[5] --type chart \
--prop chartType=bar --prop title="dispunits=thousands" --prop legend=none \
--prop dispunits=thousands \
--prop categories="Q1,Q2,Q3,Q4" \
--prop data="Rev:120000,135000,148000,162000"
# chart-axis Set: mutate axis after creation
officecli set charts-bar.pptx "/slide[5]/chart[1]/axis[@role=value]" \
--prop title="Revenue" --prop format='$#,##0' \
--prop majorGridlines=true --prop max=200 --prop min=0
```
**Features:** `axismin`, `axismax`, `majorunit`, `minorunit`, `axistitle`, `cattitle`, `axisfont`, `axisline`, `axisnumfmt`, `gridlines`, `minorGridlines`, `majorTickMark`, `minorTickMark`, `tickLabelPos`, `labelrotation`, `dispunits`, `chart-axis Set`
### Slide 6 — Series Styling
```bash
officecli add charts-bar.pptx /slide[6] --type chart \
--prop chartType=bar --prop title="colors + seriesoutline" --prop legend=bottom \
--prop colors="4472C4,ED7D31,A5A5A5" --prop seriesoutline="000000:0.5" \
--prop categories="Q1,Q2,Q3,Q4" \
--prop data="East:120,135,148,162;South:95,108,115,128;West:80,90,98,110"
officecli add charts-bar.pptx /slide[6] --type chart \
--prop chartType=bar --prop title="gradient + seriesshadow" --prop legend=bottom \
--prop gradient="FF6600-FFCC00:90" --prop seriesshadow="000000-5-45-3-50" \
--prop categories="Q1,Q2,Q3,Q4" --prop data="A:60,90,140,180"
officecli add charts-bar.pptx /slide[6] --type chart \
--prop chartType=bar --prop title="transparency=30 + gradients" --prop legend=bottom \
--prop gradients="FF0000-0000FF;00FF00-FFFF00" --prop transparency=30 \
--prop categories="Q1,Q2,Q3,Q4" \
--prop data="A:60,90,140,180;B:40,70,100,130"
# serlines — leader lines from stacked bar to legend (stackedBar only)
officecli add charts-bar.pptx /slide[6] --type chart \
--prop chartType=stackedBar --prop title="stacked + serlines=true" \
--prop serlines=true --prop legend=bottom \
--prop categories="Q1,Q2,Q3,Q4" \
--prop data="East:120,135,148,162;West:95,108,115,128"
```
**Features:** `colors`, `seriesoutline`, `gradient`, `seriesshadow`, `gradients`, `transparency`, `serlines` (stackedBar series connector lines)
### Slide 7 — Overlays
```bash
officecli add charts-bar.pptx /slide[7] --type chart \
--prop chartType=bar --prop title="referenceline=100" --prop legend=none \
--prop referenceline="100:FF0000:Target" \
--prop categories="Q1,Q2,Q3,Q4" --prop data="A:60,90,140,180"
officecli add charts-bar.pptx /slide[7] --type chart \
--prop chartType=bar --prop title="errbars=fixedVal:10" --prop legend=none \
--prop errbars="fixedVal:10" \
--prop categories="Q1,Q2,Q3,Q4" --prop data="A:60,90,140,180"
officecli add charts-bar.pptx /slide[7] --type chart \
--prop chartType=bar --prop title="gapwidth=50 + overlap=20" --prop legend=bottom \
--prop gapwidth=50 --prop overlap=20 \
--prop categories="Q1,Q2,Q3,Q4" \
--prop data="A:60,90,140,180;B:50,75,110,150"
officecli add charts-bar.pptx /slide[7] --type chart \
--prop chartType=bar --prop title="dataTable=true" --prop legend=bottom \
--prop dataTable=true \
--prop categories="Q1,Q2,Q3,Q4" --prop data="A:60,90,140,180"
```
**Features:** `referenceline`, `errbars`, `gapwidth`, `overlap`, `dataTable`
### Slide 8 — Presets and Per-Series Control
```bash
officecli add charts-bar.pptx /slide[8] --type chart \
--prop chartType=bar --prop preset=minimal --prop title="preset=minimal" \
--prop legend=bottom --prop categories="Q1,Q2,Q3,Q4" \
--prop data="A:60,90,140,180;B:50,75,110,150"
officecli add charts-bar.pptx /slide[8] --type chart \
--prop chartType=bar --prop preset=dark --prop title="preset=dark" \
--prop legend=bottom --prop categories="Q1,Q2,Q3,Q4" \
--prop data="A:60,90,140,180;B:50,75,110,150"
officecli add charts-bar.pptx /slide[8] --type chart \
--prop chartType=bar --prop preset=corporate --prop title="preset=corporate" \
--prop legend=bottom --prop categories="Q1,Q2,Q3,Q4" \
--prop data="A:60,90,140,180;B:50,75,110,150"
officecli add charts-bar.pptx /slide[8] --type chart \
--prop chartType=bar --prop title="seriesN.* Add + chart-series Set" \
--prop legend=bottom --prop categories="Q1,Q2,Q3,Q4" \
--prop series1.name="Product A" --prop series1.values="60,90,140,180" \
--prop series1.color=4472C4 \
--prop series2.name="Product B" --prop series2.values="50,75,110,150" \
--prop series2.color=ED7D31
officecli set charts-bar.pptx "/slide[8]/chart[4]/series[1]" \
--prop name="Renamed" --prop color=C00000
```
**Features:** `preset` (minimal/dark/corporate), `series1.name`/`series1.values`/`series1.color`, `chart-series Set`
## Complete Feature Coverage
| Feature | Slide |
|---------|-------|
| **Chart types:** bar, stackedBar, percentStackedBar, bar3d | 1 |
| **3D bar shape:** box/cylinder/cone/pyramid | 2 |
| **view3d** | 1 |
| **Title styling:** title.font/size/color/bold | 3 |
| **Legend:** positions, legendFont, legend.overlay | 3 |
| **autotitledeleted** | 3 |
| **dataLabels:** value/category/percent/none + combined | 4 |
| **labelPos:** outsideEnd/insideEnd/insideBase/center | 4 |
| **labelfont** | 4 |
| **Axis scaling:** axismin/max, majorunit, minorunit | 5 |
| **Axis titles/font/line/numfmt** | 5 |
| **Gridlines, tick marks** | 5 |
| **labelrotation, dispunits** | 5 |
| **chart-axis Set** | 5 |
| **colors, seriesoutline, seriesshadow** | 6 |
| **gradient, gradients, transparency** | 6 |
| **serlines** (stackedBar connector lines) | 6 |
| **referenceline, errbars** | 7 |
| **gapwidth, overlap, dataTable** | 7 |
| **preset** (minimal/dark/corporate) | 8 |
| **seriesN.*** per-series at Add time | 8 |
| **chart-series Set** | 8 |
## Inspect the Generated File
```bash
officecli query charts-bar.pptx chart
officecli get charts-bar.pptx "/slide[1]/chart[1]"
officecli get charts-bar.pptx "/slide[2]/chart[1]"
officecli get charts-bar.pptx "/slide[5]/chart[1]/axis[@role=value]"
```
Binary file not shown.
+194
View File
@@ -0,0 +1,194 @@
#!/usr/bin/env python3
"""
Bar Charts Showcase — bar, stackedBar, percentStackedBar, bar3d (cylinder/cone/pyramid).
Generates: charts-bar.pptx
Slide 1 Variants bar / stackedBar / percentStackedBar / bar3d
Slide 2 3D bar shapes shape=box/cylinder/cone/pyramid (bar3d only)
Slide 3 Title & legend title.* + legend positions + legendFont
Slide 4 Data labels flags + labelPos + labelfont
Slide 5 Axes min/max/title/font/line/numfmt/gridlines/labelrotation
Slide 6 Series styling colors, gradient, transparency, outline, shadow, invertifneg, serlines
Slide 7 Overlays referenceline, errbars, gapwidth, overlap, dataTable
Slide 8 Presets & per-ser preset bundles + seriesN.* + chart-series Set
SDK twin of charts-bar.sh (officecli CLI). Both produce an equivalent
charts-bar.pptx. This one drives the **officecli Python SDK**
(`pip install officecli-sdk`): one resident is started and every slide, title
shape and chart is shipped over the named pipe in `doc.batch(...)` round-trips.
Each item is the same `{"command","parent","type","props"}` dict you'd put in
an `officecli batch` list.
Usage:
pip install officecli-sdk # plus the `officecli` binary on PATH
python3 charts-bar.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__)), "charts-bar.pptx")
# ---- shared geometry + data ------------------------------------------------
TL = {"x": "0.3in", "y": "1.05in", "width": "6.1in", "height": "3in"}
TR = {"x": "6.95in", "y": "1.05in", "width": "6.1in", "height": "3in"}
BL = {"x": "0.3in", "y": "4.25in", "width": "6.1in", "height": "3in"}
BR = {"x": "6.95in", "y": "4.25in", "width": "6.1in", "height": "3in"}
CATS = "Q1,Q2,Q3,Q4"
D2 = "East:120,135,148,162;West:95,108,115,128"
D3 = "East:120,135,148,162;South:95,108,115,128;West:80,90,98,110"
def main():
print(f"Building {FILE} ...")
slide = 0
with officecli.create(FILE, "--force") as doc:
def new_slide(title):
"""Append a slide + its title shape; return the new slide's 1-based index."""
nonlocal slide
slide += 1
doc.batch([
{"command": "add", "parent": "/", "type": "slide", "props": {}},
{"command": "add", "parent": f"/slide[{slide}]", "type": "shape",
"props": {"text": title, "size": "24", "bold": "true",
"autoFit": "normal", "x": "0.5in", "y": "0.3in",
"width": "12.3in", "height": "0.6in"}},
])
def ch(box, props):
"""One `add chart` item (box geometry + chart props merged)."""
return {"command": "add", "parent": f"/slide[{slide}]", "type": "chart",
"props": {**box, **props}}
# ---- Slide 1: Bar variants -------------------------------------------------
new_slide("Bar variants — bar / stackedBar / percentStackedBar / bar3d")
doc.batch([
ch(TL, {"chartType": "bar", "title": "bar", "legend": "bottom", "categories": CATS, "data": D2}),
ch(TR, {"chartType": "stackedBar", "title": "stackedBar", "legend": "bottom", "categories": CATS, "data": D3}),
ch(BL, {"chartType": "percentStackedBar", "title": "percentStackedBar", "legend": "bottom", "categories": CATS, "data": D3}),
ch(BR, {"chartType": "bar3d", "title": "bar3d", "legend": "bottom", "categories": CATS, "data": D2, "view3d": "15,20,30"}),
])
# ---- Slide 2: 3D bar shapes ------------------------------------------------
new_slide("3D bar shapes — shape=box / cylinder / cone / pyramid")
doc.batch([
ch(TL, {"chartType": "bar3d", "shape": "box", "title": "shape=box", "legend": "none", "categories": CATS, "data": D2}),
ch(TR, {"chartType": "bar3d", "shape": "cylinder", "title": "shape=cylinder", "legend": "none", "categories": CATS, "data": D2}),
ch(BL, {"chartType": "bar3d", "shape": "cone", "title": "shape=cone", "legend": "none", "categories": CATS, "data": D2}),
ch(BR, {"chartType": "bar3d", "shape": "pyramid", "title": "shape=pyramid", "legend": "none", "categories": CATS, "data": D2}),
])
# ---- Slide 3: Title & legend -----------------------------------------------
new_slide("Title & legend")
doc.batch([
ch(TL, {"chartType": "bar", "title": "Styled title", "title.font": "Georgia", "title.size": "20",
"title.color": "4472C4", "title.bold": "true", "legend": "bottom", "categories": CATS, "data": D2}),
ch(TR, {"chartType": "bar", "title": "legend=top + legendFont", "legend": "top",
"legendFont": "10:333333:Calibri", "categories": CATS, "data": D2}),
ch(BL, {"chartType": "bar", "title": "legend.overlay=true", "legend": "topRight",
"legend.overlay": "true", "categories": CATS, "data": D2}),
ch(BR, {"chartType": "bar", "autotitledeleted": "true", "legend": "none", "categories": CATS, "data": D2}),
])
# ---- Slide 4: Data labels --------------------------------------------------
new_slide("Data labels — flags, labelPos, labelfont")
doc.batch([
ch(TL, {"chartType": "bar", "title": "value @ outsideEnd", "dataLabels": "value",
"labelPos": "outsideEnd", "labelfont": "10:333333:Calibri", "legend": "none",
"categories": CATS, "data": "A:60,90,140,180"}),
ch(TR, {"chartType": "bar", "title": "value,category @ insideEnd", "dataLabels": "value,category",
"labelPos": "insideEnd", "labelfont": "9:FFFFFF:Calibri", "legend": "none",
"categories": CATS, "data": "A:60,90,140,180"}),
ch(BL, {"chartType": "stackedBar", "title": "stacked + center labels", "dataLabels": "value",
"labelPos": "center", "labelfont": "9:FFFFFF:Calibri", "legend": "bottom",
"categories": CATS, "data": D3}),
ch(BR, {"chartType": "bar", "title": "dataLabels=none", "dataLabels": "none", "legend": "none",
"categories": CATS, "data": "A:60,90,140,180"}),
])
# ---- Slide 5: Axes ---------------------------------------------------------
new_slide("Axes — min/max, titles, fonts, gridlines, ticks, labelrotation")
doc.batch([
ch(TL, {"chartType": "bar", "title": "min/max + titles + numfmt", "legend": "none",
"axismin": "0", "axismax": "200", "majorunit": "50", "minorunit": "10",
"axistitle": "Revenue", "cattitle": "Quarter", "axisfont": "10:333333:Calibri",
"axisline": "666666:1", "axisnumfmt": "#,##0", "categories": CATS, "data": "Rev:60,90,140,180"}),
ch(TR, {"chartType": "bar", "title": "gridlines + ticks", "legend": "none",
"gridlines": "E0E0E0:0.3", "minorGridlines": "F0F0F0:0.25",
"majorTickMark": "out", "minorTickMark": "in", "tickLabelPos": "nextTo",
"categories": CATS, "data": "A:60,90,140,180"}),
ch(BL, {"chartType": "bar", "title": "labelrotation=-30", "legend": "none", "labelrotation": "-30",
"categories": "January,February,March,April", "data": "A:60,90,140,180"}),
ch(BR, {"chartType": "bar", "title": "dispunits=thousands", "legend": "none", "dispunits": "thousands",
"categories": CATS, "data": "Rev:120000,135000,148000,162000"}),
])
doc.batch([
{"command": "set", "path": f"/slide[{slide}]/chart[1]/axis[@role=value]",
"props": {"title": "Revenue", "format": "$#,##0", "majorGridlines": "true", "max": "200", "min": "0"}},
])
# ---- Slide 6: Series styling -----------------------------------------------
new_slide("Series styling — colors, gradient(s), transparency, outline, shadow, invertifneg, serlines")
doc.batch([
ch(TL, {"chartType": "bar", "title": "colors + seriesoutline", "legend": "bottom",
"colors": "4472C4,ED7D31,A5A5A5", "seriesoutline": "000000:0.5", "categories": CATS, "data": D3}),
ch(TR, {"chartType": "bar", "title": "gradient + seriesshadow", "legend": "bottom",
"gradient": "FF6600-FFCC00:90", "seriesshadow": "000000-5-45-3-50",
"categories": CATS, "data": "A:60,90,140,180"}),
ch(BL, {"chartType": "bar", "title": "transparency=30 + gradients", "legend": "bottom",
"gradients": "FF0000-0000FF;00FF00-FFFF00", "transparency": "30",
"categories": CATS, "data": "A:60,90,140,180;B:40,70,100,130"}),
ch(BR, {"chartType": "stackedBar", "title": "stacked + serlines=true", "serlines": "true",
"legend": "bottom", "categories": CATS, "data": D2}),
])
# ---- Slide 7: Overlays -----------------------------------------------------
new_slide("Overlays — referenceline, errbars, gapwidth, overlap, dataTable")
doc.batch([
ch(TL, {"chartType": "bar", "title": "referenceline=100", "legend": "none",
"referenceline": "100:FF0000:Target", "categories": CATS, "data": "A:60,90,140,180"}),
ch(TR, {"chartType": "bar", "title": "errbars=fixedVal:10", "legend": "none",
"errbars": "fixedVal:10", "categories": CATS, "data": "A:60,90,140,180"}),
ch(BL, {"chartType": "bar", "title": "gapwidth=50 + overlap=20", "legend": "bottom",
"gapwidth": "50", "overlap": "20", "categories": CATS,
"data": "A:60,90,140,180;B:50,75,110,150"}),
ch(BR, {"chartType": "bar", "title": "dataTable=true", "legend": "bottom",
"dataTable": "true", "categories": CATS, "data": "A:60,90,140,180"}),
])
# ---- Slide 8: Presets & per-series control ---------------------------------
new_slide("Presets & per-series control")
doc.batch([
ch(TL, {"chartType": "bar", "preset": "minimal", "title": "preset=minimal", "legend": "bottom",
"categories": CATS, "data": "A:60,90,140,180;B:50,75,110,150"}),
ch(TR, {"chartType": "bar", "preset": "dark", "title": "preset=dark", "legend": "bottom",
"categories": CATS, "data": "A:60,90,140,180;B:50,75,110,150"}),
ch(BL, {"chartType": "bar", "preset": "corporate", "title": "preset=corporate", "legend": "bottom",
"categories": CATS, "data": "A:60,90,140,180;B:50,75,110,150"}),
ch(BR, {"chartType": "bar", "title": "seriesN.* Add + chart-series Set", "legend": "bottom",
"categories": CATS,
"series1.name": "Product A", "series1.values": "60,90,140,180", "series1.color": "4472C4",
"series2.name": "Product B", "series2.values": "50,75,110,150", "series2.color": "ED7D31"}),
])
doc.batch([
{"command": "set", "path": f"/slide[{slide}]/chart[4]/series[1]",
"props": {"name": "Renamed", "color": "C00000"}},
])
doc.send({"command": "save"})
print(f"Done: {FILE} ({slide} slides)")
if __name__ == "__main__":
main()
+100
View File
@@ -0,0 +1,100 @@
#!/bin/bash
# Bar Charts Showcase — bar, stackedBar, percentStackedBar, bar3d (cylinder/cone/pyramid).
# Generates: charts-bar.pptx
#
# Slide 1 Variants bar / stackedBar / percentStackedBar / bar3d
# Slide 2 3D bar shapes shape=box/cylinder/cone/pyramid (bar3d only)
# Slide 3 Title & legend title.* + legend positions + legendFont
# Slide 4 Data labels flags + labelPos + labelfont
# Slide 5 Axes min/max/title/font/line/numfmt/gridlines/labelrotation
# Slide 6 Series styling colors, gradient, transparency, outline, shadow, invertifneg, serlines
# Slide 7 Overlays referenceline, errbars, gapwidth, overlap, dataTable
# Slide 8 Presets & per-ser preset bundles + seriesN.* + chart-series Set
#
# CLI twin of charts-bar.py (officecli Python SDK).
# Usage: ./charts-bar.sh [officecli path]
# NOTE: intentionally NO `set -e`. Like the SDK twin's doc.batch, this script
# tolerates forward-compat 'UNSUPPORTED props' warnings (officecli exit 2) and
# keeps building so the full document is produced.
CLI="${1:-officecli}"
FILE="$(dirname "$0")/charts-bar.pptx"
# shared geometry + data
CATS="Q1,Q2,Q3,Q4"
D2="East:120,135,148,162;West:95,108,115,128"
D3="East:120,135,148,162;South:95,108,115,128;West:80,90,98,110"
rm -f "$FILE"
$CLI create "$FILE"
$CLI open "$FILE"
# ==================== Slide 1: Bar variants ====================
$CLI add "$FILE" / --type slide
$CLI add "$FILE" /slide[1] --type shape --prop text="Bar variants — bar / stackedBar / percentStackedBar / bar3d" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
$CLI add "$FILE" /slide[1] --type chart --prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=bar --prop title=bar --prop legend=bottom --prop categories="$CATS" --prop data="$D2"
$CLI add "$FILE" /slide[1] --type chart --prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=stackedBar --prop title=stackedBar --prop legend=bottom --prop categories="$CATS" --prop data="$D3"
$CLI add "$FILE" /slide[1] --type chart --prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=percentStackedBar --prop title=percentStackedBar --prop legend=bottom --prop categories="$CATS" --prop data="$D3"
$CLI add "$FILE" /slide[1] --type chart --prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=bar3d --prop title=bar3d --prop legend=bottom --prop categories="$CATS" --prop data="$D2" --prop view3d=15,20,30
# ==================== Slide 2: 3D bar shapes ====================
$CLI add "$FILE" / --type slide
$CLI add "$FILE" /slide[2] --type shape --prop text="3D bar shapes — shape=box / cylinder / cone / pyramid" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
$CLI add "$FILE" /slide[2] --type chart --prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=bar3d --prop shape=box --prop title=shape=box --prop legend=none --prop categories="$CATS" --prop data="$D2"
$CLI add "$FILE" /slide[2] --type chart --prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=bar3d --prop shape=cylinder --prop title=shape=cylinder --prop legend=none --prop categories="$CATS" --prop data="$D2"
$CLI add "$FILE" /slide[2] --type chart --prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=bar3d --prop shape=cone --prop title=shape=cone --prop legend=none --prop categories="$CATS" --prop data="$D2"
$CLI add "$FILE" /slide[2] --type chart --prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=bar3d --prop shape=pyramid --prop title=shape=pyramid --prop legend=none --prop categories="$CATS" --prop data="$D2"
# ==================== Slide 3: Title & legend ====================
$CLI add "$FILE" / --type slide
$CLI add "$FILE" /slide[3] --type shape --prop text="Title & legend" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
$CLI add "$FILE" /slide[3] --type chart --prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=bar --prop title="Styled title" --prop title.font=Georgia --prop title.size=20 --prop title.color=4472C4 --prop title.bold=true --prop legend=bottom --prop categories="$CATS" --prop data="$D2"
$CLI add "$FILE" /slide[3] --type chart --prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=bar --prop title="legend=top + legendFont" --prop legend=top --prop legendFont=10:333333:Calibri --prop categories="$CATS" --prop data="$D2"
$CLI add "$FILE" /slide[3] --type chart --prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=bar --prop title="legend.overlay=true" --prop legend=topRight --prop legend.overlay=true --prop categories="$CATS" --prop data="$D2"
$CLI add "$FILE" /slide[3] --type chart --prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=bar --prop autotitledeleted=true --prop legend=none --prop categories="$CATS" --prop data="$D2"
# ==================== Slide 4: Data labels ====================
$CLI add "$FILE" / --type slide
$CLI add "$FILE" /slide[4] --type shape --prop text="Data labels — flags, labelPos, labelfont" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
$CLI add "$FILE" /slide[4] --type chart --prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=bar --prop title="value @ outsideEnd" --prop dataLabels=value --prop labelPos=outsideEnd --prop labelfont=10:333333:Calibri --prop legend=none --prop categories="$CATS" --prop data="A:60,90,140,180"
$CLI add "$FILE" /slide[4] --type chart --prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=bar --prop title="value,category @ insideEnd" --prop dataLabels=value,category --prop labelPos=insideEnd --prop labelfont=9:FFFFFF:Calibri --prop legend=none --prop categories="$CATS" --prop data="A:60,90,140,180"
$CLI add "$FILE" /slide[4] --type chart --prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=stackedBar --prop title="stacked + center labels" --prop dataLabels=value --prop labelPos=center --prop labelfont=9:FFFFFF:Calibri --prop legend=bottom --prop categories="$CATS" --prop data="$D3"
$CLI add "$FILE" /slide[4] --type chart --prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=bar --prop title="dataLabels=none" --prop dataLabels=none --prop legend=none --prop categories="$CATS" --prop data="A:60,90,140,180"
# ==================== Slide 5: Axes ====================
$CLI add "$FILE" / --type slide
$CLI add "$FILE" /slide[5] --type shape --prop text="Axes — min/max, titles, fonts, gridlines, ticks, labelrotation" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
$CLI add "$FILE" /slide[5] --type chart --prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=bar --prop title="min/max + titles + numfmt" --prop legend=none --prop axismin=0 --prop axismax=200 --prop majorunit=50 --prop minorunit=10 --prop axistitle=Revenue --prop cattitle=Quarter --prop axisfont=10:333333:Calibri --prop axisline=666666:1 --prop axisnumfmt="#,##0" --prop categories="$CATS" --prop data="Rev:60,90,140,180"
$CLI add "$FILE" /slide[5] --type chart --prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=bar --prop title="gridlines + ticks" --prop legend=none --prop gridlines=E0E0E0:0.3 --prop minorGridlines=F0F0F0:0.25 --prop majorTickMark=out --prop minorTickMark=in --prop tickLabelPos=nextTo --prop categories="$CATS" --prop data="A:60,90,140,180"
$CLI add "$FILE" /slide[5] --type chart --prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=bar --prop title="labelrotation=-30" --prop legend=none --prop labelrotation=-30 --prop categories="January,February,March,April" --prop data="A:60,90,140,180"
$CLI add "$FILE" /slide[5] --type chart --prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=bar --prop title="dispunits=thousands" --prop legend=none --prop dispunits=thousands --prop categories="$CATS" --prop data="Rev:120000,135000,148000,162000"
$CLI set "$FILE" "/slide[5]/chart[1]/axis[@role=value]" --prop title=Revenue --prop format="\$#,##0" --prop majorGridlines=true --prop max=200 --prop min=0
# ==================== Slide 6: Series styling ====================
$CLI add "$FILE" / --type slide
$CLI add "$FILE" /slide[6] --type shape --prop text="Series styling — colors, gradient(s), transparency, outline, shadow, invertifneg, serlines" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
$CLI add "$FILE" /slide[6] --type chart --prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=bar --prop title="colors + seriesoutline" --prop legend=bottom --prop colors=4472C4,ED7D31,A5A5A5 --prop seriesoutline=000000:0.5 --prop categories="$CATS" --prop data="$D3"
$CLI add "$FILE" /slide[6] --type chart --prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=bar --prop title="gradient + seriesshadow" --prop legend=bottom --prop gradient=FF6600-FFCC00:90 --prop seriesshadow=000000-5-45-3-50 --prop categories="$CATS" --prop data="A:60,90,140,180"
$CLI add "$FILE" /slide[6] --type chart --prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=bar --prop title="transparency=30 + gradients" --prop legend=bottom --prop gradients="FF0000-0000FF;00FF00-FFFF00" --prop transparency=30 --prop categories="$CATS" --prop data="A:60,90,140,180;B:40,70,100,130"
$CLI add "$FILE" /slide[6] --type chart --prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=stackedBar --prop title="stacked + serlines=true" --prop serlines=true --prop legend=bottom --prop categories="$CATS" --prop data="$D2"
# ==================== Slide 7: Overlays ====================
$CLI add "$FILE" / --type slide
$CLI add "$FILE" /slide[7] --type shape --prop text="Overlays — referenceline, errbars, gapwidth, overlap, dataTable" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
$CLI add "$FILE" /slide[7] --type chart --prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=bar --prop title="referenceline=100" --prop legend=none --prop referenceline=100:FF0000:Target --prop categories="$CATS" --prop data="A:60,90,140,180"
$CLI add "$FILE" /slide[7] --type chart --prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=bar --prop title="errbars=fixedVal:10" --prop legend=none --prop errbars=fixedVal:10 --prop categories="$CATS" --prop data="A:60,90,140,180"
$CLI add "$FILE" /slide[7] --type chart --prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=bar --prop title="gapwidth=50 + overlap=20" --prop legend=bottom --prop gapwidth=50 --prop overlap=20 --prop categories="$CATS" --prop data="A:60,90,140,180;B:50,75,110,150"
$CLI add "$FILE" /slide[7] --type chart --prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=bar --prop title="dataTable=true" --prop legend=bottom --prop dataTable=true --prop categories="$CATS" --prop data="A:60,90,140,180"
# ==================== Slide 8: Presets & per-series control ====================
$CLI add "$FILE" / --type slide
$CLI add "$FILE" /slide[8] --type shape --prop text="Presets & per-series control" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
$CLI add "$FILE" /slide[8] --type chart --prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=bar --prop preset=minimal --prop title="preset=minimal" --prop legend=bottom --prop categories="$CATS" --prop data="A:60,90,140,180;B:50,75,110,150"
$CLI add "$FILE" /slide[8] --type chart --prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=bar --prop preset=dark --prop title="preset=dark" --prop legend=bottom --prop categories="$CATS" --prop data="A:60,90,140,180;B:50,75,110,150"
$CLI add "$FILE" /slide[8] --type chart --prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=bar --prop preset=corporate --prop title="preset=corporate" --prop legend=bottom --prop categories="$CATS" --prop data="A:60,90,140,180;B:50,75,110,150"
$CLI add "$FILE" /slide[8] --type chart --prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=bar --prop title="seriesN.* Add + chart-series Set" --prop legend=bottom --prop categories="$CATS" --prop series1.name="Product A" --prop series1.values="60,90,140,180" --prop series1.color=4472C4 --prop series2.name="Product B" --prop series2.values="50,75,110,150" --prop series2.color=ED7D31
$CLI set "$FILE" "/slide[8]/chart[4]/series[1]" --prop name=Renamed --prop color=C00000
$CLI close "$FILE"
$CLI validate "$FILE"
echo "Generated: $FILE"
+231
View File
@@ -0,0 +1,231 @@
# Bubble Charts Showcase
This demo consists of three files that work together:
- **charts-bubble.py** — Python script that calls `officecli` commands to generate the deck.
- **charts-bubble.pptx** — The generated 8-slide deck (4 charts per slide, 32 charts total).
- **charts-bubble.md** — This file. Maps each slide to the features it demonstrates.
## Regenerate
```bash
cd examples/ppt/charts
python3 charts-bubble.py
# → charts-bubble.pptx
```
## Chart Slides
### Slide 1 — bubbleScale Variants
```bash
# bubbleScale controls relative size of all bubbles (% of default)
for s in 50 100 150 200; do
officecli add charts-bubble.pptx /slide[1] --type chart \
--prop chartType=bubble --prop title="bubbleScale=$s" \
--prop bubbleScale=$s --prop legend=none \
--prop data="A:5,12,8,18,22,9,15,11"
done
```
**Features:** `chartType=bubble`, `bubbleScale` (50200, % of default)
### Slide 2 — sizerepresents (area vs width)
```bash
officecli add charts-bubble.pptx /slide[2] --type chart \
--prop chartType=bubble --prop title="sizerepresents=area" \
--prop sizerepresents=area --prop legend=none \
--prop data="A:5,12,8,18,22,9,15,11"
officecli add charts-bubble.pptx /slide[2] --type chart \
--prop chartType=bubble --prop title="sizerepresents=width" \
--prop sizerepresents=width --prop legend=none \
--prop data="A:5,12,8,18,22,9,15,11"
# Two series with area
officecli add charts-bubble.pptx /slide[2] --type chart \
--prop chartType=bubble --prop title="area + 2 series" \
--prop sizerepresents=area --prop legend=bottom \
--prop data="A:5,12,8,18,22,9;B:7,11,15,9,20,14"
officecli add charts-bubble.pptx /slide[2] --type chart \
--prop chartType=bubble --prop title="width + 2 series" \
--prop sizerepresents=width --prop legend=bottom \
--prop data="A:5,12,8,18,22,9;B:7,11,15,9,20,14"
```
**Features:** `sizerepresents` (area/width) — controls whether the data value maps to bubble area or diameter
### Slide 3 — shownegbubbles
```bash
# With negative values: shownegbubbles controls visibility
officecli add charts-bubble.pptx /slide[3] --type chart \
--prop chartType=bubble --prop title="shownegbubbles=false" \
--prop shownegbubbles=false --prop legend=none \
--prop data="A:5,-8,12,-15,18,22"
officecli add charts-bubble.pptx /slide[3] --type chart \
--prop chartType=bubble --prop title="shownegbubbles=true" \
--prop shownegbubbles=true --prop legend=none \
--prop data="A:5,-8,12,-15,18,22"
```
**Features:** `shownegbubbles` (true/false) — when false, negative-size bubbles are hidden; when true, they render with inverted color
### Slide 4 — Title and Legend
```bash
officecli add charts-bubble.pptx /slide[4] --type chart \
--prop chartType=bubble --prop title="Styled title" \
--prop title.font=Georgia --prop title.size=20 \
--prop title.color=4472C4 --prop title.bold=true \
--prop legend=bottom --prop data="A:5,12,8,18;B:7,11,15,9"
officecli add charts-bubble.pptx /slide[4] --type chart \
--prop chartType=bubble --prop title="legend=top + legendFont" \
--prop legend=top --prop legendFont="10:333333:Calibri" \
--prop data="A:5,12,8,18;B:7,11,15,9"
officecli add charts-bubble.pptx /slide[4] --type chart \
--prop chartType=bubble --prop title="legend.overlay=true" \
--prop legend=topRight --prop legend.overlay=true \
--prop data="A:5,12,8,18;B:7,11,15,9"
officecli add charts-bubble.pptx /slide[4] --type chart \
--prop chartType=bubble --prop autotitledeleted=true --prop legend=none \
--prop data="A:5,12,8,18;B:7,11,15,9"
```
**Features:** `title.font/size/color/bold`, `legend` positions, `legendFont`, `legend.overlay`, `autotitledeleted`
### Slide 5 — Data Labels
```bash
officecli add charts-bubble.pptx /slide[5] --type chart \
--prop chartType=bubble --prop title="value" --prop dataLabels=value \
--prop labelfont="9:333333:Calibri" --prop legend=none \
--prop data="A:5,12,8,18,22,9,15,11"
officecli add charts-bubble.pptx /slide[5] --type chart \
--prop chartType=bubble --prop title="value,series" \
--prop dataLabels="value,series" --prop legend=none \
--prop data="A:5,12,8,18;B:7,11,15,9"
officecli add charts-bubble.pptx /slide[5] --type chart \
--prop chartType=bubble --prop title="labelPos=top" \
--prop dataLabels=value --prop labelPos=top --prop legend=none \
--prop data="A:5,12,8,18,22,9,15,11"
officecli add charts-bubble.pptx /slide[5] --type chart \
--prop chartType=bubble --prop title="dataLabels=none" \
--prop dataLabels=none --prop legend=none \
--prop data="A:5,12,8,18,22,9,15,11"
```
**Features:** `dataLabels` (value/series/none or combined), `labelPos`, `labelfont`
### Slide 6 — Axes
```bash
officecli add charts-bubble.pptx /slide[6] --type chart \
--prop chartType=bubble --prop title="min/max + titles" \
--prop axismin=0 --prop axismax=30 --prop majorunit=10 \
--prop axistitle="Y" --prop cattitle="X" \
--prop axisfont="10:333333:Calibri" --prop axisline="666666:1" \
--prop legend=none --prop data="A:5,12,8,18,22,9,15,11"
officecli add charts-bubble.pptx /slide[6] --type chart \
--prop chartType=bubble --prop title="gridlines + minorGridlines" \
--prop gridlines="E0E0E0:0.3" --prop minorGridlines="F0F0F0:0.25" \
--prop legend=none --prop data="A:5,12,8,18,22,9,15,11"
officecli add charts-bubble.pptx /slide[6] --type chart \
--prop chartType=bubble --prop title="labelrotation=-30" \
--prop labelrotation=-30 --prop legend=none \
--prop data="A:5,12,8,18,22,9,15,11"
officecli add charts-bubble.pptx /slide[6] --type chart \
--prop chartType=bubble --prop title="dispunits=hundreds" \
--prop dispunits=hundreds --prop legend=none \
--prop data="A:500,1200,800,1800,2200,900"
```
**Features:** `axismin/max`, `majorunit`, `axistitle/cattitle`, `axisfont/axisline`, `gridlines/minorGridlines`, `labelrotation`, `dispunits`
### Slide 7 — Series Styling
```bash
officecli add charts-bubble.pptx /slide[7] --type chart \
--prop chartType=bubble --prop title="colors + seriesoutline" \
--prop colors="4472C4,ED7D31" --prop seriesoutline="000000:0.5" \
--prop legend=bottom --prop data="A:5,12,8,18;B:7,11,15,9"
officecli add charts-bubble.pptx /slide[7] --type chart \
--prop chartType=bubble --prop title="gradient + seriesshadow" \
--prop gradient="FF6600-FFCC00" --prop seriesshadow="000000-5-45-3-50" \
--prop legend=none --prop data="A:5,12,8,18,22,9,15,11"
officecli add charts-bubble.pptx /slide[7] --type chart \
--prop chartType=bubble --prop title="transparency=30" \
--prop transparency=30 --prop legend=bottom \
--prop data="A:5,12,8,18;B:7,11,15,9"
officecli add charts-bubble.pptx /slide[7] --type chart \
--prop chartType=bubble --prop title="per-series gradients" \
--prop gradients="FF0000-0000FF;00FF00-FFFF00" --prop legend=bottom \
--prop data="A:5,12,8,18;B:7,11,15,9"
```
**Features:** `colors`, `seriesoutline`, `gradient`, `seriesshadow`, `transparency`, `gradients`
### Slide 8 — Presets and Per-Series Set
```bash
for p in minimal dark corporate; do
officecli add charts-bubble.pptx /slide[8] --type chart \
--prop chartType=bubble --prop preset=$p --prop title="preset=$p" \
--prop legend=bottom --prop data="A:5,12,8,18;B:7,11,15,9"
done
officecli add charts-bubble.pptx /slide[8] --type chart \
--prop chartType=bubble --prop title="chart-series Set name+color" \
--prop legend=bottom --prop data="A:5,12,8,18;B:7,11,15,9"
officecli set charts-bubble.pptx "/slide[8]/chart[4]/series[1]" \
--prop name="Renamed A" --prop color=C00000
officecli set charts-bubble.pptx "/slide[8]/chart[4]/series[2]" \
--prop name="Renamed B" --prop color=2E75B6
```
**Features:** `preset` (minimal/dark/corporate), `chart-series Set`
## Complete Feature Coverage
| Feature | Slide |
|---------|-------|
| **bubbleScale** (50200) | 1 |
| **sizerepresents** (area/width) | 2 |
| **shownegbubbles** | 3 |
| **title.font/size/color/bold** | 4 |
| **legend** positions, legendFont, legend.overlay | 4 |
| **autotitledeleted** | 4 |
| **dataLabels:** value/series/none | 5 |
| **labelPos, labelfont** | 5 |
| **axismin/max**, majorunit, axistitle/cattitle | 6 |
| **axisfont, axisline, gridlines** | 6 |
| **labelrotation, dispunits** | 6 |
| **colors, seriesoutline, gradient, seriesshadow** | 7 |
| **transparency, gradients** | 7 |
| **preset** | 8 |
| **chart-series Set** | 8 |
## Inspect the Generated File
```bash
officecli query charts-bubble.pptx chart
officecli get charts-bubble.pptx "/slide[1]/chart[1]"
officecli get charts-bubble.pptx "/slide[3]/chart[1]"
officecli get charts-bubble.pptx "/slide[8]/chart[4]/series[1]"
```
Binary file not shown.
+183
View File
@@ -0,0 +1,183 @@
#!/usr/bin/env python3
"""
Bubble Charts Showcase — generates charts-bubble.pptx exercising the pptx
`chart` element with chartType=bubble across the full styling surface.
SDK twin of charts-bubble.sh (officecli CLI). Both produce an equivalent
charts-bubble.pptx. This one drives the **officecli Python SDK**
(`pip install officecli-sdk`): one resident is started and every slide, title
shape, and chart is shipped over the named pipe in `doc.batch(...)`
round-trips. Each item is the same `{"command","parent","type","props"}` dict
you'd put in an `officecli batch` list.
Slide 1 bubbleScale 50 / 100 / 150 / 200 (% of default)
Slide 2 sizerepresents area vs width
Slide 3 shownegbubbles true vs false (with negative values)
Slide 4 Title & legend title.* + legend positions + legendFont
Slide 5 Data labels value/category/bubbleSize, labelfont
Slide 6 Axes min/max, gridlines, ticks
Slide 7 Series styling colors, gradient, transparency, outline, shadow
Slide 8 Presets & per-series preset bundles + chart-series Set
Usage:
pip install officecli-sdk # plus the `officecli` binary on PATH
python3 charts-bubble.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__)), "charts-bubble.pptx")
# Quadrant boxes (same layout the CLI twin uses for every slide).
TL = {"x": "0.3in", "y": "1.05in", "width": "6.1in", "height": "3in"}
TR = {"x": "6.95in", "y": "1.05in", "width": "6.1in", "height": "3in"}
BL = {"x": "0.3in", "y": "4.25in", "width": "6.1in", "height": "3in"}
BR = {"x": "6.95in", "y": "4.25in", "width": "6.1in", "height": "3in"}
D = "A:5,12,8,18,22,9,15,11"
D2 = "A:5,12,8,18,22,9;B:7,11,15,9,20,14"
_slide = 0
def new_slide(title):
"""Batch items: one `add slide` + its bold title shape. Bumps the slide index."""
global _slide
_slide += 1
return [
{"command": "add", "parent": "/", "type": "slide", "props": {}},
{"command": "add", "parent": f"/slide[{_slide}]", "type": "shape",
"props": {"text": title, "size": "24", "bold": "true", "autoFit": "normal",
"x": "0.5in", "y": "0.3in", "width": "12.3in", "height": "0.6in"}},
]
def ch(box, props):
"""One `add chart` item in the current slide, merging the quadrant box."""
return {"command": "add", "parent": f"/slide[{_slide}]", "type": "chart",
"props": {**box, **props}}
print(f"Building {FILE} ...")
with officecli.create(FILE, "--force") as doc:
items = []
# --- Slide 1: bubbleScale 50 / 100 / 150 / 200 -----------------------------
items += new_slide("bubbleScale — 50 / 100 / 150 / 200 (% of default)")
for box, s in zip([TL, TR, BL, BR], [50, 100, 150, 200]):
items.append(ch(box, {"chartType": "bubble", "title": f"bubbleScale={s}",
"bubbleScale": str(s), "legend": "none", "data": D}))
# --- Slide 2: sizerepresents area vs width ---------------------------------
items += new_slide("sizerepresents — area vs width")
items.append(ch(TL, {"chartType": "bubble", "title": "sizerepresents=area",
"sizerepresents": "area", "legend": "none", "data": D}))
items.append(ch(TR, {"chartType": "bubble", "title": "sizerepresents=width",
"sizerepresents": "width", "legend": "none", "data": D}))
items.append(ch(BL, {"chartType": "bubble", "title": "area + 2 series",
"sizerepresents": "area", "legend": "bottom", "data": D2}))
items.append(ch(BR, {"chartType": "bubble", "title": "width + 2 series",
"sizerepresents": "width", "legend": "bottom", "data": D2}))
# --- Slide 3: shownegbubbles false vs true ---------------------------------
items += new_slide("shownegbubbles — false vs true")
items.append(ch(TL, {"chartType": "bubble", "title": "shownegbubbles=false",
"shownegbubbles": "false", "legend": "none",
"data": "A:5,-8,12,-15,18,22"}))
items.append(ch(TR, {"chartType": "bubble", "title": "shownegbubbles=true",
"shownegbubbles": "true", "legend": "none",
"data": "A:5,-8,12,-15,18,22"}))
items.append(ch(BL, {"chartType": "bubble", "title": "false + 2 series",
"shownegbubbles": "false", "legend": "bottom",
"data": "A:5,-8,12,-15,18,22;B:8,11,-9,14,-16,20"}))
items.append(ch(BR, {"chartType": "bubble", "title": "true + 2 series",
"shownegbubbles": "true", "legend": "bottom",
"data": "A:5,-8,12,-15,18,22;B:8,11,-9,14,-16,20"}))
# --- Slide 4: Title & legend -----------------------------------------------
items += new_slide("Title & legend")
items.append(ch(TL, {"chartType": "bubble", "title": "Styled title",
"title.font": "Georgia", "title.size": "20",
"title.color": "4472C4", "title.bold": "true",
"legend": "bottom", "data": D2}))
items.append(ch(TR, {"chartType": "bubble", "title": "legend=top + legendFont",
"legend": "top", "legendFont": "10:333333:Calibri", "data": D2}))
items.append(ch(BL, {"chartType": "bubble", "title": "legend.overlay=true",
"legend": "topRight", "legend.overlay": "true", "data": D2}))
items.append(ch(BR, {"chartType": "bubble", "autotitledeleted": "true",
"legend": "none", "data": D2}))
# --- Slide 5: Data labels --------------------------------------------------
items += new_slide("Data labels — flags + labelfont")
items.append(ch(TL, {"chartType": "bubble", "title": "value", "dataLabels": "value",
"labelfont": "9:333333:Calibri", "legend": "none", "data": D}))
items.append(ch(TR, {"chartType": "bubble", "title": "value,series",
"dataLabels": "value,series", "legend": "none", "data": D2}))
items.append(ch(BL, {"chartType": "bubble", "title": "labelPos=top",
"dataLabels": "value", "labelPos": "top",
"legend": "none", "data": D}))
items.append(ch(BR, {"chartType": "bubble", "title": "dataLabels=none",
"dataLabels": "none", "legend": "none", "data": D}))
# --- Slide 6: Axes ---------------------------------------------------------
items += new_slide("Axes — min/max, gridlines, ticks")
items.append(ch(TL, {"chartType": "bubble", "title": "min/max + titles",
"axismin": "0", "axismax": "30", "majorunit": "10",
"axistitle": "Y", "cattitle": "X",
"axisfont": "10:333333:Calibri", "axisline": "666666:1",
"legend": "none", "data": D}))
items.append(ch(TR, {"chartType": "bubble", "title": "gridlines + minorGridlines",
"gridlines": "E0E0E0:0.3", "minorGridlines": "F0F0F0:0.25",
"legend": "none", "data": D}))
items.append(ch(BL, {"chartType": "bubble", "title": "labelrotation=-30",
"labelrotation": "-30", "legend": "none", "data": D}))
items.append(ch(BR, {"chartType": "bubble", "title": "dispunits=hundreds",
"dispunits": "hundreds", "legend": "none",
"data": "A:500,1200,800,1800,2200,900"}))
# --- Slide 7: Series styling -----------------------------------------------
items += new_slide("Series styling — colors, gradient, transparency, outline, shadow")
items.append(ch(TL, {"chartType": "bubble", "title": "colors + seriesoutline",
"colors": "4472C4,ED7D31", "seriesoutline": "000000:0.5",
"legend": "bottom", "data": D2}))
items.append(ch(TR, {"chartType": "bubble", "title": "gradient + seriesshadow",
"gradient": "FF6600-FFCC00", "seriesshadow": "000000-5-45-3-50",
"legend": "none", "data": D}))
items.append(ch(BL, {"chartType": "bubble", "title": "transparency=30",
"transparency": "30", "legend": "bottom", "data": D2}))
items.append(ch(BR, {"chartType": "bubble", "title": "per-series gradients",
"gradients": "FF0000-0000FF;00FF00-FFFF00",
"legend": "bottom", "data": D2}))
# --- Slide 8: Presets & per-series Set -------------------------------------
items += new_slide("Presets & per-series Set")
for box, p in zip([TL, TR, BL], ["minimal", "dark", "corporate"]):
items.append(ch(box, {"chartType": "bubble", "preset": p, "title": f"preset={p}",
"legend": "bottom", "data": D2}))
items.append(ch(BR, {"chartType": "bubble", "title": "chart-series Set name+color",
"legend": "bottom", "data": D2}))
doc.batch(items)
print(f" added {_slide} slides ({len(items)} items)")
# chart-series Set (slide 8, chart[4]) — must run after the chart exists.
doc.batch([
{"command": "set", "path": f"/slide[{_slide}]/chart[4]/series[1]",
"props": {"name": "Renamed A", "color": "C00000"}},
{"command": "set", "path": f"/slide[{_slide}]/chart[4]/series[2]",
"props": {"name": "Renamed B", "color": "2E75B6"}},
])
print(" applied per-series name+color Set on slide 8 chart[4]")
doc.send({"command": "save"})
print(f"Generated: {FILE} ({_slide} slides)")
+106
View File
@@ -0,0 +1,106 @@
#!/bin/bash
# Bubble Charts Showcase — generates charts-bubble.pptx exercising the pptx
# `chart` element with chartType=bubble across the full styling surface.
#
# CLI twin of charts-bubble.py (officecli Python SDK). Both produce an
# equivalent charts-bubble.pptx.
#
# Slide 1 bubbleScale 50 / 100 / 150 / 200 (% of default)
# Slide 2 sizerepresents area vs width
# Slide 3 shownegbubbles true vs false (with negative values)
# Slide 4 Title & legend title.* + legend positions + legendFont
# Slide 5 Data labels value/category/bubbleSize, labelfont
# Slide 6 Axes min/max, gridlines, ticks
# Slide 7 Series styling colors, gradient, transparency, outline, shadow
# Slide 8 Presets & per-series preset bundles + chart-series Set
#
# Usage: ./charts-bubble.sh [officecli path]
# NOTE: intentionally NO `set -e`. Like the SDK twin's doc.batch, this script
# tolerates forward-compat 'UNSUPPORTED props' warnings (officecli exit 2) and
# keeps building so the full document is produced.
CLI="${1:-officecli}"
FILE="$(dirname "$0")/charts-bubble.pptx"
# Quadrant boxes (reused on every slide).
TL=(--prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in)
TR=(--prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in)
BL=(--prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in)
BR=(--prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in)
D="A:5,12,8,18,22,9,15,11"
D2="A:5,12,8,18,22,9;B:7,11,15,9,20,14"
rm -f "$FILE"
$CLI create "$FILE"
$CLI open "$FILE"
# ==================== Slide 1: bubbleScale ====================
$CLI add "$FILE" / --type slide
$CLI add "$FILE" /slide[1] --type shape --prop text="bubbleScale — 50 / 100 / 150 / 200 (% of default)" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
$CLI add "$FILE" /slide[1] --type chart "${TL[@]}" --prop chartType=bubble --prop title=bubbleScale=50 --prop bubbleScale=50 --prop legend=none --prop data="$D"
$CLI add "$FILE" /slide[1] --type chart "${TR[@]}" --prop chartType=bubble --prop title=bubbleScale=100 --prop bubbleScale=100 --prop legend=none --prop data="$D"
$CLI add "$FILE" /slide[1] --type chart "${BL[@]}" --prop chartType=bubble --prop title=bubbleScale=150 --prop bubbleScale=150 --prop legend=none --prop data="$D"
$CLI add "$FILE" /slide[1] --type chart "${BR[@]}" --prop chartType=bubble --prop title=bubbleScale=200 --prop bubbleScale=200 --prop legend=none --prop data="$D"
# ==================== Slide 2: sizerepresents ====================
$CLI add "$FILE" / --type slide
$CLI add "$FILE" /slide[2] --type shape --prop text="sizerepresents — area vs width" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
$CLI add "$FILE" /slide[2] --type chart "${TL[@]}" --prop chartType=bubble --prop title="sizerepresents=area" --prop sizerepresents=area --prop legend=none --prop data="$D"
$CLI add "$FILE" /slide[2] --type chart "${TR[@]}" --prop chartType=bubble --prop title="sizerepresents=width" --prop sizerepresents=width --prop legend=none --prop data="$D"
$CLI add "$FILE" /slide[2] --type chart "${BL[@]}" --prop chartType=bubble --prop title="area + 2 series" --prop sizerepresents=area --prop legend=bottom --prop data="$D2"
$CLI add "$FILE" /slide[2] --type chart "${BR[@]}" --prop chartType=bubble --prop title="width + 2 series" --prop sizerepresents=width --prop legend=bottom --prop data="$D2"
# ==================== Slide 3: shownegbubbles ====================
$CLI add "$FILE" / --type slide
$CLI add "$FILE" /slide[3] --type shape --prop text="shownegbubbles — false vs true" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
$CLI add "$FILE" /slide[3] --type chart "${TL[@]}" --prop chartType=bubble --prop title="shownegbubbles=false" --prop shownegbubbles=false --prop legend=none --prop data="A:5,-8,12,-15,18,22"
$CLI add "$FILE" /slide[3] --type chart "${TR[@]}" --prop chartType=bubble --prop title="shownegbubbles=true" --prop shownegbubbles=true --prop legend=none --prop data="A:5,-8,12,-15,18,22"
$CLI add "$FILE" /slide[3] --type chart "${BL[@]}" --prop chartType=bubble --prop title="false + 2 series" --prop shownegbubbles=false --prop legend=bottom --prop data="A:5,-8,12,-15,18,22;B:8,11,-9,14,-16,20"
$CLI add "$FILE" /slide[3] --type chart "${BR[@]}" --prop chartType=bubble --prop title="true + 2 series" --prop shownegbubbles=true --prop legend=bottom --prop data="A:5,-8,12,-15,18,22;B:8,11,-9,14,-16,20"
# ==================== Slide 4: Title & legend ====================
$CLI add "$FILE" / --type slide
$CLI add "$FILE" /slide[4] --type shape --prop text="Title & legend" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
$CLI add "$FILE" /slide[4] --type chart "${TL[@]}" --prop chartType=bubble --prop title="Styled title" --prop title.font=Georgia --prop title.size=20 --prop title.color=4472C4 --prop title.bold=true --prop legend=bottom --prop data="$D2"
$CLI add "$FILE" /slide[4] --type chart "${TR[@]}" --prop chartType=bubble --prop title="legend=top + legendFont" --prop legend=top --prop legendFont=10:333333:Calibri --prop data="$D2"
$CLI add "$FILE" /slide[4] --type chart "${BL[@]}" --prop chartType=bubble --prop title="legend.overlay=true" --prop legend=topRight --prop legend.overlay=true --prop data="$D2"
$CLI add "$FILE" /slide[4] --type chart "${BR[@]}" --prop chartType=bubble --prop autotitledeleted=true --prop legend=none --prop data="$D2"
# ==================== Slide 5: Data labels ====================
$CLI add "$FILE" / --type slide
$CLI add "$FILE" /slide[5] --type shape --prop text="Data labels — flags + labelfont" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
$CLI add "$FILE" /slide[5] --type chart "${TL[@]}" --prop chartType=bubble --prop title=value --prop dataLabels=value --prop labelfont=9:333333:Calibri --prop legend=none --prop data="$D"
$CLI add "$FILE" /slide[5] --type chart "${TR[@]}" --prop chartType=bubble --prop title="value,series" --prop dataLabels=value,series --prop legend=none --prop data="$D2"
$CLI add "$FILE" /slide[5] --type chart "${BL[@]}" --prop chartType=bubble --prop title="labelPos=top" --prop dataLabels=value --prop labelPos=top --prop legend=none --prop data="$D"
$CLI add "$FILE" /slide[5] --type chart "${BR[@]}" --prop chartType=bubble --prop title="dataLabels=none" --prop dataLabels=none --prop legend=none --prop data="$D"
# ==================== Slide 6: Axes ====================
$CLI add "$FILE" / --type slide
$CLI add "$FILE" /slide[6] --type shape --prop text="Axes — min/max, gridlines, ticks" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
$CLI add "$FILE" /slide[6] --type chart "${TL[@]}" --prop chartType=bubble --prop title="min/max + titles" --prop axismin=0 --prop axismax=30 --prop majorunit=10 --prop axistitle=Y --prop cattitle=X --prop axisfont=10:333333:Calibri --prop axisline=666666:1 --prop legend=none --prop data="$D"
$CLI add "$FILE" /slide[6] --type chart "${TR[@]}" --prop chartType=bubble --prop title="gridlines + minorGridlines" --prop gridlines=E0E0E0:0.3 --prop minorGridlines=F0F0F0:0.25 --prop legend=none --prop data="$D"
$CLI add "$FILE" /slide[6] --type chart "${BL[@]}" --prop chartType=bubble --prop title="labelrotation=-30" --prop labelrotation=-30 --prop legend=none --prop data="$D"
$CLI add "$FILE" /slide[6] --type chart "${BR[@]}" --prop chartType=bubble --prop title="dispunits=hundreds" --prop dispunits=hundreds --prop legend=none --prop data="A:500,1200,800,1800,2200,900"
# ==================== Slide 7: Series styling ====================
$CLI add "$FILE" / --type slide
$CLI add "$FILE" /slide[7] --type shape --prop text="Series styling — colors, gradient, transparency, outline, shadow" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
$CLI add "$FILE" /slide[7] --type chart "${TL[@]}" --prop chartType=bubble --prop title="colors + seriesoutline" --prop colors=4472C4,ED7D31 --prop seriesoutline=000000:0.5 --prop legend=bottom --prop data="$D2"
$CLI add "$FILE" /slide[7] --type chart "${TR[@]}" --prop chartType=bubble --prop title="gradient + seriesshadow" --prop gradient=FF6600-FFCC00 --prop seriesshadow=000000-5-45-3-50 --prop legend=none --prop data="$D"
$CLI add "$FILE" /slide[7] --type chart "${BL[@]}" --prop chartType=bubble --prop title="transparency=30" --prop transparency=30 --prop legend=bottom --prop data="$D2"
$CLI add "$FILE" /slide[7] --type chart "${BR[@]}" --prop chartType=bubble --prop title="per-series gradients" --prop gradients="FF0000-0000FF;00FF00-FFFF00" --prop legend=bottom --prop data="$D2"
# ==================== Slide 8: Presets & per-series Set ====================
$CLI add "$FILE" / --type slide
$CLI add "$FILE" /slide[8] --type shape --prop text="Presets & per-series Set" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
$CLI add "$FILE" /slide[8] --type chart "${TL[@]}" --prop chartType=bubble --prop preset=minimal --prop title="preset=minimal" --prop legend=bottom --prop data="$D2"
$CLI add "$FILE" /slide[8] --type chart "${TR[@]}" --prop chartType=bubble --prop preset=dark --prop title="preset=dark" --prop legend=bottom --prop data="$D2"
$CLI add "$FILE" /slide[8] --type chart "${BL[@]}" --prop chartType=bubble --prop preset=corporate --prop title="preset=corporate" --prop legend=bottom --prop data="$D2"
$CLI add "$FILE" /slide[8] --type chart "${BR[@]}" --prop chartType=bubble --prop title="chart-series Set name+color" --prop legend=bottom --prop data="$D2"
# chart-series Set (slide 8, chart[4]) — runs after the chart exists.
$CLI set "$FILE" /slide[8]/chart[4]/series[1] --prop name="Renamed A" --prop color=C00000
$CLI set "$FILE" /slide[8]/chart[4]/series[2] --prop name="Renamed B" --prop color=2E75B6
$CLI close "$FILE"
$CLI validate "$FILE"
echo "Generated: $FILE"
+354
View File
@@ -0,0 +1,354 @@
# Column Charts Showcase
This demo consists of three files that work together:
- **charts-column.py** — Python script that calls `officecli` commands to generate the deck. Each chart command is shown as a copyable shell command below.
- **charts-column.pptx** — The generated 8-slide deck (4 charts per slide, 32 charts total).
- **charts-column.md** — This file. Maps each slide to the features it demonstrates.
## Regenerate
```bash
cd examples/ppt/charts
python3 charts-column.py
# → charts-column.pptx
```
## Chart Slides
### Slide 1 — Basic Variants
Four column chart type variants covering the basic options.
```bash
# Standard clustered column
officecli add charts-column.pptx /slide[1] --type chart \
--prop chartType=column --prop title="column" --prop legend=bottom \
--prop categories="Q1,Q2,Q3,Q4" \
--prop data="East:120,135,148,162;West:95,108,115,128" \
--prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in
# Stacked column — values accumulate per category
officecli add charts-column.pptx /slide[1] --type chart \
--prop chartType=stackedColumn --prop title="stackedColumn" --prop legend=bottom \
--prop categories="Q1,Q2,Q3,Q4" \
--prop data="East:120,135,148,162;South:95,108,115,128;West:80,90,98,110" \
--prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in
# 100% stacked column — proportional
officecli add charts-column.pptx /slide[1] --type chart \
--prop chartType=percentStackedColumn --prop title="percentStackedColumn" \
--prop legend=bottom --prop categories="Q1,Q2,Q3,Q4" \
--prop data="East:120,135,148,162;South:95,108,115,128;West:80,90,98,110" \
--prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in
# 3D column with perspective and depth
officecli add charts-column.pptx /slide[1] --type chart \
--prop chartType=column3d --prop view3d="15,20,30" --prop gapdepth=150 \
--prop title="column3d (view3d=15,20,30)" --prop legend=bottom \
--prop categories="Q1,Q2,Q3,Q4" \
--prop data="East:120,135,148,162;West:95,108,115,128" \
--prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in
```
**Features:** `chartType` (column/stackedColumn/percentStackedColumn/column3d), `categories`, `data` (Name:v1,v2,… semicolon-separated), `legend` (bottom/top/right/none), `view3d` (rotX,rotY,perspective), `gapdepth`
### Slide 2 — Title and Legend
```bash
# Styled chart title
officecli add charts-column.pptx /slide[2] --type chart \
--prop chartType=column --prop title="Styled title" \
--prop title.font=Georgia --prop title.size=20 \
--prop title.color=4472C4 --prop title.bold=true \
--prop legend=bottom --prop categories="Q1,Q2,Q3,Q4" \
--prop data="East:120,135,148,162;West:95,108,115,128"
# Legend at top with custom font
officecli add charts-column.pptx /slide[2] --type chart \
--prop chartType=column --prop title="legend=top + legendFont" \
--prop legend=top --prop legendFont="10:333333:Calibri" \
--prop categories="Q1,Q2,Q3,Q4" \
--prop data="East:120,135,148,162;West:95,108,115,128"
# Legend overlay (drawn over chart area, not reserving space)
officecli add charts-column.pptx /slide[2] --type chart \
--prop chartType=column --prop title="legend=topRight overlay" \
--prop legend=topRight --prop legend.overlay=true \
--prop categories="Q1,Q2,Q3,Q4" \
--prop data="East:120,135,148,162;West:95,108,115,128"
# No title, no legend
officecli add charts-column.pptx /slide[2] --type chart \
--prop chartType=column --prop autotitledeleted=true --prop legend=none \
--prop categories="Q1,Q2,Q3,Q4" \
--prop data="East:120,135,148,162;West:95,108,115,128"
```
**Features:** `title.font`, `title.size`, `title.color`, `title.bold`, `legend` (bottom/top/topRight/none), `legendFont` (size:color:face), `legend.overlay`, `autotitledeleted`
### Slide 3 — Data Labels
```bash
# Value labels above bars (outsideEnd)
officecli add charts-column.pptx /slide[3] --type chart \
--prop chartType=column --prop title="value @ outsideEnd" \
--prop dataLabels=value --prop labelPos=outsideEnd \
--prop labelfont="10:333333:Calibri" --prop legend=none \
--prop categories="Q1,Q2,Q3,Q4" --prop data="A:60,90,140,180"
# Value + category labels inside top of bars
officecli add charts-column.pptx /slide[3] --type chart \
--prop chartType=column --prop title="value,category @ insideEnd" \
--prop dataLabels="value,category" --prop labelPos=insideEnd \
--prop labelfont="9:FFFFFF:Calibri" --prop legend=none \
--prop categories="Q1,Q2,Q3,Q4" --prop data="A:60,90,140,180"
# Stacked column with center labels
officecli add charts-column.pptx /slide[3] --type chart \
--prop chartType=stackedColumn --prop title="stacked + center labels" \
--prop dataLabels=value --prop labelPos=center \
--prop labelfont="9:FFFFFF:Calibri" --prop legend=bottom \
--prop categories="Q1,Q2,Q3,Q4" \
--prop data="East:120,135,148,162;South:95,108,115,128;West:80,90,98,110"
# Suppress labels
officecli add charts-column.pptx /slide[3] --type chart \
--prop chartType=column --prop title="dataLabels=none" \
--prop dataLabels=none --prop legend=none \
--prop categories="Q1,Q2,Q3,Q4" --prop data="A:60,90,140,180"
```
**Features:** `dataLabels` (value/category/percent/none or comma-combined), `labelPos` (outsideEnd/insideEnd/insideBase/center), `labelfont` (size:color:face)
### Slide 4 — Axes
```bash
# Axis scaling, titles, number format, axis line
officecli add charts-column.pptx /slide[4] --type chart \
--prop chartType=column --prop title="axis min/max + titles + numfmt" \
--prop legend=none \
--prop axismin=0 --prop axismax=200 --prop majorunit=50 --prop minorunit=10 \
--prop axistitle="Revenue (USD)" --prop cattitle="Quarter" \
--prop axisfont="10:333333:Calibri" --prop axisline="666666:1" \
--prop axisnumfmt="#,##0" \
--prop categories="Q1,Q2,Q3,Q4" --prop data="Rev:60,90,140,180"
# Gridlines and tick marks
officecli add charts-column.pptx /slide[4] --type chart \
--prop chartType=column --prop title="gridlines + minorGridlines + ticks" \
--prop legend=none \
--prop gridlines="E0E0E0:0.3" --prop minorGridlines="F0F0F0:0.25" \
--prop majorTickMark=out --prop minorTickMark=in --prop tickLabelPos=nextTo \
--prop labelrotation=-30 \
--prop categories="January,February,March,April" \
--prop data="A:60,90,140,180"
# Display units (thousands)
officecli add charts-column.pptx /slide[4] --type chart \
--prop chartType=column --prop title="dispunits=thousands" --prop legend=none \
--prop dispunits=thousands \
--prop categories="Q1,Q2,Q3,Q4" \
--prop data="Rev:120000,135000,148000,162000"
# Secondary axis (combo: column + line on right axis)
officecli add charts-column.pptx /slide[4] --type chart \
--prop chartType=combo --prop combotypes="column,line" --prop secondaryaxis=2 \
--prop title="secondaryaxis=2 (line on right)" --prop legend=bottom \
--prop categories="Q1,Q2,Q3,Q4" \
--prop data="Sales:120,135,148,162;Growth %:5,12,18,22"
# chart-axis Set: modify axis properties after chart creation
officecli set charts-column.pptx "/slide[4]/chart[1]/axis[@role=value]" \
--prop title="Revenue (USD)" --prop format='$#,##0' \
--prop majorGridlines=true --prop minorGridlines=false \
--prop max=200 --prop min=0 --prop majorUnit=50
```
**Features:** `axismin`, `axismax`, `majorunit`, `minorunit`, `axistitle`, `cattitle`, `axisfont`, `axisline` (color:width), `axisnumfmt`, `gridlines` (color:width), `minorGridlines`, `majorTickMark` (out/in/cross/none), `minorTickMark`, `tickLabelPos` (nextTo/high/low/none), `labelrotation`, `dispunits` (hundreds/thousands/millions/…), `secondaryaxis`, `chart-axis Set`
### Slide 5 — Series Styling
```bash
# Explicit palette + series outline
officecli add charts-column.pptx /slide[5] --type chart \
--prop chartType=column --prop title="colors + seriesoutline" --prop legend=bottom \
--prop colors="4472C4,ED7D31,A5A5A5" --prop seriesoutline="000000:0.5" \
--prop categories="Q1,Q2,Q3,Q4" \
--prop data="East:120,135,148,162;South:95,108,115,128;West:80,90,98,110"
# Gradient fill + drop shadow on series
officecli add charts-column.pptx /slide[5] --type chart \
--prop chartType=column --prop title="gradient + seriesshadow" --prop legend=bottom \
--prop gradient="FF6600-FFCC00:90" --prop seriesshadow="000000-5-45-3-50" \
--prop categories="Q1,Q2,Q3,Q4" --prop data="A:60,90,140,180"
# Per-series gradients + transparency
officecli add charts-column.pptx /slide[5] --type chart \
--prop chartType=column --prop title="per-series gradients + transparency=30" \
--prop legend=bottom \
--prop gradients="FF0000-0000FF;00FF00-FFFF00" --prop transparency=30 \
--prop categories="Q1,Q2,Q3,Q4" \
--prop data="A:60,90,140,180;B:40,70,100,130"
# Invert negative bars + conditional color rule
officecli add charts-column.pptx /slide[5] --type chart \
--prop chartType=column --prop title="invertifneg + colorrule" --prop legend=none \
--prop invertifneg=true --prop colorrule="0:FF0000:00AA00" \
--prop categories="Q1,Q2,Q3,Q4,Q5" \
--prop data="Net:60,-30,40,-50,80"
# chart-series Set: recolor series 1 after creation
officecli set charts-column.pptx "/slide[5]/chart[1]/series[1]" \
--prop color=2E75B6
```
**Features:** `colors` (comma palette), `seriesoutline` (color:width), `gradient` (color1-color2:angle), `seriesshadow` (color-blur-angle-dist-opacity), `gradients` (semicolon-separated per-series), `transparency` (0100), `invertifneg`, `colorrule` (threshold:belowColor:aboveColor), `chart-series Set color=`
### Slide 6 — Layout and Overlays
```bash
# Gap width + overlap (clustered spacing)
officecli add charts-column.pptx /slide[6] --type chart \
--prop chartType=column --prop title="gapwidth=50 + overlap=20" \
--prop legend=bottom --prop gapwidth=50 --prop overlap=20 \
--prop categories="Q1,Q2,Q3,Q4" \
--prop data="A:60,90,140,180;B:50,75,110,150"
# Reference line (horizontal threshold marker)
officecli add charts-column.pptx /slide[6] --type chart \
--prop chartType=column --prop title="referenceline=100" --prop legend=none \
--prop referenceline="100:FF0000:Target" \
--prop categories="Q1,Q2,Q3,Q4" --prop data="A:60,90,140,180"
# Error bars
officecli add charts-column.pptx /slide[6] --type chart \
--prop chartType=column --prop title="errbars=percentage:10" --prop legend=none \
--prop errbars="percentage:10" \
--prop categories="Q1,Q2,Q3,Q4" --prop data="A:60,90,140,180"
# Data table + trend line
officecli add charts-column.pptx /slide[6] --type chart \
--prop chartType=column --prop title="dataTable=true + trendline=linear" \
--prop legend=bottom --prop dataTable=true --prop trendline=linear \
--prop categories="Q1,Q2,Q3,Q4" --prop data="A:60,90,140,180"
```
**Features:** `gapwidth` (0500), `overlap` (-100100), `referenceline` (value:color:label), `errbars` (fixedVal/percentage/stdDev/stdError:value), `trendline` (linear/poly/exp/log/power/movingAvg), `dataTable`
### Slide 7 — Backgrounds
```bash
# Chart area + plot area fills with borders
officecli add charts-column.pptx /slide[7] --type chart \
--prop chartType=column --prop title="chartareafill + plotFill + borders" \
--prop legend=bottom \
--prop chartareafill=FFF8E7 --prop plotFill=FAFAFA \
--prop chartborder="000000:1" --prop plotborder="CCCCCC:0.5" \
--prop categories="Q1,Q2,Q3,Q4" --prop data="A:60,90,140,180"
# Rounded corners on chart area
officecli add charts-column.pptx /slide[7] --type chart \
--prop chartType=column --prop title="roundedcorners=true" \
--prop legend=bottom --prop roundedcorners=true \
--prop chartborder="4472C4:2" \
--prop categories="Q1,Q2,Q3,Q4" --prop data="A:60,90,140,180"
# Transparent plot area, no gridlines
officecli add charts-column.pptx /slide[7] --type chart \
--prop chartType=column --prop title="plotFill=none, gridlines=none" \
--prop legend=none --prop plotFill=none --prop gridlines=none \
--prop categories="Q1,Q2,Q3,Q4" --prop data="A:60,90,140,180"
# Per-bar color variation (varyColors)
officecli add charts-column.pptx /slide[7] --type chart \
--prop chartType=column --prop title="varyColors=true (single series)" \
--prop legend=none --prop varyColors=true \
--prop categories="Q1,Q2,Q3,Q4" --prop data="A:60,90,140,180"
```
**Features:** `chartareafill` (hex or none), `plotFill` (hex or none), `chartborder` (color:width), `plotborder` (color:width), `roundedcorners`, `gridlines=none`, `varyColors`
### Slide 8 — Presets and Per-Series Control
```bash
# Built-in preset bundles
officecli add charts-column.pptx /slide[8] --type chart \
--prop chartType=column --prop preset=minimal --prop title="preset=minimal" \
--prop legend=bottom --prop categories="Q1,Q2,Q3,Q4" \
--prop data="A:60,90,140,180;B:50,75,110,150"
officecli add charts-column.pptx /slide[8] --type chart \
--prop chartType=column --prop preset=corporate --prop title="preset=corporate" \
--prop legend=bottom --prop categories="Q1,Q2,Q3,Q4" \
--prop data="A:60,90,140,180;B:50,75,110,150"
officecli add charts-column.pptx /slide[8] --type chart \
--prop chartType=column --prop preset=dark --prop title="preset=dark" \
--prop legend=bottom --prop categories="Q1,Q2,Q3,Q4" \
--prop data="A:60,90,140,180;B:50,75,110,150"
# Per-series control via seriesN.* compound properties
officecli add charts-column.pptx /slide[8] --type chart \
--prop chartType=column --prop title="seriesN.* Add + chart-series Set" \
--prop legend=bottom --prop categories="Q1,Q2,Q3,Q4" \
--prop series1.name="Product A" --prop series1.values="60,90,140,180" \
--prop series1.color=4472C4 \
--prop series2.name="Product B" --prop series2.values="50,75,110,150" \
--prop series2.color=ED7D31 \
--prop series3.name="Product C" --prop series3.values="40,65,90,120" \
--prop series3.color=70AD47
# chart-series Set: rename + recolor after creation
officecli set charts-column.pptx "/slide[8]/chart[4]/series[1]" \
--prop name="Renamed Alpha" --prop color=C00000
```
**Features:** `preset` (minimal/corporate/dark/colorful), `series1.name`/`series1.values`/`series1.color` (per-series at Add time), `chart-series Set name=/color=` (post-Add mutation)
## Complete Feature Coverage
| Feature | Slide |
|---------|-------|
| **Chart types:** column, stackedColumn, percentStackedColumn, column3d | 1 |
| **3D:** view3d (rotX,rotY,perspective), gapdepth | 1 |
| **Data input:** data=, categories=, seriesN.name/values/color | 1, 8 |
| **Title styling:** title.font/size/color/bold | 2 |
| **Legend:** bottom/top/topRight/none, legendFont, legend.overlay | 2 |
| **autotitledeleted** | 2 |
| **dataLabels:** value/category/percent/none + combo | 3 |
| **labelPos:** outsideEnd/insideEnd/insideBase/center | 3 |
| **labelfont** | 3 |
| **Axis scaling:** axismin/max, majorunit, minorunit | 4 |
| **Axis titles:** axistitle, cattitle | 4 |
| **Axis font/line/numfmt:** axisfont, axisline, axisnumfmt | 4 |
| **Gridlines:** gridlines, minorGridlines, gridlines=none | 4, 7 |
| **Tick marks:** majorTickMark, minorTickMark, tickLabelPos | 4 |
| **labelrotation** | 4 |
| **dispunits** (hundreds/thousands/millions/…) | 4 |
| **secondaryaxis** | 4 |
| **chart-axis Set** | 4 |
| **colors** (palette), **seriesoutline**, **seriesshadow** | 5 |
| **gradient**, **gradients** (per-series) | 5 |
| **transparency** (0100) | 5 |
| **invertifneg**, **colorrule** | 5 |
| **chart-series Set** (color, name) | 5, 8 |
| **gapwidth**, **overlap** | 6 |
| **referenceline** | 6 |
| **errbars** (fixedVal/percentage/stdDev/stdError) | 6 |
| **trendline** (linear/poly/exp/…) | 6 |
| **dataTable** | 6 |
| **chartareafill**, **plotFill**, **chartborder**, **plotborder** | 7 |
| **roundedcorners** | 7 |
| **varyColors** | 7 |
| **preset** (minimal/corporate/dark/colorful) | 8 |
| **seriesN.*** per-series at Add time | 8 |
## Inspect the Generated File
```bash
officecli query charts-column.pptx chart
officecli get charts-column.pptx "/slide[1]/chart[1]"
officecli get charts-column.pptx "/slide[5]/chart[1]/series[1]"
officecli get charts-column.pptx "/slide[4]/chart[1]/axis[@role=value]"
```
Binary file not shown.
+287
View File
@@ -0,0 +1,287 @@
#!/usr/bin/env python3
"""
Column Charts Showcase — column, stackedColumn, percentStackedColumn, column3d.
Generates: charts-column.pptx
Every column-applicable property officecli exposes is demonstrated at least
once across the slides:
Slide 1 Basic variants column / stackedColumn / percentStackedColumn / column3d
Slide 2 Title & legend title.font/size/color/bold, legend positions, legendFont
Slide 3 Data labels dataLabels flags, labelPos, labelfont
Slide 4 Axes axismin/max, axistitle, axisfont, axisline, axisnumfmt,
gridlines, minorGridlines, majorunit, minorunit, labelrotation,
dispunits, logbase, secondaryaxis, chart-axis Set
Slide 5 Series styling colors, gradient, gradients, transparency, seriesoutline,
seriesshadow, invertifneg, colorrule
Slide 6 Layout & overlays gapwidth, overlap, referenceline, errbars, trendline, dataTable
Slide 7 Backgrounds chartareafill, plotFill, chartborder, plotborder, roundedcorners
Slide 8 Presets & per-ser preset bundles + seriesN.name/values/color + chart-series Set
SDK twin of charts-column.sh (officecli CLI). Both produce an equivalent
charts-column.pptx. This one drives the **officecli Python SDK**
(`pip install officecli-sdk`): one resident is started and every slide, shape,
chart and post-Add Set is shipped over the named pipe in a single
`doc.batch(...)` round-trip. Each item is the same
`{"command","parent","type","props"}` / `{"command","path","props"}` dict you'd
put in an `officecli batch` list.
Usage:
pip install officecli-sdk # plus the `officecli` binary on PATH
python3 charts-column.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__)), "charts-column.pptx")
# 2x2 grid boxes (widescreen 13.33 x 7.5in)
TL = {"x": "0.3in", "y": "1.05in", "width": "6.1in", "height": "3in"}
TR = {"x": "6.95in", "y": "1.05in", "width": "6.1in", "height": "3in"}
BL = {"x": "0.3in", "y": "4.25in", "width": "6.1in", "height": "3in"}
BR = {"x": "6.95in", "y": "4.25in", "width": "6.1in", "height": "3in"}
CATS = "Q1,Q2,Q3,Q4"
TWO_SERIES = "East:120,135,148,162;West:95,108,115,128"
THREE_SERIES = "East:120,135,148,162;South:95,108,115,128;West:80,90,98,110"
# Slide cursor — mirrors the .sh, where each new slide lands at /slide[N].
_slide = 0
def slide_title(title):
"""Two items: add a slide, then add its title shape."""
global _slide
_slide += 1
return [
{"command": "add", "parent": "/", "type": "slide", "props": {}},
{"command": "add", "parent": f"/slide[{_slide}]", "type": "shape",
"props": {"text": title, "size": 24, "bold": "true", "autoFit": "normal",
"x": "0.5in", "y": "0.3in", "width": "12.3in", "height": "0.6in"}},
]
def chart(box, p):
"""One `add chart` item on the current slide, box props merged in."""
return {"command": "add", "parent": f"/slide[{_slide}]", "type": "chart",
"props": {**box, **p}}
def chart_set(path, p):
"""One post-Add `set` item against a chart axis/series."""
return {"command": "set", "path": path, "props": p}
print(f"Building {FILE} ...")
with officecli.create(FILE, "--force") as doc:
items = []
# -----------------------------------------------------------------------
# Slide 1 — Basic variants
# -----------------------------------------------------------------------
items += slide_title(
"Column variants — column / stackedColumn / percentStackedColumn / column3d")
items += [
chart(TL, {"chartType": "column", "title": "column", "legend": "bottom",
"categories": CATS, "data": TWO_SERIES}),
chart(TR, {"chartType": "stackedColumn", "title": "stackedColumn", "legend": "bottom",
"categories": CATS, "data": THREE_SERIES}),
chart(BL, {"chartType": "percentStackedColumn", "title": "percentStackedColumn",
"legend": "bottom", "categories": CATS, "data": THREE_SERIES}),
chart(BR, {"chartType": "column3d", "view3d": "15,20,30", "gapdepth": "150",
"title": "column3d (view3d=15,20,30)", "legend": "bottom",
"categories": CATS, "data": TWO_SERIES}),
]
# -----------------------------------------------------------------------
# Slide 2 — Title & legend
# -----------------------------------------------------------------------
items += slide_title(
"Title & legend — title.font/size/color/bold, legend positions, legendFont")
items += [
chart(TL, {"chartType": "column", "title": "Styled title",
"title.font": "Georgia", "title.size": "20", "title.color": "4472C4",
"title.bold": "true", "legend": "bottom",
"categories": CATS, "data": TWO_SERIES}),
chart(TR, {"chartType": "column", "title": "legend=top + legendFont",
"legend": "top", "legendFont": "10:333333:Calibri",
"categories": CATS, "data": TWO_SERIES}),
chart(BL, {"chartType": "column", "title": "legend=topRight overlay",
"legend": "topRight", "legend.overlay": "true",
"categories": CATS, "data": TWO_SERIES}),
chart(BR, {"chartType": "column", "autotitledeleted": "true", "legend": "none",
"categories": CATS, "data": TWO_SERIES}),
]
# -----------------------------------------------------------------------
# Slide 3 — Data labels
# -----------------------------------------------------------------------
items += slide_title(
"Data labels — flags (value/category/percent/none), labelPos, labelfont")
items += [
chart(TL, {"chartType": "column", "title": "value @ outsideEnd",
"dataLabels": "value", "labelPos": "outsideEnd",
"labelfont": "10:333333:Calibri", "legend": "none",
"categories": CATS, "data": "A:60,90,140,180"}),
chart(TR, {"chartType": "column", "title": "value,category @ insideEnd",
"dataLabels": "value,category", "labelPos": "insideEnd",
"labelfont": "9:FFFFFF:Calibri", "legend": "none",
"categories": CATS, "data": "A:60,90,140,180"}),
chart(BL, {"chartType": "stackedColumn", "title": "stacked + center labels",
"dataLabels": "value", "labelPos": "center",
"labelfont": "9:FFFFFF:Calibri", "legend": "bottom",
"categories": CATS, "data": THREE_SERIES}),
chart(BR, {"chartType": "column", "title": "dataLabels=none",
"dataLabels": "none", "legend": "none",
"categories": CATS, "data": "A:60,90,140,180"}),
]
# -----------------------------------------------------------------------
# Slide 4 — Axes
# -----------------------------------------------------------------------
items += slide_title("Axes — min/max, titles, fonts, gridlines, units, log, secondary")
items += [
chart(TL, {"chartType": "column", "title": "axis min/max + titles + numfmt",
"legend": "none",
"axismin": "0", "axismax": "200", "majorunit": "50", "minorunit": "10",
"axistitle": "Revenue (USD)", "cattitle": "Quarter",
"axisfont": "10:333333:Calibri", "axisline": "666666:1",
"axisnumfmt": "#,##0",
"categories": CATS, "data": "Rev:60,90,140,180"}),
chart(TR, {"chartType": "column", "title": "gridlines + minorGridlines + ticks",
"legend": "none",
"gridlines": "E0E0E0:0.3", "minorGridlines": "F0F0F0:0.25",
"majorTickMark": "out", "minorTickMark": "in", "tickLabelPos": "nextTo",
"labelrotation": "-30",
"categories": "January,February,March,April",
"data": "A:60,90,140,180"}),
chart(BL, {"chartType": "column", "title": "dispunits=thousands",
"legend": "none", "dispunits": "thousands",
"categories": CATS, "data": "Rev:120000,135000,148000,162000"}),
chart(BR, {"chartType": "combo", "combotypes": "column,line", "secondaryaxis": "2",
"title": "secondaryaxis=2 (line on right)", "legend": "bottom",
"categories": CATS, "data": "Sales:120,135,148,162;Growth %:5,12,18,22"}),
]
# Post-Add chart-axis Set on first chart
items += [
chart_set(f"/slide[{_slide}]/chart[1]/axis[@role=value]",
{"title": "Revenue (USD)", "format": "$#,##0",
"majorGridlines": "true", "minorGridlines": "false",
"max": "200", "min": "0", "majorUnit": "50"}),
]
# -----------------------------------------------------------------------
# Slide 5 — Series styling
# -----------------------------------------------------------------------
items += slide_title(
"Series styling — colors, gradient(s), transparency, outline, shadow, invertifneg, colorrule")
items += [
chart(TL, {"chartType": "column", "title": "colors + seriesoutline",
"legend": "bottom",
"colors": "4472C4,ED7D31,A5A5A5",
"seriesoutline": "000000:0.5",
"categories": CATS, "data": THREE_SERIES}),
chart(TR, {"chartType": "column", "title": "gradient + seriesshadow",
"legend": "bottom",
"gradient": "FF6600-FFCC00:90",
"seriesshadow": "000000-5-45-3-50",
"categories": CATS, "data": "A:60,90,140,180"}),
chart(BL, {"chartType": "column", "title": "per-series gradients + transparency=30",
"legend": "bottom",
"gradients": "FF0000-0000FF;00FF00-FFFF00",
"transparency": "30",
"categories": CATS,
"data": "A:60,90,140,180;B:40,70,100,130"}),
chart(BR, {"chartType": "column", "title": "invertifneg + colorrule",
"legend": "none",
"invertifneg": "true",
"colorrule": "0:FF0000:00AA00",
"categories": "Q1,Q2,Q3,Q4,Q5",
"data": "Net:60,-30,40,-50,80"}),
]
# Recolor series 1 of the first chart via chart-series Set
items += [chart_set(f"/slide[{_slide}]/chart[1]/series[1]", {"color": "2E75B6"})]
# -----------------------------------------------------------------------
# Slide 6 — Layout & overlays
# -----------------------------------------------------------------------
items += slide_title(
"Layout & overlays — gapwidth, overlap, referenceline, errbars, trendline, dataTable")
items += [
chart(TL, {"chartType": "column", "title": "gapwidth=50 + overlap=20",
"legend": "bottom", "gapwidth": "50", "overlap": "20",
"categories": CATS, "data": "A:60,90,140,180;B:50,75,110,150"}),
chart(TR, {"chartType": "column", "title": "referenceline=100",
"legend": "none", "referenceline": "100:FF0000:Target",
"categories": CATS, "data": "A:60,90,140,180"}),
chart(BL, {"chartType": "column", "title": "errbars=percentage:10",
"legend": "none", "errbars": "percentage:10",
"categories": CATS, "data": "A:60,90,140,180"}),
chart(BR, {"chartType": "column", "title": "dataTable=true + trendline=linear",
"legend": "bottom", "dataTable": "true", "trendline": "linear",
"categories": CATS, "data": "A:60,90,140,180"}),
]
# -----------------------------------------------------------------------
# Slide 7 — Backgrounds
# -----------------------------------------------------------------------
items += slide_title("Backgrounds — chartareafill, plotFill, borders, roundedcorners")
items += [
chart(TL, {"chartType": "column", "title": "chartareafill + plotFill + borders",
"legend": "bottom",
"chartareafill": "FFF8E7", "plotFill": "FAFAFA",
"chartborder": "000000:1", "plotborder": "CCCCCC:0.5",
"categories": CATS, "data": "A:60,90,140,180"}),
chart(TR, {"chartType": "column", "title": "roundedcorners=true",
"legend": "bottom",
"roundedcorners": "true", "chartborder": "4472C4:2",
"categories": CATS, "data": "A:60,90,140,180"}),
chart(BL, {"chartType": "column", "title": "plotFill=none, gridlines=none",
"legend": "none",
"plotFill": "none", "gridlines": "none",
"categories": CATS, "data": "A:60,90,140,180"}),
chart(BR, {"chartType": "column", "title": "varyColors=true (single series)",
"legend": "none", "varyColors": "true",
"categories": CATS, "data": "A:60,90,140,180"}),
]
# -----------------------------------------------------------------------
# Slide 8 — Presets & per-series control
# -----------------------------------------------------------------------
items += slide_title("Presets & per-series — preset bundles + seriesN.* + chart-series Set")
items += [
chart(TL, {"chartType": "column", "preset": "minimal", "title": "preset=minimal",
"legend": "bottom", "categories": CATS,
"data": "A:60,90,140,180;B:50,75,110,150"}),
chart(TR, {"chartType": "column", "preset": "corporate", "title": "preset=corporate",
"legend": "bottom", "categories": CATS,
"data": "A:60,90,140,180;B:50,75,110,150"}),
chart(BL, {"chartType": "column", "preset": "dark", "title": "preset=dark",
"legend": "bottom", "categories": CATS,
"data": "A:60,90,140,180;B:50,75,110,150"}),
chart(BR, {"chartType": "column", "title": "seriesN.* Add + chart-series Set",
"legend": "bottom", "categories": CATS,
"series1.name": "Product A", "series1.values": "60,90,140,180",
"series1.color": "4472C4",
"series2.name": "Product B", "series2.values": "50,75,110,150",
"series2.color": "ED7D31",
"series3.name": "Product C", "series3.values": "40,65,90,120",
"series3.color": "70AD47"}),
]
items += [chart_set(f"/slide[{_slide}]/chart[4]/series[1]",
{"name": "Renamed Alpha", "color": "C00000"})]
doc.batch(items)
print(f" shipped {len(items)} items across {_slide} slides")
print(f"Generated: {FILE}")
+107
View File
@@ -0,0 +1,107 @@
#!/bin/bash
# Column Charts Showcase — column, stackedColumn, percentStackedColumn, column3d.
# Generates charts-column.pptx exercising every column-applicable chart property.
# CLI twin of charts-column.py (officecli Python SDK). Both produce an
# equivalent charts-column.pptx.
#
# Slide 1 Basic variants column / stackedColumn / percentStackedColumn / column3d
# Slide 2 Title & legend title.font/size/color/bold, legend positions, legendFont
# Slide 3 Data labels dataLabels flags, labelPos, labelfont
# Slide 4 Axes min/max, titles, fonts, gridlines, units, log, secondary
# Slide 5 Series styling colors, gradient(s), transparency, outline, shadow, ...
# Slide 6 Layout & overlays gapwidth, overlap, referenceline, errbars, trendline, dataTable
# Slide 7 Backgrounds chartareafill, plotFill, borders, roundedcorners
# Slide 8 Presets & per-ser preset bundles + seriesN.* + chart-series Set
#
# Usage: ./charts-column.sh [officecli path]
# NOTE: intentionally NO `set -e`. Like the SDK twin's doc.batch, this script
# tolerates forward-compat 'UNSUPPORTED props' warnings (officecli exit 2) and
# keeps building so the full document is produced.
CLI="${1:-officecli}"
FILE="$(dirname "$0")/charts-column.pptx"
rm -f "$FILE"
$CLI create "$FILE"
$CLI open "$FILE"
# 2x2 grid boxes (widescreen 13.33 x 7.5in): TL / TR / BL / BR
# TL --prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in
# TR --prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in
# BL --prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in
# BR --prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in
CATS="Q1,Q2,Q3,Q4"
TWO_SERIES="East:120,135,148,162;West:95,108,115,128"
THREE_SERIES="East:120,135,148,162;South:95,108,115,128;West:80,90,98,110"
# ==================== Slide 1 — Basic variants ====================
$CLI add "$FILE" / --type slide
$CLI add "$FILE" /slide[1] --type shape --prop text="Column variants — column / stackedColumn / percentStackedColumn / column3d" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
$CLI add "$FILE" /slide[1] --type chart --prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=column --prop title=column --prop legend=bottom --prop categories="$CATS" --prop data="$TWO_SERIES"
$CLI add "$FILE" /slide[1] --type chart --prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=stackedColumn --prop title=stackedColumn --prop legend=bottom --prop categories="$CATS" --prop data="$THREE_SERIES"
$CLI add "$FILE" /slide[1] --type chart --prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=percentStackedColumn --prop title=percentStackedColumn --prop legend=bottom --prop categories="$CATS" --prop data="$THREE_SERIES"
$CLI add "$FILE" /slide[1] --type chart --prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=column3d --prop view3d=15,20,30 --prop gapdepth=150 --prop title="column3d (view3d=15,20,30)" --prop legend=bottom --prop categories="$CATS" --prop data="$TWO_SERIES"
# ==================== Slide 2 — Title & legend ====================
$CLI add "$FILE" / --type slide
$CLI add "$FILE" /slide[2] --type shape --prop text="Title & legend — title.font/size/color/bold, legend positions, legendFont" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
$CLI add "$FILE" /slide[2] --type chart --prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=column --prop title="Styled title" --prop title.font=Georgia --prop title.size=20 --prop title.color=4472C4 --prop title.bold=true --prop legend=bottom --prop categories="$CATS" --prop data="$TWO_SERIES"
$CLI add "$FILE" /slide[2] --type chart --prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=column --prop title="legend=top + legendFont" --prop legend=top --prop legendFont=10:333333:Calibri --prop categories="$CATS" --prop data="$TWO_SERIES"
$CLI add "$FILE" /slide[2] --type chart --prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=column --prop title="legend=topRight overlay" --prop legend=topRight --prop legend.overlay=true --prop categories="$CATS" --prop data="$TWO_SERIES"
$CLI add "$FILE" /slide[2] --type chart --prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=column --prop autotitledeleted=true --prop legend=none --prop categories="$CATS" --prop data="$TWO_SERIES"
# ==================== Slide 3 — Data labels ====================
$CLI add "$FILE" / --type slide
$CLI add "$FILE" /slide[3] --type shape --prop text="Data labels — flags (value/category/percent/none), labelPos, labelfont" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
$CLI add "$FILE" /slide[3] --type chart --prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=column --prop title="value @ outsideEnd" --prop dataLabels=value --prop labelPos=outsideEnd --prop labelfont=10:333333:Calibri --prop legend=none --prop categories="$CATS" --prop data="A:60,90,140,180"
$CLI add "$FILE" /slide[3] --type chart --prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=column --prop title="value,category @ insideEnd" --prop dataLabels=value,category --prop labelPos=insideEnd --prop labelfont=9:FFFFFF:Calibri --prop legend=none --prop categories="$CATS" --prop data="A:60,90,140,180"
$CLI add "$FILE" /slide[3] --type chart --prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=stackedColumn --prop title="stacked + center labels" --prop dataLabels=value --prop labelPos=center --prop labelfont=9:FFFFFF:Calibri --prop legend=bottom --prop categories="$CATS" --prop data="$THREE_SERIES"
$CLI add "$FILE" /slide[3] --type chart --prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=column --prop title="dataLabels=none" --prop dataLabels=none --prop legend=none --prop categories="$CATS" --prop data="A:60,90,140,180"
# ==================== Slide 4 — Axes ====================
$CLI add "$FILE" / --type slide
$CLI add "$FILE" /slide[4] --type shape --prop text="Axes — min/max, titles, fonts, gridlines, units, log, secondary" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
$CLI add "$FILE" /slide[4] --type chart --prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=column --prop title="axis min/max + titles + numfmt" --prop legend=none --prop axismin=0 --prop axismax=200 --prop majorunit=50 --prop minorunit=10 --prop axistitle="Revenue (USD)" --prop cattitle=Quarter --prop axisfont=10:333333:Calibri --prop axisline=666666:1 --prop axisnumfmt="#,##0" --prop categories="$CATS" --prop data="Rev:60,90,140,180"
$CLI add "$FILE" /slide[4] --type chart --prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=column --prop title="gridlines + minorGridlines + ticks" --prop legend=none --prop gridlines=E0E0E0:0.3 --prop minorGridlines=F0F0F0:0.25 --prop majorTickMark=out --prop minorTickMark=in --prop tickLabelPos=nextTo --prop labelrotation=-30 --prop categories="January,February,March,April" --prop data="A:60,90,140,180"
$CLI add "$FILE" /slide[4] --type chart --prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=column --prop title="dispunits=thousands" --prop legend=none --prop dispunits=thousands --prop categories="$CATS" --prop data="Rev:120000,135000,148000,162000"
$CLI add "$FILE" /slide[4] --type chart --prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=combo --prop combotypes=column,line --prop secondaryaxis=2 --prop title="secondaryaxis=2 (line on right)" --prop legend=bottom --prop categories="$CATS" --prop data="Sales:120,135,148,162;Growth %:5,12,18,22"
# Post-Add chart-axis Set on first chart
$CLI set "$FILE" "/slide[4]/chart[1]/axis[@role=value]" --prop title="Revenue (USD)" --prop format="$#,##0" --prop majorGridlines=true --prop minorGridlines=false --prop max=200 --prop min=0 --prop majorUnit=50
# ==================== Slide 5 — Series styling ====================
$CLI add "$FILE" / --type slide
$CLI add "$FILE" /slide[5] --type shape --prop text="Series styling — colors, gradient(s), transparency, outline, shadow, invertifneg, colorrule" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
$CLI add "$FILE" /slide[5] --type chart --prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=column --prop title="colors + seriesoutline" --prop legend=bottom --prop colors=4472C4,ED7D31,A5A5A5 --prop seriesoutline=000000:0.5 --prop categories="$CATS" --prop data="$THREE_SERIES"
$CLI add "$FILE" /slide[5] --type chart --prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=column --prop title="gradient + seriesshadow" --prop legend=bottom --prop gradient=FF6600-FFCC00:90 --prop seriesshadow=000000-5-45-3-50 --prop categories="$CATS" --prop data="A:60,90,140,180"
$CLI add "$FILE" /slide[5] --type chart --prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=column --prop title="per-series gradients + transparency=30" --prop legend=bottom --prop gradients="FF0000-0000FF;00FF00-FFFF00" --prop transparency=30 --prop categories="$CATS" --prop data="A:60,90,140,180;B:40,70,100,130"
$CLI add "$FILE" /slide[5] --type chart --prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=column --prop title="invertifneg + colorrule" --prop legend=none --prop invertifneg=true --prop colorrule=0:FF0000:00AA00 --prop categories="Q1,Q2,Q3,Q4,Q5" --prop data="Net:60,-30,40,-50,80"
# Recolor series 1 of the first chart via chart-series Set
$CLI set "$FILE" "/slide[5]/chart[1]/series[1]" --prop color=2E75B6
# ==================== Slide 6 — Layout & overlays ====================
$CLI add "$FILE" / --type slide
$CLI add "$FILE" /slide[6] --type shape --prop text="Layout & overlays — gapwidth, overlap, referenceline, errbars, trendline, dataTable" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
$CLI add "$FILE" /slide[6] --type chart --prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=column --prop title="gapwidth=50 + overlap=20" --prop legend=bottom --prop gapwidth=50 --prop overlap=20 --prop categories="$CATS" --prop data="A:60,90,140,180;B:50,75,110,150"
$CLI add "$FILE" /slide[6] --type chart --prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=column --prop title="referenceline=100" --prop legend=none --prop referenceline=100:FF0000:Target --prop categories="$CATS" --prop data="A:60,90,140,180"
$CLI add "$FILE" /slide[6] --type chart --prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=column --prop title="errbars=percentage:10" --prop legend=none --prop errbars=percentage:10 --prop categories="$CATS" --prop data="A:60,90,140,180"
$CLI add "$FILE" /slide[6] --type chart --prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=column --prop title="dataTable=true + trendline=linear" --prop legend=bottom --prop dataTable=true --prop trendline=linear --prop categories="$CATS" --prop data="A:60,90,140,180"
# ==================== Slide 7 — Backgrounds ====================
$CLI add "$FILE" / --type slide
$CLI add "$FILE" /slide[7] --type shape --prop text="Backgrounds — chartareafill, plotFill, borders, roundedcorners" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
$CLI add "$FILE" /slide[7] --type chart --prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=column --prop title="chartareafill + plotFill + borders" --prop legend=bottom --prop chartareafill=FFF8E7 --prop plotFill=FAFAFA --prop chartborder=000000:1 --prop plotborder=CCCCCC:0.5 --prop categories="$CATS" --prop data="A:60,90,140,180"
$CLI add "$FILE" /slide[7] --type chart --prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=column --prop title="roundedcorners=true" --prop legend=bottom --prop roundedcorners=true --prop chartborder=4472C4:2 --prop categories="$CATS" --prop data="A:60,90,140,180"
$CLI add "$FILE" /slide[7] --type chart --prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=column --prop title="plotFill=none, gridlines=none" --prop legend=none --prop plotFill=none --prop gridlines=none --prop categories="$CATS" --prop data="A:60,90,140,180"
$CLI add "$FILE" /slide[7] --type chart --prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=column --prop title="varyColors=true (single series)" --prop legend=none --prop varyColors=true --prop categories="$CATS" --prop data="A:60,90,140,180"
# ==================== Slide 8 — Presets & per-series control ====================
$CLI add "$FILE" / --type slide
$CLI add "$FILE" /slide[8] --type shape --prop text="Presets & per-series — preset bundles + seriesN.* + chart-series Set" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
$CLI add "$FILE" /slide[8] --type chart --prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=column --prop preset=minimal --prop title="preset=minimal" --prop legend=bottom --prop categories="$CATS" --prop data="A:60,90,140,180;B:50,75,110,150"
$CLI add "$FILE" /slide[8] --type chart --prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=column --prop preset=corporate --prop title="preset=corporate" --prop legend=bottom --prop categories="$CATS" --prop data="A:60,90,140,180;B:50,75,110,150"
$CLI add "$FILE" /slide[8] --type chart --prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=column --prop preset=dark --prop title="preset=dark" --prop legend=bottom --prop categories="$CATS" --prop data="A:60,90,140,180;B:50,75,110,150"
$CLI add "$FILE" /slide[8] --type chart --prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=column --prop title="seriesN.* Add + chart-series Set" --prop legend=bottom --prop categories="$CATS" --prop series1.name="Product A" --prop series1.values="60,90,140,180" --prop series1.color=4472C4 --prop series2.name="Product B" --prop series2.values="50,75,110,150" --prop series2.color=ED7D31 --prop series3.name="Product C" --prop series3.values="40,65,90,120" --prop series3.color=70AD47
$CLI set "$FILE" "/slide[8]/chart[4]/series[1]" --prop name="Renamed Alpha" --prop color=C00000
$CLI close "$FILE"
$CLI validate "$FILE"
echo "Generated: $FILE"
+293
View File
@@ -0,0 +1,293 @@
# Combo Charts Showcase
This demo consists of three files that work together:
- **charts-combo.py** — Python script that calls `officecli` commands to generate the deck.
- **charts-combo.pptx** — The generated 8-slide deck (4 charts per slide, 32 charts total).
- **charts-combo.md** — This file. Maps each slide to the features it demonstrates.
## Regenerate
```bash
cd examples/ppt/charts
python3 charts-combo.py
# → charts-combo.pptx
```
## Chart Slides
### Slide 1 — combotypes Mixes
```bash
CATS="Q1,Q2,Q3,Q4"
D2="Sales:120,135,148,162;Growth %:5,12,18,22"
# Column bars + line overlay
officecli add charts-combo.pptx /slide[1] --type chart \
--prop chartType=combo --prop combotypes="column,line" \
--prop title="column + line" --prop legend=bottom \
--prop categories="$CATS" --prop data="$D2" \
--prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in
# Column bars + area fill
officecli add charts-combo.pptx /slide[1] --type chart \
--prop chartType=combo --prop combotypes="column,area" \
--prop title="column + area" --prop legend=bottom \
--prop categories="$CATS" --prop data="$D2" \
--prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in
# Line + area
officecli add charts-combo.pptx /slide[1] --type chart \
--prop chartType=combo --prop combotypes="line,area" \
--prop title="line + area" --prop legend=bottom \
--prop categories="$CATS" --prop data="$D2" \
--prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in
# Horizontal bar + line (bar direction)
officecli add charts-combo.pptx /slide[1] --type chart \
--prop chartType=combo --prop combotypes="bar,line" \
--prop title="bar + line" --prop legend=bottom \
--prop categories="$CATS" --prop data="$D2" \
--prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in
```
**Features:** `chartType=combo`, `combotypes` (comma-separated chart type per series: column/line/area/bar)
### Slide 2 — combosplit
```bash
D3="Sales:120,135,148,162;Cost:80,90,95,105;Growth %:5,12,18,22"
# combosplit=2: first 2 series use primary type (column), rest use secondary type (line)
officecli add charts-combo.pptx /slide[2] --type chart \
--prop chartType=combo --prop combotypes="column,column,line" \
--prop combosplit=2 --prop title="combosplit=2 (2 columns + 1 line)" \
--prop legend=bottom --prop categories="$CATS" --prop data="$D3"
# combosplit=1: first 1 series uses primary type (column), rest use secondary type (line)
officecli add charts-combo.pptx /slide[2] --type chart \
--prop chartType=combo --prop combotypes="column,line,line" \
--prop combosplit=1 --prop title="combosplit=1 (1 column + 2 lines)" \
--prop legend=bottom --prop categories="$CATS" --prop data="$D3"
# combosplit=2 with reversed order
officecli add charts-combo.pptx /slide[2] --type chart \
--prop chartType=combo --prop combotypes="line,line,column" \
--prop combosplit=2 --prop title="combosplit=2 (2 lines + 1 column)" \
--prop legend=bottom --prop categories="$CATS" --prop data="$D3"
# Three distinct types: area + column + line
officecli add charts-combo.pptx /slide[2] --type chart \
--prop chartType=combo --prop combotypes="area,column,line" \
--prop combosplit=1 --prop title="area + column + line" \
--prop legend=bottom --prop categories="$CATS" --prop data="$D3"
```
**Features:** `combosplit` (N = number of series using the first combotype)
### Slide 3 — secondaryaxis
```bash
# Line series on right (secondary) axis
officecli add charts-combo.pptx /slide[3] --type chart \
--prop chartType=combo --prop combotypes="column,line" --prop secondaryaxis=2 \
--prop title="secondaryaxis=2" --prop legend=bottom \
--prop categories="$CATS" --prop data="$D2"
# Growth % (3rd series) on right axis
officecli add charts-combo.pptx /slide[3] --type chart \
--prop chartType=combo --prop combotypes="column,column,line" \
--prop secondaryaxis=3 --prop combosplit=2 \
--prop title="secondaryaxis=3 (Growth on right)" --prop legend=bottom \
--prop categories="$CATS" --prop data="$D3"
# Two series on secondary axis
officecli add charts-combo.pptx /slide[3] --type chart \
--prop chartType=combo --prop combotypes="column,line,line" \
--prop secondaryaxis="2,3" --prop combosplit=1 \
--prop title="secondaryaxis=2,3" --prop legend=bottom \
--prop categories="$CATS" --prop data="$D3"
# Secondary axis with gridlines and axis font
officecli add charts-combo.pptx /slide[3] --type chart \
--prop chartType=combo --prop combotypes="column,line" --prop secondaryaxis=2 \
--prop title="with grid + tick fonts" \
--prop gridlines="E0E0E0:0.3" --prop axisfont="9:333333:Calibri" \
--prop legend=bottom --prop categories="$CATS" --prop data="$D2"
```
**Features:** `secondaryaxis` (1-based series index, or comma-separated list for multiple)
### Slide 4 — Title and Legend
```bash
officecli add charts-combo.pptx /slide[4] --type chart \
--prop chartType=combo --prop combotypes="column,line" \
--prop title="Styled title" --prop title.font=Georgia --prop title.size=20 \
--prop title.color=4472C4 --prop title.bold=true \
--prop legend=bottom --prop categories="$CATS" --prop data="$D2"
officecli add charts-combo.pptx /slide[4] --type chart \
--prop chartType=combo --prop combotypes="column,line" \
--prop title="legend=top + legendFont" --prop legend=top \
--prop legendFont="10:333333:Calibri" \
--prop categories="$CATS" --prop data="$D2"
officecli add charts-combo.pptx /slide[4] --type chart \
--prop chartType=combo --prop combotypes="column,line" \
--prop title="legend.overlay=true" --prop legend=topRight \
--prop legend.overlay=true \
--prop categories="$CATS" --prop data="$D2"
officecli add charts-combo.pptx /slide[4] --type chart \
--prop chartType=combo --prop combotypes="column,line" \
--prop autotitledeleted=true --prop legend=none \
--prop categories="$CATS" --prop data="$D2"
```
**Features:** `title.font/size/color/bold`, `legend` positions, `legendFont`, `legend.overlay`, `autotitledeleted`
### Slide 5 — Data Labels
```bash
officecli add charts-combo.pptx /slide[5] --type chart \
--prop chartType=combo --prop combotypes="column,line" \
--prop title="dataLabels=value" --prop dataLabels=value \
--prop legend=bottom --prop categories="$CATS" --prop data="$D2"
officecli add charts-combo.pptx /slide[5] --type chart \
--prop chartType=combo --prop combotypes="column,line" \
--prop title="value,series" --prop dataLabels="value,series" \
--prop legend=bottom --prop categories="$CATS" --prop data="$D2"
officecli add charts-combo.pptx /slide[5] --type chart \
--prop chartType=combo --prop combotypes="column,line" \
--prop title="dataLabels=none" --prop dataLabels=none \
--prop legend=bottom --prop categories="$CATS" --prop data="$D2"
officecli add charts-combo.pptx /slide[5] --type chart \
--prop chartType=combo --prop combotypes="column,line" \
--prop title="labelfont styled" --prop dataLabels=value \
--prop labelfont="10:C00000:Georgia" \
--prop legend=bottom --prop categories="$CATS" --prop data="$D2"
```
**Note:** `labelPos` is chart-type conditional — combo charts skip it since column and line have different valid positions.
**Features:** `dataLabels` (value/series/none or combined), `labelfont`
### Slide 6 — Axes
```bash
# Axis min/max + titles + number format
officecli add charts-combo.pptx /slide[6] --type chart \
--prop chartType=combo --prop combotypes="column,line" --prop secondaryaxis=2 \
--prop title="both axes min/max" --prop axismin=0 --prop axismax=200 \
--prop axistitle="Sales" --prop cattitle="Quarter" \
--prop axisfont="10:333333:Calibri" --prop axisnumfmt="#,##0" \
--prop legend=bottom --prop categories="$CATS" --prop data="$D2"
officecli add charts-combo.pptx /slide[6] --type chart \
--prop chartType=combo --prop combotypes="column,line" \
--prop title="gridlines + minorGridlines" \
--prop gridlines="E0E0E0:0.3" --prop minorGridlines="F0F0F0:0.25" \
--prop legend=bottom --prop categories="$CATS" --prop data="$D2"
officecli add charts-combo.pptx /slide[6] --type chart \
--prop chartType=combo --prop combotypes="column,line" \
--prop title="labelrotation=-30" --prop labelrotation=-30 \
--prop legend=bottom --prop categories="$CATS" --prop data="$D2"
# chart-axis Set: mutate axis after creation
officecli add charts-combo.pptx /slide[6] --type chart \
--prop chartType=combo --prop combotypes="column,line" \
--prop title="chart-axis Set after add" \
--prop legend=bottom --prop categories="$CATS" --prop data="$D2"
officecli set charts-combo.pptx "/slide[6]/chart[4]/axis[@role=value]" \
--prop title="Sales (USD)" --prop format='$#,##0' \
--prop majorGridlines=true --prop min=0 --prop max=200
```
**Features:** `axismin/max`, `axistitle/cattitle`, `axisfont`, `axisnumfmt`, `gridlines/minorGridlines`, `labelrotation`, `chart-axis Set`
### Slide 7 — Series Styling
```bash
officecli add charts-combo.pptx /slide[7] --type chart \
--prop chartType=combo --prop combotypes="column,line" \
--prop title="colors + seriesoutline" --prop legend=bottom \
--prop colors="4472C4,ED7D31" --prop seriesoutline="000000:0.5" \
--prop categories="$CATS" --prop data="$D2"
officecli add charts-combo.pptx /slide[7] --type chart \
--prop chartType=combo --prop combotypes="column,line" \
--prop title="gradient + seriesshadow" --prop legend=bottom \
--prop gradient="FF6600-FFCC00" --prop seriesshadow="000000-5-45-3-50" \
--prop categories="$CATS" --prop data="$D2"
officecli add charts-combo.pptx /slide[7] --type chart \
--prop chartType=combo --prop combotypes="column,line" \
--prop title="transparency=30" --prop legend=bottom \
--prop transparency=30 \
--prop categories="$CATS" --prop data="$D2"
officecli add charts-combo.pptx /slide[7] --type chart \
--prop chartType=combo --prop combotypes="column,line" \
--prop title="per-series gradients" --prop legend=bottom \
--prop gradients="FF0000-0000FF;00FF00-FFFF00" \
--prop categories="$CATS" --prop data="$D2"
```
**Features:** `colors`, `seriesoutline`, `gradient`, `seriesshadow`, `transparency`, `gradients`
### Slide 8 — Presets and Per-Series Set
```bash
for p in minimal dark corporate; do
officecli add charts-combo.pptx /slide[8] --type chart \
--prop chartType=combo --prop combotypes="column,line" \
--prop preset=$p --prop title="preset=$p" --prop legend=bottom \
--prop categories="$CATS" --prop data="$D2"
done
officecli add charts-combo.pptx /slide[8] --type chart \
--prop chartType=combo --prop combotypes="column,line" \
--prop title="chart-series Set" --prop legend=bottom \
--prop categories="$CATS" --prop data="$D2"
officecli set charts-combo.pptx "/slide[8]/chart[4]/series[1]" \
--prop name="Renamed Sales" --prop color=C00000
officecli set charts-combo.pptx "/slide[8]/chart[4]/series[2]" \
--prop name="Renamed Growth" --prop color=2E75B6 \
--prop lineWidth=2.5 --prop marker=circle --prop markerSize=8
```
**Features:** `preset`, `chart-series Set`: `name`, `color`, `lineWidth`, `marker`, `markerSize`
## Complete Feature Coverage
| Feature | Slide |
|---------|-------|
| **combotypes** (column/line/area/bar combinations) | 1 |
| **combosplit** (first N series in primary type) | 2 |
| **secondaryaxis** (1-based index, or comma list) | 3 |
| **title.font/size/color/bold** | 4 |
| **legend** positions, legendFont, legend.overlay | 4 |
| **autotitledeleted** | 4 |
| **dataLabels** (value/series/none), **labelfont** | 5 |
| **axismin/max**, axistitle/cattitle, axisfont, axisnumfmt | 6 |
| **gridlines/minorGridlines**, labelrotation | 6 |
| **chart-axis Set** | 6 |
| **colors**, seriesoutline, gradient, seriesshadow | 7 |
| **transparency**, gradients | 7 |
| **preset** | 8 |
| **chart-series Set:** name/color/lineWidth/marker/markerSize | 8 |
## Inspect the Generated File
```bash
officecli query charts-combo.pptx chart
officecli get charts-combo.pptx "/slide[1]/chart[1]"
officecli get charts-combo.pptx "/slide[3]/chart[1]"
officecli get charts-combo.pptx "/slide[8]/chart[4]/series[2]"
```
Binary file not shown.
+216
View File
@@ -0,0 +1,216 @@
#!/usr/bin/env python3
"""
Combo Charts Showcase — combotypes, combosplit, secondaryaxis.
Generates: charts-combo.pptx
Slide 1 combotypes mixes column+line, column+area, line+area, bar+line
Slide 2 combosplit split index 1, 2, 3 (first N series use primary)
Slide 3 secondaryaxis 1 series, 2 series, multiple series on secondary
Slide 4 Title & legend
Slide 5 Data labels
Slide 6 Axes min/max on both axes, titles, gridlines
Slide 7 Series styling colors, gradients, transparency, outline, shadow
Slide 8 Presets & per-series preset bundles + chart-series Set
SDK twin of charts-combo.sh (officecli CLI). Both produce an equivalent
charts-combo.pptx. This one drives the **officecli Python SDK**
(`pip install officecli-sdk`): one resident is started and every slide, shape,
chart and per-element Set is shipped over the named pipe in `doc.batch(...)`
round-trips. Each item is the same `{"command","parent"/"path","type","props"}`
dict you'd put in an `officecli batch` list.
Forward-compat note: any prop a future-built handler doesn't yet support is
carried through verbatim (faithful to charts-combo.sh). The resident
silently skips unsupported props during `add`/`set`; nothing here strips them.
Usage:
pip install officecli-sdk # plus the `officecli` binary on PATH
python3 charts-combo.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__)), "charts-combo.pptx")
# Four quadrant boxes (top-left, top-right, bottom-left, bottom-right).
TL = {"x": "0.3in", "y": "1.05in", "width": "6.1in", "height": "3in"}
TR = {"x": "6.95in", "y": "1.05in", "width": "6.1in", "height": "3in"}
BL = {"x": "0.3in", "y": "4.25in", "width": "6.1in", "height": "3in"}
BR = {"x": "6.95in", "y": "4.25in", "width": "6.1in", "height": "3in"}
CATS = "Q1,Q2,Q3,Q4"
D2 = "Sales:120,135,148,162;Growth %:5,12,18,22"
D3 = "Sales:120,135,148,162;Cost:80,90,95,105;Growth %:5,12,18,22"
def slide():
"""One `add slide` item in batch-shape."""
return {"command": "add", "parent": "/", "type": "slide", "props": {}}
def title(n, text):
"""Slide title shape — `add shape` item in batch-shape."""
return {"command": "add", "parent": f"/slide[{n}]", "type": "shape",
"props": {"text": text, "size": "24", "bold": "true", "autoFit": "normal",
"x": "0.5in", "y": "0.3in", "width": "12.3in", "height": "0.6in"}}
def ch(n, box, p):
"""One `add chart` item in batch-shape (box geometry merged with props)."""
return {"command": "add", "parent": f"/slide[{n}]", "type": "chart",
"props": {**box, **p}}
print(f"Building {FILE} ...")
with officecli.create(FILE, "--force") as doc:
# ---- Slide 1: combotypes ---------------------------------------------
doc.batch([
slide(),
title(1, "combotypes — column+line / column+area / line+area / bar+line"),
ch(1, TL, {"chartType": "combo", "combotypes": "column,line", "title": "column + line",
"legend": "bottom", "categories": CATS, "data": D2}),
ch(1, TR, {"chartType": "combo", "combotypes": "column,area", "title": "column + area",
"legend": "bottom", "categories": CATS, "data": D2}),
ch(1, BL, {"chartType": "combo", "combotypes": "line,area", "title": "line + area",
"legend": "bottom", "categories": CATS, "data": D2}),
ch(1, BR, {"chartType": "combo", "combotypes": "bar,line", "title": "bar + line",
"legend": "bottom", "categories": CATS, "data": D2}),
])
# ---- Slide 2: combosplit — first N series use primary type -----------
doc.batch([
slide(),
title(2, "combosplit — first N series use primary type"),
ch(2, TL, {"chartType": "combo", "combotypes": "column,column,line", "combosplit": "2",
"title": "combosplit=2 (2 columns + 1 line)", "legend": "bottom",
"categories": CATS, "data": D3}),
ch(2, TR, {"chartType": "combo", "combotypes": "column,line,line", "combosplit": "1",
"title": "combosplit=1 (1 column + 2 lines)", "legend": "bottom",
"categories": CATS, "data": D3}),
ch(2, BL, {"chartType": "combo", "combotypes": "line,line,column", "combosplit": "2",
"title": "combosplit=2 (2 lines + 1 column)", "legend": "bottom",
"categories": CATS, "data": D3}),
ch(2, BR, {"chartType": "combo", "combotypes": "area,column,line", "combosplit": "1",
"title": "area + column + line", "legend": "bottom",
"categories": CATS, "data": D3}),
])
# ---- Slide 3: secondaryaxis — line on secondary value axis -----------
doc.batch([
slide(),
title(3, "secondaryaxis — line on secondary value axis"),
ch(3, TL, {"chartType": "combo", "combotypes": "column,line", "secondaryaxis": "2",
"title": "secondaryaxis=2", "legend": "bottom", "categories": CATS, "data": D2}),
ch(3, TR, {"chartType": "combo", "combotypes": "column,column,line", "secondaryaxis": "3",
"combosplit": "2", "title": "secondaryaxis=3 (Growth on right)", "legend": "bottom",
"categories": CATS, "data": D3}),
ch(3, BL, {"chartType": "combo", "combotypes": "column,line,line", "secondaryaxis": "2,3",
"combosplit": "1", "title": "secondaryaxis=2,3", "legend": "bottom",
"categories": CATS, "data": D3}),
ch(3, BR, {"chartType": "combo", "combotypes": "column,line", "secondaryaxis": "2",
"title": "with grid + tick fonts",
"gridlines": "E0E0E0:0.3", "axisfont": "9:333333:Calibri",
"legend": "bottom", "categories": CATS, "data": D2}),
])
# ---- Slide 4: Title & legend -----------------------------------------
doc.batch([
slide(),
title(4, "Title & legend"),
ch(4, TL, {"chartType": "combo", "combotypes": "column,line", "title": "Styled title",
"title.font": "Georgia", "title.size": "20", "title.color": "4472C4",
"title.bold": "true",
"legend": "bottom", "categories": CATS, "data": D2}),
ch(4, TR, {"chartType": "combo", "combotypes": "column,line", "title": "legend=top + legendFont",
"legend": "top", "legendFont": "10:333333:Calibri", "categories": CATS, "data": D2}),
ch(4, BL, {"chartType": "combo", "combotypes": "column,line", "title": "legend.overlay=true",
"legend": "topRight", "legend.overlay": "true", "categories": CATS, "data": D2}),
ch(4, BR, {"chartType": "combo", "combotypes": "column,line", "autotitledeleted": "true",
"legend": "none", "categories": CATS, "data": D2}),
])
# ---- Slide 5: Data labels (combo charts skip labelPos) ---------------
doc.batch([
slide(),
title(5, "Data labels — combo charts skip labelPos (chart-type conditional)"),
ch(5, TL, {"chartType": "combo", "combotypes": "column,line", "title": "dataLabels=value",
"dataLabels": "value", "legend": "bottom", "categories": CATS, "data": D2}),
ch(5, TR, {"chartType": "combo", "combotypes": "column,line", "title": "value,series",
"dataLabels": "value,series", "legend": "bottom", "categories": CATS, "data": D2}),
ch(5, BL, {"chartType": "combo", "combotypes": "column,line", "title": "dataLabels=none",
"dataLabels": "none", "legend": "bottom", "categories": CATS, "data": D2}),
ch(5, BR, {"chartType": "combo", "combotypes": "column,line", "title": "labelfont styled",
"dataLabels": "value", "labelfont": "10:C00000:Georgia",
"legend": "bottom", "categories": CATS, "data": D2}),
])
# ---- Slide 6: Axes — min/max, secondary, gridlines, axisnumfmt -------
doc.batch([
slide(),
title(6, "Axes — min/max on primary, secondary, gridlines, axisnumfmt"),
ch(6, TL, {"chartType": "combo", "combotypes": "column,line", "secondaryaxis": "2",
"title": "both axes min/max", "axismin": "0", "axismax": "200",
"axistitle": "Sales", "cattitle": "Quarter", "axisfont": "10:333333:Calibri",
"axisnumfmt": "#,##0", "legend": "bottom", "categories": CATS, "data": D2}),
ch(6, TR, {"chartType": "combo", "combotypes": "column,line", "title": "gridlines + minorGridlines",
"gridlines": "E0E0E0:0.3", "minorGridlines": "F0F0F0:0.25",
"legend": "bottom", "categories": CATS, "data": D2}),
ch(6, BL, {"chartType": "combo", "combotypes": "column,line", "title": "labelrotation=-30",
"labelrotation": "-30", "legend": "bottom", "categories": CATS, "data": D2}),
ch(6, BR, {"chartType": "combo", "combotypes": "column,line", "title": "chart-axis Set after add",
"legend": "bottom", "categories": CATS, "data": D2}),
# chart-axis Set after add (value axis of chart[4])
{"command": "set", "path": "/slide[6]/chart[4]/axis[@role=value]",
"props": {"title": "Sales (USD)", "format": "$#,##0", "majorGridlines": "true",
"min": "0", "max": "200"}},
])
# ---- Slide 7: Series styling -----------------------------------------
doc.batch([
slide(),
title(7, "Series styling — colors, gradient(s), transparency, outline, shadow"),
ch(7, TL, {"chartType": "combo", "combotypes": "column,line", "title": "colors + seriesoutline",
"colors": "4472C4,ED7D31", "seriesoutline": "000000:0.5",
"legend": "bottom", "categories": CATS, "data": D2}),
ch(7, TR, {"chartType": "combo", "combotypes": "column,line", "title": "gradient + seriesshadow",
"gradient": "FF6600-FFCC00", "seriesshadow": "000000-5-45-3-50",
"legend": "bottom", "categories": CATS, "data": D2}),
ch(7, BL, {"chartType": "combo", "combotypes": "column,line", "title": "transparency=30",
"transparency": "30", "legend": "bottom", "categories": CATS, "data": D2}),
ch(7, BR, {"chartType": "combo", "combotypes": "column,line", "title": "per-series gradients",
"gradients": "FF0000-0000FF;00FF00-FFFF00",
"legend": "bottom", "categories": CATS, "data": D2}),
])
# ---- Slide 8: Presets & per-series Set -------------------------------
items = [slide(), title(8, "Presets & per-series Set")]
for box, p in zip([TL, TR, BL], ["minimal", "dark", "corporate"]):
items.append(ch(8, box, {"chartType": "combo", "combotypes": "column,line", "preset": p,
"title": f"preset={p}", "legend": "bottom",
"categories": CATS, "data": D2}))
items.append(ch(8, BR, {"chartType": "combo", "combotypes": "column,line", "title": "chart-series Set",
"legend": "bottom", "categories": CATS, "data": D2}))
# chart-series Set after add (series[1], series[2] of chart[4])
items.append({"command": "set", "path": "/slide[8]/chart[4]/series[1]",
"props": {"name": "Renamed Sales", "color": "C00000"}})
items.append({"command": "set", "path": "/slide[8]/chart[4]/series[2]",
"props": {"name": "Renamed Growth", "color": "2E75B6", "lineWidth": "2.5",
"marker": "circle", "markerSize": "8"}})
doc.batch(items)
doc.send({"command": "save"})
# context exit closes the resident, flushing the presentation to disk.
print(f"Generated: {FILE} (8 slides)")
+104
View File
@@ -0,0 +1,104 @@
#!/bin/bash
# Combo Charts Showcase — combotypes, combosplit, secondaryaxis.
# Generates: charts-combo.pptx
#
# Slide 1 combotypes mixes column+line, column+area, line+area, bar+line
# Slide 2 combosplit split index 1, 2, 3 (first N series use primary)
# Slide 3 secondaryaxis 1 series, 2 series, multiple series on secondary
# Slide 4 Title & legend
# Slide 5 Data labels
# Slide 6 Axes min/max on both axes, titles, gridlines
# Slide 7 Series styling colors, gradients, transparency, outline, shadow
# Slide 8 Presets & per-series preset bundles + chart-series Set
#
# CLI twin of charts-combo.py (officecli Python SDK). Both produce an
# equivalent charts-combo.pptx.
#
# Usage:
# ./charts-combo.sh [officecli path]
# NOTE: intentionally NO `set -e`. Like the SDK twin's doc.batch, this script
# tolerates forward-compat 'UNSUPPORTED props' warnings (officecli exit 2) and
# keeps building so the full document is produced.
CLI="${1:-officecli}"
FILE="$(dirname "$0")/charts-combo.pptx"
rm -f "$FILE"
$CLI create "$FILE"
$CLI open "$FILE"
# Shared category + data strings (reused across every chart).
CATS="Q1,Q2,Q3,Q4"
D2="Sales:120,135,148,162;Growth %:5,12,18,22"
D3="Sales:120,135,148,162;Cost:80,90,95,105;Growth %:5,12,18,22"
# ==================== Slide 1: combotypes ====================
$CLI add "$FILE" / --type slide
$CLI add "$FILE" /slide[1] --type shape --prop text="combotypes — column+line / column+area / line+area / bar+line" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
$CLI add "$FILE" /slide[1] --type chart --prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=combo --prop combotypes=column,line --prop title="column + line" --prop legend=bottom --prop categories="$CATS" --prop data="$D2"
$CLI add "$FILE" /slide[1] --type chart --prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=combo --prop combotypes=column,area --prop title="column + area" --prop legend=bottom --prop categories="$CATS" --prop data="$D2"
$CLI add "$FILE" /slide[1] --type chart --prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=combo --prop combotypes=line,area --prop title="line + area" --prop legend=bottom --prop categories="$CATS" --prop data="$D2"
$CLI add "$FILE" /slide[1] --type chart --prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=combo --prop combotypes=bar,line --prop title="bar + line" --prop legend=bottom --prop categories="$CATS" --prop data="$D2"
# ==================== Slide 2: combosplit ====================
$CLI add "$FILE" / --type slide
$CLI add "$FILE" /slide[2] --type shape --prop text="combosplit — first N series use primary type" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
$CLI add "$FILE" /slide[2] --type chart --prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=combo --prop combotypes=column,column,line --prop combosplit=2 --prop title="combosplit=2 (2 columns + 1 line)" --prop legend=bottom --prop categories="$CATS" --prop data="$D3"
$CLI add "$FILE" /slide[2] --type chart --prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=combo --prop combotypes=column,line,line --prop combosplit=1 --prop title="combosplit=1 (1 column + 2 lines)" --prop legend=bottom --prop categories="$CATS" --prop data="$D3"
$CLI add "$FILE" /slide[2] --type chart --prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=combo --prop combotypes=line,line,column --prop combosplit=2 --prop title="combosplit=2 (2 lines + 1 column)" --prop legend=bottom --prop categories="$CATS" --prop data="$D3"
$CLI add "$FILE" /slide[2] --type chart --prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=combo --prop combotypes=area,column,line --prop combosplit=1 --prop title="area + column + line" --prop legend=bottom --prop categories="$CATS" --prop data="$D3"
# ==================== Slide 3: secondaryaxis ====================
$CLI add "$FILE" / --type slide
$CLI add "$FILE" /slide[3] --type shape --prop text="secondaryaxis — line on secondary value axis" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
$CLI add "$FILE" /slide[3] --type chart --prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=combo --prop combotypes=column,line --prop secondaryaxis=2 --prop title="secondaryaxis=2" --prop legend=bottom --prop categories="$CATS" --prop data="$D2"
$CLI add "$FILE" /slide[3] --type chart --prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=combo --prop combotypes=column,column,line --prop secondaryaxis=3 --prop combosplit=2 --prop title="secondaryaxis=3 (Growth on right)" --prop legend=bottom --prop categories="$CATS" --prop data="$D3"
$CLI add "$FILE" /slide[3] --type chart --prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=combo --prop combotypes=column,line,line --prop secondaryaxis=2,3 --prop combosplit=1 --prop title="secondaryaxis=2,3" --prop legend=bottom --prop categories="$CATS" --prop data="$D3"
$CLI add "$FILE" /slide[3] --type chart --prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=combo --prop combotypes=column,line --prop secondaryaxis=2 --prop title="with grid + tick fonts" --prop gridlines=E0E0E0:0.3 --prop axisfont=9:333333:Calibri --prop legend=bottom --prop categories="$CATS" --prop data="$D2"
# ==================== Slide 4: Title & legend ====================
$CLI add "$FILE" / --type slide
$CLI add "$FILE" /slide[4] --type shape --prop text="Title & legend" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
$CLI add "$FILE" /slide[4] --type chart --prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=combo --prop combotypes=column,line --prop title="Styled title" --prop title.font=Georgia --prop title.size=20 --prop title.color=4472C4 --prop title.bold=true --prop legend=bottom --prop categories="$CATS" --prop data="$D2"
$CLI add "$FILE" /slide[4] --type chart --prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=combo --prop combotypes=column,line --prop title="legend=top + legendFont" --prop legend=top --prop legendFont=10:333333:Calibri --prop categories="$CATS" --prop data="$D2"
$CLI add "$FILE" /slide[4] --type chart --prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=combo --prop combotypes=column,line --prop title="legend.overlay=true" --prop legend=topRight --prop legend.overlay=true --prop categories="$CATS" --prop data="$D2"
$CLI add "$FILE" /slide[4] --type chart --prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=combo --prop combotypes=column,line --prop autotitledeleted=true --prop legend=none --prop categories="$CATS" --prop data="$D2"
# ==================== Slide 5: Data labels ====================
$CLI add "$FILE" / --type slide
$CLI add "$FILE" /slide[5] --type shape --prop text="Data labels — combo charts skip labelPos (chart-type conditional)" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
$CLI add "$FILE" /slide[5] --type chart --prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=combo --prop combotypes=column,line --prop title="dataLabels=value" --prop dataLabels=value --prop legend=bottom --prop categories="$CATS" --prop data="$D2"
$CLI add "$FILE" /slide[5] --type chart --prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=combo --prop combotypes=column,line --prop title="value,series" --prop dataLabels=value,series --prop legend=bottom --prop categories="$CATS" --prop data="$D2"
$CLI add "$FILE" /slide[5] --type chart --prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=combo --prop combotypes=column,line --prop title="dataLabels=none" --prop dataLabels=none --prop legend=bottom --prop categories="$CATS" --prop data="$D2"
$CLI add "$FILE" /slide[5] --type chart --prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=combo --prop combotypes=column,line --prop title="labelfont styled" --prop dataLabels=value --prop labelfont=10:C00000:Georgia --prop legend=bottom --prop categories="$CATS" --prop data="$D2"
# ==================== Slide 6: Axes ====================
$CLI add "$FILE" / --type slide
$CLI add "$FILE" /slide[6] --type shape --prop text="Axes — min/max on primary, secondary, gridlines, axisnumfmt" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
$CLI add "$FILE" /slide[6] --type chart --prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=combo --prop combotypes=column,line --prop secondaryaxis=2 --prop title="both axes min/max" --prop axismin=0 --prop axismax=200 --prop axistitle=Sales --prop cattitle=Quarter --prop axisfont=10:333333:Calibri --prop axisnumfmt="#,##0" --prop legend=bottom --prop categories="$CATS" --prop data="$D2"
$CLI add "$FILE" /slide[6] --type chart --prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=combo --prop combotypes=column,line --prop title="gridlines + minorGridlines" --prop gridlines=E0E0E0:0.3 --prop minorGridlines=F0F0F0:0.25 --prop legend=bottom --prop categories="$CATS" --prop data="$D2"
$CLI add "$FILE" /slide[6] --type chart --prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=combo --prop combotypes=column,line --prop title="labelrotation=-30" --prop labelrotation=-30 --prop legend=bottom --prop categories="$CATS" --prop data="$D2"
$CLI add "$FILE" /slide[6] --type chart --prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=combo --prop combotypes=column,line --prop title="chart-axis Set after add" --prop legend=bottom --prop categories="$CATS" --prop data="$D2"
$CLI set "$FILE" "/slide[6]/chart[4]/axis[@role=value]" --prop title="Sales (USD)" --prop format="\$#,##0" --prop majorGridlines=true --prop min=0 --prop max=200
# ==================== Slide 7: Series styling ====================
$CLI add "$FILE" / --type slide
$CLI add "$FILE" /slide[7] --type shape --prop text="Series styling — colors, gradient(s), transparency, outline, shadow" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
$CLI add "$FILE" /slide[7] --type chart --prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=combo --prop combotypes=column,line --prop title="colors + seriesoutline" --prop colors=4472C4,ED7D31 --prop seriesoutline=000000:0.5 --prop legend=bottom --prop categories="$CATS" --prop data="$D2"
$CLI add "$FILE" /slide[7] --type chart --prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=combo --prop combotypes=column,line --prop title="gradient + seriesshadow" --prop gradient=FF6600-FFCC00 --prop seriesshadow=000000-5-45-3-50 --prop legend=bottom --prop categories="$CATS" --prop data="$D2"
$CLI add "$FILE" /slide[7] --type chart --prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=combo --prop combotypes=column,line --prop title="transparency=30" --prop transparency=30 --prop legend=bottom --prop categories="$CATS" --prop data="$D2"
$CLI add "$FILE" /slide[7] --type chart --prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=combo --prop combotypes=column,line --prop title="per-series gradients" --prop gradients="FF0000-0000FF;00FF00-FFFF00" --prop legend=bottom --prop categories="$CATS" --prop data="$D2"
# ==================== Slide 8: Presets & per-series Set ====================
$CLI add "$FILE" / --type slide
$CLI add "$FILE" /slide[8] --type shape --prop text="Presets & per-series Set" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
$CLI add "$FILE" /slide[8] --type chart --prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=combo --prop combotypes=column,line --prop preset=minimal --prop title="preset=minimal" --prop legend=bottom --prop categories="$CATS" --prop data="$D2"
$CLI add "$FILE" /slide[8] --type chart --prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=combo --prop combotypes=column,line --prop preset=dark --prop title="preset=dark" --prop legend=bottom --prop categories="$CATS" --prop data="$D2"
$CLI add "$FILE" /slide[8] --type chart --prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=combo --prop combotypes=column,line --prop preset=corporate --prop title="preset=corporate" --prop legend=bottom --prop categories="$CATS" --prop data="$D2"
$CLI add "$FILE" /slide[8] --type chart --prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=combo --prop combotypes=column,line --prop title="chart-series Set" --prop legend=bottom --prop categories="$CATS" --prop data="$D2"
$CLI set "$FILE" /slide[8]/chart[4]/series[1] --prop name="Renamed Sales" --prop color=C00000
$CLI set "$FILE" /slide[8]/chart[4]/series[2] --prop name="Renamed Growth" --prop color=2E75B6 --prop lineWidth=2.5 --prop marker=circle --prop markerSize=8
$CLI close "$FILE"
$CLI validate "$FILE"
echo "Generated: $FILE"
+239
View File
@@ -0,0 +1,239 @@
# Doughnut Charts Showcase
This demo consists of three files that work together:
- **charts-doughnut.py** — Python script that calls `officecli` commands to generate the deck.
- **charts-doughnut.pptx** — The generated 8-slide deck (4 charts per slide, 32 charts total).
- **charts-doughnut.md** — This file. Maps each slide to the features it demonstrates.
## Regenerate
```bash
cd examples/ppt/charts
python3 charts-doughnut.py
# → charts-doughnut.pptx
```
## Chart Slides
### Slide 1 — holeSize Variants
```bash
# holeSize controls the size of the center hole (1090, % of radius)
for h in 10 30 55 75; do
officecli add charts-doughnut.pptx /slide[1] --type chart \
--prop chartType=doughnut --prop title="holeSize=$h" \
--prop holeSize=$h --prop legend=right --prop varyColors=true \
--prop categories="North,South,East,West" --prop data="Share:30,25,28,17"
done
```
**Features:** `chartType=doughnut`, `holeSize` (1090), `varyColors`
### Slide 2 — Multi-Ring (Concentric Series)
```bash
# Single ring
officecli add charts-doughnut.pptx /slide[2] --type chart \
--prop chartType=doughnut --prop title="single ring" \
--prop holeSize=50 --prop legend=right \
--prop categories="North,South,East,West" --prop data="Share:30,25,28,17"
# Two concentric rings
officecli add charts-doughnut.pptx /slide[2] --type chart \
--prop chartType=doughnut --prop title="two rings" \
--prop holeSize=40 --prop legend=right \
--prop categories="North,South,East,West" \
--prop data="Last:25,30,25,20;This:30,25,28,17"
# Three concentric rings
officecli add charts-doughnut.pptx /slide[2] --type chart \
--prop chartType=doughnut --prop title="three rings" \
--prop holeSize=30 --prop legend=right \
--prop categories="North,South,East,West" \
--prop data="Region1:30,25,28,17;Region2:25,30,20,25;Region3:20,25,30,25"
# Two rings + percent labels
officecli add charts-doughnut.pptx /slide[2] --type chart \
--prop chartType=doughnut --prop title="two rings + dataLabels=percent" \
--prop holeSize=40 --prop dataLabels=percent --prop legend=right \
--prop categories="North,South,East,West" \
--prop data="Last:25,30,25,20;This:30,25,28,17"
```
**Features:** Multi-series doughnut = concentric rings (outer = first series), `holeSize` interacts with ring width
### Slide 3 — First Slice Angle
```bash
for ang in 0 90 180 270; do
officecli add charts-doughnut.pptx /slide[3] --type chart \
--prop chartType=doughnut --prop title="firstSliceAngle=$ang" \
--prop firstSliceAngle=$ang --prop holeSize=50 --prop legend=right \
--prop varyColors=true \
--prop categories="North,South,East,West" --prop data="Share:30,25,28,17"
done
```
**Features:** `firstSliceAngle` (0360°)
### Slide 4 — Data Labels
```bash
officecli add charts-doughnut.pptx /slide[4] --type chart \
--prop chartType=doughnut --prop title="dataLabels=percent" \
--prop dataLabels=percent --prop holeSize=50 --prop legend=right \
--prop labelfont="10:333333:Calibri" \
--prop categories="North,South,East,West" --prop data="Share:30,25,28,17"
officecli add charts-doughnut.pptx /slide[4] --type chart \
--prop chartType=doughnut --prop title="percent,category + leaderlines" \
--prop dataLabels="percent,category" --prop holeSize=50 \
--prop leaderlines=true --prop legend=none \
--prop labelfont="10:333333:Calibri" \
--prop categories="North,South,East,West" --prop data="Share:30,25,28,17"
officecli add charts-doughnut.pptx /slide[4] --type chart \
--prop chartType=doughnut --prop title="all flags (value,percent,category)" \
--prop dataLabels="value,percent,category" --prop holeSize=50 \
--prop leaderlines=true --prop legend=none \
--prop categories="North,South,East,West" --prop data="Share:30,25,28,17"
officecli add charts-doughnut.pptx /slide[4] --type chart \
--prop chartType=doughnut --prop title="dataLabels=none" \
--prop dataLabels=none --prop holeSize=50 --prop legend=right \
--prop categories="North,South,East,West" --prop data="Share:30,25,28,17"
```
**Features:** `dataLabels` (percent/category/value/none or combined), `leaderlines`, `labelfont`
### Slide 5 — Series Styling
```bash
officecli add charts-doughnut.pptx /slide[5] --type chart \
--prop chartType=doughnut --prop title="colors=" --prop holeSize=50 --prop legend=right \
--prop colors="4472C4,ED7D31,A5A5A5,70AD47" \
--prop categories="North,South,East,West" --prop data="Share:30,25,28,17"
officecli add charts-doughnut.pptx /slide[5] --type chart \
--prop chartType=doughnut --prop title="gradient + seriesshadow" \
--prop holeSize=50 --prop gradient="FF6600-FFCC00" \
--prop seriesshadow="000000-5-45-3-50" --prop legend=right \
--prop categories="North,South,East,West" --prop data="Share:30,25,28,17"
officecli add charts-doughnut.pptx /slide[5] --type chart \
--prop chartType=doughnut --prop title="seriesoutline white" \
--prop holeSize=50 --prop seriesoutline="FFFFFF:2" --prop legend=right \
--prop categories="North,South,East,West" --prop data="Share:30,25,28,17"
officecli add charts-doughnut.pptx /slide[5] --type chart \
--prop chartType=doughnut --prop title="transparency=30" \
--prop holeSize=50 --prop transparency=30 --prop legend=right \
--prop categories="North,South,East,West" --prop data="Share:30,25,28,17"
```
**Features:** `colors`, `gradient`, `seriesshadow`, `seriesoutline`, `transparency`
### Slide 6 — Title and Legend
```bash
officecli add charts-doughnut.pptx /slide[6] --type chart \
--prop chartType=doughnut --prop title="Styled title" \
--prop title.font=Georgia --prop title.size=20 \
--prop title.color=4472C4 --prop title.bold=true \
--prop holeSize=50 --prop legend=right \
--prop categories="North,South,East,West" --prop data="Share:30,25,28,17"
officecli add charts-doughnut.pptx /slide[6] --type chart \
--prop chartType=doughnut --prop title="legend=bottom + legendFont" \
--prop holeSize=50 --prop legend=bottom --prop legendFont="10:333333:Calibri" \
--prop categories="North,South,East,West" --prop data="Share:30,25,28,17"
officecli add charts-doughnut.pptx /slide[6] --type chart \
--prop chartType=doughnut --prop title="legend.overlay=true" \
--prop holeSize=50 --prop legend=topRight --prop legend.overlay=true \
--prop categories="North,South,East,West" --prop data="Share:30,25,28,17"
officecli add charts-doughnut.pptx /slide[6] --type chart \
--prop chartType=doughnut --prop autotitledeleted=true \
--prop holeSize=50 --prop legend=none \
--prop categories="North,South,East,West" --prop data="Share:30,25,28,17"
```
**Features:** `title.font/size/color/bold`, `legend` positions, `legendFont`, `legend.overlay`, `autotitledeleted`
### Slide 7 — Backgrounds
```bash
officecli add charts-doughnut.pptx /slide[7] --type chart \
--prop chartType=doughnut --prop title="chartareafill + chartborder" \
--prop holeSize=50 --prop chartareafill=FFF8E7 --prop chartborder="000000:1" \
--prop legend=right \
--prop categories="North,South,East,West" --prop data="Share:30,25,28,17"
officecli add charts-doughnut.pptx /slide[7] --type chart \
--prop chartType=doughnut --prop title="roundedcorners=true" \
--prop holeSize=50 --prop roundedcorners=true --prop chartborder="4472C4:2" \
--prop legend=right \
--prop categories="North,South,East,West" --prop data="Share:30,25,28,17"
officecli add charts-doughnut.pptx /slide[7] --type chart \
--prop chartType=doughnut --prop title="plotFill=none" \
--prop holeSize=50 --prop plotFill=none --prop legend=right \
--prop categories="North,South,East,West" --prop data="Share:30,25,28,17"
officecli add charts-doughnut.pptx /slide[7] --type chart \
--prop chartType=doughnut --prop title="chartareafill=none" \
--prop holeSize=50 --prop chartareafill=none --prop legend=right \
--prop categories="North,South,East,West" --prop data="Share:30,25,28,17"
```
**Features:** `chartareafill`, `plotFill`, `chartborder`, `roundedcorners`
### Slide 8 — Presets and Per-Series Set
```bash
for p in minimal dark corporate; do
officecli add charts-doughnut.pptx /slide[8] --type chart \
--prop chartType=doughnut --prop preset=$p --prop title="preset=$p" \
--prop holeSize=50 --prop legend=right \
--prop categories="North,South,East,West" --prop data="Share:30,25,28,17"
done
officecli add charts-doughnut.pptx /slide[8] --type chart \
--prop chartType=doughnut --prop title="chart-series Set name+color" \
--prop holeSize=50 --prop legend=right \
--prop categories="North,South,East,West" --prop data="Share:30,25,28,17"
officecli set charts-doughnut.pptx "/slide[8]/chart[4]/series[1]" \
--prop name="Renamed Share" --prop color=C00000
```
**Features:** `preset` (minimal/dark/corporate), `chart-series Set`
## Complete Feature Coverage
| Feature | Slide |
|---------|-------|
| **holeSize** (1090%) | 1 |
| **varyColors** | 1 |
| **Multi-ring** (concentric series) | 2 |
| **firstSliceAngle** (0360) | 3 |
| **dataLabels:** percent/category/value/none + combined | 4 |
| **leaderlines**, **labelfont** | 4 |
| **colors, gradient, seriesshadow, seriesoutline, transparency** | 5 |
| **title.font/size/color/bold** | 6 |
| **legend** positions, **legendFont**, **legend.overlay** | 6 |
| **autotitledeleted** | 6 |
| **chartareafill, plotFill, chartborder, roundedcorners** | 7 |
| **preset** (minimal/dark/corporate) | 8 |
| **chart-series Set** | 8 |
## Inspect the Generated File
```bash
officecli query charts-doughnut.pptx chart
officecli get charts-doughnut.pptx "/slide[1]/chart[1]"
officecli get charts-doughnut.pptx "/slide[2]/chart[3]"
officecli get charts-doughnut.pptx "/slide[8]/chart[4]/series[1]"
```
Binary file not shown.
+187
View File
@@ -0,0 +1,187 @@
#!/usr/bin/env python3
"""
Doughnut Charts Showcase — generates charts-doughnut.pptx exercising the pptx
`chart` element with chartType=doughnut across 8 slides.
Slide 1 holeSize variants holeSize=10/30/55/75
Slide 2 Multi-ring two-series + three-series concentric rings
Slide 3 firstSliceAngle 0 / 90 / 180 / 270
Slide 4 Data labels percent / category / value, leaderlines, labelfont
Slide 5 Series styling colors, gradient, seriesoutline, seriesshadow, transparency
Slide 6 Title & legend title.* + legend positions + legendFont
Slide 7 Backgrounds chartareafill, plotFill, chartborder, roundedcorners
Slide 8 Presets & per-series preset bundles + chart-series Set
SDK twin of charts-doughnut.sh (officecli CLI). Both produce an equivalent
charts-doughnut.pptx. This one drives the **officecli Python SDK**
(`pip install officecli-sdk`): one resident is started and every slide, title
shape and chart is shipped over the named pipe in `doc.batch(...)` round-trips.
Each item is the same `{"command","parent","type","props"}` dict you'd put in an
`officecli batch` list. batch runs with force=True so a prop a future build
doesn't yet support is skipped (forward-compat) rather than aborting the run.
Usage:
pip install officecli-sdk # plus the `officecli` binary on PATH
python3 charts-doughnut.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__)), "charts-doughnut.pptx")
# --- shared geometry & data -------------------------------------------------
TL = {"x": "0.3in", "y": "1.05in", "width": "6.1in", "height": "3in"}
TR = {"x": "6.95in", "y": "1.05in", "width": "6.1in", "height": "3in"}
BL = {"x": "0.3in", "y": "4.25in", "width": "6.1in", "height": "3in"}
BR = {"x": "6.95in", "y": "4.25in", "width": "6.1in", "height": "3in"}
CATS = "North,South,East,West"
D = "Share:30,25,28,17"
D2 = "Last:25,30,25,20;This:30,25,28,17"
D3 = "Region1:30,25,28,17;Region2:25,30,20,25;Region3:20,25,30,25"
def slide():
"""One `add slide` item in batch-shape."""
return {"command": "add", "parent": "/", "type": "slide", "props": {}}
def title(n, text):
"""One `add shape` item (slide heading) in batch-shape."""
return {"command": "add", "parent": f"/slide[{n}]", "type": "shape",
"props": {"text": text, "size": "24", "bold": "true", "autoFit": "normal",
"x": "0.5in", "y": "0.3in", "width": "12.3in", "height": "0.6in"}}
def ch(n, box, props):
"""One `add chart` item in batch-shape (box geometry merged with props)."""
return {"command": "add", "parent": f"/slide[{n}]", "type": "chart",
"props": {**box, **props}}
print(f"Building {FILE} ...")
with officecli.create(FILE, "--force") as doc:
# ---- Slide 1: holeSize — 10 / 30 / 55 / 75 ----
items = [slide(), title(1, "holeSize — 10 / 30 / 55 / 75")]
for box, h in zip([TL, TR, BL, BR], [10, 30, 55, 75]):
items.append(ch(1, box, {"chartType": "doughnut", "title": f"holeSize={h}",
"holeSize": str(h), "legend": "right", "varyColors": "true",
"categories": CATS, "data": D}))
doc.batch(items)
# ---- Slide 2: Multi-ring — concentric series ----
items = [slide(), title(2, "Multi-ring — concentric series")]
items.append(ch(2, TL, {"chartType": "doughnut", "title": "single ring", "holeSize": "50",
"legend": "right", "categories": CATS, "data": D}))
items.append(ch(2, TR, {"chartType": "doughnut", "title": "two rings", "holeSize": "40",
"legend": "right", "categories": CATS, "data": D2}))
items.append(ch(2, BL, {"chartType": "doughnut", "title": "three rings", "holeSize": "30",
"legend": "right", "categories": CATS, "data": D3}))
items.append(ch(2, BR, {"chartType": "doughnut", "title": "two rings + dataLabels=percent",
"holeSize": "40", "dataLabels": "percent", "legend": "right",
"categories": CATS, "data": D2}))
doc.batch(items)
# ---- Slide 3: First slice angle — 0 / 90 / 180 / 270 ----
items = [slide(), title(3, "First slice angle — 0 / 90 / 180 / 270")]
for box, ang in zip([TL, TR, BL, BR], [0, 90, 180, 270]):
items.append(ch(3, box, {"chartType": "doughnut", "title": f"firstSliceAngle={ang}",
"firstSliceAngle": str(ang), "holeSize": "50", "legend": "right",
"varyColors": "true", "categories": CATS, "data": D}))
doc.batch(items)
# ---- Slide 4: Data labels — percent / category / value, leaderlines, labelfont ----
items = [slide(), title(4, "Data labels — percent / category / value, leaderlines, labelfont")]
items.append(ch(4, TL, {"chartType": "doughnut", "title": "dataLabels=percent",
"dataLabels": "percent", "holeSize": "50", "legend": "right",
"labelfont": "10:333333:Calibri", "categories": CATS, "data": D}))
items.append(ch(4, TR, {"chartType": "doughnut", "title": "percent,category",
"dataLabels": "percent,category", "holeSize": "50", "leaderlines": "true",
"legend": "none", "labelfont": "10:333333:Calibri",
"categories": CATS, "data": D}))
items.append(ch(4, BL, {"chartType": "doughnut", "title": "all flags",
"dataLabels": "value,percent,category", "holeSize": "50",
"leaderlines": "true", "legend": "none", "categories": CATS, "data": D}))
items.append(ch(4, BR, {"chartType": "doughnut", "title": "dataLabels=none",
"dataLabels": "none", "holeSize": "50", "legend": "right",
"categories": CATS, "data": D}))
doc.batch(items)
# ---- Slide 5: Series styling — colors, gradient, outline, shadow, transparency ----
items = [slide(), title(5, "Series styling — colors, gradient, outline, shadow, transparency")]
items.append(ch(5, TL, {"chartType": "doughnut", "title": "colors=", "holeSize": "50",
"legend": "right", "colors": "4472C4,ED7D31,A5A5A5,70AD47",
"categories": CATS, "data": D}))
items.append(ch(5, TR, {"chartType": "doughnut", "title": "gradient + seriesshadow",
"holeSize": "50", "gradient": "FF6600-FFCC00",
"seriesshadow": "000000-5-45-3-50", "legend": "right",
"categories": CATS, "data": D}))
items.append(ch(5, BL, {"chartType": "doughnut", "title": "seriesoutline white", "holeSize": "50",
"seriesoutline": "FFFFFF:2", "legend": "right",
"categories": CATS, "data": D}))
items.append(ch(5, BR, {"chartType": "doughnut", "title": "transparency=30", "holeSize": "50",
"transparency": "30", "legend": "right", "categories": CATS, "data": D}))
doc.batch(items)
# ---- Slide 6: Title & legend ----
items = [slide(), title(6, "Title & legend")]
items.append(ch(6, TL, {"chartType": "doughnut", "title": "Styled title", "title.font": "Georgia",
"title.size": "20", "title.color": "4472C4", "title.bold": "true",
"holeSize": "50", "legend": "right", "categories": CATS, "data": D}))
items.append(ch(6, TR, {"chartType": "doughnut", "title": "legend=bottom + legendFont",
"holeSize": "50", "legend": "bottom", "legendFont": "10:333333:Calibri",
"categories": CATS, "data": D}))
items.append(ch(6, BL, {"chartType": "doughnut", "title": "legend.overlay=true", "holeSize": "50",
"legend": "topRight", "legend.overlay": "true",
"categories": CATS, "data": D}))
items.append(ch(6, BR, {"chartType": "doughnut", "autotitledeleted": "true", "holeSize": "50",
"legend": "none", "categories": CATS, "data": D}))
doc.batch(items)
# ---- Slide 7: Backgrounds — chartareafill, plotFill, chartborder, roundedcorners ----
items = [slide(), title(7, "Backgrounds — chartareafill, plotFill, chartborder, roundedcorners")]
items.append(ch(7, TL, {"chartType": "doughnut", "title": "chartareafill + chartborder",
"holeSize": "50", "chartareafill": "FFF8E7", "chartborder": "000000:1",
"legend": "right", "categories": CATS, "data": D}))
items.append(ch(7, TR, {"chartType": "doughnut", "title": "roundedcorners=true", "holeSize": "50",
"roundedcorners": "true", "chartborder": "4472C4:2", "legend": "right",
"categories": CATS, "data": D}))
items.append(ch(7, BL, {"chartType": "doughnut", "title": "plotFill=none", "holeSize": "50",
"plotFill": "none", "legend": "right", "categories": CATS, "data": D}))
items.append(ch(7, BR, {"chartType": "doughnut", "title": "chartareafill=none", "holeSize": "50",
"chartareafill": "none", "legend": "right", "categories": CATS, "data": D}))
doc.batch(items)
# ---- Slide 8: Presets & per-series Set ----
items = [slide(), title(8, "Presets & per-series Set")]
for box, p in zip([TL, TR, BL], ["minimal", "dark", "corporate"]):
items.append(ch(8, box, {"chartType": "doughnut", "preset": p, "title": f"preset={p}",
"holeSize": "50", "legend": "right", "categories": CATS, "data": D}))
items.append(ch(8, BR, {"chartType": "doughnut", "title": "chart-series Set name+color",
"holeSize": "50", "legend": "right", "categories": CATS, "data": D}))
doc.batch(items)
# per-series Set: rename + recolor the single series of the 4th chart
doc.send({"command": "set", "path": "/slide[8]/chart[4]/series[1]",
"props": {"name": "Renamed Share", "color": "C00000"}})
print(" built 8 slides")
doc.send({"command": "save"})
# context exit closes the resident, flushing the presentation to disk.
# Validate the SAVED file with a fresh one-shot process (from disk).
import subprocess
print("--- Validate (fresh process, from disk) ---")
r = subprocess.run(["officecli", "validate", FILE], capture_output=True, text=True)
print(" ", (r.stdout or r.stderr).strip().split("\n")[0])
print(f"Generated: {FILE}")
+102
View File
@@ -0,0 +1,102 @@
#!/bin/bash
# Doughnut Charts Showcase — generates charts-doughnut.pptx exercising the pptx
# `chart` element with chartType=doughnut across 8 slides.
#
# Slide 1 holeSize variants holeSize=10/30/55/75
# Slide 2 Multi-ring two-series + three-series concentric rings
# Slide 3 firstSliceAngle 0 / 90 / 180 / 270
# Slide 4 Data labels percent / category / value, leaderlines, labelfont
# Slide 5 Series styling colors, gradient, seriesoutline, seriesshadow, transparency
# Slide 6 Title & legend title.* + legend positions + legendFont
# Slide 7 Backgrounds chartareafill, plotFill, chartborder, roundedcorners
# Slide 8 Presets & per-series preset bundles + chart-series Set
#
# CLI twin of charts-doughnut.py (officecli Python SDK).
# Usage: ./charts-doughnut.sh [officecli path]
# NOTE: intentionally NO `set -e`. Like the SDK twin's doc.batch, this script
# tolerates forward-compat 'UNSUPPORTED props' warnings (officecli exit 2) and
# keeps building so the full document is produced.
CLI="${1:-officecli}"
FILE="$(dirname "$0")/charts-doughnut.pptx"
# shared data
CATS="North,South,East,West"
D="Share:30,25,28,17"
D2="Last:25,30,25,20;This:30,25,28,17"
D3="Region1:30,25,28,17;Region2:25,30,20,25;Region3:20,25,30,25"
rm -f "$FILE"
$CLI create "$FILE"
$CLI open "$FILE"
# ==================== Slide 1: holeSize — 10 / 30 / 55 / 75 ====================
$CLI add "$FILE" / --type slide
$CLI add "$FILE" /slide[1] --type shape --prop text="holeSize — 10 / 30 / 55 / 75" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
$CLI add "$FILE" /slide[1] --type chart --prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=doughnut --prop title=holeSize=10 --prop holeSize=10 --prop legend=right --prop varyColors=true --prop categories="$CATS" --prop data="$D"
$CLI add "$FILE" /slide[1] --type chart --prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=doughnut --prop title=holeSize=30 --prop holeSize=30 --prop legend=right --prop varyColors=true --prop categories="$CATS" --prop data="$D"
$CLI add "$FILE" /slide[1] --type chart --prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=doughnut --prop title=holeSize=55 --prop holeSize=55 --prop legend=right --prop varyColors=true --prop categories="$CATS" --prop data="$D"
$CLI add "$FILE" /slide[1] --type chart --prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=doughnut --prop title=holeSize=75 --prop holeSize=75 --prop legend=right --prop varyColors=true --prop categories="$CATS" --prop data="$D"
# ==================== Slide 2: Multi-ring — concentric series ====================
$CLI add "$FILE" / --type slide
$CLI add "$FILE" /slide[2] --type shape --prop text="Multi-ring — concentric series" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
$CLI add "$FILE" /slide[2] --type chart --prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=doughnut --prop title="single ring" --prop holeSize=50 --prop legend=right --prop categories="$CATS" --prop data="$D"
$CLI add "$FILE" /slide[2] --type chart --prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=doughnut --prop title="two rings" --prop holeSize=40 --prop legend=right --prop categories="$CATS" --prop data="$D2"
$CLI add "$FILE" /slide[2] --type chart --prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=doughnut --prop title="three rings" --prop holeSize=30 --prop legend=right --prop categories="$CATS" --prop data="$D3"
$CLI add "$FILE" /slide[2] --type chart --prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=doughnut --prop title="two rings + dataLabels=percent" --prop holeSize=40 --prop dataLabels=percent --prop legend=right --prop categories="$CATS" --prop data="$D2"
# ==================== Slide 3: First slice angle — 0 / 90 / 180 / 270 ====================
$CLI add "$FILE" / --type slide
$CLI add "$FILE" /slide[3] --type shape --prop text="First slice angle — 0 / 90 / 180 / 270" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
$CLI add "$FILE" /slide[3] --type chart --prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=doughnut --prop title=firstSliceAngle=0 --prop firstSliceAngle=0 --prop holeSize=50 --prop legend=right --prop varyColors=true --prop categories="$CATS" --prop data="$D"
$CLI add "$FILE" /slide[3] --type chart --prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=doughnut --prop title=firstSliceAngle=90 --prop firstSliceAngle=90 --prop holeSize=50 --prop legend=right --prop varyColors=true --prop categories="$CATS" --prop data="$D"
$CLI add "$FILE" /slide[3] --type chart --prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=doughnut --prop title=firstSliceAngle=180 --prop firstSliceAngle=180 --prop holeSize=50 --prop legend=right --prop varyColors=true --prop categories="$CATS" --prop data="$D"
$CLI add "$FILE" /slide[3] --type chart --prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=doughnut --prop title=firstSliceAngle=270 --prop firstSliceAngle=270 --prop holeSize=50 --prop legend=right --prop varyColors=true --prop categories="$CATS" --prop data="$D"
# ==================== Slide 4: Data labels — percent / category / value, leaderlines, labelfont ====================
$CLI add "$FILE" / --type slide
$CLI add "$FILE" /slide[4] --type shape --prop text="Data labels — percent / category / value, leaderlines, labelfont" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
$CLI add "$FILE" /slide[4] --type chart --prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=doughnut --prop title=dataLabels=percent --prop dataLabels=percent --prop holeSize=50 --prop legend=right --prop labelfont=10:333333:Calibri --prop categories="$CATS" --prop data="$D"
$CLI add "$FILE" /slide[4] --type chart --prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=doughnut --prop title="percent,category" --prop dataLabels="percent,category" --prop holeSize=50 --prop leaderlines=true --prop legend=none --prop labelfont=10:333333:Calibri --prop categories="$CATS" --prop data="$D"
$CLI add "$FILE" /slide[4] --type chart --prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=doughnut --prop title="all flags" --prop dataLabels="value,percent,category" --prop holeSize=50 --prop leaderlines=true --prop legend=none --prop categories="$CATS" --prop data="$D"
$CLI add "$FILE" /slide[4] --type chart --prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=doughnut --prop title=dataLabels=none --prop dataLabels=none --prop holeSize=50 --prop legend=right --prop categories="$CATS" --prop data="$D"
# ==================== Slide 5: Series styling — colors, gradient, outline, shadow, transparency ====================
$CLI add "$FILE" / --type slide
$CLI add "$FILE" /slide[5] --type shape --prop text="Series styling — colors, gradient, outline, shadow, transparency" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
$CLI add "$FILE" /slide[5] --type chart --prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=doughnut --prop title=colors= --prop holeSize=50 --prop legend=right --prop colors=4472C4,ED7D31,A5A5A5,70AD47 --prop categories="$CATS" --prop data="$D"
$CLI add "$FILE" /slide[5] --type chart --prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=doughnut --prop title="gradient + seriesshadow" --prop holeSize=50 --prop gradient=FF6600-FFCC00 --prop seriesshadow=000000-5-45-3-50 --prop legend=right --prop categories="$CATS" --prop data="$D"
$CLI add "$FILE" /slide[5] --type chart --prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=doughnut --prop title="seriesoutline white" --prop holeSize=50 --prop seriesoutline=FFFFFF:2 --prop legend=right --prop categories="$CATS" --prop data="$D"
$CLI add "$FILE" /slide[5] --type chart --prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=doughnut --prop title=transparency=30 --prop holeSize=50 --prop transparency=30 --prop legend=right --prop categories="$CATS" --prop data="$D"
# ==================== Slide 6: Title & legend ====================
$CLI add "$FILE" / --type slide
$CLI add "$FILE" /slide[6] --type shape --prop text="Title & legend" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
$CLI add "$FILE" /slide[6] --type chart --prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=doughnut --prop title="Styled title" --prop title.font=Georgia --prop title.size=20 --prop title.color=4472C4 --prop title.bold=true --prop holeSize=50 --prop legend=right --prop categories="$CATS" --prop data="$D"
$CLI add "$FILE" /slide[6] --type chart --prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=doughnut --prop title="legend=bottom + legendFont" --prop holeSize=50 --prop legend=bottom --prop legendFont=10:333333:Calibri --prop categories="$CATS" --prop data="$D"
$CLI add "$FILE" /slide[6] --type chart --prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=doughnut --prop title="legend.overlay=true" --prop holeSize=50 --prop legend=topRight --prop legend.overlay=true --prop categories="$CATS" --prop data="$D"
$CLI add "$FILE" /slide[6] --type chart --prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=doughnut --prop autotitledeleted=true --prop holeSize=50 --prop legend=none --prop categories="$CATS" --prop data="$D"
# ==================== Slide 7: Backgrounds — chartareafill, plotFill, chartborder, roundedcorners ====================
$CLI add "$FILE" / --type slide
$CLI add "$FILE" /slide[7] --type shape --prop text="Backgrounds — chartareafill, plotFill, chartborder, roundedcorners" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
$CLI add "$FILE" /slide[7] --type chart --prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=doughnut --prop title="chartareafill + chartborder" --prop holeSize=50 --prop chartareafill=FFF8E7 --prop chartborder=000000:1 --prop legend=right --prop categories="$CATS" --prop data="$D"
$CLI add "$FILE" /slide[7] --type chart --prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=doughnut --prop title=roundedcorners=true --prop holeSize=50 --prop roundedcorners=true --prop chartborder=4472C4:2 --prop legend=right --prop categories="$CATS" --prop data="$D"
$CLI add "$FILE" /slide[7] --type chart --prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=doughnut --prop title=plotFill=none --prop holeSize=50 --prop plotFill=none --prop legend=right --prop categories="$CATS" --prop data="$D"
$CLI add "$FILE" /slide[7] --type chart --prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=doughnut --prop title=chartareafill=none --prop holeSize=50 --prop chartareafill=none --prop legend=right --prop categories="$CATS" --prop data="$D"
# ==================== Slide 8: Presets & per-series Set ====================
$CLI add "$FILE" / --type slide
$CLI add "$FILE" /slide[8] --type shape --prop text="Presets & per-series Set" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
$CLI add "$FILE" /slide[8] --type chart --prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=doughnut --prop preset=minimal --prop title=preset=minimal --prop holeSize=50 --prop legend=right --prop categories="$CATS" --prop data="$D"
$CLI add "$FILE" /slide[8] --type chart --prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=doughnut --prop preset=dark --prop title=preset=dark --prop holeSize=50 --prop legend=right --prop categories="$CATS" --prop data="$D"
$CLI add "$FILE" /slide[8] --type chart --prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=doughnut --prop preset=corporate --prop title=preset=corporate --prop holeSize=50 --prop legend=right --prop categories="$CATS" --prop data="$D"
$CLI add "$FILE" /slide[8] --type chart --prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=doughnut --prop title="chart-series Set name+color" --prop holeSize=50 --prop legend=right --prop categories="$CATS" --prop data="$D"
# per-series Set: rename + recolor the single series of the 4th chart
$CLI set "$FILE" /slide[8]/chart[4]/series[1] --prop name="Renamed Share" --prop color=C00000
$CLI close "$FILE"
$CLI validate "$FILE"
echo "Generated: $FILE"
+287
View File
@@ -0,0 +1,287 @@
# Line Charts Showcase
This demo consists of three files that work together:
- **charts-line.py** — Python script that calls `officecli` commands to generate the deck.
- **charts-line.pptx** — The generated 8-slide deck (4 charts per slide, 32 charts total).
- **charts-line.md** — This file. Maps each slide to the features it demonstrates.
## Regenerate
```bash
cd examples/ppt/charts
python3 charts-line.py
# → charts-line.pptx
```
## Chart Slides
### Slide 1 — Variants
```bash
CATS="Mon,Tue,Wed,Thu,Fri"
D2="A:50,60,70,65,80;B:40,45,55,60,75"
officecli add charts-line.pptx /slide[1] --type chart \
--prop chartType=line --prop title="line" --prop legend=bottom \
--prop categories="$CATS" --prop data="$D2" \
--prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in
officecli add charts-line.pptx /slide[1] --type chart \
--prop chartType=stackedLine --prop title="stackedLine" --prop legend=bottom \
--prop categories="$CATS" --prop data="$D2" \
--prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in
officecli add charts-line.pptx /slide[1] --type chart \
--prop chartType=percentStackedLine --prop title="percentStackedLine" \
--prop legend=bottom --prop categories="$CATS" --prop data="$D2" \
--prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in
officecli add charts-line.pptx /slide[1] --type chart \
--prop chartType=line3d --prop title="line3d" --prop legend=bottom \
--prop categories="$CATS" --prop data="$D2" \
--prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in
```
**Features:** `chartType` (line/stackedLine/percentStackedLine/line3d)
### Slide 2 — Markers
```bash
# Explicit marker with symbol, size, and color
officecli add charts-line.pptx /slide[2] --type chart \
--prop chartType=line --prop title="marker=circle:8:FF0000" \
--prop marker="circle:8:FF0000" --prop linewidth=2 --prop legend=none \
--prop categories="$CATS" --prop data="A:50,60,70,65,80"
officecli add charts-line.pptx /slide[2] --type chart \
--prop chartType=line --prop title="marker=square:6" \
--prop marker="square:6" --prop linewidth=2 --prop legend=none \
--prop categories="$CATS" --prop data="A:50,60,70,65,80"
officecli add charts-line.pptx /slide[2] --type chart \
--prop chartType=line --prop title="marker=diamond:10:0070C0" \
--prop marker="diamond:10:0070C0" --prop linewidth=2 --prop legend=none \
--prop categories="$CATS" --prop data="A:50,60,70,65,80"
# showMarker=true: use default auto-markers
officecli add charts-line.pptx /slide[2] --type chart \
--prop chartType=line --prop title="showMarker=true (default markers)" \
--prop showMarker=true --prop legend=bottom \
--prop categories="$CATS" --prop data="$D2"
```
**Features:** `marker` (symbol:size:color compound), symbols: circle/square/diamond/triangle/star/…; `showMarker=true` (auto markers), `linewidth`
### Slide 3 — Smoothing and Line Dash
```bash
# Smooth curve
officecli add charts-line.pptx /slide[3] --type chart \
--prop chartType=line --prop title="smooth=true" \
--prop smooth=true --prop linewidth=2.5 --prop legend=none \
--prop categories="$CATS" --prop data="A:50,60,70,65,80"
# Dashed line styles
officecli add charts-line.pptx /slide[3] --type chart \
--prop chartType=line --prop title="linedash=dash" \
--prop linedash=dash --prop linewidth=2 --prop legend=none \
--prop categories="$CATS" --prop data="A:50,60,70,65,80"
officecli add charts-line.pptx /slide[3] --type chart \
--prop chartType=line --prop title="linedash=dot" \
--prop linedash=dot --prop linewidth=2 --prop legend=none \
--prop categories="$CATS" --prop data="A:50,60,70,65,80"
officecli add charts-line.pptx /slide[3] --type chart \
--prop chartType=line --prop title="linedash=dashDot" \
--prop linedash=dashDot --prop linewidth=2 --prop legend=none \
--prop categories="$CATS" --prop data="A:50,60,70,65,80"
```
**Features:** `smooth`, `linewidth` (pt float), `linedash` (solid/dash/dot/dashDot/longDash/longDashDot/longDashDotDot)
### Slide 4 — Title and Legend
```bash
officecli add charts-line.pptx /slide[4] --type chart \
--prop chartType=line --prop title="Styled title" \
--prop title.font=Georgia --prop title.size=20 \
--prop title.color=4472C4 --prop title.bold=true \
--prop legend=bottom --prop categories="$CATS" --prop data="$D2"
officecli add charts-line.pptx /slide[4] --type chart \
--prop chartType=line --prop title="legend=top + legendFont" \
--prop legend=top --prop legendFont="10:333333:Calibri" \
--prop categories="$CATS" --prop data="$D2"
officecli add charts-line.pptx /slide[4] --type chart \
--prop chartType=line --prop title="legend.overlay=true" \
--prop legend=topRight --prop legend.overlay=true \
--prop categories="$CATS" --prop data="$D2"
officecli add charts-line.pptx /slide[4] --type chart \
--prop chartType=line --prop autotitledeleted=true --prop legend=none \
--prop categories="$CATS" --prop data="$D2"
```
**Features:** `title.font/size/color/bold`, `legend` positions, `legendFont`, `legend.overlay`, `autotitledeleted`
### Slide 5 — Data Labels
```bash
officecli add charts-line.pptx /slide[5] --type chart \
--prop chartType=line --prop title="dataLabels=value @ top" \
--prop dataLabels=value --prop labelPos=top \
--prop labelfont="10:333333:Calibri" --prop legend=none \
--prop categories="$CATS" --prop data="A:50,60,70,65,80"
officecli add charts-line.pptx /slide[5] --type chart \
--prop chartType=line --prop title="value,category" \
--prop dataLabels="value,category" --prop labelPos=top --prop legend=none \
--prop categories="$CATS" --prop data="A:50,60,70,65,80"
officecli add charts-line.pptx /slide[5] --type chart \
--prop chartType=line --prop title="dataLabels=none" \
--prop dataLabels=none --prop legend=none \
--prop categories="$CATS" --prop data="A:50,60,70,65,80"
officecli add charts-line.pptx /slide[5] --type chart \
--prop chartType=line --prop title="labelfont styled" \
--prop dataLabels=value --prop labelPos=top \
--prop labelfont="12:C00000:Georgia" --prop legend=none \
--prop categories="$CATS" --prop data="A:50,60,70,65,80"
```
**Features:** `dataLabels` (value/category/none or combined), `labelPos` (top/center/insideEnd/outsideEnd/bestFit), `labelfont`
### Slide 6 — Axes
```bash
# Axis scaling, titles, number format
officecli add charts-line.pptx /slide[6] --type chart \
--prop chartType=line --prop title="min/max + titles" --prop legend=none \
--prop axismin=0 --prop axismax=100 --prop majorunit=25 \
--prop axistitle="Visits" --prop cattitle="Day" \
--prop axisfont="10:333333:Calibri" --prop axisline="666666:1" \
--prop axisnumfmt="#,##0" \
--prop categories="$CATS" --prop data="A:50,60,70,65,80"
# Gridlines and tick marks
officecli add charts-line.pptx /slide[6] --type chart \
--prop chartType=line --prop title="gridlines + ticks" --prop legend=none \
--prop gridlines="E0E0E0:0.3" --prop minorGridlines="F0F0F0:0.25" \
--prop majorTickMark=out --prop minorTickMark=in --prop tickLabelPos=nextTo \
--prop categories="$CATS" --prop data="A:50,60,70,65,80"
# Label rotation
officecli add charts-line.pptx /slide[6] --type chart \
--prop chartType=line --prop title="labelrotation=-30" --prop legend=none \
--prop labelrotation=-30 \
--prop categories="January,February,March,April,May,June" \
--prop data="A:60,90,140,180,160,210"
# Logarithmic scale on value axis
officecli add charts-line.pptx /slide[6] --type chart \
--prop chartType=line --prop title="logbase=10" --prop legend=none \
--prop logbase=10 --prop axismin=1 --prop axismax=10000 \
--prop categories="$CATS" --prop data="Growth:5,50,500,5000,3000"
```
**Features:** `axismin/max`, `majorunit`, `axistitle/cattitle`, `axisfont/axisline/axisnumfmt`, `gridlines/minorGridlines`, `majorTickMark/minorTickMark/tickLabelPos`, `labelrotation`, `logbase`
### Slide 7 — Overlays
```bash
# Drop lines + hi-low lines
officecli add charts-line.pptx /slide[7] --type chart \
--prop chartType=line --prop title="droplines + hilowlines" \
--prop droplines="808080:0.5" --prop hilowlines=true \
--prop legend=bottom \
--prop categories="$CATS" \
--prop data="High:130,135,140,138,145;Low:118,122,128,125,132"
# Up-down bars with custom colors
officecli add charts-line.pptx /slide[7] --type chart \
--prop chartType=line --prop title="updownbars=150:00AA00:FF0000" \
--prop updownbars="150:00AA00:FF0000" --prop legend=bottom \
--prop categories="$CATS" \
--prop data="Open:120,128,130,135,138;Close:128,125,135,138,142"
# Trendline + error bars
officecli add charts-line.pptx /slide[7] --type chart \
--prop chartType=line --prop title="trendline=linear + errbars=stdDev:1" \
--prop trendline=linear --prop errbars="stdDev:1" --prop legend=none \
--prop categories="$CATS" --prop data="A:50,60,70,65,80"
# Reference line (horizontal threshold)
officecli add charts-line.pptx /slide[7] --type chart \
--prop chartType=line --prop title="referenceline=70:FF0000:Target" \
--prop referenceline="70:FF0000:Target" --prop legend=none \
--prop categories="$CATS" --prop data="A:50,60,70,65,80"
```
**Features:** `droplines` (color:width), `hilowlines` (true or color:width), `updownbars` (gapWidth:upColor:downColor), `trendline` (linear/…), `errbars`, `referenceline` (value:color:label)
### Slide 8 — Per-Series Set and Presets
```bash
for p in minimal dark corporate; do
officecli add charts-line.pptx /slide[8] --type chart \
--prop chartType=line --prop preset=$p --prop title="preset=$p" \
--prop legend=bottom --prop categories="$CATS" --prop data="$D2"
done
officecli add charts-line.pptx /slide[8] --type chart \
--prop chartType=line --prop title="chart-series Set per line" \
--prop showMarker=true --prop legend=bottom \
--prop categories="$CATS" --prop data="$D2"
# Per-series mutation: lineWidth, lineDash, marker, markerSize, smooth
officecli set charts-line.pptx "/slide[8]/chart[4]/series[1]" \
--prop name="Alpha" --prop color=C00000 --prop lineWidth=2.5 \
--prop lineDash=solid --prop marker=circle --prop markerSize=9 \
--prop smooth=true
officecli set charts-line.pptx "/slide[8]/chart[4]/series[2]" \
--prop name="Beta" --prop color=2E75B6 --prop lineWidth=1.5 \
--prop lineDash=dash --prop marker=diamond --prop markerSize=8
```
**Features:** `preset`, `chart-series Set`: `name`, `color`, `lineWidth`, `lineDash`, `marker`, `markerSize`, `smooth`
## Complete Feature Coverage
| Feature | Slide |
|---------|-------|
| **Chart types:** line, stackedLine, percentStackedLine, line3d | 1 |
| **marker** (symbol:size:color compound) | 2 |
| **showMarker** (auto markers) | 2 |
| **linewidth** | 2, 3 |
| **smooth** | 3 |
| **linedash** (solid/dash/dot/dashDot/longDash/…) | 3 |
| **title.font/size/color/bold** | 4 |
| **legend** positions, legendFont, legend.overlay | 4 |
| **autotitledeleted** | 4 |
| **dataLabels:** value/category/none + combined | 5 |
| **labelPos** (top/center/insideEnd/outsideEnd) | 5 |
| **labelfont** | 5 |
| **axismin/max**, majorunit, axistitle/cattitle | 6 |
| **axisfont/axisline/axisnumfmt** | 6 |
| **gridlines/minorGridlines**, tickmarks | 6 |
| **labelrotation**, **logbase** | 6 |
| **droplines** | 7 |
| **hilowlines** | 7 |
| **updownbars** (gapWidth:upColor:downColor) | 7 |
| **trendline**, errbars | 7 |
| **referenceline** | 7 |
| **preset** | 8 |
| **chart-series Set:** lineWidth/lineDash/marker/markerSize/smooth | 8 |
## Inspect the Generated File
```bash
officecli query charts-line.pptx chart
officecli get charts-line.pptx "/slide[1]/chart[1]"
officecli get charts-line.pptx "/slide[7]/chart[1]"
officecli get charts-line.pptx "/slide[8]/chart[4]/series[1]"
```
Binary file not shown.
+180
View File
@@ -0,0 +1,180 @@
#!/usr/bin/env python3
"""
Line Charts Showcase — line, stackedLine, percentStackedLine, line3d.
Generates: charts-line.pptx
Slide 1 Variants line / stackedLine / percentStackedLine / line3d
Slide 2 Markers marker symbol/size/color, markersize, showMarker
Slide 3 Smoothing & dash smooth, linedash, linewidth
Slide 4 Title & legend title.* + legend positions + legendFont
Slide 5 Data labels flags, labelPos, labelfont
Slide 6 Axes min/max, titles, fonts, gridlines, ticks, labelrotation, log
Slide 7 Overlays droplines, hilowlines, updownbars, trendline, errbars, referenceline
Slide 8 Per-series Set lineWidth/lineDash/marker/markerSize/color/smooth + presets
SDK twin of charts-line.sh (officecli CLI). Both produce an equivalent
charts-line.pptx. This one drives the **officecli Python SDK**
(`pip install officecli-sdk`): one resident is started and every slide's shapes
and charts are shipped over the named pipe in `doc.batch(...)` round-trips.
Each item is the same `{"command","parent","type","props"}` dict you'd put in
an `officecli batch` list. Unsupported props are forwarded as-is: the resident
warns (forward-compat) without failing the batch.
Usage:
pip install officecli-sdk # plus the `officecli` binary on PATH
python3 charts-line.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__)), "charts-line.pptx")
# Quadrant boxes (top-left / top-right / bottom-left / bottom-right).
TL = {"x": "0.3in", "y": "1.05in", "width": "6.1in", "height": "3in"}
TR = {"x": "6.95in", "y": "1.05in", "width": "6.1in", "height": "3in"}
BL = {"x": "0.3in", "y": "4.25in", "width": "6.1in", "height": "3in"}
BR = {"x": "6.95in", "y": "4.25in", "width": "6.1in", "height": "3in"}
CATS = "Mon,Tue,Wed,Thu,Fri"
D2 = "A:50,60,70,65,80;B:40,45,55,60,75"
def slide_items(slide_idx, title, charts):
"""Build the batch items for one slide: an `add slide`, a title `shape`,
then one `add chart` per (box, props) pair. `slide_idx` is the 1-based index
of the slide AFTER it is added (used to anchor the title + charts)."""
items = [{"command": "add", "parent": "/", "type": "slide", "props": {}}]
items.append({"command": "add", "parent": f"/slide[{slide_idx}]", "type": "shape",
"props": {"text": title, "size": "24", "bold": "true",
"autoFit": "normal", "x": "0.5in", "y": "0.3in",
"width": "12.3in", "height": "0.6in"}})
for box, props in charts:
items.append({"command": "add", "parent": f"/slide[{slide_idx}]", "type": "chart",
"props": {**box, **props}})
return items
print(f"Building {FILE} ...")
with officecli.create(FILE, "--force") as doc:
# ---- Slide 1: Line variants ------------------------------------------
doc.batch(slide_items(1, "Line variants — line / stackedLine / percentStackedLine / line3d", [
(TL, {"chartType": "line", "title": "line", "legend": "bottom", "categories": CATS, "data": D2}),
(TR, {"chartType": "stackedLine", "title": "stackedLine", "legend": "bottom", "categories": CATS, "data": D2}),
(BL, {"chartType": "percentStackedLine", "title": "percentStackedLine", "legend": "bottom", "categories": CATS, "data": D2}),
(BR, {"chartType": "line3d", "title": "line3d", "legend": "bottom", "categories": CATS, "data": D2}),
]))
# ---- Slide 2: Markers ------------------------------------------------
doc.batch(slide_items(2, "Markers — symbol, size, color, showMarker", [
(TL, {"chartType": "line", "title": "marker=circle:8:FF0000", "marker": "circle:8:FF0000",
"linewidth": "2", "legend": "none", "categories": CATS, "data": "A:50,60,70,65,80"}),
(TR, {"chartType": "line", "title": "marker=square:6", "marker": "square:6", "linewidth": "2",
"legend": "none", "categories": CATS, "data": "A:50,60,70,65,80"}),
(BL, {"chartType": "line", "title": "marker=diamond:10:0070C0", "marker": "diamond:10:0070C0",
"linewidth": "2", "legend": "none", "categories": CATS, "data": "A:50,60,70,65,80"}),
(BR, {"chartType": "line", "title": "showMarker=true (default markers)", "showMarker": "true",
"legend": "bottom", "categories": CATS, "data": D2}),
]))
# ---- Slide 3: Smoothing & dash ---------------------------------------
doc.batch(slide_items(3, "Smoothing & dash — smooth, linedash, linewidth", [
(TL, {"chartType": "line", "title": "smooth=true", "smooth": "true", "linewidth": "2.5",
"legend": "none", "categories": CATS, "data": "A:50,60,70,65,80"}),
(TR, {"chartType": "line", "title": "linedash=dash", "linedash": "dash", "linewidth": "2",
"legend": "none", "categories": CATS, "data": "A:50,60,70,65,80"}),
(BL, {"chartType": "line", "title": "linedash=dot", "linedash": "dot", "linewidth": "2",
"legend": "none", "categories": CATS, "data": "A:50,60,70,65,80"}),
(BR, {"chartType": "line", "title": "linedash=dashDot", "linedash": "dashDot", "linewidth": "2",
"legend": "none", "categories": CATS, "data": "A:50,60,70,65,80"}),
]))
# ---- Slide 4: Title & legend -----------------------------------------
doc.batch(slide_items(4, "Title & legend", [
(TL, {"chartType": "line", "title": "Styled title", "title.font": "Georgia", "title.size": "20",
"title.color": "4472C4", "title.bold": "true", "legend": "bottom", "categories": CATS, "data": D2}),
(TR, {"chartType": "line", "title": "legend=top + legendFont", "legend": "top",
"legendFont": "10:333333:Calibri", "categories": CATS, "data": D2}),
(BL, {"chartType": "line", "title": "legend.overlay=true", "legend": "topRight",
"legend.overlay": "true", "categories": CATS, "data": D2}),
(BR, {"chartType": "line", "autotitledeleted": "true", "legend": "none", "categories": CATS, "data": D2}),
]))
# ---- Slide 5: Data labels --------------------------------------------
doc.batch(slide_items(5, "Data labels — flags, labelPos, labelfont", [
(TL, {"chartType": "line", "title": "dataLabels=value @ top", "dataLabels": "value", "labelPos": "top",
"labelfont": "10:333333:Calibri", "legend": "none", "categories": CATS, "data": "A:50,60,70,65,80"}),
(TR, {"chartType": "line", "title": "value,category", "dataLabels": "value,category", "labelPos": "top",
"legend": "none", "categories": CATS, "data": "A:50,60,70,65,80"}),
(BL, {"chartType": "line", "title": "dataLabels=none", "dataLabels": "none", "legend": "none",
"categories": CATS, "data": "A:50,60,70,65,80"}),
(BR, {"chartType": "line", "title": "labelfont styled", "dataLabels": "value", "labelPos": "top",
"labelfont": "12:C00000:Georgia", "legend": "none", "categories": CATS, "data": "A:50,60,70,65,80"}),
]))
# ---- Slide 6: Axes ---------------------------------------------------
doc.batch(slide_items(6, "Axes — min/max, gridlines, ticks, labelrotation, log", [
(TL, {"chartType": "line", "title": "min/max + titles", "legend": "none",
"axismin": "0", "axismax": "100", "majorunit": "25", "axistitle": "Visits", "cattitle": "Day",
"axisfont": "10:333333:Calibri", "axisline": "666666:1", "axisnumfmt": "#,##0",
"categories": CATS, "data": "A:50,60,70,65,80"}),
(TR, {"chartType": "line", "title": "gridlines + ticks", "legend": "none",
"gridlines": "E0E0E0:0.3", "minorGridlines": "F0F0F0:0.25",
"majorTickMark": "out", "minorTickMark": "in", "tickLabelPos": "nextTo",
"categories": CATS, "data": "A:50,60,70,65,80"}),
(BL, {"chartType": "line", "title": "labelrotation=-30", "legend": "none",
"labelrotation": "-30", "categories": "January,February,March,April,May,June",
"data": "A:60,90,140,180,160,210"}),
(BR, {"chartType": "line", "title": "logbase=10", "legend": "none", "logbase": "10",
"axismin": "1", "axismax": "10000", "categories": CATS, "data": "Growth:5,50,500,5000,3000"}),
]))
# ---- Slide 7: Overlays -----------------------------------------------
doc.batch(slide_items(7, "Overlays — droplines, hilowlines, updownbars, trendline, errbars, referenceline", [
(TL, {"chartType": "line", "title": "droplines + hilowlines", "droplines": "808080:0.5", "hilowlines": "true",
"legend": "bottom", "categories": CATS, "data": "High:130,135,140,138,145;Low:118,122,128,125,132"}),
(TR, {"chartType": "line", "title": "updownbars=150:00AA00:FF0000",
"updownbars": "150:00AA00:FF0000", "legend": "bottom", "categories": CATS,
"data": "Open:120,128,130,135,138;Close:128,125,135,138,142"}),
(BL, {"chartType": "line", "title": "trendline=linear + errbars=stdDev:1",
"trendline": "linear", "errbars": "stdDev:1", "legend": "none",
"categories": CATS, "data": "A:50,60,70,65,80"}),
(BR, {"chartType": "line", "title": "referenceline=70:FF0000:Target",
"referenceline": "70:FF0000:Target", "legend": "none",
"categories": CATS, "data": "A:50,60,70,65,80"}),
]))
# ---- Slide 8: Per-series Set + presets -------------------------------
doc.batch(slide_items(8, "Per-series Set + presets — chart-series lineWidth/lineDash/marker/markerSize/color/smooth", [
(TL, {"chartType": "line", "preset": "minimal", "title": "preset=minimal",
"legend": "bottom", "categories": CATS, "data": D2}),
(TR, {"chartType": "line", "preset": "dark", "title": "preset=dark",
"legend": "bottom", "categories": CATS, "data": D2}),
(BL, {"chartType": "line", "preset": "corporate", "title": "preset=corporate",
"legend": "bottom", "categories": CATS, "data": D2}),
(BR, {"chartType": "line", "title": "chart-series Set per line", "showMarker": "true",
"legend": "bottom", "categories": CATS, "data": D2}),
]))
# chart-series Set on the 4th chart's two lines (after the chart exists).
doc.batch([
{"command": "set", "path": "/slide[8]/chart[4]/series[1]",
"props": {"name": "Alpha", "color": "C00000", "lineWidth": "2.5", "lineDash": "solid",
"marker": "circle", "markerSize": "9", "smooth": "true"}},
{"command": "set", "path": "/slide[8]/chart[4]/series[2]",
"props": {"name": "Beta", "color": "2E75B6", "lineWidth": "1.5", "lineDash": "dash",
"marker": "diamond", "markerSize": "8"}},
])
print(" built 8 slides")
print(f"Generated: {FILE}")
+102
View File
@@ -0,0 +1,102 @@
#!/bin/bash
# Line Charts Showcase — line / stackedLine / percentStackedLine / line3d.
# CLI twin of charts-line.py (officecli Python SDK). Both produce an equivalent
# charts-line.pptx.
#
# Slide 1 Variants line / stackedLine / percentStackedLine / line3d
# Slide 2 Markers marker symbol/size/color, markersize, showMarker
# Slide 3 Smoothing smooth, linedash, linewidth
# Slide 4 Title&legend title.* + legend positions + legendFont
# Slide 5 Data labels flags, labelPos, labelfont
# Slide 6 Axes min/max, titles, fonts, gridlines, ticks, labelrotation, log
# Slide 7 Overlays droplines, hilowlines, updownbars, trendline, errbars, referenceline
# Slide 8 Per-series lineWidth/lineDash/marker/markerSize/color/smooth + presets
#
# Usage: ./charts-line.sh
# NOTE: intentionally NO `set -e`. Like the SDK twin's doc.batch, this script
# tolerates forward-compat 'UNSUPPORTED props' warnings (officecli exit 2) and
# keeps building so the full document is produced.
CLI="${1:-officecli}"
FILE="$(dirname "$0")/charts-line.pptx"
CATS="Mon,Tue,Wed,Thu,Fri"
D2="A:50,60,70,65,80;B:40,45,55,60,75"
rm -f "$FILE"
$CLI create "$FILE"
$CLI open "$FILE"
# title shape helper is inlined per slide (bash has no kwargs).
# ==================== Slide 1: Line variants ====================
$CLI add "$FILE" / --type slide
$CLI add "$FILE" /slide[1] --type shape --prop text="Line variants — line / stackedLine / percentStackedLine / line3d" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
$CLI add "$FILE" /slide[1] --type chart --prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=line --prop title=line --prop legend=bottom --prop categories="$CATS" --prop data="$D2"
$CLI add "$FILE" /slide[1] --type chart --prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=stackedLine --prop title=stackedLine --prop legend=bottom --prop categories="$CATS" --prop data="$D2"
$CLI add "$FILE" /slide[1] --type chart --prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=percentStackedLine --prop title=percentStackedLine --prop legend=bottom --prop categories="$CATS" --prop data="$D2"
$CLI add "$FILE" /slide[1] --type chart --prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=line3d --prop title=line3d --prop legend=bottom --prop categories="$CATS" --prop data="$D2"
# ==================== Slide 2: Markers ====================
$CLI add "$FILE" / --type slide
$CLI add "$FILE" /slide[2] --type shape --prop text="Markers — symbol, size, color, showMarker" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
$CLI add "$FILE" /slide[2] --type chart --prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=line --prop title=marker=circle:8:FF0000 --prop marker=circle:8:FF0000 --prop linewidth=2 --prop legend=none --prop categories="$CATS" --prop data="A:50,60,70,65,80"
$CLI add "$FILE" /slide[2] --type chart --prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=line --prop title=marker=square:6 --prop marker=square:6 --prop linewidth=2 --prop legend=none --prop categories="$CATS" --prop data="A:50,60,70,65,80"
$CLI add "$FILE" /slide[2] --type chart --prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=line --prop title=marker=diamond:10:0070C0 --prop marker=diamond:10:0070C0 --prop linewidth=2 --prop legend=none --prop categories="$CATS" --prop data="A:50,60,70,65,80"
$CLI add "$FILE" /slide[2] --type chart --prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=line --prop title="showMarker=true (default markers)" --prop showMarker=true --prop legend=bottom --prop categories="$CATS" --prop data="$D2"
# ==================== Slide 3: Smoothing & dash ====================
$CLI add "$FILE" / --type slide
$CLI add "$FILE" /slide[3] --type shape --prop text="Smoothing & dash — smooth, linedash, linewidth" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
$CLI add "$FILE" /slide[3] --type chart --prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=line --prop title=smooth=true --prop smooth=true --prop linewidth=2.5 --prop legend=none --prop categories="$CATS" --prop data="A:50,60,70,65,80"
$CLI add "$FILE" /slide[3] --type chart --prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=line --prop title=linedash=dash --prop linedash=dash --prop linewidth=2 --prop legend=none --prop categories="$CATS" --prop data="A:50,60,70,65,80"
$CLI add "$FILE" /slide[3] --type chart --prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=line --prop title=linedash=dot --prop linedash=dot --prop linewidth=2 --prop legend=none --prop categories="$CATS" --prop data="A:50,60,70,65,80"
$CLI add "$FILE" /slide[3] --type chart --prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=line --prop title=linedash=dashDot --prop linedash=dashDot --prop linewidth=2 --prop legend=none --prop categories="$CATS" --prop data="A:50,60,70,65,80"
# ==================== Slide 4: Title & legend ====================
$CLI add "$FILE" / --type slide
$CLI add "$FILE" /slide[4] --type shape --prop text="Title & legend" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
$CLI add "$FILE" /slide[4] --type chart --prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=line --prop title="Styled title" --prop title.font=Georgia --prop title.size=20 --prop title.color=4472C4 --prop title.bold=true --prop legend=bottom --prop categories="$CATS" --prop data="$D2"
$CLI add "$FILE" /slide[4] --type chart --prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=line --prop title="legend=top + legendFont" --prop legend=top --prop legendFont=10:333333:Calibri --prop categories="$CATS" --prop data="$D2"
$CLI add "$FILE" /slide[4] --type chart --prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=line --prop title="legend.overlay=true" --prop legend=topRight --prop legend.overlay=true --prop categories="$CATS" --prop data="$D2"
$CLI add "$FILE" /slide[4] --type chart --prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=line --prop autotitledeleted=true --prop legend=none --prop categories="$CATS" --prop data="$D2"
# ==================== Slide 5: Data labels ====================
$CLI add "$FILE" / --type slide
$CLI add "$FILE" /slide[5] --type shape --prop text="Data labels — flags, labelPos, labelfont" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
$CLI add "$FILE" /slide[5] --type chart --prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=line --prop title="dataLabels=value @ top" --prop dataLabels=value --prop labelPos=top --prop labelfont=10:333333:Calibri --prop legend=none --prop categories="$CATS" --prop data="A:50,60,70,65,80"
$CLI add "$FILE" /slide[5] --type chart --prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=line --prop title=value,category --prop dataLabels=value,category --prop labelPos=top --prop legend=none --prop categories="$CATS" --prop data="A:50,60,70,65,80"
$CLI add "$FILE" /slide[5] --type chart --prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=line --prop title=dataLabels=none --prop dataLabels=none --prop legend=none --prop categories="$CATS" --prop data="A:50,60,70,65,80"
$CLI add "$FILE" /slide[5] --type chart --prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=line --prop title="labelfont styled" --prop dataLabels=value --prop labelPos=top --prop labelfont=12:C00000:Georgia --prop legend=none --prop categories="$CATS" --prop data="A:50,60,70,65,80"
# ==================== Slide 6: Axes ====================
$CLI add "$FILE" / --type slide
$CLI add "$FILE" /slide[6] --type shape --prop text="Axes — min/max, gridlines, ticks, labelrotation, log" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
$CLI add "$FILE" /slide[6] --type chart --prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=line --prop title="min/max + titles" --prop legend=none --prop axismin=0 --prop axismax=100 --prop majorunit=25 --prop axistitle=Visits --prop cattitle=Day --prop axisfont=10:333333:Calibri --prop axisline=666666:1 --prop axisnumfmt="#,##0" --prop categories="$CATS" --prop data="A:50,60,70,65,80"
$CLI add "$FILE" /slide[6] --type chart --prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=line --prop title="gridlines + ticks" --prop legend=none --prop gridlines=E0E0E0:0.3 --prop minorGridlines=F0F0F0:0.25 --prop majorTickMark=out --prop minorTickMark=in --prop tickLabelPos=nextTo --prop categories="$CATS" --prop data="A:50,60,70,65,80"
$CLI add "$FILE" /slide[6] --type chart --prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=line --prop title=labelrotation=-30 --prop legend=none --prop labelrotation=-30 --prop categories="January,February,March,April,May,June" --prop data="A:60,90,140,180,160,210"
$CLI add "$FILE" /slide[6] --type chart --prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=line --prop title=logbase=10 --prop legend=none --prop logbase=10 --prop axismin=1 --prop axismax=10000 --prop categories="$CATS" --prop data="Growth:5,50,500,5000,3000"
# ==================== Slide 7: Overlays ====================
$CLI add "$FILE" / --type slide
$CLI add "$FILE" /slide[7] --type shape --prop text="Overlays — droplines, hilowlines, updownbars, trendline, errbars, referenceline" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
$CLI add "$FILE" /slide[7] --type chart --prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=line --prop title="droplines + hilowlines" --prop droplines=808080:0.5 --prop hilowlines=true --prop legend=bottom --prop categories="$CATS" --prop data="High:130,135,140,138,145;Low:118,122,128,125,132"
$CLI add "$FILE" /slide[7] --type chart --prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=line --prop title=updownbars=150:00AA00:FF0000 --prop updownbars=150:00AA00:FF0000 --prop legend=bottom --prop categories="$CATS" --prop data="Open:120,128,130,135,138;Close:128,125,135,138,142"
$CLI add "$FILE" /slide[7] --type chart --prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=line --prop title="trendline=linear + errbars=stdDev:1" --prop trendline=linear --prop errbars=stdDev:1 --prop legend=none --prop categories="$CATS" --prop data="A:50,60,70,65,80"
$CLI add "$FILE" /slide[7] --type chart --prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=line --prop title=referenceline=70:FF0000:Target --prop referenceline=70:FF0000:Target --prop legend=none --prop categories="$CATS" --prop data="A:50,60,70,65,80"
# ==================== Slide 8: Per-series Set + presets ====================
$CLI add "$FILE" / --type slide
$CLI add "$FILE" /slide[8] --type shape --prop text="Per-series Set + presets — chart-series lineWidth/lineDash/marker/markerSize/color/smooth" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
$CLI add "$FILE" /slide[8] --type chart --prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=line --prop preset=minimal --prop title=preset=minimal --prop legend=bottom --prop categories="$CATS" --prop data="$D2"
$CLI add "$FILE" /slide[8] --type chart --prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=line --prop preset=dark --prop title=preset=dark --prop legend=bottom --prop categories="$CATS" --prop data="$D2"
$CLI add "$FILE" /slide[8] --type chart --prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=line --prop preset=corporate --prop title=preset=corporate --prop legend=bottom --prop categories="$CATS" --prop data="$D2"
$CLI add "$FILE" /slide[8] --type chart --prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=line --prop title="chart-series Set per line" --prop showMarker=true --prop legend=bottom --prop categories="$CATS" --prop data="$D2"
# chart-series Set on the 4th chart's two lines (after the chart exists).
$CLI set "$FILE" /slide[8]/chart[4]/series[1] --prop name=Alpha --prop color=C00000 --prop lineWidth=2.5 --prop lineDash=solid --prop marker=circle --prop markerSize=9 --prop smooth=true
$CLI set "$FILE" /slide[8]/chart[4]/series[2] --prop name=Beta --prop color=2E75B6 --prop lineWidth=1.5 --prop lineDash=dash --prop marker=diamond --prop markerSize=8
$CLI close "$FILE"
$CLI validate "$FILE"
echo "Generated: $FILE"
+238
View File
@@ -0,0 +1,238 @@
# Pie Charts Showcase
This demo consists of three files that work together:
- **charts-pie.py** — Python script that calls `officecli` commands to generate the deck.
- **charts-pie.pptx** — The generated 8-slide deck (4 charts per slide, 32 charts total).
- **charts-pie.md** — This file. Maps each slide to the features it demonstrates.
## Regenerate
```bash
cd examples/ppt/charts
python3 charts-pie.py
# → charts-pie.pptx
```
## Chart Slides
### Slide 1 — Variants (pie, pie3d, firstSliceAngle, varyColors)
```bash
# Standard pie with auto per-slice colors
officecli add charts-pie.pptx /slide[1] --type chart \
--prop chartType=pie --prop title="pie" --prop legend=right \
--prop varyColors=true \
--prop categories="North,South,East,West" --prop data="Share:30,25,28,17" \
--prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in
# 3D pie with view3d perspective
officecli add charts-pie.pptx /slide[1] --type chart \
--prop chartType=pie3d --prop title="pie3d (view3d=20,20,30)" \
--prop view3d="20,20,30" --prop legend=right --prop varyColors=true \
--prop categories="North,South,East,West" --prop data="Share:30,25,28,17" \
--prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in
# First slice starts at 90° instead of 0°
officecli add charts-pie.pptx /slide[1] --type chart \
--prop chartType=pie --prop title="firstSliceAngle=90" \
--prop firstSliceAngle=90 --prop legend=right \
--prop categories="North,South,East,West" --prop data="Share:30,25,28,17" \
--prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in
# Single solid color (varyColors=false)
officecli add charts-pie.pptx /slide[1] --type chart \
--prop chartType=pie --prop title="varyColors=false" \
--prop varyColors=false --prop legend=right \
--prop categories="North,South,East,West" --prop data="Share:30,25,28,17" \
--prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in
```
**Features:** `chartType` (pie/pie3d), `varyColors`, `firstSliceAngle` (0360°), `view3d`
### Slide 2 — Explosion
```bash
# explosion= pushes all slices outward by N% of the radius
for angle in 0 10 20 30; do
officecli add charts-pie.pptx /slide[2] --type chart \
--prop chartType=pie --prop title="explosion=$angle" \
--prop explosion=$angle --prop legend=right \
--prop categories="North,South,East,West" --prop data="Share:30,25,28,17"
done
```
**Features:** `explosion` (0100, % of pie radius)
### Slide 3 — Title and Legend
```bash
officecli add charts-pie.pptx /slide[3] --type chart \
--prop chartType=pie --prop title="Styled title" \
--prop title.font=Georgia --prop title.size=20 \
--prop title.color=4472C4 --prop title.bold=true \
--prop legend=right --prop categories="North,South,East,West" \
--prop data="Share:30,25,28,17"
officecli add charts-pie.pptx /slide[3] --type chart \
--prop chartType=pie --prop title="legend=bottom + legendFont" \
--prop legend=bottom --prop legendFont="10:333333:Calibri" \
--prop categories="North,South,East,West" --prop data="Share:30,25,28,17"
officecli add charts-pie.pptx /slide[3] --type chart \
--prop chartType=pie --prop title="legend.overlay=true" \
--prop legend=topRight --prop legend.overlay=true \
--prop categories="North,South,East,West" --prop data="Share:30,25,28,17"
officecli add charts-pie.pptx /slide[3] --type chart \
--prop chartType=pie --prop autotitledeleted=true --prop legend=none \
--prop categories="North,South,East,West" --prop data="Share:30,25,28,17"
```
**Features:** `title.font`, `title.size`, `title.color`, `title.bold`, `legend` (right/bottom/topRight/none), `legendFont`, `legend.overlay`, `autotitledeleted`
### Slide 4 — Data Labels
```bash
officecli add charts-pie.pptx /slide[4] --type chart \
--prop chartType=pie --prop title="dataLabels=percent" \
--prop dataLabels=percent --prop legend=right \
--prop labelfont="10:333333:Calibri" \
--prop categories="North,South,East,West" --prop data="Share:30,25,28,17"
# percent + category with leader lines to each slice
officecli add charts-pie.pptx /slide[4] --type chart \
--prop chartType=pie --prop title="percent,category + leaderlines" \
--prop dataLabels="percent,category" --prop leaderlines=true \
--prop legend=none --prop labelfont="10:333333:Calibri" \
--prop categories="North,South,East,West" --prop data="Share:30,25,28,17"
officecli add charts-pie.pptx /slide[4] --type chart \
--prop chartType=pie --prop title="all flags (value,percent,category)" \
--prop dataLabels="value,percent,category" --prop leaderlines=true \
--prop legend=none \
--prop categories="North,South,East,West" --prop data="Share:30,25,28,17"
officecli add charts-pie.pptx /slide[4] --type chart \
--prop chartType=pie --prop title="dataLabels=none" \
--prop dataLabels=none --prop legend=right \
--prop categories="North,South,East,West" --prop data="Share:30,25,28,17"
```
**Features:** `dataLabels` (percent/category/value/none or combined), `leaderlines`, `labelfont`
### Slide 5 — Series Styling
```bash
officecli add charts-pie.pptx /slide[5] --type chart \
--prop chartType=pie --prop title="colors= explicit palette" --prop legend=right \
--prop colors="4472C4,ED7D31,A5A5A5,70AD47" \
--prop categories="North,South,East,West" --prop data="Share:30,25,28,17"
officecli add charts-pie.pptx /slide[5] --type chart \
--prop chartType=pie --prop title="gradient + seriesshadow" --prop legend=right \
--prop gradient="FF6600-FFCC00" --prop seriesshadow="000000-5-45-3-50" \
--prop categories="North,South,East,West" --prop data="Share:30,25,28,17"
officecli add charts-pie.pptx /slide[5] --type chart \
--prop chartType=pie --prop title="seriesoutline white" --prop legend=right \
--prop seriesoutline="FFFFFF:2" \
--prop categories="North,South,East,West" --prop data="Share:30,25,28,17"
officecli add charts-pie.pptx /slide[5] --type chart \
--prop chartType=pie --prop title="transparency=30" --prop legend=right \
--prop transparency=30 \
--prop categories="North,South,East,West" --prop data="Share:30,25,28,17"
```
**Features:** `colors`, `gradient`, `seriesshadow`, `seriesoutline`, `transparency`
### Slide 6 — First Slice Angle Variations
```bash
for ang in 0 90 180 270; do
officecli add charts-pie.pptx /slide[6] --type chart \
--prop chartType=pie --prop title="firstSliceAngle=$ang" \
--prop firstSliceAngle=$ang --prop legend=right --prop varyColors=true \
--prop categories="North,South,East,West" --prop data="Share:30,25,28,17"
done
```
**Features:** `firstSliceAngle` (0/90/180/270 degrees — full range survey)
### Slide 7 — Backgrounds
```bash
officecli add charts-pie.pptx /slide[7] --type chart \
--prop chartType=pie --prop title="chartareafill + chartborder" --prop legend=right \
--prop chartareafill=FFF8E7 --prop chartborder="000000:1" \
--prop categories="North,South,East,West" --prop data="Share:30,25,28,17"
officecli add charts-pie.pptx /slide[7] --type chart \
--prop chartType=pie --prop title="roundedcorners=true" --prop legend=right \
--prop roundedcorners=true --prop chartborder="4472C4:2" \
--prop categories="North,South,East,West" --prop data="Share:30,25,28,17"
officecli add charts-pie.pptx /slide[7] --type chart \
--prop chartType=pie --prop title="plotFill=none" --prop legend=right \
--prop plotFill=none \
--prop categories="North,South,East,West" --prop data="Share:30,25,28,17"
officecli add charts-pie.pptx /slide[7] --type chart \
--prop chartType=pie --prop title="chartareafill=none" --prop legend=right \
--prop chartareafill=none \
--prop categories="North,South,East,West" --prop data="Share:30,25,28,17"
```
**Features:** `chartareafill` (hex or none), `plotFill` (hex or none), `chartborder`, `roundedcorners`
### Slide 8 — Presets and Per-Series Set
```bash
for p in minimal dark corporate; do
officecli add charts-pie.pptx /slide[8] --type chart \
--prop chartType=pie --prop preset=$p --prop title="preset=$p" \
--prop legend=right \
--prop categories="North,South,East,West" --prop data="Share:30,25,28,17"
done
officecli add charts-pie.pptx /slide[8] --type chart \
--prop chartType=pie --prop title="chart-series Set name+color" --prop legend=right \
--prop categories="North,South,East,West" --prop data="Share:30,25,28,17"
# Post-Add mutation of series name and color
officecli set charts-pie.pptx "/slide[8]/chart[4]/series[1]" \
--prop name="Renamed Share" --prop color=C00000
```
**Features:** `preset` (minimal/dark/corporate), `chart-series Set name=/color=`
## Complete Feature Coverage
| Feature | Slide |
|---------|-------|
| **Chart types:** pie, pie3d | 1 |
| **varyColors** | 1 |
| **firstSliceAngle** (0360) | 1, 6 |
| **view3d** (pie3d) | 1 |
| **explosion** (0100%) | 2 |
| **Title styling:** title.font/size/color/bold | 3 |
| **Legend:** right/bottom/topRight/none, legendFont, legend.overlay | 3 |
| **autotitledeleted** | 3 |
| **dataLabels:** percent/category/value/none + combined | 4 |
| **leaderlines** | 4 |
| **labelfont** | 4 |
| **colors** (palette) | 5 |
| **gradient, seriesshadow, seriesoutline, transparency** | 5 |
| **chartareafill**, **plotFill**, **chartborder**, **roundedcorners** | 7 |
| **preset** (minimal/dark/corporate) | 8 |
| **chart-series Set** | 8 |
## Inspect the Generated File
```bash
officecli query charts-pie.pptx chart
officecli get charts-pie.pptx "/slide[1]/chart[1]"
officecli get charts-pie.pptx "/slide[2]/chart[2]"
officecli get charts-pie.pptx "/slide[8]/chart[4]/series[1]"
```
Binary file not shown.
+187
View File
@@ -0,0 +1,187 @@
#!/usr/bin/env python3
"""
Pie Charts Showcase — pie, pie3d, pieOfPie, barOfPie (where supported).
Generates: charts-pie.pptx
Slide 1 Variants pie / pie3d (view3d) — varyColors, firstSliceAngle
Slide 2 Explosion explosion=0/10/20/30
Slide 3 Title & legend title.* + legend positions + legendFont
Slide 4 Data labels flags (percent/category/value), labelfont, leaderlines
Slide 5 Series styling colors, gradient, transparency, seriesoutline, seriesshadow
Slide 6 First-slice angle 0 / 90 / 180 / 270
Slide 7 Backgrounds chartareafill, plotFill, chartborder, roundedcorners
Slide 8 Presets & per-pt preset bundles + per-point recolor via chart-series Set
SDK twin of charts-pie.sh (officecli CLI). Both produce an equivalent
charts-pie.pptx. This one drives the **officecli Python SDK**
(`pip install officecli-sdk`): one resident is started and every slide, shape
and chart is shipped over the named pipe with `doc.batch(...)` round-trips.
Each item is the same `{"command","parent","type","props"}` dict you'd put in
an `officecli batch` list.
Usage:
pip install officecli-sdk # plus the `officecli` binary on PATH
python3 charts-pie.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__)), "charts-pie.pptx")
# --- four-quadrant layout for the charts on each slide
TL = {"x": "0.3in", "y": "1.05in", "width": "6.1in", "height": "3in"}
TR = {"x": "6.95in", "y": "1.05in", "width": "6.1in", "height": "3in"}
BL = {"x": "0.3in", "y": "4.25in", "width": "6.1in", "height": "3in"}
BR = {"x": "6.95in", "y": "4.25in", "width": "6.1in", "height": "3in"}
CATS = "North,South,East,West"
D = "Share:30,25,28,17"
def slide_items(n, title):
"""Items that add slide #n plus its title shape."""
return [
{"command": "add", "parent": "/", "type": "slide", "props": {}},
{"command": "add", "parent": f"/slide[{n}]", "type": "shape",
"props": {"text": title, "size": "24", "bold": "true", "autoFit": "normal",
"x": "0.5in", "y": "0.3in", "width": "12.3in", "height": "0.6in"}},
]
def ch(n, box, props):
"""One `add chart` item on slide #n in quadrant `box`."""
return {"command": "add", "parent": f"/slide[{n}]", "type": "chart",
"props": {**box, **props}}
print(f"Building {FILE} ...")
with officecli.create(FILE, "--force") as doc:
# ---- Slide 1: pie variants -------------------------------------------
s = 1
items = slide_items(s, "Pie variants — pie / pie3d (varyColors, firstSliceAngle)")
items += [
ch(s, TL, {"chartType": "pie", "title": "pie", "legend": "right", "varyColors": "true",
"categories": CATS, "data": D}),
ch(s, TR, {"chartType": "pie3d", "title": "pie3d (view3d=20,20,30)", "view3d": "20,20,30",
"legend": "right", "varyColors": "true", "categories": CATS, "data": D}),
ch(s, BL, {"chartType": "pie", "title": "firstSliceAngle=90", "firstSliceAngle": "90",
"legend": "right", "categories": CATS, "data": D}),
ch(s, BR, {"chartType": "pie", "title": "varyColors=false", "varyColors": "false",
"legend": "right", "categories": CATS, "data": D}),
]
doc.batch(items)
# ---- Slide 2: explosion ----------------------------------------------
s = 2
items = slide_items(s, "Explosion — 0 / 10 / 20 / 30 (% of radius)")
items += [
ch(s, TL, {"chartType": "pie", "title": "explosion=0", "explosion": "0", "legend": "right",
"categories": CATS, "data": D}),
ch(s, TR, {"chartType": "pie", "title": "explosion=10", "explosion": "10", "legend": "right",
"categories": CATS, "data": D}),
ch(s, BL, {"chartType": "pie", "title": "explosion=20", "explosion": "20", "legend": "right",
"categories": CATS, "data": D}),
ch(s, BR, {"chartType": "pie", "title": "explosion=30", "explosion": "30", "legend": "right",
"categories": CATS, "data": D}),
]
doc.batch(items)
# ---- Slide 3: title & legend -----------------------------------------
s = 3
items = slide_items(s, "Title & legend")
items += [
ch(s, TL, {"chartType": "pie", "title": "Styled title", "title.font": "Georgia",
"title.size": "20", "title.color": "4472C4", "title.bold": "true",
"legend": "right", "categories": CATS, "data": D}),
ch(s, TR, {"chartType": "pie", "title": "legend=bottom + legendFont", "legend": "bottom",
"legendFont": "10:333333:Calibri", "categories": CATS, "data": D}),
ch(s, BL, {"chartType": "pie", "title": "legend.overlay=true", "legend": "topRight",
"legend.overlay": "true", "categories": CATS, "data": D}),
ch(s, BR, {"chartType": "pie", "autotitledeleted": "true", "legend": "none",
"categories": CATS, "data": D}),
]
doc.batch(items)
# ---- Slide 4: data labels --------------------------------------------
s = 4
items = slide_items(s, "Data labels — percent / category / value, labelfont, leaderlines")
items += [
ch(s, TL, {"chartType": "pie", "title": "dataLabels=percent", "dataLabels": "percent",
"legend": "right", "labelfont": "10:333333:Calibri", "categories": CATS, "data": D}),
ch(s, TR, {"chartType": "pie", "title": "percent,category", "dataLabels": "percent,category",
"leaderlines": "true", "legend": "none", "labelfont": "10:333333:Calibri",
"categories": CATS, "data": D}),
ch(s, BL, {"chartType": "pie", "title": "all flags", "dataLabels": "value,percent,category",
"leaderlines": "true", "legend": "none", "categories": CATS, "data": D}),
ch(s, BR, {"chartType": "pie", "title": "dataLabels=none", "dataLabels": "none",
"legend": "right", "categories": CATS, "data": D}),
]
doc.batch(items)
# ---- Slide 5: series styling -----------------------------------------
s = 5
items = slide_items(s, "Series styling — colors, gradient, transparency, outline, shadow")
items += [
ch(s, TL, {"chartType": "pie", "title": "colors= explicit palette", "legend": "right",
"colors": "4472C4,ED7D31,A5A5A5,70AD47", "categories": CATS, "data": D}),
ch(s, TR, {"chartType": "pie", "title": "gradient + seriesshadow", "legend": "right",
"gradient": "FF6600-FFCC00", "seriesshadow": "000000-5-45-3-50",
"categories": CATS, "data": D}),
ch(s, BL, {"chartType": "pie", "title": "seriesoutline white", "legend": "right",
"seriesoutline": "FFFFFF:2", "categories": CATS, "data": D}),
ch(s, BR, {"chartType": "pie", "title": "transparency=30", "legend": "right",
"transparency": "30", "categories": CATS, "data": D}),
]
doc.batch(items)
# ---- Slide 6: first-slice angle --------------------------------------
s = 6
items = slide_items(s, "First slice angle — 0 / 90 / 180 / 270")
for box, ang in zip([TL, TR, BL, BR], [0, 90, 180, 270]):
items.append(ch(s, box, {"chartType": "pie", "title": f"firstSliceAngle={ang}",
"firstSliceAngle": str(ang), "legend": "right",
"varyColors": "true", "categories": CATS, "data": D}))
doc.batch(items)
# ---- Slide 7: backgrounds --------------------------------------------
s = 7
items = slide_items(s, "Backgrounds — chartareafill, plotFill, chartborder, roundedcorners")
items += [
ch(s, TL, {"chartType": "pie", "title": "chartareafill + chartborder", "legend": "right",
"chartareafill": "FFF8E7", "chartborder": "000000:1", "categories": CATS, "data": D}),
ch(s, TR, {"chartType": "pie", "title": "roundedcorners=true", "legend": "right",
"roundedcorners": "true", "chartborder": "4472C4:2", "categories": CATS, "data": D}),
ch(s, BL, {"chartType": "pie", "title": "plotFill=none", "legend": "right",
"plotFill": "none", "categories": CATS, "data": D}),
ch(s, BR, {"chartType": "pie", "title": "chartareafill=none", "legend": "right",
"chartareafill": "none", "categories": CATS, "data": D}),
]
doc.batch(items)
# ---- Slide 8: presets & per-series Set -------------------------------
s = 8
items = slide_items(s, "Presets & per-series Set")
for box, p in zip([TL, TR, BL], ["minimal", "dark", "corporate"]):
items.append(ch(s, box, {"chartType": "pie", "preset": p, "title": f"preset={p}",
"legend": "right", "categories": CATS, "data": D}))
items.append(ch(s, BR, {"chartType": "pie", "title": "chart-series Set name+color",
"legend": "right", "categories": CATS, "data": D}))
doc.batch(items)
# per-point recolor via chart-series Set (must follow the chart[4] add above)
doc.send({"command": "set", "path": f"/slide[{s}]/chart[4]/series[1]",
"props": {"name": "Renamed Share", "color": "C00000"}})
print(f" built {s} slides")
print(f"Generated: {FILE} ({s} slides)")
+97
View File
@@ -0,0 +1,97 @@
#!/bin/bash
# Pie Charts Showcase — pie, pie3d variants across 8 slides.
# CLI twin of charts-pie.py (officecli Python SDK). Both produce an equivalent
# charts-pie.pptx.
#
# Slide 1 Variants pie / pie3d (view3d) — varyColors, firstSliceAngle
# Slide 2 Explosion explosion=0/10/20/30
# Slide 3 Title & legend title.* + legend positions + legendFont
# Slide 4 Data labels flags (percent/category/value), labelfont, leaderlines
# Slide 5 Series styling colors, gradient, transparency, seriesoutline, seriesshadow
# Slide 6 First-slice angle 0 / 90 / 180 / 270
# Slide 7 Backgrounds chartareafill, plotFill, chartborder, roundedcorners
# Slide 8 Presets & per-pt preset bundles + per-point recolor via chart-series Set
#
# Usage:
# ./charts-pie.sh
# NOTE: intentionally NO `set -e`. Like the SDK twin's doc.batch, this script
# tolerates forward-compat 'UNSUPPORTED props' warnings (officecli exit 2) and
# keeps building so the full document is produced.
FILE="$(dirname "$0")/charts-pie.pptx"
CATS="North,South,East,West"
D="Share:30,25,28,17"
rm -f "$FILE"
officecli create "$FILE"
officecli open "$FILE"
# ==================== Slide 1: pie variants ====================
officecli add "$FILE" / --type slide
officecli add "$FILE" /slide[1] --type shape --prop text="Pie variants — pie / pie3d (varyColors, firstSliceAngle)" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
officecli add "$FILE" /slide[1] --type chart --prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=pie --prop title=pie --prop legend=right --prop varyColors=true --prop categories="$CATS" --prop data="$D"
officecli add "$FILE" /slide[1] --type chart --prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=pie3d --prop title="pie3d (view3d=20,20,30)" --prop view3d=20,20,30 --prop legend=right --prop varyColors=true --prop categories="$CATS" --prop data="$D"
officecli add "$FILE" /slide[1] --type chart --prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=pie --prop title="firstSliceAngle=90" --prop firstSliceAngle=90 --prop legend=right --prop categories="$CATS" --prop data="$D"
officecli add "$FILE" /slide[1] --type chart --prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=pie --prop title="varyColors=false" --prop varyColors=false --prop legend=right --prop categories="$CATS" --prop data="$D"
# ==================== Slide 2: explosion ====================
officecli add "$FILE" / --type slide
officecli add "$FILE" /slide[2] --type shape --prop text="Explosion — 0 / 10 / 20 / 30 (% of radius)" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
officecli add "$FILE" /slide[2] --type chart --prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=pie --prop title="explosion=0" --prop explosion=0 --prop legend=right --prop categories="$CATS" --prop data="$D"
officecli add "$FILE" /slide[2] --type chart --prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=pie --prop title="explosion=10" --prop explosion=10 --prop legend=right --prop categories="$CATS" --prop data="$D"
officecli add "$FILE" /slide[2] --type chart --prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=pie --prop title="explosion=20" --prop explosion=20 --prop legend=right --prop categories="$CATS" --prop data="$D"
officecli add "$FILE" /slide[2] --type chart --prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=pie --prop title="explosion=30" --prop explosion=30 --prop legend=right --prop categories="$CATS" --prop data="$D"
# ==================== Slide 3: title & legend ====================
officecli add "$FILE" / --type slide
officecli add "$FILE" /slide[3] --type shape --prop text="Title & legend" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
officecli add "$FILE" /slide[3] --type chart --prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=pie --prop title="Styled title" --prop title.font=Georgia --prop title.size=20 --prop title.color=4472C4 --prop title.bold=true --prop legend=right --prop categories="$CATS" --prop data="$D"
officecli add "$FILE" /slide[3] --type chart --prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=pie --prop title="legend=bottom + legendFont" --prop legend=bottom --prop legendFont=10:333333:Calibri --prop categories="$CATS" --prop data="$D"
officecli add "$FILE" /slide[3] --type chart --prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=pie --prop title="legend.overlay=true" --prop legend=topRight --prop legend.overlay=true --prop categories="$CATS" --prop data="$D"
officecli add "$FILE" /slide[3] --type chart --prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=pie --prop autotitledeleted=true --prop legend=none --prop categories="$CATS" --prop data="$D"
# ==================== Slide 4: data labels ====================
officecli add "$FILE" / --type slide
officecli add "$FILE" /slide[4] --type shape --prop text="Data labels — percent / category / value, labelfont, leaderlines" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
officecli add "$FILE" /slide[4] --type chart --prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=pie --prop title="dataLabels=percent" --prop dataLabels=percent --prop legend=right --prop labelfont=10:333333:Calibri --prop categories="$CATS" --prop data="$D"
officecli add "$FILE" /slide[4] --type chart --prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=pie --prop title="percent,category" --prop dataLabels=percent,category --prop leaderlines=true --prop legend=none --prop labelfont=10:333333:Calibri --prop categories="$CATS" --prop data="$D"
officecli add "$FILE" /slide[4] --type chart --prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=pie --prop title="all flags" --prop dataLabels=value,percent,category --prop leaderlines=true --prop legend=none --prop categories="$CATS" --prop data="$D"
officecli add "$FILE" /slide[4] --type chart --prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=pie --prop title="dataLabels=none" --prop dataLabels=none --prop legend=right --prop categories="$CATS" --prop data="$D"
# ==================== Slide 5: series styling ====================
officecli add "$FILE" / --type slide
officecli add "$FILE" /slide[5] --type shape --prop text="Series styling — colors, gradient, transparency, outline, shadow" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
officecli add "$FILE" /slide[5] --type chart --prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=pie --prop title="colors= explicit palette" --prop legend=right --prop colors=4472C4,ED7D31,A5A5A5,70AD47 --prop categories="$CATS" --prop data="$D"
officecli add "$FILE" /slide[5] --type chart --prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=pie --prop title="gradient + seriesshadow" --prop legend=right --prop gradient=FF6600-FFCC00 --prop seriesshadow=000000-5-45-3-50 --prop categories="$CATS" --prop data="$D"
officecli add "$FILE" /slide[5] --type chart --prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=pie --prop title="seriesoutline white" --prop legend=right --prop seriesoutline=FFFFFF:2 --prop categories="$CATS" --prop data="$D"
officecli add "$FILE" /slide[5] --type chart --prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=pie --prop title="transparency=30" --prop legend=right --prop transparency=30 --prop categories="$CATS" --prop data="$D"
# ==================== Slide 6: first-slice angle ====================
officecli add "$FILE" / --type slide
officecli add "$FILE" /slide[6] --type shape --prop text="First slice angle — 0 / 90 / 180 / 270" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
officecli add "$FILE" /slide[6] --type chart --prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=pie --prop title="firstSliceAngle=0" --prop firstSliceAngle=0 --prop legend=right --prop varyColors=true --prop categories="$CATS" --prop data="$D"
officecli add "$FILE" /slide[6] --type chart --prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=pie --prop title="firstSliceAngle=90" --prop firstSliceAngle=90 --prop legend=right --prop varyColors=true --prop categories="$CATS" --prop data="$D"
officecli add "$FILE" /slide[6] --type chart --prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=pie --prop title="firstSliceAngle=180" --prop firstSliceAngle=180 --prop legend=right --prop varyColors=true --prop categories="$CATS" --prop data="$D"
officecli add "$FILE" /slide[6] --type chart --prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=pie --prop title="firstSliceAngle=270" --prop firstSliceAngle=270 --prop legend=right --prop varyColors=true --prop categories="$CATS" --prop data="$D"
# ==================== Slide 7: backgrounds ====================
officecli add "$FILE" / --type slide
officecli add "$FILE" /slide[7] --type shape --prop text="Backgrounds — chartareafill, plotFill, chartborder, roundedcorners" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
officecli add "$FILE" /slide[7] --type chart --prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=pie --prop title="chartareafill + chartborder" --prop legend=right --prop chartareafill=FFF8E7 --prop chartborder=000000:1 --prop categories="$CATS" --prop data="$D"
officecli add "$FILE" /slide[7] --type chart --prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=pie --prop title="roundedcorners=true" --prop legend=right --prop roundedcorners=true --prop chartborder=4472C4:2 --prop categories="$CATS" --prop data="$D"
officecli add "$FILE" /slide[7] --type chart --prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=pie --prop title="plotFill=none" --prop legend=right --prop plotFill=none --prop categories="$CATS" --prop data="$D"
officecli add "$FILE" /slide[7] --type chart --prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=pie --prop title="chartareafill=none" --prop legend=right --prop chartareafill=none --prop categories="$CATS" --prop data="$D"
# ==================== Slide 8: presets & per-series Set ====================
officecli add "$FILE" / --type slide
officecli add "$FILE" /slide[8] --type shape --prop text="Presets & per-series Set" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
officecli add "$FILE" /slide[8] --type chart --prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=pie --prop preset=minimal --prop title="preset=minimal" --prop legend=right --prop categories="$CATS" --prop data="$D"
officecli add "$FILE" /slide[8] --type chart --prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=pie --prop preset=dark --prop title="preset=dark" --prop legend=right --prop categories="$CATS" --prop data="$D"
officecli add "$FILE" /slide[8] --type chart --prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=pie --prop preset=corporate --prop title="preset=corporate" --prop legend=right --prop categories="$CATS" --prop data="$D"
officecli add "$FILE" /slide[8] --type chart --prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=pie --prop title="chart-series Set name+color" --prop legend=right --prop categories="$CATS" --prop data="$D"
# per-point recolor via chart-series Set (must follow the chart[4] add above)
officecli set "$FILE" /slide[8]/chart[4]/series[1] --prop name="Renamed Share" --prop color=C00000
officecli close "$FILE"
officecli validate "$FILE"
echo "Generated: $FILE"
+286
View File
@@ -0,0 +1,286 @@
# Radar Charts Showcase
This demo consists of three files that work together:
- **charts-radar.py** — Python script that calls `officecli` commands to generate the deck.
- **charts-radar.pptx** — The generated 8-slide deck (4 charts per slide, 32 charts total).
- **charts-radar.md** — This file. Maps each slide to the features it demonstrates.
## Regenerate
```bash
cd examples/ppt/charts
python3 charts-radar.py
# → charts-radar.pptx
```
## Chart Slides
### Slide 1 — radarstyle Variants
```bash
CATS="Speed,Power,Range,Style,Tech,Price"
officecli add charts-radar.pptx /slide[1] --type chart \
--prop chartType=radar --prop radarstyle=standard \
--prop title="radarstyle=standard" --prop legend=bottom \
--prop categories="$CATS" \
--prop data="Model A:8,7,9,6,8,7;Model B:6,9,7,8,9,6" \
--prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in
officecli add charts-radar.pptx /slide[1] --type chart \
--prop chartType=radar --prop radarstyle=marker \
--prop title="radarstyle=marker" --prop legend=bottom \
--prop categories="$CATS" \
--prop data="Model A:8,7,9,6,8,7;Model B:6,9,7,8,9,6" \
--prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in
officecli add charts-radar.pptx /slide[1] --type chart \
--prop chartType=radar --prop radarstyle=filled \
--prop title="radarstyle=filled" --prop legend=bottom \
--prop categories="$CATS" \
--prop data="Model A:8,7,9,6,8,7;Model B:6,9,7,8,9,6" \
--prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in
officecli add charts-radar.pptx /slide[1] --type chart \
--prop chartType=radar --prop radarstyle=standard \
--prop title="single series" --prop legend=bottom \
--prop categories="$CATS" --prop data="A:8,7,9,6,8,7" \
--prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in
```
**Features:** `chartType=radar`, `radarstyle` (standard/marker/filled)
### Slide 2 — Title and Legend
```bash
officecli add charts-radar.pptx /slide[2] --type chart \
--prop chartType=radar --prop radarstyle=filled \
--prop title="Styled title" --prop title.font=Georgia --prop title.size=20 \
--prop title.color=4472C4 --prop title.bold=true \
--prop legend=bottom --prop categories="$CATS" \
--prop data="Model A:8,7,9,6,8,7;Model B:6,9,7,8,9,6"
officecli add charts-radar.pptx /slide[2] --type chart \
--prop chartType=radar --prop radarstyle=standard \
--prop title="legend=top + legendFont" --prop legend=top \
--prop legendFont="10:333333:Calibri" \
--prop categories="$CATS" \
--prop data="Model A:8,7,9,6,8,7;Model B:6,9,7,8,9,6"
officecli add charts-radar.pptx /slide[2] --type chart \
--prop chartType=radar --prop radarstyle=standard \
--prop title="legend.overlay=true" --prop legend=topRight \
--prop legend.overlay=true \
--prop categories="$CATS" \
--prop data="Model A:8,7,9,6,8,7;Model B:6,9,7,8,9,6"
officecli add charts-radar.pptx /slide[2] --type chart \
--prop chartType=radar --prop radarstyle=filled \
--prop autotitledeleted=true --prop legend=none \
--prop categories="$CATS" \
--prop data="Model A:8,7,9,6,8,7;Model B:6,9,7,8,9,6"
```
**Features:** `title.font/size/color/bold`, `legend` positions, `legendFont`, `legend.overlay`, `autotitledeleted`
### Slide 3 — Data Labels
```bash
officecli add charts-radar.pptx /slide[3] --type chart \
--prop chartType=radar --prop radarstyle=marker \
--prop title="value" --prop dataLabels=value \
--prop labelfont="9:333333:Calibri" --prop legend=none \
--prop categories="$CATS" --prop data="A:8,7,9,6,8,7"
officecli add charts-radar.pptx /slide[3] --type chart \
--prop chartType=radar --prop radarstyle=marker \
--prop title="value,series" --prop dataLabels="value,series" \
--prop legend=bottom --prop categories="$CATS" \
--prop data="Model A:8,7,9,6,8,7;Model B:6,9,7,8,9,6"
officecli add charts-radar.pptx /slide[3] --type chart \
--prop chartType=radar --prop radarstyle=standard \
--prop title="value,category" --prop dataLabels="value,category" \
--prop legend=none --prop categories="$CATS" --prop data="A:8,7,9,6,8,7"
officecli add charts-radar.pptx /slide[3] --type chart \
--prop chartType=radar --prop radarstyle=filled \
--prop title="dataLabels=none" --prop dataLabels=none \
--prop legend=bottom --prop categories="$CATS" \
--prop data="Model A:8,7,9,6,8,7;Model B:6,9,7,8,9,6"
```
**Features:** `dataLabels` (value/series/category/none or combined), `labelfont`
### Slide 4 — Axes
```bash
officecli add charts-radar.pptx /slide[4] --type chart \
--prop chartType=radar --prop radarstyle=standard \
--prop title="min/max + titles" --prop legend=none \
--prop axismin=0 --prop axismax=10 --prop majorunit=2 \
--prop axisfont="10:333333:Calibri" \
--prop categories="$CATS" --prop data="A:8,7,9,6,8,7"
officecli add charts-radar.pptx /slide[4] --type chart \
--prop chartType=radar --prop radarstyle=standard \
--prop title="gridlines + minorGridlines" --prop legend=none \
--prop gridlines="E0E0E0:0.3" --prop minorGridlines="F0F0F0:0.25" \
--prop categories="$CATS" --prop data="A:8,7,9,6,8,7"
officecli add charts-radar.pptx /slide[4] --type chart \
--prop chartType=radar --prop radarstyle=standard \
--prop title="labelrotation=30" --prop labelrotation=30 --prop legend=none \
--prop categories="$CATS" --prop data="A:8,7,9,6,8,7"
officecli add charts-radar.pptx /slide[4] --type chart \
--prop chartType=radar --prop radarstyle=standard \
--prop title="axisnumfmt=0.0" --prop axisnumfmt="0.0" --prop legend=none \
--prop categories="$CATS" --prop data="A:8,7,9,6,8,7"
```
**Features:** `axismin/max`, `majorunit`, `axisfont`, `gridlines/minorGridlines`, `labelrotation`, `axisnumfmt`
### Slide 5 — Series Styling
```bash
officecli add charts-radar.pptx /slide[5] --type chart \
--prop chartType=radar --prop radarstyle=filled \
--prop title="colors + seriesoutline" --prop legend=bottom \
--prop colors="4472C4,ED7D31" --prop seriesoutline="000000:0.5" \
--prop categories="$CATS" \
--prop data="Model A:8,7,9,6,8,7;Model B:6,9,7,8,9,6"
officecli add charts-radar.pptx /slide[5] --type chart \
--prop chartType=radar --prop radarstyle=filled \
--prop title="gradient + seriesshadow" --prop legend=none \
--prop gradient="FF6600-FFCC00" --prop seriesshadow="000000-5-45-3-50" \
--prop categories="$CATS" --prop data="A:8,7,9,6,8,7"
officecli add charts-radar.pptx /slide[5] --type chart \
--prop chartType=radar --prop radarstyle=filled \
--prop title="transparency=40" --prop legend=bottom \
--prop transparency=40 \
--prop categories="$CATS" \
--prop data="Model A:8,7,9,6,8,7;Model B:6,9,7,8,9,6"
officecli add charts-radar.pptx /slide[5] --type chart \
--prop chartType=radar --prop radarstyle=filled \
--prop title="per-series gradients" --prop legend=bottom \
--prop gradients="FF0000-0000FF;00FF00-FFFF00" \
--prop categories="$CATS" \
--prop data="Model A:8,7,9,6,8,7;Model B:6,9,7,8,9,6"
```
**Features:** `colors`, `seriesoutline`, `gradient`, `seriesshadow`, `transparency`, `gradients`
### Slide 6 — Markers (radarstyle=marker only)
```bash
officecli add charts-radar.pptx /slide[6] --type chart \
--prop chartType=radar --prop radarstyle=marker \
--prop title="circle:10:FF0000" --prop marker="circle:10:FF0000" \
--prop legend=none --prop categories="$CATS" --prop data="A:8,7,9,6,8,7"
officecli add charts-radar.pptx /slide[6] --type chart \
--prop chartType=radar --prop radarstyle=marker \
--prop title="square:8:0070C0" --prop marker="square:8:0070C0" \
--prop legend=none --prop categories="$CATS" --prop data="A:8,7,9,6,8,7"
officecli add charts-radar.pptx /slide[6] --type chart \
--prop chartType=radar --prop radarstyle=marker \
--prop title="diamond:12" --prop marker="diamond:12" \
--prop legend=none --prop categories="$CATS" --prop data="A:8,7,9,6,8,7"
officecli add charts-radar.pptx /slide[6] --type chart \
--prop chartType=radar --prop radarstyle=marker \
--prop title="triangle:10:70AD47" --prop marker="triangle:10:70AD47" \
--prop legend=none --prop categories="$CATS" --prop data="A:8,7,9,6,8,7"
```
**Features:** `marker` (symbol:size:color compound), symbols: circle/square/diamond/triangle
### Slide 7 — Backgrounds
```bash
officecli add charts-radar.pptx /slide[7] --type chart \
--prop chartType=radar --prop radarstyle=filled \
--prop title="chartareafill + plotFill + borders" --prop legend=bottom \
--prop chartareafill=FFF8E7 --prop plotFill=FAFAFA \
--prop chartborder="000000:1" --prop plotborder="CCCCCC:0.5" \
--prop categories="$CATS" \
--prop data="Model A:8,7,9,6,8,7;Model B:6,9,7,8,9,6"
officecli add charts-radar.pptx /slide[7] --type chart \
--prop chartType=radar --prop radarstyle=filled \
--prop title="roundedcorners=true" --prop legend=bottom \
--prop roundedcorners=true --prop chartborder="4472C4:2" \
--prop categories="$CATS" \
--prop data="Model A:8,7,9,6,8,7;Model B:6,9,7,8,9,6"
officecli add charts-radar.pptx /slide[7] --type chart \
--prop chartType=radar --prop radarstyle=standard \
--prop title="plotFill=none" --prop plotFill=none --prop legend=none \
--prop categories="$CATS" --prop data="A:8,7,9,6,8,7"
officecli add charts-radar.pptx /slide[7] --type chart \
--prop chartType=radar --prop radarstyle=filled \
--prop title="chartareafill=none" --prop chartareafill=none --prop legend=bottom \
--prop categories="$CATS" \
--prop data="Model A:8,7,9,6,8,7;Model B:6,9,7,8,9,6"
```
**Features:** `chartareafill`, `plotFill`, `chartborder`, `plotborder`, `roundedcorners`
### Slide 8 — Presets and Per-Series Set
```bash
for p in minimal dark corporate; do
officecli add charts-radar.pptx /slide[8] --type chart \
--prop chartType=radar --prop radarstyle=filled --prop preset=$p \
--prop title="preset=$p" --prop legend=bottom \
--prop categories="$CATS" \
--prop data="Model A:8,7,9,6,8,7;Model B:6,9,7,8,9,6"
done
officecli add charts-radar.pptx /slide[8] --type chart \
--prop chartType=radar --prop radarstyle=marker \
--prop title="chart-series Set" --prop legend=bottom \
--prop categories="$CATS" \
--prop data="Model A:8,7,9,6,8,7;Model B:6,9,7,8,9,6"
officecli set charts-radar.pptx "/slide[8]/chart[4]/series[1]" \
--prop name="Renamed A" --prop color=C00000 \
--prop marker=circle --prop markerSize=9
```
**Features:** `preset`, `chart-series Set`: `name`, `color`, `marker`, `markerSize`
## Complete Feature Coverage
| Feature | Slide |
|---------|-------|
| **radarstyle:** standard/marker/filled | 1 |
| **title.font/size/color/bold** | 2 |
| **legend** positions, legendFont, legend.overlay | 2 |
| **autotitledeleted** | 2 |
| **dataLabels:** value/series/category/none | 3 |
| **labelfont** | 3 |
| **axismin/max**, majorunit, axisfont | 4 |
| **gridlines/minorGridlines, labelrotation, axisnumfmt** | 4 |
| **colors, seriesoutline, gradient, seriesshadow** | 5 |
| **transparency, gradients** | 5 |
| **marker** (symbol:size:color) — radarstyle=marker | 6 |
| **chartareafill, plotFill, chartborder, plotborder, roundedcorners** | 7 |
| **preset** | 8 |
| **chart-series Set:** name/color/marker/markerSize | 8 |
## Inspect the Generated File
```bash
officecli query charts-radar.pptx chart
officecli get charts-radar.pptx "/slide[1]/chart[1]"
officecli get charts-radar.pptx "/slide[6]/chart[1]"
officecli get charts-radar.pptx "/slide[8]/chart[4]/series[1]"
```
Binary file not shown.
+206
View File
@@ -0,0 +1,206 @@
#!/usr/bin/env python3
"""
Radar Charts Showcase — radarstyle standard / marker / filled.
Generates: charts-radar.pptx
Slide 1 radarstyle standard / marker / filled
Slide 2 Title & legend title.* + legend positions + legendFont
Slide 3 Data labels flags + labelfont
Slide 4 Axes min/max, gridlines, axisfont, labelrotation
Slide 5 Series styling colors, gradient, transparency, outline, shadow
Slide 6 Markers marker symbol/size/color (radarstyle=marker only)
Slide 7 Backgrounds chartareafill, plotFill, chartborder, roundedcorners
Slide 8 Presets & per-series preset bundles + chart-series Set
SDK twin of charts-radar.sh (officecli CLI). Both produce an equivalent
charts-radar.pptx. This one drives the **officecli Python SDK**
(`pip install officecli-sdk`): one resident is started and each slide's
title shape plus its four charts are shipped over the named pipe in a single
`doc.batch(...)` round-trip. Each item is the same
`{"command","parent","type","props"}` dict you'd put in an `officecli batch`
list.
Usage:
pip install officecli-sdk # plus the `officecli` binary on PATH
python3 charts-radar.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__)), "charts-radar.pptx")
# Four-up grid boxes (inches) shared by every slide.
TL = {"x": "0.3in", "y": "1.05in", "width": "6.1in", "height": "3in"}
TR = {"x": "6.95in", "y": "1.05in", "width": "6.1in", "height": "3in"}
BL = {"x": "0.3in", "y": "4.25in", "width": "6.1in", "height": "3in"}
BR = {"x": "6.95in", "y": "4.25in", "width": "6.1in", "height": "3in"}
CATS = "Speed,Power,Range,Style,Tech,Price"
D = "A:8,7,9,6,8,7"
D2 = "Model A:8,7,9,6,8,7;Model B:6,9,7,8,9,6"
def title_shape(slide, text):
"""One `add shape` item: the slide's bold title bar."""
return {"command": "add", "parent": f"/slide[{slide}]", "type": "shape",
"props": {"text": text, "size": "24", "bold": "true", "autoFit": "normal",
"x": "0.5in", "y": "0.3in", "width": "12.3in", "height": "0.6in"}}
def chart(slide, box, props):
"""One `add chart` item at grid box `box` on `slide`."""
return {"command": "add", "parent": f"/slide[{slide}]", "type": "chart",
"props": {**box, **props}}
print(f"Building {FILE} ...")
with officecli.create(FILE, "--force") as doc:
# ---- Slide 1: radarstyle — standard / marker / filled ------------------
doc.batch([
{"command": "add", "parent": "/", "type": "slide"},
title_shape(1, "radarstyle — standard / marker / filled"),
chart(1, TL, {"chartType": "radar", "radarstyle": "standard", "title": "radarstyle=standard",
"legend": "bottom", "categories": CATS, "data": D2}),
chart(1, TR, {"chartType": "radar", "radarstyle": "marker", "title": "radarstyle=marker",
"legend": "bottom", "categories": CATS, "data": D2}),
chart(1, BL, {"chartType": "radar", "radarstyle": "filled", "title": "radarstyle=filled",
"legend": "bottom", "categories": CATS, "data": D2}),
chart(1, BR, {"chartType": "radar", "radarstyle": "standard", "title": "single series",
"legend": "bottom", "categories": CATS, "data": D}),
])
# ---- Slide 2: Title & legend -------------------------------------------
doc.batch([
{"command": "add", "parent": "/", "type": "slide"},
title_shape(2, "Title & legend"),
chart(2, TL, {"chartType": "radar", "radarstyle": "filled", "title": "Styled title",
"title.font": "Georgia", "title.size": "20", "title.color": "4472C4",
"title.bold": "true",
"legend": "bottom", "categories": CATS, "data": D2}),
chart(2, TR, {"chartType": "radar", "radarstyle": "standard", "title": "legend=top + legendFont",
"legend": "top", "legendFont": "10:333333:Calibri",
"categories": CATS, "data": D2}),
chart(2, BL, {"chartType": "radar", "radarstyle": "standard", "title": "legend.overlay=true",
"legend": "topRight", "legend.overlay": "true",
"categories": CATS, "data": D2}),
chart(2, BR, {"chartType": "radar", "radarstyle": "filled", "autotitledeleted": "true",
"legend": "none", "categories": CATS, "data": D2}),
])
# ---- Slide 3: Data labels — flags + labelfont --------------------------
doc.batch([
{"command": "add", "parent": "/", "type": "slide"},
title_shape(3, "Data labels — flags + labelfont"),
chart(3, TL, {"chartType": "radar", "radarstyle": "marker", "title": "value",
"dataLabels": "value", "labelfont": "9:333333:Calibri",
"legend": "none", "categories": CATS, "data": D}),
chart(3, TR, {"chartType": "radar", "radarstyle": "marker", "title": "value,series",
"dataLabels": "value,series", "legend": "bottom",
"categories": CATS, "data": D2}),
chart(3, BL, {"chartType": "radar", "radarstyle": "standard", "title": "value,category",
"dataLabels": "value,category", "legend": "none",
"categories": CATS, "data": D}),
chart(3, BR, {"chartType": "radar", "radarstyle": "filled", "title": "dataLabels=none",
"dataLabels": "none", "legend": "bottom",
"categories": CATS, "data": D2}),
])
# ---- Slide 4: Axes — min/max, gridlines, axisfont, labelrotation -------
doc.batch([
{"command": "add", "parent": "/", "type": "slide"},
title_shape(4, "Axes — min/max, gridlines, axisfont, labelrotation"),
chart(4, TL, {"chartType": "radar", "radarstyle": "standard", "title": "min/max + titles",
"axismin": "0", "axismax": "10", "majorunit": "2",
"axisfont": "10:333333:Calibri",
"legend": "none", "categories": CATS, "data": D}),
chart(4, TR, {"chartType": "radar", "radarstyle": "standard", "title": "gridlines + minorGridlines",
"gridlines": "E0E0E0:0.3", "minorGridlines": "F0F0F0:0.25",
"legend": "none", "categories": CATS, "data": D}),
chart(4, BL, {"chartType": "radar", "radarstyle": "standard", "title": "labelrotation=30",
"labelrotation": "30", "legend": "none", "categories": CATS, "data": D}),
chart(4, BR, {"chartType": "radar", "radarstyle": "standard", "title": "axisnumfmt=0.0",
"axisnumfmt": "0.0", "legend": "none", "categories": CATS, "data": D}),
])
# ---- Slide 5: Series styling — colors/gradient/transparency/outline/shadow
doc.batch([
{"command": "add", "parent": "/", "type": "slide"},
title_shape(5, "Series styling — colors, gradient, transparency, outline, shadow"),
chart(5, TL, {"chartType": "radar", "radarstyle": "filled", "title": "colors + seriesoutline",
"colors": "4472C4,ED7D31", "seriesoutline": "000000:0.5",
"legend": "bottom", "categories": CATS, "data": D2}),
chart(5, TR, {"chartType": "radar", "radarstyle": "filled", "title": "gradient + seriesshadow",
"gradient": "FF6600-FFCC00", "seriesshadow": "000000-5-45-3-50",
"legend": "none", "categories": CATS, "data": D}),
chart(5, BL, {"chartType": "radar", "radarstyle": "filled", "title": "transparency=40",
"transparency": "40", "legend": "bottom", "categories": CATS, "data": D2}),
chart(5, BR, {"chartType": "radar", "radarstyle": "filled", "title": "per-series gradients",
"gradients": "FF0000-0000FF;00FF00-FFFF00", "legend": "bottom",
"categories": CATS, "data": D2}),
])
# ---- Slide 6: Markers (radarstyle=marker) — symbol/size/color ----------
doc.batch([
{"command": "add", "parent": "/", "type": "slide"},
title_shape(6, "Markers (radarstyle=marker) — symbol/size/color"),
chart(6, TL, {"chartType": "radar", "radarstyle": "marker", "title": "circle:10:FF0000",
"marker": "circle:10:FF0000", "legend": "none", "categories": CATS, "data": D}),
chart(6, TR, {"chartType": "radar", "radarstyle": "marker", "title": "square:8:0070C0",
"marker": "square:8:0070C0", "legend": "none", "categories": CATS, "data": D}),
chart(6, BL, {"chartType": "radar", "radarstyle": "marker", "title": "diamond:12",
"marker": "diamond:12", "legend": "none", "categories": CATS, "data": D}),
chart(6, BR, {"chartType": "radar", "radarstyle": "marker", "title": "triangle:10:70AD47",
"marker": "triangle:10:70AD47", "legend": "none", "categories": CATS, "data": D}),
])
# ---- Slide 7: Backgrounds — chartareafill/plotFill/chartborder/rounded --
doc.batch([
{"command": "add", "parent": "/", "type": "slide"},
title_shape(7, "Backgrounds — chartareafill, plotFill, chartborder, roundedcorners"),
chart(7, TL, {"chartType": "radar", "radarstyle": "filled",
"title": "chartareafill + plotFill + borders",
"chartareafill": "FFF8E7", "plotFill": "FAFAFA", "chartborder": "000000:1",
"plotborder": "CCCCCC:0.5", "legend": "bottom", "categories": CATS, "data": D2}),
chart(7, TR, {"chartType": "radar", "radarstyle": "filled", "title": "roundedcorners=true",
"roundedcorners": "true", "chartborder": "4472C4:2",
"legend": "bottom", "categories": CATS, "data": D2}),
chart(7, BL, {"chartType": "radar", "radarstyle": "standard", "title": "plotFill=none",
"plotFill": "none", "legend": "none", "categories": CATS, "data": D}),
chart(7, BR, {"chartType": "radar", "radarstyle": "filled", "title": "chartareafill=none",
"chartareafill": "none", "legend": "bottom", "categories": CATS, "data": D2}),
])
# ---- Slide 8: Presets & per-series Set ---------------------------------
items = [
{"command": "add", "parent": "/", "type": "slide"},
title_shape(8, "Presets & per-series Set"),
]
for box, p in zip([TL, TR, BL], ["minimal", "dark", "corporate"]):
items.append(chart(8, box, {"chartType": "radar", "radarstyle": "filled", "preset": p,
"title": f"preset={p}",
"legend": "bottom", "categories": CATS, "data": D2}))
items.append(chart(8, BR, {"chartType": "radar", "radarstyle": "marker", "title": "chart-series Set",
"legend": "bottom", "categories": CATS, "data": D2}))
# per-series Set applies AFTER chart[4] exists in the same batch (items apply
# in order), recoloring + remarking the first series.
items.append({"command": "set", "path": "/slide[8]/chart[4]/series[1]",
"props": {"name": "Renamed A", "color": "C00000",
"marker": "circle", "markerSize": "9"}})
doc.batch(items)
doc.send({"command": "save"})
# context exit closes the resident, flushing the deck to disk.
print(f"Generated: {FILE} (8 slides)")
+98
View File
@@ -0,0 +1,98 @@
#!/bin/bash
# Radar Charts Showcase — radarstyle standard / marker / filled.
# CLI twin of charts-radar.py (officecli Python SDK). Both produce an
# equivalent charts-radar.pptx.
#
# Slide 1 radarstyle standard / marker / filled
# Slide 2 Title & legend title.* + legend positions + legendFont
# Slide 3 Data labels flags + labelfont
# Slide 4 Axes min/max, gridlines, axisfont, labelrotation
# Slide 5 Series styling colors, gradient, transparency, outline, shadow
# Slide 6 Markers marker symbol/size/color (radarstyle=marker only)
# Slide 7 Backgrounds chartareafill, plotFill, chartborder, roundedcorners
# Slide 8 Presets & per-series preset bundles + chart-series Set
#
# Usage: ./charts-radar.sh
# NOTE: intentionally NO `set -e`. Like the SDK twin's doc.batch, this script
# tolerates forward-compat 'UNSUPPORTED props' warnings (officecli exit 2) and
# keeps building so the full document is produced.
FILE="$(dirname "$0")/charts-radar.pptx"
rm -f "$FILE"
officecli create "$FILE"
officecli open "$FILE"
# Shared category/data series and four-up grid boxes (inches).
CATS="Speed,Power,Range,Style,Tech,Price"
D="A:8,7,9,6,8,7"
D2="Model A:8,7,9,6,8,7;Model B:6,9,7,8,9,6"
# ==================== Slide 1: radarstyle — standard / marker / filled ====================
officecli add "$FILE" / --type slide
officecli add "$FILE" /slide[1] --type shape --prop text="radarstyle — standard / marker / filled" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
officecli add "$FILE" /slide[1] --type chart --prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=radar --prop radarstyle=standard --prop title=radarstyle=standard --prop legend=bottom --prop categories="$CATS" --prop data="$D2"
officecli add "$FILE" /slide[1] --type chart --prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=radar --prop radarstyle=marker --prop title=radarstyle=marker --prop legend=bottom --prop categories="$CATS" --prop data="$D2"
officecli add "$FILE" /slide[1] --type chart --prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=radar --prop radarstyle=filled --prop title=radarstyle=filled --prop legend=bottom --prop categories="$CATS" --prop data="$D2"
officecli add "$FILE" /slide[1] --type chart --prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=radar --prop radarstyle=standard --prop title="single series" --prop legend=bottom --prop categories="$CATS" --prop data="$D"
# ==================== Slide 2: Title & legend ====================
officecli add "$FILE" / --type slide
officecli add "$FILE" /slide[2] --type shape --prop text="Title & legend" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
officecli add "$FILE" /slide[2] --type chart --prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=radar --prop radarstyle=filled --prop title="Styled title" --prop title.font=Georgia --prop title.size=20 --prop title.color=4472C4 --prop title.bold=true --prop legend=bottom --prop categories="$CATS" --prop data="$D2"
officecli add "$FILE" /slide[2] --type chart --prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=radar --prop radarstyle=standard --prop title="legend=top + legendFont" --prop legend=top --prop legendFont=10:333333:Calibri --prop categories="$CATS" --prop data="$D2"
officecli add "$FILE" /slide[2] --type chart --prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=radar --prop radarstyle=standard --prop title="legend.overlay=true" --prop legend=topRight --prop legend.overlay=true --prop categories="$CATS" --prop data="$D2"
officecli add "$FILE" /slide[2] --type chart --prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=radar --prop radarstyle=filled --prop autotitledeleted=true --prop legend=none --prop categories="$CATS" --prop data="$D2"
# ==================== Slide 3: Data labels — flags + labelfont ====================
officecli add "$FILE" / --type slide
officecli add "$FILE" /slide[3] --type shape --prop text="Data labels — flags + labelfont" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
officecli add "$FILE" /slide[3] --type chart --prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=radar --prop radarstyle=marker --prop title=value --prop dataLabels=value --prop labelfont=9:333333:Calibri --prop legend=none --prop categories="$CATS" --prop data="$D"
officecli add "$FILE" /slide[3] --type chart --prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=radar --prop radarstyle=marker --prop title="value,series" --prop dataLabels="value,series" --prop legend=bottom --prop categories="$CATS" --prop data="$D2"
officecli add "$FILE" /slide[3] --type chart --prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=radar --prop radarstyle=standard --prop title="value,category" --prop dataLabels="value,category" --prop legend=none --prop categories="$CATS" --prop data="$D"
officecli add "$FILE" /slide[3] --type chart --prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=radar --prop radarstyle=filled --prop title="dataLabels=none" --prop dataLabels=none --prop legend=bottom --prop categories="$CATS" --prop data="$D2"
# ==================== Slide 4: Axes — min/max, gridlines, axisfont, labelrotation ====================
officecli add "$FILE" / --type slide
officecli add "$FILE" /slide[4] --type shape --prop text="Axes — min/max, gridlines, axisfont, labelrotation" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
officecli add "$FILE" /slide[4] --type chart --prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=radar --prop radarstyle=standard --prop title="min/max + titles" --prop axismin=0 --prop axismax=10 --prop majorunit=2 --prop axisfont=10:333333:Calibri --prop legend=none --prop categories="$CATS" --prop data="$D"
officecli add "$FILE" /slide[4] --type chart --prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=radar --prop radarstyle=standard --prop title="gridlines + minorGridlines" --prop gridlines=E0E0E0:0.3 --prop minorGridlines=F0F0F0:0.25 --prop legend=none --prop categories="$CATS" --prop data="$D"
officecli add "$FILE" /slide[4] --type chart --prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=radar --prop radarstyle=standard --prop title="labelrotation=30" --prop labelrotation=30 --prop legend=none --prop categories="$CATS" --prop data="$D"
officecli add "$FILE" /slide[4] --type chart --prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=radar --prop radarstyle=standard --prop title="axisnumfmt=0.0" --prop axisnumfmt=0.0 --prop legend=none --prop categories="$CATS" --prop data="$D"
# ==================== Slide 5: Series styling — colors, gradient, transparency, outline, shadow ====================
officecli add "$FILE" / --type slide
officecli add "$FILE" /slide[5] --type shape --prop text="Series styling — colors, gradient, transparency, outline, shadow" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
officecli add "$FILE" /slide[5] --type chart --prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=radar --prop radarstyle=filled --prop title="colors + seriesoutline" --prop colors=4472C4,ED7D31 --prop seriesoutline=000000:0.5 --prop legend=bottom --prop categories="$CATS" --prop data="$D2"
officecli add "$FILE" /slide[5] --type chart --prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=radar --prop radarstyle=filled --prop title="gradient + seriesshadow" --prop gradient=FF6600-FFCC00 --prop seriesshadow=000000-5-45-3-50 --prop legend=none --prop categories="$CATS" --prop data="$D"
officecli add "$FILE" /slide[5] --type chart --prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=radar --prop radarstyle=filled --prop title="transparency=40" --prop transparency=40 --prop legend=bottom --prop categories="$CATS" --prop data="$D2"
officecli add "$FILE" /slide[5] --type chart --prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=radar --prop radarstyle=filled --prop title="per-series gradients" --prop gradients="FF0000-0000FF;00FF00-FFFF00" --prop legend=bottom --prop categories="$CATS" --prop data="$D2"
# ==================== Slide 6: Markers (radarstyle=marker) — symbol/size/color ====================
officecli add "$FILE" / --type slide
officecli add "$FILE" /slide[6] --type shape --prop text="Markers (radarstyle=marker) — symbol/size/color" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
officecli add "$FILE" /slide[6] --type chart --prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=radar --prop radarstyle=marker --prop title=circle:10:FF0000 --prop marker=circle:10:FF0000 --prop legend=none --prop categories="$CATS" --prop data="$D"
officecli add "$FILE" /slide[6] --type chart --prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=radar --prop radarstyle=marker --prop title=square:8:0070C0 --prop marker=square:8:0070C0 --prop legend=none --prop categories="$CATS" --prop data="$D"
officecli add "$FILE" /slide[6] --type chart --prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=radar --prop radarstyle=marker --prop title=diamond:12 --prop marker=diamond:12 --prop legend=none --prop categories="$CATS" --prop data="$D"
officecli add "$FILE" /slide[6] --type chart --prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=radar --prop radarstyle=marker --prop title=triangle:10:70AD47 --prop marker=triangle:10:70AD47 --prop legend=none --prop categories="$CATS" --prop data="$D"
# ==================== Slide 7: Backgrounds — chartareafill, plotFill, chartborder, roundedcorners ====================
officecli add "$FILE" / --type slide
officecli add "$FILE" /slide[7] --type shape --prop text="Backgrounds — chartareafill, plotFill, chartborder, roundedcorners" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
officecli add "$FILE" /slide[7] --type chart --prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=radar --prop radarstyle=filled --prop title="chartareafill + plotFill + borders" --prop chartareafill=FFF8E7 --prop plotFill=FAFAFA --prop chartborder=000000:1 --prop plotborder=CCCCCC:0.5 --prop legend=bottom --prop categories="$CATS" --prop data="$D2"
officecli add "$FILE" /slide[7] --type chart --prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=radar --prop radarstyle=filled --prop title="roundedcorners=true" --prop roundedcorners=true --prop chartborder=4472C4:2 --prop legend=bottom --prop categories="$CATS" --prop data="$D2"
officecli add "$FILE" /slide[7] --type chart --prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=radar --prop radarstyle=standard --prop title="plotFill=none" --prop plotFill=none --prop legend=none --prop categories="$CATS" --prop data="$D"
officecli add "$FILE" /slide[7] --type chart --prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=radar --prop radarstyle=filled --prop title="chartareafill=none" --prop chartareafill=none --prop legend=bottom --prop categories="$CATS" --prop data="$D2"
# ==================== Slide 8: Presets & per-series Set ====================
officecli add "$FILE" / --type slide
officecli add "$FILE" /slide[8] --type shape --prop text="Presets & per-series Set" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
officecli add "$FILE" /slide[8] --type chart --prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=radar --prop radarstyle=filled --prop preset=minimal --prop title=preset=minimal --prop legend=bottom --prop categories="$CATS" --prop data="$D2"
officecli add "$FILE" /slide[8] --type chart --prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=radar --prop radarstyle=filled --prop preset=dark --prop title=preset=dark --prop legend=bottom --prop categories="$CATS" --prop data="$D2"
officecli add "$FILE" /slide[8] --type chart --prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=radar --prop radarstyle=filled --prop preset=corporate --prop title=preset=corporate --prop legend=bottom --prop categories="$CATS" --prop data="$D2"
officecli add "$FILE" /slide[8] --type chart --prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=radar --prop radarstyle=marker --prop title="chart-series Set" --prop legend=bottom --prop categories="$CATS" --prop data="$D2"
# per-series Set: recolor + remark the first series of chart[4]
officecli set "$FILE" /slide[8]/chart[4]/series[1] --prop name="Renamed A" --prop color=C00000 --prop marker=circle --prop markerSize=9
officecli close "$FILE"
officecli validate "$FILE"
echo "Generated: $FILE"
+290
View File
@@ -0,0 +1,290 @@
# Scatter Charts Showcase
This demo consists of three files that work together:
- **charts-scatter.py** — Python script that calls `officecli` commands to generate the deck (9 slides).
- **charts-scatter.pptx** — The generated 9-slide deck.
- **charts-scatter.md** — This file. Maps each slide to the features it demonstrates.
## Regenerate
```bash
cd examples/ppt/charts
python3 charts-scatter.py
# → charts-scatter.pptx
```
## Chart Slides
### Slide 1 — scatterstyle Variants
Five scatter style modes demonstrated with the same dataset.
```bash
officecli add charts-scatter.pptx /slide[1] --type chart \
--prop chartType=scatter --prop scatterstyle=line --prop title="scatterstyle=line" \
--prop legend=none --prop data="A:10,20,18,30,28,40,42,55,52,65" \
--prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in
officecli add charts-scatter.pptx /slide[1] --type chart \
--prop chartType=scatter --prop scatterstyle=lineMarker \
--prop title="scatterstyle=lineMarker" \
--prop legend=none --prop data="A:10,20,18,30,28,40,42,55,52,65" \
--prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in
officecli add charts-scatter.pptx /slide[1] --type chart \
--prop chartType=scatter --prop scatterstyle=marker \
--prop title="scatterstyle=marker" \
--prop legend=none --prop data="A:10,20,18,30,28,40,42,55,52,65" \
--prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in
officecli add charts-scatter.pptx /slide[1] --type chart \
--prop chartType=scatter --prop scatterstyle=smoothMarker \
--prop title="scatterstyle=smoothMarker" \
--prop legend=none --prop data="A:10,20,18,30,28,40,42,55,52,65" \
--prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in
```
**Features:** `scatterstyle` (line/lineMarker/marker/smooth/smoothMarker)
### Slide 2 — Markers
```bash
# circle with explicit size and color
officecli add charts-scatter.pptx /slide[2] --type chart \
--prop chartType=scatter --prop scatterstyle=marker \
--prop title="circle:10:FF0000" --prop marker="circle:10:FF0000" \
--prop legend=none --prop data="A:10,20,18,30,28,40,42,55,52,65"
officecli add charts-scatter.pptx /slide[2] --type chart \
--prop chartType=scatter --prop scatterstyle=marker \
--prop title="diamond:12:0070C0" --prop marker="diamond:12:0070C0" \
--prop legend=none --prop data="A:10,20,18,30,28,40,42,55,52,65"
officecli add charts-scatter.pptx /slide[2] --type chart \
--prop chartType=scatter --prop scatterstyle=marker \
--prop title="square:8:70AD47" --prop marker="square:8:70AD47" \
--prop legend=none --prop data="A:10,20,18,30,28,40,42,55,52,65"
# markercolor — fill color independent of marker= compound form
officecli add charts-scatter.pptx /slide[2] --type chart \
--prop chartType=scatter --prop scatterstyle=marker \
--prop title="markercolor=E63946" --prop marker="circle:10" \
--prop markercolor=E63946 \
--prop legend=none --prop data="A:10,20,18,30,28,40,42,55,52,65"
```
**Features:** `marker` (symbol:size:color compound), symbols: circle/diamond/square/triangle/star/…; `markercolor` (standalone fill color)
### Slide 3 — Title and Legend
```bash
officecli add charts-scatter.pptx /slide[3] --type chart \
--prop chartType=scatter --prop scatterstyle=smoothMarker \
--prop title="Styled title" \
--prop title.font=Georgia --prop title.size=20 \
--prop title.color=4472C4 --prop title.bold=true \
--prop legend=bottom --prop data="A:10,20,18,30;B:5,12,15,22"
officecli add charts-scatter.pptx /slide[3] --type chart \
--prop chartType=scatter --prop scatterstyle=lineMarker \
--prop title="legend=top + legendFont" --prop legend=top \
--prop legendFont="10:333333:Calibri" \
--prop data="A:10,20,18,30;B:5,12,15,22"
# title.overlay — title drawn over plot area (saves vertical space)
officecli add charts-scatter.pptx /slide[3] --type chart \
--prop chartType=scatter --prop scatterstyle=marker \
--prop title="title.overlay=true" --prop title.overlay=true \
--prop legend=none --prop data="A:10,20,18,30;B:5,12,15,22"
```
**Features:** `title.font/size/color/bold`, `title.overlay`, `legend` positions, `legendFont`, `legend.overlay`
### Slide 4 — Data Labels
```bash
officecli add charts-scatter.pptx /slide[4] --type chart \
--prop chartType=scatter --prop scatterstyle=marker \
--prop title="value" --prop dataLabels=value \
--prop labelfont="9:333333:Calibri" --prop legend=none \
--prop data="A:10,20,18,30,28,40,42,55"
officecli add charts-scatter.pptx /slide[4] --type chart \
--prop chartType=scatter --prop scatterstyle=marker \
--prop title="value,series" --prop dataLabels="value,series" \
--prop legend=none --prop data="A:10,20,18,30;B:5,12,15,22"
officecli add charts-scatter.pptx /slide[4] --type chart \
--prop chartType=scatter --prop scatterstyle=marker \
--prop title="labelPos=top" --prop dataLabels=value --prop labelPos=top \
--prop legend=none --prop data="A:10,20,18,30,28,40,42,55"
officecli add charts-scatter.pptx /slide[4] --type chart \
--prop chartType=scatter --prop scatterstyle=marker \
--prop title="dataLabels=none" --prop dataLabels=none \
--prop legend=none --prop data="A:10,20,18,30,28,40,42,55"
```
**Features:** `dataLabels` (value/series/none or combined), `labelPos` (top), `labelfont`
### Slide 5 — Axes
```bash
officecli add charts-scatter.pptx /slide[5] --type chart \
--prop chartType=scatter --prop scatterstyle=lineMarker \
--prop title="min/max + titles" --prop legend=none \
--prop axismin=0 --prop axismax=80 --prop majorunit=20 \
--prop axistitle="Y" --prop cattitle="X" \
--prop axisfont="10:333333:Calibri" --prop axisline="666666:1" \
--prop axisnumfmt="#,##0" --prop data="A:10,20,18,30,28,40,42,55"
officecli add charts-scatter.pptx /slide[5] --type chart \
--prop chartType=scatter --prop scatterstyle=marker \
--prop title="gridlines + minorGridlines" --prop legend=none \
--prop gridlines="E0E0E0:0.3" --prop minorGridlines="F0F0F0:0.25" \
--prop data="A:10,20,18,30,28,40,42,55"
# Log scale on Y axis
officecli add charts-scatter.pptx /slide[5] --type chart \
--prop chartType=scatter --prop scatterstyle=marker \
--prop title="logbase=10 (Y)" --prop logbase=10 \
--prop axismin=1 --prop axismax=100 --prop legend=none \
--prop data="A:2,5,8,12,20,40,80"
```
**Features:** `axismin/max`, `majorunit`, `axistitle/cattitle`, `axisfont/axisline/axisnumfmt`, `gridlines/minorGridlines`, `labelrotation`, `logbase`
### Slide 6 — Series Styling
```bash
officecli add charts-scatter.pptx /slide[6] --type chart \
--prop chartType=scatter --prop scatterstyle=marker \
--prop title="colors + seriesoutline" --prop legend=bottom \
--prop colors="4472C4,ED7D31" --prop seriesoutline="000000:0.5" \
--prop data="A:10,20,18,30;B:5,12,15,22"
officecli add charts-scatter.pptx /slide[6] --type chart \
--prop chartType=scatter --prop scatterstyle=marker \
--prop title="gradient + seriesshadow" --prop legend=none \
--prop gradient="FF6600-FFCC00" --prop seriesshadow="000000-5-45-3-50" \
--prop data="A:10,20,18,30,28,40,42,55"
officecli add charts-scatter.pptx /slide[6] --type chart \
--prop chartType=scatter --prop scatterstyle=marker \
--prop title="transparency=30" --prop legend=bottom \
--prop transparency=30 --prop data="A:10,20,18,30;B:5,12,15,22"
officecli add charts-scatter.pptx /slide[6] --type chart \
--prop chartType=scatter --prop scatterstyle=marker \
--prop title="per-series gradients" --prop legend=bottom \
--prop gradients="FF0000-0000FF;00FF00-FFFF00" \
--prop data="A:10,20,18,30;B:5,12,15,22"
```
**Features:** `colors`, `seriesoutline`, `gradient`, `seriesshadow`, `transparency`, `gradients`
### Slide 7 — Overlays (trendlines, error bars)
```bash
officecli add charts-scatter.pptx /slide[7] --type chart \
--prop chartType=scatter --prop scatterstyle=marker \
--prop title="trendline=linear" --prop trendline=linear \
--prop legend=none --prop data="A:10,20,18,30,28,40,42,55"
officecli add charts-scatter.pptx /slide[7] --type chart \
--prop chartType=scatter --prop scatterstyle=marker \
--prop title="trendline=poly:3" --prop trendline="poly:3" \
--prop legend=none --prop data="A:10,20,18,30,28,40,42,55"
officecli add charts-scatter.pptx /slide[7] --type chart \
--prop chartType=scatter --prop scatterstyle=marker \
--prop title="trendline=movingAvg:3" --prop trendline="movingAvg:3" \
--prop legend=none --prop data="A:10,20,18,30,28,40,42,55"
officecli add charts-scatter.pptx /slide[7] --type chart \
--prop chartType=scatter --prop scatterstyle=marker \
--prop title="errbars=stdDev:1" --prop errbars="stdDev:1" \
--prop legend=none --prop data="A:10,20,18,30,28,40,42,55"
```
**Features:** `trendline` (linear/poly:N/exp/log/power/movingAvg:N), `errbars`
### Slide 8 — Per-Series Set and Presets
```bash
for p in minimal dark corporate; do
officecli add charts-scatter.pptx /slide[8] --type chart \
--prop chartType=scatter --prop scatterstyle=smoothMarker \
--prop preset=$p --prop title="preset=$p" --prop legend=bottom \
--prop data="A:10,20,18,30;B:5,12,15,22"
done
officecli add charts-scatter.pptx /slide[8] --type chart \
--prop chartType=scatter --prop scatterstyle=lineMarker \
--prop title="chart-series Set per series" --prop legend=bottom \
--prop data="A:10,20,18,30;B:5,12,15,22"
# Per-series Set: lineWidth, lineDash, marker, markerSize, smooth
officecli set charts-scatter.pptx "/slide[8]/chart[4]/series[1]" \
--prop name="Alpha" --prop color=C00000 --prop lineWidth=2.5 \
--prop lineDash=solid --prop marker=circle --prop markerSize=10 \
--prop smooth=true
officecli set charts-scatter.pptx "/slide[8]/chart[4]/series[2]" \
--prop name="Beta" --prop color=2E75B6 --prop lineWidth=1.5 \
--prop lineDash=dash --prop marker=diamond --prop markerSize=8
```
**Features:** `preset`, `chart-series Set`: `name`, `color`, `lineWidth`, `lineDash` (solid/dash/dot/…), `marker`, `markerSize`, `smooth`
### Slide 9 — Named Series Shorthand
```bash
# series{N}= is an alternative to data= that names each series at Add time
officecli add charts-scatter.pptx /slide[9] --type chart \
--prop chartType=scatter --prop scatterstyle=lineMarker \
--prop title="series1= + series2=" \
--prop series1="Alpha:10,25,18,40" --prop series2="Beta:5,15,12,30" \
--prop legend=bottom
officecli add charts-scatter.pptx /slide[9] --type chart \
--prop chartType=scatter --prop scatterstyle=marker \
--prop title="series1.* per-series naming + colors=" \
--prop series1.name="Alpha" --prop series1.values="10,25,18,40" \
--prop series2.name="Beta" --prop series2.values="5,15,12,30" \
--prop colors="4472C4,E63946" --prop legend=bottom
```
**Features:** `series{N}=Name:v1,v2,…` (named series shorthand), `series{N}.name`/`series{N}.values` per-series at Add time, mixing with `colors=`
## Complete Feature Coverage
| Feature | Slide |
|---------|-------|
| **scatterstyle:** line/lineMarker/marker/smooth/smoothMarker | 1 |
| **marker** (symbol:size:color compound) | 2 |
| **markercolor** (standalone) | 2 |
| **title.font/size/color/bold**, **title.overlay** | 3 |
| **legend** positions, legendFont, legend.overlay | 3 |
| **dataLabels:** value/series/none + combined | 4 |
| **labelPos**, **labelfont** | 4 |
| **axismin/max**, majorunit, axistitle/cattitle | 5 |
| **axisfont/axisline/axisnumfmt**, gridlines | 5 |
| **logbase** | 5 |
| **colors**, seriesoutline, gradient, seriesshadow | 6 |
| **gradients**, transparency | 6 |
| **trendline** (linear/poly/exp/log/power/movingAvg) | 7 |
| **errbars** | 7 |
| **preset** | 8 |
| **chart-series Set:** lineWidth/lineDash/marker/markerSize/smooth | 8 |
| **series{N}=** shorthand | 9 |
| **series{N}.name/values** per-series Add | 9 |
## Inspect the Generated File
```bash
officecli query charts-scatter.pptx chart
officecli get charts-scatter.pptx "/slide[1]/chart[1]"
officecli get charts-scatter.pptx "/slide[8]/chart[4]/series[1]"
officecli get charts-scatter.pptx "/slide[5]/chart[1]/axis[@role=value]"
```
Binary file not shown.
+245
View File
@@ -0,0 +1,245 @@
#!/usr/bin/env python3
"""
Scatter Charts Showcase — scatterstyle line/lineMarker/marker/smooth/smoothMarker.
Generates: charts-scatter.pptx
Slide 1 scatterstyle variants line / lineMarker / marker / smooth / smoothMarker (5 charts)
Slide 2 Markers marker symbol/size/color
Slide 3 Title & legend
Slide 4 Data labels
Slide 5 Axes min/max, gridlines, log on both axes
Slide 6 Series styling colors, gradient, transparency, outline, shadow
Slide 7 Overlays trendline (linear/poly/exp/log/power/movingAvg), errbars, referenceline
Slide 8 Per-series Set lineWidth/lineDash/marker/markerSize/color/smooth + presets
SDK twin of charts-scatter.sh (officecli CLI). Both produce an equivalent
charts-scatter.pptx. This one drives the **officecli Python SDK**
(`pip install officecli-sdk`): one resident is started and every slide, shape,
chart and per-series Set is shipped over the named pipe in `doc.batch(...)`
round-trips. Each item is the same `{"command","parent"/"path","type","props"}`
dict you'd put in an `officecli batch` list.
Forward-compat: a chart prop that this officecli build doesn't yet support is
reported by the resident as an `unsupported_property` warning inside the batch
envelope (not a hard failure); we surface those so silent gaps stay visible,
mirroring the .sh twin's UNSUPPORTED-skip behaviour.
Usage:
pip install officecli-sdk # plus the `officecli` binary on PATH
python3 charts-scatter.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__)), "charts-scatter.pptx")
# --- slide layout boxes (4-up grid) and shared scatter data
TL = {"x": "0.3in", "y": "1.05in", "width": "6.1in", "height": "3in"}
TR = {"x": "6.95in", "y": "1.05in", "width": "6.1in", "height": "3in"}
BL = {"x": "0.3in", "y": "4.25in", "width": "6.1in", "height": "3in"}
BR = {"x": "6.95in", "y": "4.25in", "width": "6.1in", "height": "3in"}
D = "A:10,20,18,30,28,40,42,55,52,65"
D2 = "A:10,20,18,30,28,40,42,55;B:5,12,15,22,25,30,35,40"
# slide counter — tracks the current slide index used in parent/path strings
slide = 0
def new_slide(title):
"""Return [add slide, add title-shape] batch items and bump the counter."""
global slide
slide += 1
return [
{"command": "add", "parent": "/", "type": "slide", "props": {}},
{"command": "add", "parent": f"/slide[{slide}]", "type": "shape",
"props": {"text": title, "size": "24", "bold": "true", "autoFit": "normal",
"x": "0.5in", "y": "0.3in", "width": "12.3in", "height": "0.6in"}},
]
def ch(box, props):
"""One `add chart` item in batch-shape on the current slide."""
return {"command": "add", "parent": f"/slide[{slide}]", "type": "chart",
"props": {**box, **props}}
def warn_unsupported(env, label):
"""Surface any unsupported_property warnings in a batch envelope (forward-compat)."""
if not isinstance(env, dict):
return
data = env.get("data", env)
warnings = []
if isinstance(data, dict):
warnings = data.get("warnings") or data.get("Warnings") or []
for w in warnings:
msg = w if isinstance(w, str) else (w.get("message") or w.get("type") or str(w))
print(f"{label}{msg}", file=sys.stderr)
print(f"Building {FILE} ...")
with officecli.create(FILE, "--force") as doc:
# --- Slide 1: scatterstyle variants ---
items = new_slide("scatterstyle — line / lineMarker / marker / smooth / smoothMarker")
items += [
ch(TL, {"chartType": "scatter", "scatterstyle": "line", "title": "scatterstyle=line",
"legend": "none", "data": D}),
ch(TR, {"chartType": "scatter", "scatterstyle": "lineMarker", "title": "scatterstyle=lineMarker",
"legend": "none", "data": D}),
ch(BL, {"chartType": "scatter", "scatterstyle": "marker", "title": "scatterstyle=marker",
"legend": "none", "data": D}),
ch(BR, {"chartType": "scatter", "scatterstyle": "smoothMarker", "title": "scatterstyle=smoothMarker",
"legend": "none", "data": D}),
]
warn_unsupported(doc.batch(items), "slide1")
# --- Slide 2: Markers ---
items = new_slide("Markers — symbol / size / color / markercolor")
items += [
ch(TL, {"chartType": "scatter", "scatterstyle": "marker", "title": "circle:10:FF0000",
"marker": "circle:10:FF0000", "legend": "none", "data": D}),
ch(TR, {"chartType": "scatter", "scatterstyle": "marker", "title": "diamond:12:0070C0",
"marker": "diamond:12:0070C0", "legend": "none", "data": D}),
ch(BL, {"chartType": "scatter", "scatterstyle": "marker", "title": "square:8:70AD47",
"marker": "square:8:70AD47", "legend": "none", "data": D}),
# markercolor — per-series marker fill color (independent of marker= compound form)
ch(BR, {"chartType": "scatter", "scatterstyle": "marker", "title": "markercolor=E63946",
"marker": "circle:10", "markercolor": "E63946", "legend": "none", "data": D}),
]
warn_unsupported(doc.batch(items), "slide2")
# --- Slide 3: Title & legend ---
items = new_slide("Title & legend — title.overlay / legend.overlay")
items += [
ch(TL, {"chartType": "scatter", "scatterstyle": "smoothMarker", "title": "Styled title",
"title.font": "Georgia", "title.size": "20", "title.color": "4472C4", "title.bold": "true",
"legend": "bottom", "data": D2}),
ch(TR, {"chartType": "scatter", "scatterstyle": "lineMarker", "title": "legend=top + legendFont",
"legend": "top", "legendFont": "10:333333:Calibri", "data": D2}),
ch(BL, {"chartType": "scatter", "scatterstyle": "lineMarker", "title": "legend.overlay=true",
"legend": "topRight", "legend.overlay": "true", "data": D2}),
# title.overlay — title rendered over the plot area (saves vertical space)
ch(BR, {"chartType": "scatter", "scatterstyle": "marker", "title": "title.overlay=true",
"title.overlay": "true", "legend": "none", "data": D2}),
]
warn_unsupported(doc.batch(items), "slide3")
# --- Slide 4: Data labels ---
items = new_slide("Data labels — flags + labelfont")
items += [
ch(TL, {"chartType": "scatter", "scatterstyle": "marker", "title": "value", "dataLabels": "value",
"labelfont": "9:333333:Calibri", "legend": "none", "data": D}),
ch(TR, {"chartType": "scatter", "scatterstyle": "marker", "title": "value,series",
"dataLabels": "value,series", "legend": "none", "data": D2}),
ch(BL, {"chartType": "scatter", "scatterstyle": "marker", "title": "labelPos=top",
"dataLabels": "value", "labelPos": "top", "legend": "none", "data": D}),
ch(BR, {"chartType": "scatter", "scatterstyle": "marker", "title": "dataLabels=none",
"dataLabels": "none", "legend": "none", "data": D}),
]
warn_unsupported(doc.batch(items), "slide4")
# --- Slide 5: Axes ---
items = new_slide("Axes — min/max, gridlines, ticks, log on both axes")
items += [
ch(TL, {"chartType": "scatter", "scatterstyle": "lineMarker", "title": "min/max + titles",
"axismin": "0", "axismax": "80", "majorunit": "20", "axistitle": "Y", "cattitle": "X",
"axisfont": "10:333333:Calibri", "axisline": "666666:1", "axisnumfmt": "#,##0",
"legend": "none", "data": D}),
ch(TR, {"chartType": "scatter", "scatterstyle": "marker", "title": "gridlines + minorGridlines",
"gridlines": "E0E0E0:0.3", "minorGridlines": "F0F0F0:0.25", "legend": "none", "data": D}),
ch(BL, {"chartType": "scatter", "scatterstyle": "marker", "title": "labelrotation=-30",
"labelrotation": "-30", "legend": "none", "data": D}),
ch(BR, {"chartType": "scatter", "scatterstyle": "marker", "title": "logbase=10 (Y)",
"logbase": "10", "axismin": "1", "axismax": "100", "legend": "none",
"data": "A:2,5,8,12,20,40,80"}),
]
warn_unsupported(doc.batch(items), "slide5")
# --- Slide 6: Series styling ---
items = new_slide("Series styling — colors, gradient, transparency, outline, shadow")
items += [
ch(TL, {"chartType": "scatter", "scatterstyle": "marker", "title": "colors + seriesoutline",
"colors": "4472C4,ED7D31", "seriesoutline": "000000:0.5", "legend": "bottom", "data": D2}),
ch(TR, {"chartType": "scatter", "scatterstyle": "marker", "title": "gradient + seriesshadow",
"gradient": "FF6600-FFCC00", "seriesshadow": "000000-5-45-3-50", "legend": "none", "data": D}),
ch(BL, {"chartType": "scatter", "scatterstyle": "marker", "title": "transparency=30",
"transparency": "30", "legend": "bottom", "data": D2}),
ch(BR, {"chartType": "scatter", "scatterstyle": "marker", "title": "per-series gradients",
"gradients": "FF0000-0000FF;00FF00-FFFF00", "legend": "bottom", "data": D2}),
]
warn_unsupported(doc.batch(items), "slide6")
# --- Slide 7: Overlays ---
items = new_slide("Overlays — trendline (linear/poly/exp/movingAvg), errbars, referenceline")
items += [
ch(TL, {"chartType": "scatter", "scatterstyle": "marker", "title": "trendline=linear",
"trendline": "linear", "legend": "none", "data": D}),
ch(TR, {"chartType": "scatter", "scatterstyle": "marker", "title": "trendline=poly:3",
"trendline": "poly:3", "legend": "none", "data": D}),
ch(BL, {"chartType": "scatter", "scatterstyle": "marker", "title": "trendline=movingAvg:3",
"trendline": "movingAvg:3", "legend": "none", "data": D}),
ch(BR, {"chartType": "scatter", "scatterstyle": "marker", "title": "errbars=stdDev:1",
"errbars": "stdDev:1", "legend": "none", "data": D}),
]
warn_unsupported(doc.batch(items), "slide7")
# --- Slide 8: Per-series Set + presets ---
items = new_slide("Per-series Set + presets — lineWidth/lineDash/marker/markerSize/color/smooth")
for box, p in zip([TL, TR, BL], ["minimal", "dark", "corporate"]):
items.append(ch(box, {"chartType": "scatter", "scatterstyle": "smoothMarker", "preset": p,
"title": f"preset={p}", "legend": "bottom", "data": D2}))
items.append(ch(BR, {"chartType": "scatter", "scatterstyle": "lineMarker",
"title": "chart-series Set per series", "legend": "bottom", "data": D2}))
warn_unsupported(doc.batch(items), "slide8")
# chart-series Set per series (path-based set, after the chart exists)
set_items = [
{"command": "set", "path": f"/slide[{slide}]/chart[4]/series[1]",
"props": {"name": "Alpha", "color": "C00000", "lineWidth": "2.5", "lineDash": "solid",
"marker": "circle", "markerSize": "10", "smooth": "true"}},
{"command": "set", "path": f"/slide[{slide}]/chart[4]/series[2]",
"props": {"name": "Beta", "color": "2E75B6", "lineWidth": "1.5", "lineDash": "dash",
"marker": "diamond", "markerSize": "8"}},
]
warn_unsupported(doc.batch(set_items), "slide8-set")
# --- Slide 9: series{N}= named series shorthand ---
# series{N}= is an alternative to data= that names each series at Add time.
# series1=Name:v1,v2,… series2=Name:v1,v2,… (no shared categories needed for scatter)
items = new_slide("series{N}= — named series shorthand (name:v1,v2,…)")
items += [
ch(TL, {"chartType": "scatter", "scatterstyle": "lineMarker",
"title": "series1= + series2=",
"series1": "Alpha:10,25,18,40", "series2": "Beta:5,15,12,30",
"legend": "bottom"}),
ch(TR, {"chartType": "scatter", "scatterstyle": "marker",
"title": "three named series",
"series1": "Group A:8,20,15", "series2": "Group B:4,12,10", "series3": "Group C:12,28,22",
"legend": "bottom"}),
ch(BL, {"chartType": "scatter", "scatterstyle": "smoothMarker",
"title": "series1 with colors",
"series1": "Rev:30,45,55,70", "series2": "Cost:20,30,35,42",
"colors": "4472C4,E63946", "legend": "bottom"}),
ch(BR, {"chartType": "scatter", "scatterstyle": "marker",
"title": "series1.* per-series naming + colors=",
"series1.name": "Alpha", "series1.values": "10,25,18,40",
"series2.name": "Beta", "series2.values": "5,15,12,30",
"colors": "4472C4,E63946", "legend": "bottom"}),
]
warn_unsupported(doc.batch(items), "slide9")
doc.send({"command": "save"})
# context exit closes the resident, flushing the presentation to disk.
print(f"Done: {FILE} ({slide} slides)")
+112
View File
@@ -0,0 +1,112 @@
#!/bin/bash
# Scatter Charts Showcase — scatterstyle line/lineMarker/marker/smooth/smoothMarker.
# CLI twin of charts-scatter.py (officecli Python SDK). Both produce an
# equivalent charts-scatter.pptx.
#
# Slide 1 scatterstyle variants line / lineMarker / marker / smooth / smoothMarker
# Slide 2 Markers marker symbol/size/color/markercolor
# Slide 3 Title & legend title.overlay / legend.overlay
# Slide 4 Data labels flags + labelfont
# Slide 5 Axes min/max, gridlines, log
# Slide 6 Series styling colors, gradient, transparency, outline, shadow
# Slide 7 Overlays trendline / errbars
# Slide 8 Per-series Set lineWidth/lineDash/marker/markerSize/color/smooth + presets
# Slide 9 series{N}= named series shorthand
#
# Usage:
# ./charts-scatter.sh
# NOTE: intentionally NO `set -e`. Like the SDK twin's doc.batch, this script
# tolerates forward-compat 'UNSUPPORTED props' warnings (officecli exit 2) and
# keeps building so the full document is produced.
FILE="$(dirname "$0")/charts-scatter.pptx"
rm -f "$FILE"
officecli create "$FILE"
officecli open "$FILE"
# Shared scatter data
D="A:10,20,18,30,28,40,42,55,52,65"
D2="A:10,20,18,30,28,40,42,55;B:5,12,15,22,25,30,35,40"
# ==================== Slide 1: scatterstyle variants ====================
officecli add "$FILE" / --type slide
officecli add "$FILE" /slide[1] --type shape --prop text="scatterstyle — line / lineMarker / marker / smooth / smoothMarker" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
officecli add "$FILE" /slide[1] --type chart --prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=scatter --prop scatterstyle=line --prop title="scatterstyle=line" --prop legend=none --prop data="$D"
officecli add "$FILE" /slide[1] --type chart --prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=scatter --prop scatterstyle=lineMarker --prop title="scatterstyle=lineMarker" --prop legend=none --prop data="$D"
officecli add "$FILE" /slide[1] --type chart --prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=scatter --prop scatterstyle=marker --prop title="scatterstyle=marker" --prop legend=none --prop data="$D"
officecli add "$FILE" /slide[1] --type chart --prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=scatter --prop scatterstyle=smoothMarker --prop title="scatterstyle=smoothMarker" --prop legend=none --prop data="$D"
# ==================== Slide 2: Markers ====================
officecli add "$FILE" / --type slide
officecli add "$FILE" /slide[2] --type shape --prop text="Markers — symbol / size / color / markercolor" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
officecli add "$FILE" /slide[2] --type chart --prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=scatter --prop scatterstyle=marker --prop title="circle:10:FF0000" --prop marker=circle:10:FF0000 --prop legend=none --prop data="$D"
officecli add "$FILE" /slide[2] --type chart --prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=scatter --prop scatterstyle=marker --prop title="diamond:12:0070C0" --prop marker=diamond:12:0070C0 --prop legend=none --prop data="$D"
officecli add "$FILE" /slide[2] --type chart --prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=scatter --prop scatterstyle=marker --prop title="square:8:70AD47" --prop marker=square:8:70AD47 --prop legend=none --prop data="$D"
# markercolor — per-series marker fill color (independent of marker= compound form)
officecli add "$FILE" /slide[2] --type chart --prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=scatter --prop scatterstyle=marker --prop title="markercolor=E63946" --prop marker=circle:10 --prop markercolor=E63946 --prop legend=none --prop data="$D"
# ==================== Slide 3: Title & legend ====================
officecli add "$FILE" / --type slide
officecli add "$FILE" /slide[3] --type shape --prop text="Title & legend — title.overlay / legend.overlay" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
officecli add "$FILE" /slide[3] --type chart --prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=scatter --prop scatterstyle=smoothMarker --prop title="Styled title" --prop title.font=Georgia --prop title.size=20 --prop title.color=4472C4 --prop title.bold=true --prop legend=bottom --prop data="$D2"
officecli add "$FILE" /slide[3] --type chart --prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=scatter --prop scatterstyle=lineMarker --prop title="legend=top + legendFont" --prop legend=top --prop legendFont=10:333333:Calibri --prop data="$D2"
officecli add "$FILE" /slide[3] --type chart --prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=scatter --prop scatterstyle=lineMarker --prop title="legend.overlay=true" --prop legend=topRight --prop legend.overlay=true --prop data="$D2"
# title.overlay — title rendered over the plot area (saves vertical space)
officecli add "$FILE" /slide[3] --type chart --prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=scatter --prop scatterstyle=marker --prop title="title.overlay=true" --prop title.overlay=true --prop legend=none --prop data="$D2"
# ==================== Slide 4: Data labels ====================
officecli add "$FILE" / --type slide
officecli add "$FILE" /slide[4] --type shape --prop text="Data labels — flags + labelfont" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
officecli add "$FILE" /slide[4] --type chart --prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=scatter --prop scatterstyle=marker --prop title="value" --prop dataLabels=value --prop labelfont=9:333333:Calibri --prop legend=none --prop data="$D"
officecli add "$FILE" /slide[4] --type chart --prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=scatter --prop scatterstyle=marker --prop title="value,series" --prop dataLabels=value,series --prop legend=none --prop data="$D2"
officecli add "$FILE" /slide[4] --type chart --prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=scatter --prop scatterstyle=marker --prop title="labelPos=top" --prop dataLabels=value --prop labelPos=top --prop legend=none --prop data="$D"
officecli add "$FILE" /slide[4] --type chart --prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=scatter --prop scatterstyle=marker --prop title="dataLabels=none" --prop dataLabels=none --prop legend=none --prop data="$D"
# ==================== Slide 5: Axes ====================
officecli add "$FILE" / --type slide
officecli add "$FILE" /slide[5] --type shape --prop text="Axes — min/max, gridlines, ticks, log on both axes" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
officecli add "$FILE" /slide[5] --type chart --prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=scatter --prop scatterstyle=lineMarker --prop title="min/max + titles" --prop axismin=0 --prop axismax=80 --prop majorunit=20 --prop axistitle=Y --prop cattitle=X --prop axisfont=10:333333:Calibri --prop axisline=666666:1 --prop axisnumfmt="#,##0" --prop legend=none --prop data="$D"
officecli add "$FILE" /slide[5] --type chart --prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=scatter --prop scatterstyle=marker --prop title="gridlines + minorGridlines" --prop gridlines=E0E0E0:0.3 --prop minorGridlines=F0F0F0:0.25 --prop legend=none --prop data="$D"
officecli add "$FILE" /slide[5] --type chart --prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=scatter --prop scatterstyle=marker --prop title="labelrotation=-30" --prop labelrotation=-30 --prop legend=none --prop data="$D"
officecli add "$FILE" /slide[5] --type chart --prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=scatter --prop scatterstyle=marker --prop title="logbase=10 (Y)" --prop logbase=10 --prop axismin=1 --prop axismax=100 --prop legend=none --prop data="A:2,5,8,12,20,40,80"
# ==================== Slide 6: Series styling ====================
officecli add "$FILE" / --type slide
officecli add "$FILE" /slide[6] --type shape --prop text="Series styling — colors, gradient, transparency, outline, shadow" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
officecli add "$FILE" /slide[6] --type chart --prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=scatter --prop scatterstyle=marker --prop title="colors + seriesoutline" --prop colors=4472C4,ED7D31 --prop seriesoutline=000000:0.5 --prop legend=bottom --prop data="$D2"
officecli add "$FILE" /slide[6] --type chart --prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=scatter --prop scatterstyle=marker --prop title="gradient + seriesshadow" --prop gradient=FF6600-FFCC00 --prop seriesshadow=000000-5-45-3-50 --prop legend=none --prop data="$D"
officecli add "$FILE" /slide[6] --type chart --prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=scatter --prop scatterstyle=marker --prop title="transparency=30" --prop transparency=30 --prop legend=bottom --prop data="$D2"
officecli add "$FILE" /slide[6] --type chart --prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=scatter --prop scatterstyle=marker --prop title="per-series gradients" --prop gradients="FF0000-0000FF;00FF00-FFFF00" --prop legend=bottom --prop data="$D2"
# ==================== Slide 7: Overlays ====================
officecli add "$FILE" / --type slide
officecli add "$FILE" /slide[7] --type shape --prop text="Overlays — trendline (linear/poly/exp/movingAvg), errbars, referenceline" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
officecli add "$FILE" /slide[7] --type chart --prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=scatter --prop scatterstyle=marker --prop title="trendline=linear" --prop trendline=linear --prop legend=none --prop data="$D"
officecli add "$FILE" /slide[7] --type chart --prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=scatter --prop scatterstyle=marker --prop title="trendline=poly:3" --prop trendline=poly:3 --prop legend=none --prop data="$D"
officecli add "$FILE" /slide[7] --type chart --prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=scatter --prop scatterstyle=marker --prop title="trendline=movingAvg:3" --prop trendline=movingAvg:3 --prop legend=none --prop data="$D"
officecli add "$FILE" /slide[7] --type chart --prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=scatter --prop scatterstyle=marker --prop title="errbars=stdDev:1" --prop errbars=stdDev:1 --prop legend=none --prop data="$D"
# ==================== Slide 8: Per-series Set + presets ====================
officecli add "$FILE" / --type slide
officecli add "$FILE" /slide[8] --type shape --prop text="Per-series Set + presets — lineWidth/lineDash/marker/markerSize/color/smooth" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
officecli add "$FILE" /slide[8] --type chart --prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=scatter --prop scatterstyle=smoothMarker --prop preset=minimal --prop title="preset=minimal" --prop legend=bottom --prop data="$D2"
officecli add "$FILE" /slide[8] --type chart --prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=scatter --prop scatterstyle=smoothMarker --prop preset=dark --prop title="preset=dark" --prop legend=bottom --prop data="$D2"
officecli add "$FILE" /slide[8] --type chart --prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=scatter --prop scatterstyle=smoothMarker --prop preset=corporate --prop title="preset=corporate" --prop legend=bottom --prop data="$D2"
officecli add "$FILE" /slide[8] --type chart --prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=scatter --prop scatterstyle=lineMarker --prop title="chart-series Set per series" --prop legend=bottom --prop data="$D2"
# chart-series Set per series (path-based set, after the chart exists)
officecli set "$FILE" /slide[8]/chart[4]/series[1] --prop name=Alpha --prop color=C00000 --prop lineWidth=2.5 --prop lineDash=solid --prop marker=circle --prop markerSize=10 --prop smooth=true
officecli set "$FILE" /slide[8]/chart[4]/series[2] --prop name=Beta --prop color=2E75B6 --prop lineWidth=1.5 --prop lineDash=dash --prop marker=diamond --prop markerSize=8
# ==================== Slide 9: series{N}= named series shorthand ====================
# series{N}= is an alternative to data= that names each series at Add time.
# series1=Name:v1,v2,… series2=Name:v1,v2,… (no shared categories needed for scatter)
officecli add "$FILE" / --type slide
officecli add "$FILE" /slide[9] --type shape --prop text="series{N}= — named series shorthand (name:v1,v2,…)" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
officecli add "$FILE" /slide[9] --type chart --prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=scatter --prop scatterstyle=lineMarker --prop title="series1= + series2=" --prop series1="Alpha:10,25,18,40" --prop series2="Beta:5,15,12,30" --prop legend=bottom
officecli add "$FILE" /slide[9] --type chart --prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=scatter --prop scatterstyle=marker --prop title="three named series" --prop series1="Group A:8,20,15" --prop series2="Group B:4,12,10" --prop series3="Group C:12,28,22" --prop legend=bottom
officecli add "$FILE" /slide[9] --type chart --prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=scatter --prop scatterstyle=smoothMarker --prop title="series1 with colors" --prop series1="Rev:30,45,55,70" --prop series2="Cost:20,30,35,42" --prop colors=4472C4,E63946 --prop legend=bottom
officecli add "$FILE" /slide[9] --type chart --prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=scatter --prop scatterstyle=marker --prop title="series1.* per-series naming + colors=" --prop series1.name=Alpha --prop series1.values="10,25,18,40" --prop series2.name=Beta --prop series2.values="5,15,12,30" --prop colors=4472C4,E63946 --prop legend=bottom
officecli close "$FILE"
officecli validate "$FILE"
echo "Generated: $FILE"
+273
View File
@@ -0,0 +1,273 @@
# Stock Charts Showcase
This demo consists of three files that work together:
- **charts-stock.py** — Python script that calls `officecli` commands to generate the deck.
- **charts-stock.pptx** — The generated 8-slide deck (4 charts per slide, 32 charts total).
- **charts-stock.md** — This file. Maps each slide to the features it demonstrates.
## Regenerate
```bash
cd examples/ppt/charts
python3 charts-stock.py
# → charts-stock.pptx
```
Stock charts require series in a fixed order: for HLC provide three series (High, Low, Close); for OHLC provide four (Open, High, Low, Close).
## Chart Slides
### Slide 1 — Basic Stock (HLC and OHLC)
```bash
HLC="High:130,135,140,138,145;Low:118,122,128,125,132;Close:125,130,135,132,140"
OHLC="Open:120,128,130,135,138;High:130,135,140,138,145;Low:118,122,128,125,132;Close:125,130,135,132,140"
CATS="Mon,Tue,Wed,Thu,Fri"
# High-Low-Close (3-series)
officecli add charts-stock.pptx /slide[1] --type chart \
--prop chartType=stock --prop title="HLC" --prop legend=bottom \
--prop categories="$CATS" --prop data="$HLC" \
--prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in
# Open-High-Low-Close (4-series)
officecli add charts-stock.pptx /slide[1] --type chart \
--prop chartType=stock --prop title="OHLC" --prop legend=bottom \
--prop categories="$CATS" --prop data="$OHLC" \
--prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in
# HLC with data table
officecli add charts-stock.pptx /slide[1] --type chart \
--prop chartType=stock --prop title="HLC + dataTable=true" \
--prop dataTable=true --prop legend=bottom \
--prop categories="$CATS" --prop data="$HLC" \
--prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in
# OHLC with data table
officecli add charts-stock.pptx /slide[1] --type chart \
--prop chartType=stock --prop title="OHLC + dataTable=true" \
--prop dataTable=true --prop legend=bottom \
--prop categories="$CATS" --prop data="$OHLC" \
--prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in
```
**Features:** `chartType=stock`, HLC (3-series) vs OHLC (4-series), `dataTable`
### Slide 2 — Hi-Low Lines and Up-Down Bars
```bash
# hilowlines — vertical lines connecting high and low of each period
officecli add charts-stock.pptx /slide[2] --type chart \
--prop chartType=stock --prop title="hilowlines=true" \
--prop hilowlines=true --prop legend=bottom \
--prop categories="$CATS" --prop data="$HLC"
# hilowlines with custom color and width
officecli add charts-stock.pptx /slide[2] --type chart \
--prop chartType=stock --prop title="hilowlines=808080:0.5" \
--prop hilowlines="808080:0.5" --prop legend=bottom \
--prop categories="$CATS" --prop data="$HLC"
# updownbars — candlestick-like up/down fill bars (OHLC only)
officecli add charts-stock.pptx /slide[2] --type chart \
--prop chartType=stock --prop title="updownbars=true (OHLC)" \
--prop updownbars=true --prop legend=bottom \
--prop categories="$CATS" --prop data="$OHLC"
# updownbars with custom width and colors
officecli add charts-stock.pptx /slide[2] --type chart \
--prop chartType=stock --prop title="updownbars=150:00AA00:FF0000" \
--prop updownbars="150:00AA00:FF0000" --prop legend=bottom \
--prop categories="$CATS" --prop data="$OHLC"
```
**Features:** `hilowlines` (true or color:width), `updownbars` (true or gapWidth:upColor:downColor — OHLC only)
### Slide 3 — Title and Legend
```bash
officecli add charts-stock.pptx /slide[3] --type chart \
--prop chartType=stock --prop title="Styled title" \
--prop title.font=Georgia --prop title.size=20 \
--prop title.color=4472C4 --prop title.bold=true \
--prop legend=bottom --prop categories="$CATS" --prop data="$HLC"
officecli add charts-stock.pptx /slide[3] --type chart \
--prop chartType=stock --prop title="legend=top + legendFont" \
--prop legend=top --prop legendFont="10:333333:Calibri" \
--prop categories="$CATS" --prop data="$HLC"
officecli add charts-stock.pptx /slide[3] --type chart \
--prop chartType=stock --prop title="legend.overlay=true" \
--prop legend=topRight --prop legend.overlay=true \
--prop categories="$CATS" --prop data="$HLC"
officecli add charts-stock.pptx /slide[3] --type chart \
--prop chartType=stock --prop autotitledeleted=true --prop legend=none \
--prop categories="$CATS" --prop data="$HLC"
```
**Features:** `title.font/size/color/bold`, `legend` positions, `legendFont`, `legend.overlay`, `autotitledeleted`
### Slide 4 — Data Labels
```bash
officecli add charts-stock.pptx /slide[4] --type chart \
--prop chartType=stock --prop title="dataLabels=value" \
--prop dataLabels=value --prop labelfont="9:333333:Calibri" \
--prop legend=bottom --prop categories="$CATS" --prop data="$HLC"
officecli add charts-stock.pptx /slide[4] --type chart \
--prop chartType=stock --prop title="value,series" \
--prop dataLabels="value,series" --prop legend=bottom \
--prop categories="$CATS" --prop data="$HLC"
officecli add charts-stock.pptx /slide[4] --type chart \
--prop chartType=stock --prop title="value,category" \
--prop dataLabels="value,category" --prop legend=bottom \
--prop categories="$CATS" --prop data="$HLC"
officecli add charts-stock.pptx /slide[4] --type chart \
--prop chartType=stock --prop title="dataLabels=none" \
--prop dataLabels=none --prop legend=bottom \
--prop categories="$CATS" --prop data="$HLC"
```
**Features:** `dataLabels` (value/series/category/none or combined), `labelfont`
### Slide 5 — Axes
```bash
# axis min/max + currency number format
officecli add charts-stock.pptx /slide[5] --type chart \
--prop chartType=stock --prop title="min/max + currency format" \
--prop axismin=100 --prop axismax=160 --prop majorunit=10 \
--prop axistitle="Price (USD)" --prop cattitle="Day" \
--prop axisfont="10:333333:Calibri" --prop axisnumfmt='$#,##0.00' \
--prop legend=bottom --prop categories="$CATS" --prop data="$HLC"
officecli add charts-stock.pptx /slide[5] --type chart \
--prop chartType=stock --prop title="gridlines + minorGridlines" \
--prop gridlines="E0E0E0:0.3" --prop minorGridlines="F0F0F0:0.25" \
--prop legend=bottom --prop categories="$CATS" --prop data="$HLC"
officecli add charts-stock.pptx /slide[5] --type chart \
--prop chartType=stock --prop title="labelrotation=-30" \
--prop labelrotation=-30 --prop legend=bottom \
--prop categories="$CATS" --prop data="$HLC"
officecli add charts-stock.pptx /slide[5] --type chart \
--prop chartType=stock --prop title="dispunits=hundreds" \
--prop dispunits=hundreds --prop legend=bottom \
--prop categories="$CATS" \
--prop data="High:13000,13500,14000,13800,14500;Low:11800,12200,12800,12500,13200;Close:12500,13000,13500,13200,14000"
```
**Features:** `axismin/max`, `majorunit`, `axistitle/cattitle`, `axisfont`, `axisnumfmt` (currency), `gridlines/minorGridlines`, `labelrotation`, `dispunits`
### Slide 6 — Series Styling
```bash
officecli add charts-stock.pptx /slide[6] --type chart \
--prop chartType=stock --prop title="colors" \
--prop colors="4472C4,ED7D31,70AD47" --prop legend=bottom \
--prop categories="$CATS" --prop data="$HLC"
officecli add charts-stock.pptx /slide[6] --type chart \
--prop chartType=stock --prop title="seriesoutline" \
--prop seriesoutline="000000:1" --prop legend=bottom \
--prop categories="$CATS" --prop data="$HLC"
officecli add charts-stock.pptx /slide[6] --type chart \
--prop chartType=stock --prop title="transparency=30" \
--prop transparency=30 --prop legend=bottom \
--prop categories="$CATS" --prop data="$HLC"
officecli add charts-stock.pptx /slide[6] --type chart \
--prop chartType=stock --prop title="seriesshadow" \
--prop seriesshadow="000000-5-45-3-50" --prop legend=bottom \
--prop categories="$CATS" --prop data="$HLC"
```
**Features:** `colors`, `seriesoutline`, `transparency`, `seriesshadow`
### Slide 7 — Backgrounds
```bash
officecli add charts-stock.pptx /slide[7] --type chart \
--prop chartType=stock --prop title="chartareafill + plotFill + borders" \
--prop chartareafill=FFF8E7 --prop plotFill=FAFAFA \
--prop chartborder="000000:1" --prop plotborder="CCCCCC:0.5" \
--prop legend=bottom --prop categories="$CATS" --prop data="$HLC"
officecli add charts-stock.pptx /slide[7] --type chart \
--prop chartType=stock --prop title="roundedcorners=true" \
--prop roundedcorners=true --prop chartborder="4472C4:2" \
--prop legend=bottom --prop categories="$CATS" --prop data="$HLC"
officecli add charts-stock.pptx /slide[7] --type chart \
--prop chartType=stock --prop title="plotFill=none" \
--prop plotFill=none --prop gridlines=none \
--prop legend=bottom --prop categories="$CATS" --prop data="$HLC"
officecli add charts-stock.pptx /slide[7] --type chart \
--prop chartType=stock --prop title="chartareafill=none" \
--prop chartareafill=none --prop legend=bottom \
--prop categories="$CATS" --prop data="$HLC"
```
**Features:** `chartareafill`, `plotFill`, `chartborder`, `plotborder`, `roundedcorners`
### Slide 8 — Presets and Per-Series Set
```bash
for p in minimal dark corporate; do
officecli add charts-stock.pptx /slide[8] --type chart \
--prop chartType=stock --prop preset=$p --prop title="preset=$p" \
--prop legend=bottom --prop categories="$CATS" --prop data="$HLC"
done
officecli add charts-stock.pptx /slide[8] --type chart \
--prop chartType=stock --prop title="chart-series Set name+color" \
--prop legend=bottom --prop categories="$CATS" --prop data="$HLC"
officecli set charts-stock.pptx "/slide[8]/chart[4]/series[1]" \
--prop name="H" --prop color=00AA00
officecli set charts-stock.pptx "/slide[8]/chart[4]/series[2]" \
--prop name="L" --prop color=C00000
officecli set charts-stock.pptx "/slide[8]/chart[4]/series[3]" \
--prop name="C" --prop color=4472C4
```
**Features:** `preset` (minimal/dark/corporate), `chart-series Set` (name/color per series)
## Complete Feature Coverage
| Feature | Slide |
|---------|-------|
| **chartType=stock**, HLC vs OHLC series order | 1 |
| **dataTable** | 1 |
| **hilowlines** (true or color:width) | 2 |
| **updownbars** (true or gapWidth:upColor:downColor) | 2 |
| **title.font/size/color/bold** | 3 |
| **legend** positions, legendFont, legend.overlay | 3 |
| **autotitledeleted** | 3 |
| **dataLabels:** value/series/category/none | 4 |
| **labelfont** | 4 |
| **axismin/max**, majorunit, axistitle/cattitle | 5 |
| **axisfont**, axisnumfmt (currency), gridlines | 5 |
| **labelrotation**, dispunits | 5 |
| **colors**, seriesoutline, transparency, seriesshadow | 6 |
| **chartareafill, plotFill, chartborder, plotborder, roundedcorners** | 7 |
| **preset** | 8 |
| **chart-series Set** | 8 |
## Inspect the Generated File
```bash
officecli query charts-stock.pptx chart
officecli get charts-stock.pptx "/slide[1]/chart[1]"
officecli get charts-stock.pptx "/slide[2]/chart[3]"
officecli get charts-stock.pptx "/slide[8]/chart[4]/series[1]"
```
Binary file not shown.
+174
View File
@@ -0,0 +1,174 @@
#!/usr/bin/env python3
"""
Stock Charts Showcase — High-Low-Close and OHLC variants.
Generates: charts-stock.pptx
Slide 1 Basic stock 3-series HLC + 4-series OHLC
Slide 2 Hi-low / up-down hilowlines, updownbars
Slide 3 Title & legend
Slide 4 Data labels
Slide 5 Axes min/max, gridlines, axisnumfmt (currency)
Slide 6 Series styling colors, transparency, outline, shadow
Slide 7 Backgrounds chartareafill, plotFill, chartborder
Slide 8 Presets & per-ser preset bundles + chart-series Set
SDK twin of charts-stock.sh (officecli CLI). Both produce an equivalent
charts-stock.pptx. This one drives the **officecli Python SDK**
(`pip install officecli-sdk`): one resident is started and every slide's shapes
and charts are shipped over the named pipe in `doc.batch(...)` round-trips.
Each item is the same `{"command","parent","type","props"}` dict you'd put in
an `officecli batch` list. Unsupported props are forwarded as-is: the resident
warns (forward-compat) without failing the batch.
Usage:
pip install officecli-sdk # plus the `officecli` binary on PATH
python3 charts-stock.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__)), "charts-stock.pptx")
# Quadrant boxes (top-left / top-right / bottom-left / bottom-right).
TL = {"x": "0.3in", "y": "1.05in", "width": "6.1in", "height": "3in"}
TR = {"x": "6.95in", "y": "1.05in", "width": "6.1in", "height": "3in"}
BL = {"x": "0.3in", "y": "4.25in", "width": "6.1in", "height": "3in"}
BR = {"x": "6.95in", "y": "4.25in", "width": "6.1in", "height": "3in"}
CATS = "Mon,Tue,Wed,Thu,Fri"
HLC = "High:130,135,140,138,145;Low:118,122,128,125,132;Close:125,130,135,132,140"
OHLC = "Open:120,128,130,135,138;High:130,135,140,138,145;Low:118,122,128,125,132;Close:125,130,135,132,140"
def slide_items(slide_idx, title, charts):
"""Build the batch items for one slide: an `add slide`, a title `shape`,
then one `add chart` per (box, props) pair. `slide_idx` is the 1-based index
of the slide AFTER it is added (used to anchor the title + charts)."""
items = [{"command": "add", "parent": "/", "type": "slide", "props": {}}]
items.append({"command": "add", "parent": f"/slide[{slide_idx}]", "type": "shape",
"props": {"text": title, "size": "24", "bold": "true",
"autoFit": "normal", "x": "0.5in", "y": "0.3in",
"width": "12.3in", "height": "0.6in"}})
for box, props in charts:
items.append({"command": "add", "parent": f"/slide[{slide_idx}]", "type": "chart",
"props": {**box, **props}})
return items
print(f"Building {FILE} ...")
with officecli.create(FILE, "--force") as doc:
# ---- Slide 1: Basic stock — HLC vs OHLC ------------------------------
doc.batch(slide_items(1, "Basic stock — High-Low-Close vs Open-High-Low-Close", [
(TL, {"chartType": "stock", "title": "HLC", "legend": "bottom", "categories": CATS, "data": HLC}),
(TR, {"chartType": "stock", "title": "OHLC", "legend": "bottom", "categories": CATS, "data": OHLC}),
(BL, {"chartType": "stock", "title": "HLC + dataTable=true", "dataTable": "true",
"legend": "bottom", "categories": CATS, "data": HLC}),
(BR, {"chartType": "stock", "title": "OHLC + dataTable=true", "dataTable": "true",
"legend": "bottom", "categories": CATS, "data": OHLC}),
]))
# ---- Slide 2: hilowlines & updownbars --------------------------------
doc.batch(slide_items(2, "hilowlines & updownbars", [
(TL, {"chartType": "stock", "title": "hilowlines=true", "hilowlines": "true",
"legend": "bottom", "categories": CATS, "data": HLC}),
(TR, {"chartType": "stock", "title": "hilowlines=808080:0.5", "hilowlines": "808080:0.5",
"legend": "bottom", "categories": CATS, "data": HLC}),
(BL, {"chartType": "stock", "title": "updownbars=true (OHLC)", "updownbars": "true",
"legend": "bottom", "categories": CATS, "data": OHLC}),
(BR, {"chartType": "stock", "title": "updownbars=150:00AA00:FF0000",
"updownbars": "150:00AA00:FF0000", "legend": "bottom", "categories": CATS, "data": OHLC}),
]))
# ---- Slide 3: Title & legend -----------------------------------------
doc.batch(slide_items(3, "Title & legend", [
(TL, {"chartType": "stock", "title": "Styled title", "title.font": "Georgia", "title.size": "20",
"title.color": "4472C4", "title.bold": "true", "legend": "bottom", "categories": CATS, "data": HLC}),
(TR, {"chartType": "stock", "title": "legend=top + legendFont", "legend": "top",
"legendFont": "10:333333:Calibri", "categories": CATS, "data": HLC}),
(BL, {"chartType": "stock", "title": "legend.overlay=true", "legend": "topRight",
"legend.overlay": "true", "categories": CATS, "data": HLC}),
(BR, {"chartType": "stock", "autotitledeleted": "true", "legend": "none", "categories": CATS, "data": HLC}),
]))
# ---- Slide 4: Data labels — flags + labelfont ------------------------
doc.batch(slide_items(4, "Data labels — flags + labelfont", [
(TL, {"chartType": "stock", "title": "dataLabels=value", "dataLabels": "value",
"labelfont": "9:333333:Calibri", "legend": "bottom", "categories": CATS, "data": HLC}),
(TR, {"chartType": "stock", "title": "value,series", "dataLabels": "value,series",
"legend": "bottom", "categories": CATS, "data": HLC}),
(BL, {"chartType": "stock", "title": "value,category", "dataLabels": "value,category",
"legend": "bottom", "categories": CATS, "data": HLC}),
(BR, {"chartType": "stock", "title": "dataLabels=none", "dataLabels": "none",
"legend": "bottom", "categories": CATS, "data": HLC}),
]))
# ---- Slide 5: Axes — min/max, gridlines, currency format -------------
doc.batch(slide_items(5, "Axes — min/max, gridlines, currency format", [
(TL, {"chartType": "stock", "title": "min/max + titles", "axismin": "100", "axismax": "160",
"majorunit": "10", "axistitle": "Price (USD)", "cattitle": "Day",
"axisfont": "10:333333:Calibri", "axisnumfmt": "$#,##0.00",
"legend": "bottom", "categories": CATS, "data": HLC}),
(TR, {"chartType": "stock", "title": "gridlines + minorGridlines",
"gridlines": "E0E0E0:0.3", "minorGridlines": "F0F0F0:0.25",
"legend": "bottom", "categories": CATS, "data": HLC}),
(BL, {"chartType": "stock", "title": "labelrotation=-30", "labelrotation": "-30",
"legend": "bottom", "categories": CATS, "data": HLC}),
(BR, {"chartType": "stock", "title": "dispunits=hundreds", "dispunits": "hundreds",
"legend": "bottom", "categories": CATS,
"data": "High:13000,13500,14000,13800,14500;Low:11800,12200,12800,12500,13200;Close:12500,13000,13500,13200,14000"}),
]))
# ---- Slide 6: Series styling — colors, transparency, outline, shadow -
doc.batch(slide_items(6, "Series styling — colors, transparency, outline, shadow", [
(TL, {"chartType": "stock", "title": "colors", "colors": "4472C4,ED7D31,70AD47",
"legend": "bottom", "categories": CATS, "data": HLC}),
(TR, {"chartType": "stock", "title": "seriesoutline", "seriesoutline": "000000:1",
"legend": "bottom", "categories": CATS, "data": HLC}),
(BL, {"chartType": "stock", "title": "transparency=30", "transparency": "30",
"legend": "bottom", "categories": CATS, "data": HLC}),
(BR, {"chartType": "stock", "title": "seriesshadow", "seriesshadow": "000000-5-45-3-50",
"legend": "bottom", "categories": CATS, "data": HLC}),
]))
# ---- Slide 7: Backgrounds — chartareafill, plotFill, borders ---------
doc.batch(slide_items(7, "Backgrounds — chartareafill, plotFill, chartborder, roundedcorners", [
(TL, {"chartType": "stock", "title": "chartareafill + plotFill + borders",
"chartareafill": "FFF8E7", "plotFill": "FAFAFA", "chartborder": "000000:1",
"plotborder": "CCCCCC:0.5", "legend": "bottom", "categories": CATS, "data": HLC}),
(TR, {"chartType": "stock", "title": "roundedcorners=true", "roundedcorners": "true",
"chartborder": "4472C4:2", "legend": "bottom", "categories": CATS, "data": HLC}),
(BL, {"chartType": "stock", "title": "plotFill=none", "plotFill": "none", "gridlines": "none",
"legend": "bottom", "categories": CATS, "data": HLC}),
(BR, {"chartType": "stock", "title": "chartareafill=none", "chartareafill": "none",
"legend": "bottom", "categories": CATS, "data": HLC}),
]))
# ---- Slide 8: Presets & per-series Set -------------------------------
presets = ["minimal", "dark", "corporate"]
charts8 = [(box, {"chartType": "stock", "preset": p, "title": f"preset={p}", "legend": "bottom",
"categories": CATS, "data": HLC})
for box, p in zip([TL, TR, BL], presets)]
charts8.append((BR, {"chartType": "stock", "title": "chart-series Set name+color", "legend": "bottom",
"categories": CATS, "data": HLC}))
doc.batch(slide_items(8, "Presets & per-series Set", charts8))
# chart-series Set on the 4th chart's three series (after the chart exists).
doc.batch([
{"command": "set", "path": "/slide[8]/chart[4]/series[1]", "props": {"name": "H", "color": "00AA00"}},
{"command": "set", "path": "/slide[8]/chart[4]/series[2]", "props": {"name": "L", "color": "C00000"}},
{"command": "set", "path": "/slide[8]/chart[4]/series[3]", "props": {"name": "C", "color": "4472C4"}},
])
print(" built 8 slides")
print(f"Generated: {FILE}")
+101
View File
@@ -0,0 +1,101 @@
#!/bin/bash
# Stock Charts Showcase — High-Low-Close and OHLC variants.
# Generates: charts-stock.pptx
#
# Slide 1 Basic stock 3-series HLC + 4-series OHLC
# Slide 2 Hi-low / up-down hilowlines, updownbars
# Slide 3 Title & legend
# Slide 4 Data labels
# Slide 5 Axes min/max, gridlines, axisnumfmt (currency)
# Slide 6 Series styling colors, transparency, outline, shadow
# Slide 7 Backgrounds chartareafill, plotFill, chartborder
# Slide 8 Presets & per-ser preset bundles + chart-series Set
#
# CLI twin of charts-stock.py (officecli Python SDK).
# Usage: ./charts-stock.sh [officecli path]
# NOTE: intentionally NO `set -e`. Like the SDK twin's doc.batch, this script
# tolerates forward-compat 'UNSUPPORTED props' warnings (officecli exit 2) and
# keeps building so the full document is produced.
CLI="${1:-officecli}"
FILE="$(dirname "$0")/charts-stock.pptx"
# shared geometry + data
CATS="Mon,Tue,Wed,Thu,Fri"
HLC="High:130,135,140,138,145;Low:118,122,128,125,132;Close:125,130,135,132,140"
OHLC="Open:120,128,130,135,138;High:130,135,140,138,145;Low:118,122,128,125,132;Close:125,130,135,132,140"
rm -f "$FILE"
$CLI create "$FILE"
$CLI open "$FILE"
# ==================== Slide 1: Basic stock — HLC vs OHLC ====================
$CLI add "$FILE" / --type slide
$CLI add "$FILE" /slide[1] --type shape --prop text="Basic stock — High-Low-Close vs Open-High-Low-Close" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
$CLI add "$FILE" /slide[1] --type chart --prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=stock --prop title=HLC --prop legend=bottom --prop categories="$CATS" --prop data="$HLC"
$CLI add "$FILE" /slide[1] --type chart --prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=stock --prop title=OHLC --prop legend=bottom --prop categories="$CATS" --prop data="$OHLC"
$CLI add "$FILE" /slide[1] --type chart --prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=stock --prop title="HLC + dataTable=true" --prop dataTable=true --prop legend=bottom --prop categories="$CATS" --prop data="$HLC"
$CLI add "$FILE" /slide[1] --type chart --prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=stock --prop title="OHLC + dataTable=true" --prop dataTable=true --prop legend=bottom --prop categories="$CATS" --prop data="$OHLC"
# ==================== Slide 2: hilowlines & updownbars ====================
$CLI add "$FILE" / --type slide
$CLI add "$FILE" /slide[2] --type shape --prop text="hilowlines & updownbars" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
$CLI add "$FILE" /slide[2] --type chart --prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=stock --prop title="hilowlines=true" --prop hilowlines=true --prop legend=bottom --prop categories="$CATS" --prop data="$HLC"
$CLI add "$FILE" /slide[2] --type chart --prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=stock --prop title="hilowlines=808080:0.5" --prop hilowlines=808080:0.5 --prop legend=bottom --prop categories="$CATS" --prop data="$HLC"
$CLI add "$FILE" /slide[2] --type chart --prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=stock --prop title="updownbars=true (OHLC)" --prop updownbars=true --prop legend=bottom --prop categories="$CATS" --prop data="$OHLC"
$CLI add "$FILE" /slide[2] --type chart --prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=stock --prop title="updownbars=150:00AA00:FF0000" --prop updownbars=150:00AA00:FF0000 --prop legend=bottom --prop categories="$CATS" --prop data="$OHLC"
# ==================== Slide 3: Title & legend ====================
$CLI add "$FILE" / --type slide
$CLI add "$FILE" /slide[3] --type shape --prop text="Title & legend" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
$CLI add "$FILE" /slide[3] --type chart --prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=stock --prop title="Styled title" --prop title.font=Georgia --prop title.size=20 --prop title.color=4472C4 --prop title.bold=true --prop legend=bottom --prop categories="$CATS" --prop data="$HLC"
$CLI add "$FILE" /slide[3] --type chart --prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=stock --prop title="legend=top + legendFont" --prop legend=top --prop legendFont=10:333333:Calibri --prop categories="$CATS" --prop data="$HLC"
$CLI add "$FILE" /slide[3] --type chart --prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=stock --prop title="legend.overlay=true" --prop legend=topRight --prop legend.overlay=true --prop categories="$CATS" --prop data="$HLC"
$CLI add "$FILE" /slide[3] --type chart --prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=stock --prop autotitledeleted=true --prop legend=none --prop categories="$CATS" --prop data="$HLC"
# ==================== Slide 4: Data labels — flags + labelfont ====================
$CLI add "$FILE" / --type slide
$CLI add "$FILE" /slide[4] --type shape --prop text="Data labels — flags + labelfont" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
$CLI add "$FILE" /slide[4] --type chart --prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=stock --prop title="dataLabels=value" --prop dataLabels=value --prop labelfont=9:333333:Calibri --prop legend=bottom --prop categories="$CATS" --prop data="$HLC"
$CLI add "$FILE" /slide[4] --type chart --prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=stock --prop title="value,series" --prop dataLabels=value,series --prop legend=bottom --prop categories="$CATS" --prop data="$HLC"
$CLI add "$FILE" /slide[4] --type chart --prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=stock --prop title="value,category" --prop dataLabels=value,category --prop legend=bottom --prop categories="$CATS" --prop data="$HLC"
$CLI add "$FILE" /slide[4] --type chart --prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=stock --prop title="dataLabels=none" --prop dataLabels=none --prop legend=bottom --prop categories="$CATS" --prop data="$HLC"
# ==================== Slide 5: Axes — min/max, gridlines, currency format ====================
$CLI add "$FILE" / --type slide
$CLI add "$FILE" /slide[5] --type shape --prop text="Axes — min/max, gridlines, currency format" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
$CLI add "$FILE" /slide[5] --type chart --prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=stock --prop title="min/max + titles" --prop axismin=100 --prop axismax=160 --prop majorunit=10 --prop axistitle="Price (USD)" --prop cattitle=Day --prop axisfont=10:333333:Calibri --prop axisnumfmt="\$#,##0.00" --prop legend=bottom --prop categories="$CATS" --prop data="$HLC"
$CLI add "$FILE" /slide[5] --type chart --prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=stock --prop title="gridlines + minorGridlines" --prop gridlines=E0E0E0:0.3 --prop minorGridlines=F0F0F0:0.25 --prop legend=bottom --prop categories="$CATS" --prop data="$HLC"
$CLI add "$FILE" /slide[5] --type chart --prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=stock --prop title="labelrotation=-30" --prop labelrotation=-30 --prop legend=bottom --prop categories="$CATS" --prop data="$HLC"
$CLI add "$FILE" /slide[5] --type chart --prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=stock --prop title="dispunits=hundreds" --prop dispunits=hundreds --prop legend=bottom --prop categories="$CATS" --prop data="High:13000,13500,14000,13800,14500;Low:11800,12200,12800,12500,13200;Close:12500,13000,13500,13200,14000"
# ==================== Slide 6: Series styling — colors, transparency, outline, shadow ====================
$CLI add "$FILE" / --type slide
$CLI add "$FILE" /slide[6] --type shape --prop text="Series styling — colors, transparency, outline, shadow" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
$CLI add "$FILE" /slide[6] --type chart --prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=stock --prop title="colors" --prop colors=4472C4,ED7D31,70AD47 --prop legend=bottom --prop categories="$CATS" --prop data="$HLC"
$CLI add "$FILE" /slide[6] --type chart --prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=stock --prop title="seriesoutline" --prop seriesoutline=000000:1 --prop legend=bottom --prop categories="$CATS" --prop data="$HLC"
$CLI add "$FILE" /slide[6] --type chart --prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=stock --prop title="transparency=30" --prop transparency=30 --prop legend=bottom --prop categories="$CATS" --prop data="$HLC"
$CLI add "$FILE" /slide[6] --type chart --prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=stock --prop title="seriesshadow" --prop seriesshadow=000000-5-45-3-50 --prop legend=bottom --prop categories="$CATS" --prop data="$HLC"
# ==================== Slide 7: Backgrounds — chartareafill, plotFill, chartborder, roundedcorners ====================
$CLI add "$FILE" / --type slide
$CLI add "$FILE" /slide[7] --type shape --prop text="Backgrounds — chartareafill, plotFill, chartborder, roundedcorners" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
$CLI add "$FILE" /slide[7] --type chart --prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=stock --prop title="chartareafill + plotFill + borders" --prop chartareafill=FFF8E7 --prop plotFill=FAFAFA --prop chartborder=000000:1 --prop plotborder=CCCCCC:0.5 --prop legend=bottom --prop categories="$CATS" --prop data="$HLC"
$CLI add "$FILE" /slide[7] --type chart --prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=stock --prop title="roundedcorners=true" --prop roundedcorners=true --prop chartborder=4472C4:2 --prop legend=bottom --prop categories="$CATS" --prop data="$HLC"
$CLI add "$FILE" /slide[7] --type chart --prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=stock --prop title="plotFill=none" --prop plotFill=none --prop gridlines=none --prop legend=bottom --prop categories="$CATS" --prop data="$HLC"
$CLI add "$FILE" /slide[7] --type chart --prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=stock --prop title="chartareafill=none" --prop chartareafill=none --prop legend=bottom --prop categories="$CATS" --prop data="$HLC"
# ==================== Slide 8: Presets & per-series Set ====================
$CLI add "$FILE" / --type slide
$CLI add "$FILE" /slide[8] --type shape --prop text="Presets & per-series Set" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
$CLI add "$FILE" /slide[8] --type chart --prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=stock --prop preset=minimal --prop title="preset=minimal" --prop legend=bottom --prop categories="$CATS" --prop data="$HLC"
$CLI add "$FILE" /slide[8] --type chart --prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=stock --prop preset=dark --prop title="preset=dark" --prop legend=bottom --prop categories="$CATS" --prop data="$HLC"
$CLI add "$FILE" /slide[8] --type chart --prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=stock --prop preset=corporate --prop title="preset=corporate" --prop legend=bottom --prop categories="$CATS" --prop data="$HLC"
$CLI add "$FILE" /slide[8] --type chart --prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=stock --prop title="chart-series Set name+color" --prop legend=bottom --prop categories="$CATS" --prop data="$HLC"
$CLI set "$FILE" "/slide[8]/chart[4]/series[1]" --prop name=H --prop color=00AA00
$CLI set "$FILE" "/slide[8]/chart[4]/series[2]" --prop name=L --prop color=C00000
$CLI set "$FILE" "/slide[8]/chart[4]/series[3]" --prop name=C --prop color=4472C4
$CLI close "$FILE"
$CLI validate "$FILE"
echo "Generated: $FILE"
+258
View File
@@ -0,0 +1,258 @@
# Waterfall Charts Showcase
This demo consists of three files that work together:
- **charts-waterfall.py** — Python script that calls `officecli` commands to generate the deck.
- **charts-waterfall.pptx** — The generated 8-slide deck (4 charts per slide, with one hero full-slide chart on slide 7).
- **charts-waterfall.md** — This file. Maps each slide to the features it demonstrates.
## Regenerate
```bash
cd examples/ppt/charts
python3 charts-waterfall.py
# → charts-waterfall.pptx
```
In a waterfall chart, positive values are "increase" bars, negative values are "decrease" bars, and the first/last values are typically "total" bars. The `increaseColor`, `decreaseColor`, and `totalColor` properties control each segment type.
## Chart Slides
### Slide 1 — Basic Waterfall (Default Colors)
```bash
CATS="Start,Q1,Q2,Q3,Q4,End"
D="Cashflow:100,30,-15,40,-10,145"
officecli add charts-waterfall.pptx /slide[1] --type chart \
--prop chartType=waterfall --prop title="Default colors" --prop legend=none \
--prop categories="$CATS" --prop data="$D" \
--prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in
officecli add charts-waterfall.pptx /slide[1] --type chart \
--prop chartType=waterfall --prop title="Default + dataTable" \
--prop dataTable=true --prop legend=none \
--prop categories="$CATS" --prop data="$D" \
--prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in
officecli add charts-waterfall.pptx /slide[1] --type chart \
--prop chartType=waterfall --prop title="With legend" --prop legend=bottom \
--prop categories="$CATS" --prop data="$D" \
--prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in
# 7-step P&L walk
officecli add charts-waterfall.pptx /slide[1] --type chart \
--prop chartType=waterfall --prop title="7-step P&L" --prop legend=none \
--prop categories="Open,Revenue,COGS,Opex,R&D,Tax,Net" \
--prop data="P&L:100,80,-30,-25,-15,-10,100" \
--prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in
```
**Features:** `chartType=waterfall`, `legend`, `dataTable`, multi-step P&L data
### Slide 2 — Color Schemes
```bash
# green/red/blue (standard traffic-light colors)
officecli add charts-waterfall.pptx /slide[2] --type chart \
--prop chartType=waterfall --prop title="green/red/blue (default-ish)" \
--prop increaseColor=00AA00 --prop decreaseColor=FF0000 \
--prop totalColor=4472C4 --prop legend=none \
--prop categories="$CATS" --prop data="$D"
# Corporate teal/orange/navy
officecli add charts-waterfall.pptx /slide[2] --type chart \
--prop chartType=waterfall --prop title="corporate (teal/orange/navy)" \
--prop increaseColor=008080 --prop decreaseColor=D86600 \
--prop totalColor=1F3864 --prop legend=none \
--prop categories="$CATS" --prop data="$D"
# Monochrome grey scale
officecli add charts-waterfall.pptx /slide[2] --type chart \
--prop chartType=waterfall --prop title="monochrome" \
--prop increaseColor=606060 --prop decreaseColor=A0A0A0 \
--prop totalColor=303030 --prop legend=none \
--prop categories="$CATS" --prop data="$D"
# Vivid green/red/blue
officecli add charts-waterfall.pptx /slide[2] --type chart \
--prop chartType=waterfall --prop title="vivid" \
--prop increaseColor=00C853 --prop decreaseColor=D50000 \
--prop totalColor=2962FF --prop legend=none \
--prop categories="$CATS" --prop data="$D"
```
**Features:** `increaseColor` (positive bars), `decreaseColor` (negative bars), `totalColor` (first/last total bars)
### Slide 3 — Title and Legend
```bash
officecli add charts-waterfall.pptx /slide[3] --type chart \
--prop chartType=waterfall --prop title="Styled title" \
--prop title.font=Georgia --prop title.size=20 \
--prop title.color=4472C4 --prop title.bold=true \
--prop legend=bottom --prop categories="$CATS" --prop data="$D"
officecli add charts-waterfall.pptx /slide[3] --type chart \
--prop chartType=waterfall --prop title="legend=top + legendFont" \
--prop legend=top --prop legendFont="10:333333:Calibri" \
--prop categories="$CATS" --prop data="$D"
officecli add charts-waterfall.pptx /slide[3] --type chart \
--prop chartType=waterfall --prop title="legend.overlay=true" \
--prop legend=topRight --prop legend.overlay=true \
--prop categories="$CATS" --prop data="$D"
officecli add charts-waterfall.pptx /slide[3] --type chart \
--prop chartType=waterfall --prop autotitledeleted=true --prop legend=none \
--prop categories="$CATS" --prop data="$D"
```
**Features:** `title.font/size/color/bold`, `legend` positions, `legendFont`, `legend.overlay`, `autotitledeleted`
### Slide 4 — Data Labels
```bash
officecli add charts-waterfall.pptx /slide[4] --type chart \
--prop chartType=waterfall --prop title="value" \
--prop dataLabels=value --prop labelfont="10:333333:Calibri" --prop legend=none \
--prop categories="$CATS" --prop data="$D"
officecli add charts-waterfall.pptx /slide[4] --type chart \
--prop chartType=waterfall --prop title="value,category" \
--prop dataLabels="value,category" --prop legend=none \
--prop categories="$CATS" --prop data="$D"
officecli add charts-waterfall.pptx /slide[4] --type chart \
--prop chartType=waterfall --prop title="value @ outsideEnd" \
--prop dataLabels=value --prop labelPos=outsideEnd --prop legend=none \
--prop categories="$CATS" --prop data="$D"
officecli add charts-waterfall.pptx /slide[4] --type chart \
--prop chartType=waterfall --prop title="dataLabels=none" \
--prop dataLabels=none --prop legend=none \
--prop categories="$CATS" --prop data="$D"
```
**Features:** `dataLabels` (value/category/none or combined), `labelPos` (outsideEnd), `labelfont`
### Slide 5 — Axes
```bash
officecli add charts-waterfall.pptx /slide[5] --type chart \
--prop chartType=waterfall --prop title="min/max + titles" \
--prop axismin=0 --prop axismax=200 --prop majorunit=50 \
--prop axistitle="USD" --prop cattitle="Phase" \
--prop axisfont="10:333333:Calibri" --prop axisnumfmt='$#,##0' \
--prop legend=none --prop categories="$CATS" --prop data="$D"
officecli add charts-waterfall.pptx /slide[5] --type chart \
--prop chartType=waterfall --prop title="gridlines + minorGridlines" \
--prop gridlines="E0E0E0:0.3" --prop minorGridlines="F0F0F0:0.25" \
--prop legend=none --prop categories="$CATS" --prop data="$D"
officecli add charts-waterfall.pptx /slide[5] --type chart \
--prop chartType=waterfall --prop title="labelrotation=-30" \
--prop labelrotation=-30 --prop legend=none \
--prop categories="$CATS" --prop data="$D"
officecli add charts-waterfall.pptx /slide[5] --type chart \
--prop chartType=waterfall --prop title="dispunits=thousands" \
--prop dispunits=thousands --prop legend=none \
--prop categories="$CATS" \
--prop data="USD:100000,30000,-15000,40000,-10000,145000"
```
**Features:** `axismin/max`, `majorunit`, `axistitle/cattitle`, `axisfont`, `axisnumfmt` (currency), `gridlines/minorGridlines`, `labelrotation`, `dispunits`
### Slide 6 — Backgrounds
```bash
officecli add charts-waterfall.pptx /slide[6] --type chart \
--prop chartType=waterfall --prop title="chartareafill + chartborder" \
--prop chartareafill=FFF8E7 --prop chartborder="000000:1" \
--prop plotFill=FAFAFA --prop plotborder="CCCCCC:0.5" \
--prop legend=none --prop categories="$CATS" --prop data="$D"
officecli add charts-waterfall.pptx /slide[6] --type chart \
--prop chartType=waterfall --prop title="roundedcorners=true" \
--prop roundedcorners=true --prop chartborder="4472C4:2" \
--prop legend=none --prop categories="$CATS" --prop data="$D"
officecli add charts-waterfall.pptx /slide[6] --type chart \
--prop chartType=waterfall --prop title="plotFill=none" \
--prop plotFill=none --prop gridlines=none \
--prop legend=none --prop categories="$CATS" --prop data="$D"
officecli add charts-waterfall.pptx /slide[6] --type chart \
--prop chartType=waterfall --prop title="chartareafill=none" \
--prop chartareafill=none --prop legend=none \
--prop categories="$CATS" --prop data="$D"
```
**Features:** `chartareafill`, `plotFill`, `chartborder`, `plotborder`, `roundedcorners`, `gridlines=none`
### Slide 7 — Hero Cashflow Waterfall (Full Slide)
A real-world FY24 P&L walk on a full-slide canvas with styled title, custom colors, and labeled data points.
```bash
officecli add charts-waterfall.pptx /slide[7] --type chart \
--prop chartType=waterfall --prop title="FY24 P&L Walk" \
--prop title.font=Helvetica --prop title.size=22 \
--prop title.bold=true --prop title.color=1F3864 \
--prop increaseColor=00C853 --prop decreaseColor=D50000 \
--prop totalColor=2962FF \
--prop dataLabels="value,category" --prop labelPos=outsideEnd \
--prop labelfont="11:333333:Helvetica" \
--prop axistitle="USD" --prop axisnumfmt='$#,##0' \
--prop gridlines="E0E0E0:0.3" --prop legend=none \
--prop categories="Open,Revenue,COGS,Opex,R&D,Tax,Net" \
--prop data="P&L:100,80,-30,-25,-15,-10,100" \
--prop x=1in --prop y=1.05in --prop width=11.3in --prop height=6.2in
```
**Features:** Full-slide hero layout, combined `increaseColor/decreaseColor/totalColor`, full label suite, custom `title.font/size/bold/color`
### Slide 8 — Presets
```bash
for p in minimal dark corporate colorful; do
officecli add charts-waterfall.pptx /slide[8] --type chart \
--prop chartType=waterfall --prop preset=$p --prop title="preset=$p" \
--prop legend=none --prop categories="$CATS" --prop data="$D"
done
```
**Features:** `preset` (minimal/dark/corporate/colorful)
## Complete Feature Coverage
| Feature | Slide |
|---------|-------|
| **chartType=waterfall** | 1 |
| **dataTable**, **legend** | 1 |
| **increaseColor** (positive bars) | 2 |
| **decreaseColor** (negative bars) | 2 |
| **totalColor** (total/subtotal bars) | 2 |
| **title.font/size/color/bold** | 3 |
| **legend** positions, legendFont, legend.overlay | 3 |
| **autotitledeleted** | 3 |
| **dataLabels:** value/category/none + combined | 4 |
| **labelPos** (outsideEnd), **labelfont** | 4 |
| **axismin/max**, majorunit, axistitle/cattitle | 5 |
| **axisfont**, axisnumfmt (currency), gridlines | 5 |
| **labelrotation**, dispunits | 5 |
| **chartareafill**, plotFill, chartborder, plotborder | 6 |
| **roundedcorners**, gridlines=none | 6 |
| **Hero layout** (full-slide, combined features) | 7 |
| **preset** (minimal/dark/corporate/colorful) | 8 |
## Inspect the Generated File
```bash
officecli query charts-waterfall.pptx chart
officecli get charts-waterfall.pptx "/slide[1]/chart[1]"
officecli get charts-waterfall.pptx "/slide[2]/chart[1]"
officecli get charts-waterfall.pptx "/slide[7]/chart[1]"
```
Binary file not shown.
+195
View File
@@ -0,0 +1,195 @@
#!/usr/bin/env python3
"""
Waterfall Charts Showcase — increaseColor / decreaseColor / totalColor.
Generates: charts-waterfall.pptx
Slide 1 Basic default colors, single dataset
Slide 2 Color schemes increaseColor / decreaseColor / totalColor combinations
Slide 3 Title & legend
Slide 4 Data labels
Slide 5 Axes min/max, gridlines, axisnumfmt (currency)
Slide 6 Backgrounds chartareafill, plotFill, chartborder, roundedcorners
Slide 7 Larger story a real cashflow waterfall with labels
Slide 8 Presets
SDK twin of charts-waterfall.sh (officecli CLI). Both produce an equivalent
charts-waterfall.pptx. This one drives the **officecli Python SDK**
(`pip install officecli-sdk`): one resident is started and every slide, title
shape and chart is shipped over the named pipe in a single `doc.batch(...)`
round-trip. Each item is the same `{"command","parent","type","props"}` dict
you'd put in an `officecli batch` list.
Usage:
pip install officecli-sdk # plus the `officecli` binary on PATH
python3 charts-waterfall.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__)), "charts-waterfall.pptx")
# Quadrant + hero layout boxes (re-used across slides)
TL = {"x": "0.3in", "y": "1.05in", "width": "6.1in", "height": "3in"}
TR = {"x": "6.95in", "y": "1.05in", "width": "6.1in", "height": "3in"}
BL = {"x": "0.3in", "y": "4.25in", "width": "6.1in", "height": "3in"}
BR = {"x": "6.95in", "y": "4.25in", "width": "6.1in", "height": "3in"}
HERO = {"x": "1in", "y": "1.05in", "width": "11.3in", "height": "6.2in"}
CATS = "Start,Q1,Q2,Q3,Q4,End"
D = "Cashflow:100,30,-15,40,-10,145"
CATS_LONG = "Open,Revenue,COGS,Opex,R&D,Tax,Net"
D_LONG = "P&L:100,80,-30,-25,-15,-10,100"
# --- batch-item builders ----------------------------------------------------
_state = {"slide": 0}
def new_slide(title):
"""Add a slide + its bold title shape; returns the two batch items."""
_state["slide"] += 1
n = _state["slide"]
return [
{"command": "add", "parent": "/", "type": "slide", "props": {}},
{"command": "add", "parent": f"/slide[{n}]", "type": "shape",
"props": {"text": title, "size": "24", "bold": "true", "autoFit": "normal",
"x": "0.5in", "y": "0.3in", "width": "12.3in", "height": "0.6in"}},
]
def ch(box, props):
"""One `add chart` item on the current slide in batch-shape."""
n = _state["slide"]
return {"command": "add", "parent": f"/slide[{n}]", "type": "chart",
"props": {**box, **props}}
print(f"Building {FILE} ...")
with officecli.create(FILE, "--force") as doc:
items = []
# ---- Slide 1: Basic waterfall — default colors ----
items += new_slide("Basic waterfall — default colors")
items += [
ch(TL, {"chartType": "waterfall", "title": "Default colors", "legend": "none",
"categories": CATS, "data": D}),
ch(TR, {"chartType": "waterfall", "title": "Default + dataTable", "dataTable": "true",
"legend": "none", "categories": CATS, "data": D}),
ch(BL, {"chartType": "waterfall", "title": "With legend", "legend": "bottom",
"categories": CATS, "data": D}),
ch(BR, {"chartType": "waterfall", "title": "7-step P&L", "legend": "none",
"categories": CATS_LONG, "data": D_LONG}),
]
# ---- Slide 2: Color schemes — increaseColor / decreaseColor / totalColor ----
items += new_slide("Color schemes — increaseColor / decreaseColor / totalColor")
items += [
ch(TL, {"chartType": "waterfall", "title": "green/red/blue (default-ish)",
"increaseColor": "00AA00", "decreaseColor": "FF0000", "totalColor": "4472C4",
"legend": "none", "categories": CATS, "data": D}),
ch(TR, {"chartType": "waterfall", "title": "corporate (teal/orange/navy)",
"increaseColor": "008080", "decreaseColor": "D86600", "totalColor": "1F3864",
"legend": "none", "categories": CATS, "data": D}),
ch(BL, {"chartType": "waterfall", "title": "monochrome",
"increaseColor": "606060", "decreaseColor": "A0A0A0", "totalColor": "303030",
"legend": "none", "categories": CATS, "data": D}),
ch(BR, {"chartType": "waterfall", "title": "vivid",
"increaseColor": "00C853", "decreaseColor": "D50000", "totalColor": "2962FF",
"legend": "none", "categories": CATS, "data": D}),
]
# ---- Slide 3: Title & legend ----
items += new_slide("Title & legend")
items += [
ch(TL, {"chartType": "waterfall", "title": "Styled title", "title.font": "Georgia",
"title.size": "20", "title.color": "4472C4", "title.bold": "true",
"legend": "bottom", "categories": CATS, "data": D}),
ch(TR, {"chartType": "waterfall", "title": "legend=top + legendFont", "legend": "top",
"legendFont": "10:333333:Calibri", "categories": CATS, "data": D}),
ch(BL, {"chartType": "waterfall", "title": "legend.overlay=true", "legend": "topRight",
"legend.overlay": "true", "categories": CATS, "data": D}),
ch(BR, {"chartType": "waterfall", "autotitledeleted": "true", "legend": "none",
"categories": CATS, "data": D}),
]
# ---- Slide 4: Data labels — flags + labelfont ----
items += new_slide("Data labels — flags + labelfont")
items += [
ch(TL, {"chartType": "waterfall", "title": "value", "dataLabels": "value",
"labelfont": "10:333333:Calibri", "legend": "none", "categories": CATS, "data": D}),
ch(TR, {"chartType": "waterfall", "title": "value,category", "dataLabels": "value,category",
"legend": "none", "categories": CATS, "data": D}),
ch(BL, {"chartType": "waterfall", "title": "value @ outsideEnd", "dataLabels": "value",
"labelPos": "outsideEnd", "legend": "none", "categories": CATS, "data": D}),
ch(BR, {"chartType": "waterfall", "title": "dataLabels=none", "dataLabels": "none",
"legend": "none", "categories": CATS, "data": D}),
]
# ---- Slide 5: Axes — min/max, titles, gridlines, axisnumfmt ----
items += new_slide("Axes — min/max, titles, gridlines, axisnumfmt")
items += [
ch(TL, {"chartType": "waterfall", "title": "min/max + titles", "axismin": "0", "axismax": "200",
"majorunit": "50", "axistitle": "USD", "cattitle": "Phase",
"axisfont": "10:333333:Calibri", "axisnumfmt": "$#,##0",
"legend": "none", "categories": CATS, "data": D}),
ch(TR, {"chartType": "waterfall", "title": "gridlines + minorGridlines",
"gridlines": "E0E0E0:0.3", "minorGridlines": "F0F0F0:0.25",
"legend": "none", "categories": CATS, "data": D}),
ch(BL, {"chartType": "waterfall", "title": "labelrotation=-30", "labelrotation": "-30",
"legend": "none", "categories": CATS, "data": D}),
ch(BR, {"chartType": "waterfall", "title": "dispunits=thousands", "dispunits": "thousands",
"legend": "none", "categories": CATS,
"data": "USD:100000,30000,-15000,40000,-10000,145000"}),
]
# ---- Slide 6: Backgrounds — chartareafill, plotFill, chartborder, roundedcorners ----
items += new_slide("Backgrounds — chartareafill, plotFill, chartborder, roundedcorners")
items += [
ch(TL, {"chartType": "waterfall", "title": "chartareafill + chartborder",
"chartareafill": "FFF8E7", "chartborder": "000000:1", "plotFill": "FAFAFA",
"plotborder": "CCCCCC:0.5", "legend": "none", "categories": CATS, "data": D}),
ch(TR, {"chartType": "waterfall", "title": "roundedcorners=true", "roundedcorners": "true",
"chartborder": "4472C4:2", "legend": "none", "categories": CATS, "data": D}),
ch(BL, {"chartType": "waterfall", "title": "plotFill=none", "plotFill": "none",
"gridlines": "none", "legend": "none", "categories": CATS, "data": D}),
ch(BR, {"chartType": "waterfall", "title": "chartareafill=none", "chartareafill": "none",
"legend": "none", "categories": CATS, "data": D}),
]
# ---- Slide 7: Hero cashflow waterfall — full slide with labels ----
items += new_slide("Hero cashflow waterfall — full slide with labels")
items += [
ch(HERO, {"chartType": "waterfall", "title": "FY24 P&L Walk",
"title.font": "Helvetica", "title.size": "22", "title.bold": "true",
"title.color": "1F3864",
"increaseColor": "00C853", "decreaseColor": "D50000", "totalColor": "2962FF",
"dataLabels": "value,category", "labelPos": "outsideEnd",
"labelfont": "11:333333:Helvetica", "axistitle": "USD", "cattitle": "",
"axisnumfmt": "$#,##0", "gridlines": "E0E0E0:0.3",
"legend": "none", "categories": CATS_LONG, "data": D_LONG}),
]
# ---- Slide 8: Presets ----
items += new_slide("Presets")
for box, p in zip([TL, TR, BL, BR], ["minimal", "dark", "corporate", "colorful"]):
items += [ch(box, {"chartType": "waterfall", "preset": p, "title": f"preset={p}",
"legend": "none", "categories": CATS, "data": D})]
doc.batch(items)
print(f" added {_state['slide']} slides, {len(items)} items")
doc.send({"command": "save"})
# context exit closes the resident, flushing the presentation to disk.
print(f"Generated: {FILE} ({_state['slide']} slides)")
+93
View File
@@ -0,0 +1,93 @@
#!/bin/bash
# Waterfall Charts Showcase — increaseColor / decreaseColor / totalColor.
# Generates charts-waterfall.pptx
#
# Slide 1 Basic default colors, single dataset
# Slide 2 Color schemes increaseColor / decreaseColor / totalColor combinations
# Slide 3 Title & legend
# Slide 4 Data labels
# Slide 5 Axes min/max, gridlines, axisnumfmt (currency)
# Slide 6 Backgrounds chartareafill, plotFill, chartborder, roundedcorners
# Slide 7 Larger story a real cashflow waterfall with labels
# Slide 8 Presets
#
# CLI twin of charts-waterfall.py (officecli Python SDK).
# Usage: ./charts-waterfall.sh
# NOTE: intentionally NO `set -e`. Like the SDK twin's doc.batch, this script
# tolerates forward-compat 'UNSUPPORTED props' warnings (officecli exit 2) and
# keeps building so the full document is produced.
FILE="$(dirname "$0")/charts-waterfall.pptx"
rm -f "$FILE"
CATS="Start,Q1,Q2,Q3,Q4,End"
D="Cashflow:100,30,-15,40,-10,145"
CATS_LONG="Open,Revenue,COGS,Opex,R&D,Tax,Net"
D_LONG="P&L:100,80,-30,-25,-15,-10,100"
officecli create "$FILE"
officecli open "$FILE"
# ==================== Slide 1: Basic waterfall — default colors ====================
officecli add "$FILE" / --type slide
officecli add "$FILE" /slide[1] --type shape --prop text="Basic waterfall — default colors" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
officecli add "$FILE" /slide[1] --type chart --prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=waterfall --prop title="Default colors" --prop legend=none --prop categories="$CATS" --prop data="$D"
officecli add "$FILE" /slide[1] --type chart --prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=waterfall --prop title="Default + dataTable" --prop dataTable=true --prop legend=none --prop categories="$CATS" --prop data="$D"
officecli add "$FILE" /slide[1] --type chart --prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=waterfall --prop title="With legend" --prop legend=bottom --prop categories="$CATS" --prop data="$D"
officecli add "$FILE" /slide[1] --type chart --prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=waterfall --prop title="7-step P&L" --prop legend=none --prop categories="$CATS_LONG" --prop data="$D_LONG"
# ==================== Slide 2: Color schemes ====================
officecli add "$FILE" / --type slide
officecli add "$FILE" /slide[2] --type shape --prop text="Color schemes — increaseColor / decreaseColor / totalColor" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
officecli add "$FILE" /slide[2] --type chart --prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=waterfall --prop title="green/red/blue (default-ish)" --prop increaseColor=00AA00 --prop decreaseColor=FF0000 --prop totalColor=4472C4 --prop legend=none --prop categories="$CATS" --prop data="$D"
officecli add "$FILE" /slide[2] --type chart --prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=waterfall --prop title="corporate (teal/orange/navy)" --prop increaseColor=008080 --prop decreaseColor=D86600 --prop totalColor=1F3864 --prop legend=none --prop categories="$CATS" --prop data="$D"
officecli add "$FILE" /slide[2] --type chart --prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=waterfall --prop title="monochrome" --prop increaseColor=606060 --prop decreaseColor=A0A0A0 --prop totalColor=303030 --prop legend=none --prop categories="$CATS" --prop data="$D"
officecli add "$FILE" /slide[2] --type chart --prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=waterfall --prop title="vivid" --prop increaseColor=00C853 --prop decreaseColor=D50000 --prop totalColor=2962FF --prop legend=none --prop categories="$CATS" --prop data="$D"
# ==================== Slide 3: Title & legend ====================
officecli add "$FILE" / --type slide
officecli add "$FILE" /slide[3] --type shape --prop text="Title & legend" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
officecli add "$FILE" /slide[3] --type chart --prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=waterfall --prop title="Styled title" --prop title.font=Georgia --prop title.size=20 --prop title.color=4472C4 --prop title.bold=true --prop legend=bottom --prop categories="$CATS" --prop data="$D"
officecli add "$FILE" /slide[3] --type chart --prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=waterfall --prop title="legend=top + legendFont" --prop legend=top --prop legendFont=10:333333:Calibri --prop categories="$CATS" --prop data="$D"
officecli add "$FILE" /slide[3] --type chart --prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=waterfall --prop title="legend.overlay=true" --prop legend=topRight --prop legend.overlay=true --prop categories="$CATS" --prop data="$D"
officecli add "$FILE" /slide[3] --type chart --prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=waterfall --prop autotitledeleted=true --prop legend=none --prop categories="$CATS" --prop data="$D"
# ==================== Slide 4: Data labels ====================
officecli add "$FILE" / --type slide
officecli add "$FILE" /slide[4] --type shape --prop text="Data labels — flags + labelfont" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
officecli add "$FILE" /slide[4] --type chart --prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=waterfall --prop title="value" --prop dataLabels=value --prop labelfont=10:333333:Calibri --prop legend=none --prop categories="$CATS" --prop data="$D"
officecli add "$FILE" /slide[4] --type chart --prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=waterfall --prop title="value,category" --prop dataLabels=value,category --prop legend=none --prop categories="$CATS" --prop data="$D"
officecli add "$FILE" /slide[4] --type chart --prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=waterfall --prop title="value @ outsideEnd" --prop dataLabels=value --prop labelPos=outsideEnd --prop legend=none --prop categories="$CATS" --prop data="$D"
officecli add "$FILE" /slide[4] --type chart --prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=waterfall --prop title="dataLabels=none" --prop dataLabels=none --prop legend=none --prop categories="$CATS" --prop data="$D"
# ==================== Slide 5: Axes ====================
officecli add "$FILE" / --type slide
officecli add "$FILE" /slide[5] --type shape --prop text="Axes — min/max, titles, gridlines, axisnumfmt" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
officecli add "$FILE" /slide[5] --type chart --prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=waterfall --prop title="min/max + titles" --prop axismin=0 --prop axismax=200 --prop majorunit=50 --prop axistitle=USD --prop cattitle=Phase --prop axisfont=10:333333:Calibri --prop axisnumfmt='$#,##0' --prop legend=none --prop categories="$CATS" --prop data="$D"
officecli add "$FILE" /slide[5] --type chart --prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=waterfall --prop title="gridlines + minorGridlines" --prop gridlines=E0E0E0:0.3 --prop minorGridlines=F0F0F0:0.25 --prop legend=none --prop categories="$CATS" --prop data="$D"
officecli add "$FILE" /slide[5] --type chart --prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=waterfall --prop title="labelrotation=-30" --prop labelrotation=-30 --prop legend=none --prop categories="$CATS" --prop data="$D"
officecli add "$FILE" /slide[5] --type chart --prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=waterfall --prop title="dispunits=thousands" --prop dispunits=thousands --prop legend=none --prop categories="$CATS" --prop data="USD:100000,30000,-15000,40000,-10000,145000"
# ==================== Slide 6: Backgrounds ====================
officecli add "$FILE" / --type slide
officecli add "$FILE" /slide[6] --type shape --prop text="Backgrounds — chartareafill, plotFill, chartborder, roundedcorners" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
officecli add "$FILE" /slide[6] --type chart --prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=waterfall --prop title="chartareafill + chartborder" --prop chartareafill=FFF8E7 --prop chartborder=000000:1 --prop plotFill=FAFAFA --prop plotborder=CCCCCC:0.5 --prop legend=none --prop categories="$CATS" --prop data="$D"
officecli add "$FILE" /slide[6] --type chart --prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=waterfall --prop title="roundedcorners=true" --prop roundedcorners=true --prop chartborder=4472C4:2 --prop legend=none --prop categories="$CATS" --prop data="$D"
officecli add "$FILE" /slide[6] --type chart --prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=waterfall --prop title="plotFill=none" --prop plotFill=none --prop gridlines=none --prop legend=none --prop categories="$CATS" --prop data="$D"
officecli add "$FILE" /slide[6] --type chart --prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=waterfall --prop title="chartareafill=none" --prop chartareafill=none --prop legend=none --prop categories="$CATS" --prop data="$D"
# ==================== Slide 7: Hero cashflow waterfall ====================
officecli add "$FILE" / --type slide
officecli add "$FILE" /slide[7] --type shape --prop text="Hero cashflow waterfall — full slide with labels" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
officecli add "$FILE" /slide[7] --type chart --prop x=1in --prop y=1.05in --prop width=11.3in --prop height=6.2in --prop chartType=waterfall --prop title="FY24 P&L Walk" --prop title.font=Helvetica --prop title.size=22 --prop title.bold=true --prop title.color=1F3864 --prop increaseColor=00C853 --prop decreaseColor=D50000 --prop totalColor=2962FF --prop dataLabels=value,category --prop labelPos=outsideEnd --prop labelfont=11:333333:Helvetica --prop axistitle=USD --prop cattitle= --prop axisnumfmt='$#,##0' --prop gridlines=E0E0E0:0.3 --prop legend=none --prop categories="$CATS_LONG" --prop data="$D_LONG"
# ==================== Slide 8: Presets ====================
officecli add "$FILE" / --type slide
officecli add "$FILE" /slide[8] --type shape --prop text="Presets" --prop size=24 --prop bold=true --prop autoFit=normal --prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
officecli add "$FILE" /slide[8] --type chart --prop x=0.3in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=waterfall --prop preset=minimal --prop title="preset=minimal" --prop legend=none --prop categories="$CATS" --prop data="$D"
officecli add "$FILE" /slide[8] --type chart --prop x=6.95in --prop y=1.05in --prop width=6.1in --prop height=3in --prop chartType=waterfall --prop preset=dark --prop title="preset=dark" --prop legend=none --prop categories="$CATS" --prop data="$D"
officecli add "$FILE" /slide[8] --type chart --prop x=0.3in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=waterfall --prop preset=corporate --prop title="preset=corporate" --prop legend=none --prop categories="$CATS" --prop data="$D"
officecli add "$FILE" /slide[8] --type chart --prop x=6.95in --prop y=4.25in --prop width=6.1in --prop height=3in --prop chartType=waterfall --prop preset=colorful --prop title="preset=colorful" --prop legend=none --prop categories="$CATS" --prop data="$D"
officecli close "$FILE"
officecli validate "$FILE"
echo "Generated: $FILE"
+187
View File
@@ -0,0 +1,187 @@
# Mermaid Diagrams — native + image (full type gallery)
Render [Mermaid](https://mermaid.js.org/) source into a slide two ways:
- **`render=native`** — the built-in synthesizer draws the diagram as **editable
PowerPoint shapes + connectors** (no browser). Supported types: `flowchart` /
`graph` and `sequenceDiagram`. Fully editable in PowerPoint.
- **`render=image`** — real **mermaid.js** (headless Chrome / Chromium / Edge)
renders a **full-fidelity PNG**, covering **every** mermaid type. The mermaid
source is stamped into the picture's alt-text, so the diagram is regenerable.
- **`render=auto`** (default) — image when a browser is present, else native.
This demo ships four files:
- **diagram.sh** — CLI build script (`officecli add … --type diagram`).
- **diagram.py** — SDK twin, regenerates the same deck.
- **diagram.pptx** — the generated deck (native flowchart + sequence, the same
flowchart as PNG, then an image gallery of every other mermaid type).
- **diagram.md** — this file.
A diagram is an **ADD-ONLY synthesizer** (like `equation`): there is no persistent
`diagram` node. The whole picture is wrapped in **one object** and `add` returns
its path — a **group** in native mode (`/slide[N]/group[K]`), a single **picture**
in image mode (`/slide[N]/picture[K]`). Either is addressable and movable as one
unit; the native group re-bakes child font sizes when you resize it.
## Regenerate
```bash
cd examples/ppt
bash diagram.sh # or: python3 diagram.py
# → diagram.pptx
```
> `render=image` slides need a headless browser. Without one, use `render=auto`
> (the default) and those slides fall back to native shapes.
## Deck
| Slide | Mode | Type | Source prop |
|------|------|------|------|
| 2 | `native` | flowchart | `mermaid=` |
| 3 | `image` | flowchart (same source as 2) | `dsl=` |
| 4 | `native` | sequenceDiagram | `text=` |
| 5 | `image` | pie | `src=` (`.mmd` file) |
| 623 | `image` | classDiagram, stateDiagram-v2, erDiagram, gantt, journey, gitGraph, mindmap, timeline, quadrantChart, requirementDiagram, C4Context, sankey-beta, xychart-beta, block-beta, packet-beta, kanban, architecture-beta, radar-beta | `text=` |
### Native (slides 2 & 4)
```bash
# flowchart — full node-shape vocabulary + edge forms
officecli add diagram.pptx '/slide[2]' --type diagram \
--prop render=native \
--prop mermaid="flowchart TD
A([Start]) --> B{Decision}
B -->|yes| C[Process]
B -->|no| D[(Database)]
C --> E[[Subroutine]]
D -.-> F{{Prepare}}
E ==> G((Done))
F --> G
A --> H[/Input/]
H --x B" \
--prop x=1in --prop y=1.2in --prop width=11.3in --prop height=5.8in
# sequenceDiagram (text= is an alias of mermaid=)
officecli add diagram.pptx '/slide[4]' --type diagram \
--prop render=native \
--prop text="sequenceDiagram
participant U as User
participant S as Server
U->>S: Login request
S-->>U: Session token" \
--prop x=1in --prop y=1.2in --prop width=11.3in --prop height=5.8in
```
**Node shapes:** `([stadium])`, `{diamond}`, `[rect]`, `[(database)]`,
`[[subroutine]]`, `{{hexagon}}`, `[/parallelogram/]`, `((circle))`.
**Edges:** `-->|label|`, `-.->` (dashed), `==>` (thick), `--x` (cross end).
The diagram is fitted into the box (aspect preserved) and **centred**.
### Image — same flowchart as a PNG (slide 3)
```bash
officecli add diagram.pptx '/slide[3]' --type diagram \
--prop render=image \
--prop dsl="flowchart TD; A([Start]) --> B{Decision} --> C[Process]" \
--prop x=1in --prop y=1.2in --prop width=11.3in --prop height=5.8in
```
`dsl=` is another alias of `mermaid=`. Compare with slide 2 — same topology, a
pixel-perfect raster instead of editable shapes.
### Image gallery — every other mermaid type (slides 523)
`render=image` goes through real mermaid.js, so anything outside the native
`flowchart` / `sequenceDiagram` subset still renders. The pie slide loads its
source from a file with `src=`:
```bash
cat > pie.mmd << 'EOF'
pie showData title Traffic Sources
"Organic Search" : 45
"Direct" : 30
"Referral" : 15
"Social" : 10
EOF
officecli add diagram.pptx '/slide[5]' --type diagram \
--prop render=image --prop src=pie.mmd \
--prop x=1in --prop y=1.2in --prop width=11.3in --prop height=5.8in
```
The rest of the gallery passes the source inline with `text=`:
`classDiagram`, `stateDiagram-v2`, `erDiagram`, `gantt`, `journey`, `gitGraph`,
`mindmap`, `timeline`, `quadrantChart`, `requirementDiagram`, `C4Context`,
`sankey-beta`, `xychart-beta`, `block-beta`, `packet-beta`, `kanban`,
`architecture-beta`, `radar-beta`.
## Complete Property Coverage
| Property | Meaning | Where |
|----------|---------|-------|
| `mermaid` | Canonical source (header line picks the diagram kind) | slide 2 |
| `text` | Alias of `mermaid` | slide 4 + gallery |
| `dsl` | Alias of `mermaid` | slide 3 |
| `src` (`path`) | Load source from a `.mmd` file | slide 5 (pie) |
| `render=native` | Editable shapes + connectors (no browser) | slides 2, 4 |
| `render=image` | Full-fidelity PNG via mermaid.js (needs a browser) | slides 3, 523 |
| `render=auto` | Image when a browser is present, else native (default) | — (combines the two above) |
| `x` / `y` | Top-left of the placement box | every diagram |
| `width` / `height` | Box the diagram is scaled to fit (aspect preserved, centred) | every diagram |
| `poster=true` | Grow the **whole deck** to the diagram's natural size (export-a-diagram-as-a-slide) | see below |
### `poster` — the one deck-wide property
pptx has a single presentation-wide slide size, so `poster=true` resizes **every
slide** to the diagram's natural size. It is mutually exclusive with a multi-slide
showcase, so it lives in a single-diagram file rather than this gallery:
```bash
officecli create poster.pptx
officecli add poster.pptx / --type slide
officecli add poster.pptx '/slide[1]' --type diagram --prop poster=true \
--prop mermaid="flowchart LR; A --> B --> C"
# → the slide is grown to the diagram's exact size (x/y/width/height ignored)
```
## Manipulate the diagram after Add (`get` / `set` / `remove`)
`add` returns the object path. For a **native** diagram that is a group:
```bash
officecli get diagram.pptx '/slide[2]/group[1]' # read the box back
officecli set diagram.pptx '/slide[2]/group[1]' --prop width=6in # resize as a unit (fonts re-bake)
officecli remove diagram.pptx '/slide[2]/group[1]' # delete group + every child
```
For an **image** diagram it is a picture (`/slide[N]/picture[K]`) — move / resize
/ remove it like any other picture.
## Native vs image at a glance
| | `render=native` | `render=image` |
|---|---|---|
| Output | group of shapes + connectors | one PNG picture |
| Returned path | `/slide[N]/group[K]` | `/slide[N]/picture[K]` |
| Editable in PowerPoint | ✅ every shape | ❌ raster (source in alt-text) |
| Browser required | no | yes (Chrome / Chromium / Edge) |
| Supported types | `flowchart` / `graph`, `sequenceDiagram` | every mermaid type |
## Inspect the Generated File
```bash
officecli view diagram.pptx outline # native groups on 2/4, pictures on 3 & 523
officecli get diagram.pptx '/slide[2]/group[1]' # native flowchart — shapes + connectors
officecli get diagram.pptx '/slide[3]/picture[1]' # image flowchart — PNG (mermaid source in alt-text)
officecli query diagram.pptx '/slide[2]' shape # each editable node in the native group
```
## docx parity
The same `--type diagram` element works in Word (`officecli add report.docx /body
--type diagram …`), with the same `mermaid` / `text` / `dsl` / `src` / `width` /
`height` / `render` props. Word has no slide, so there is no `poster` and no
`x` / `y` — the diagram fits the section text-area width. The parse + layout
engine is shared; only the drawing output differs.
Binary file not shown.
+188
View File
@@ -0,0 +1,188 @@
#!/usr/bin/env python3
"""
Mermaid diagrams — every property + both render modes, enumerating the mermaid
type gallery. SDK twin of diagram.sh; both produce an equivalent diagram.pptx.
render=native → editable PowerPoint shapes + connectors (no browser).
Supported types: flowchart / graph, sequenceDiagram.
render=image → full-fidelity PNG via real mermaid.js (headless browser).
Covers EVERY mermaid type; source stamped into alt-text.
render=auto → (default) image when a browser is present, else native.
A diagram is an ADD-ONLY synthesizer (like 'equation'): no persistent 'diagram'
node — the whole picture is ONE object and Add returns its path. Native → a group
(/slide[N]/group[K]); image → a single PNG picture (/slide[N]/picture[K]).
Source props are interchangeable — mermaid= (canonical), text=, dsl=, or src= (a
.mmd file). x/y/width/height define a box the diagram is fitted into (aspect
preserved, centred). poster= is deck-wide (pptx has one slide size) so it is
documented at the end, not baked into this multi-slide file.
This one drives the officecli Python SDK (`pip install officecli-sdk`): one
resident is started and every command is shipped over the named pipe. render=image
launches a browser per slide — the SDK client retries a busy connect, so it is safe.
Usage:
pip install officecli-sdk # plus the `officecli` binary on PATH
python3 diagram.py
"""
import os
import sys
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
HERE = os.path.dirname(os.path.abspath(__file__))
FILE = os.path.join(HERE, "diagram.pptx")
MMD = os.path.join(HERE, "pie.mmd") # loaded via src= on the pie gallery slide
BOX = dict(x="1in", y="1.2in", width="11.3in", height="5.8in")
# The one flowchart the native + image comparison both render. Exercises the
# node-shape vocabulary the native synthesizer maps: ([stadium]) {diamond} [rect]
# [(database)] [[subroutine]] {{hexagon}} [/parallelogram/] ((circle)); and edge
# forms -->|label| -.-> ==> --x .
FLOW = ("flowchart TD\n"
" A([Start]) --> B{Decision}\n"
" B -->|yes| C[Process]\n"
" B -->|no| D[(Database)]\n"
" C --> E[[Subroutine]]\n"
" D -.-> F{{Prepare}}\n"
" E ==> G((Done))\n"
" F --> G\n"
" A --> H[/Input/]\n"
" H --x B")
SEQUENCE = ("sequenceDiagram\n"
" participant U as User\n"
" participant S as Server\n"
" participant D as Database\n"
" U->>S: Login request\n"
" S->>D: Validate credentials\n"
" D-->>S: OK\n"
" S-->>U: Session token")
# Image gallery — every other mermaid type (no native synthesizer). Ordered.
GALLERY = [
("pie", "pie — proportions", None), # pie loads via src= below
("class", "classDiagram — UML classes",
"classDiagram\n class Animal { +int age +run() }\n class Dog { +bark() }\n Animal <|-- Dog"),
("state", "stateDiagram-v2 — states",
"stateDiagram-v2\n [*] --> Idle\n Idle --> Running: start\n Running --> Idle: pause\n Running --> [*]: stop"),
("er", "erDiagram — entities & relations",
"erDiagram\n CUSTOMER ||--o{ ORDER : places\n ORDER ||--|{ LINE_ITEM : contains"),
("gantt", "gantt — project schedule",
"gantt\n title Project Plan\n dateFormat YYYY-MM-DD\n axisFormat %b %d\n"
" tickInterval 1week\n weekday monday\n todayMarker off\n section Design\n"
" Research :a1, 2024-01-01, 5d\n Draft :after a1, 4d\n section Build\n Code :2024-01-12, 6d"),
("journey", "journey — user journey",
"journey\n title My working day\n section Morning\n Standup: 3: Me, Team\n"
" Code: 5: Me\n section Afternoon\n Review: 2: Me"),
("git", "gitGraph — branch/merge",
"gitGraph\n commit\n branch develop\n commit\n checkout main\n merge develop\n commit"),
("mindmap", "mindmap — hierarchy",
"mindmap\n root((mermaid))\n Origins\n History\n Uses\n Docs\n Diagrams"),
("timeline", "timeline — events",
"timeline\n title Release History\n 2019 : v1\n 2021 : v2 : v2.1\n 2023 : v3"),
("quadrant", "quadrantChart — 2x2 matrix",
"quadrantChart\n title Reach vs Engagement\n x-axis Low Reach --> High Reach\n"
" y-axis Low Engagement --> High Engagement\n quadrant-1 Expand\n quadrant-2 Promote\n"
" quadrant-3 Re-evaluate\n quadrant-4 Improve\n Campaign A: [0.3, 0.6]\n Campaign B: [0.45, 0.23]"),
("requirement", "requirementDiagram — requirements",
"requirementDiagram\n requirement test_req {\n id: 1\n text: the test text\n"
" risk: high\n verifymethod: test\n }\n element test_entity {\n type: simulation\n }\n"
" test_entity - satisfies -> test_req"),
("c4", "C4Context — system context",
'C4Context\n title System Context\n Person(customer, "Customer")\n'
' System(banking, "Internet Banking")\n Rel(customer, banking, "Uses")'),
("sankey", "sankey-beta — flow volumes",
"sankey-beta\nAgricultural,Bio-conversion,124\nBio-conversion,Losses,26\n"
"Bio-conversion,Solid,280\nBio-conversion,Gas,81"),
("xychart", "xychart-beta — bar/line",
'xychart-beta\n title "Monthly Revenue"\n x-axis [jan, feb, mar, apr]\n'
' y-axis "Revenue (k$)" 0 --> 100\n bar [30, 50, 65, 80]\n line [30, 50, 65, 80]'),
("block", "block-beta — block layout",
'block-beta\n columns 3\n a["Ingest"] b["Process"] c["Store"]\n d["Log"]'),
("packet", "packet-beta — byte layout",
'packet-beta\n 0-15: "Source Port"\n 16-31: "Destination Port"\n 32-63: "Sequence Number"'),
("kanban", "kanban — board",
"kanban\n Todo\n t1[Design]\n In Progress\n t2[Build]\n Done\n t3[Ship]"),
("architecture", "architecture-beta — cloud services",
"architecture-beta\n group api(cloud)[API]\n service db(database)[Database] in api\n"
" service server(server)[Server] in api\n db:L -- R:server"),
("radar", "radar-beta — multi-axis scores",
'radar-beta\n title Skill Assessment\n axis a["Coding"], b["Design"], c["Testing"], d["Docs"]\n'
" curve x{80, 60, 70, 50}"),
]
# The pie source loaded via src= on its gallery slide.
with open(MMD, "w") as f:
f.write('pie showData title Traffic Sources\n'
' "Organic Search" : 45\n'
' "Direct" : 30\n'
' "Referral" : 15\n'
' "Social" : 10\n')
print(f"Building {FILE} ...")
with officecli.create(FILE, "--force") as doc:
def add(parent, type_, **props):
return doc.send({"command": "add", "parent": parent, "type": type_,
"props": {k: str(v) for k, v in props.items()}})
def title(slide, text):
add(f"/slide[{slide}]", "textbox", text=text, size=24, bold="true",
x="0.5in", y="0.3in", width="12.3in", height="0.6in")
# Slide 1 — Title
add("/", "slide")
add("/slide[1]", "textbox", text="Mermaid Diagrams", size=44, bold="true",
x="1in", y="2.5in", width="11.3in", height="1in", align="center")
add("/slide[1]", "textbox",
text="native editable shapes · full-fidelity PNG for every mermaid type",
size=20, color="595959",
x="1in", y="3.6in", width="11.3in", height="0.6in", align="center")
# Slide 2 — NATIVE flowchart (mermaid=), fitted + centred in the box.
add("/", "slide")
title(2, "render=native — flowchart (editable shapes + connectors)")
add("/slide[2]", "diagram", render="native", mermaid=FLOW, **BOX)
# The whole native diagram is ONE group — read its box back. set width=/height=
# resizes it as a unit (fonts re-bake); remove deletes group + children.
print(doc.send({"command": "get", "path": "/slide[2]/group[1]"}))
# Slide 3 — IMAGE of the SAME flowchart (dsl= alias). Apples-to-apples.
add("/", "slide")
title(3, "render=image — the same flowchart as a full-fidelity PNG")
add("/slide[3]", "diagram", render="image", dsl=FLOW, **BOX)
# Slide 4 — NATIVE sequenceDiagram (text= alias). 2nd native-supported type.
add("/", "slide")
title(4, "render=native — sequenceDiagram")
add("/slide[4]", "diagram", render="native", text=SEQUENCE, **BOX)
# Slides 5+ — IMAGE gallery: every other mermaid type.
n = 4
for key, desc, src in GALLERY:
n += 1
add("/", "slide")
title(n, f"render=image — {desc}")
if key == "pie":
add(f"/slide[{n}]", "diagram", render="image", src=MMD, **BOX) # src= (alias path=)
else:
add(f"/slide[{n}]", "diagram", render="image", text=src, **BOX)
doc.send({"command": "save"})
# poster= is deck-wide: pptx has a single slide size, so poster=true grows the
# WHOLE deck to the diagram's natural size (export-a-diagram-as-a-slide). Use it
# in a single-diagram file, e.g.:
# add("/slide[1]", "diagram", poster="true", mermaid="flowchart LR; A --> B --> C")
print(f"Generated: {FILE}")
+274
View File
@@ -0,0 +1,274 @@
#!/bin/bash
# Mermaid diagrams — every property + both render modes, enumerating the mermaid
# type gallery.
#
# render=native → editable PowerPoint shapes + connectors (no browser).
# Supported types: flowchart / graph, sequenceDiagram.
# render=image → full-fidelity PNG via real mermaid.js (headless browser).
# Covers EVERY mermaid type; source stamped into alt-text.
# render=auto → (default) image when a browser is present, else native.
#
# A diagram is an ADD-ONLY synthesizer (like 'equation'): no persistent 'diagram'
# node — the whole picture is ONE object and Add returns its path. Native mode →
# a group of editable shapes+connectors (/slide[N]/group[K]); image mode → a
# single PNG picture (/slide[N]/picture[K]). Both are addressable/movable as a unit.
#
# Source props are interchangeable — mermaid= (canonical), text=, dsl=, or src=
# (a .mmd file). Placement props x/y/width/height define a box the diagram is
# fitted into (aspect ratio preserved, centred in the box). poster= is deck-wide
# (see the note at the end) so it is documented, not baked into this multi-slide file.
#
# NOTE: intentionally NO `set -e` — render=image needs a headless browser
# (Chrome / Chromium / Edge); without one those slides are skipped with a clear
# message while the native slides still build.
#
# Auto-resident disabled: render=image launches a browser and can take a few
# seconds, so each add runs as its own process rather than contending for the
# resident's single command pipe. (The Python SDK twin keeps a resident — its
# client retries a busy connect, so it is safe there.)
export OFFICECLI_NO_AUTO_RESIDENT=1
DIR="$(dirname "$0")"
PPTX="$DIR/diagram.pptx"
MMD="$DIR/pie.mmd" # loaded via src= on the pie gallery slide
BOX=(--prop x=1in --prop y=1.2in --prop width=11.3in --prop height=5.8in)
# The one flowchart the native + image comparison both render. Exercises the
# node-shape vocabulary the native synthesizer maps: ([stadium]) {diamond} [rect]
# [(database)] [[subroutine]] {{hexagon}} [/parallelogram/] ((circle)); and edge
# forms -->|label| -.-> ==> --x .
FLOW="flowchart TD
A([Start]) --> B{Decision}
B -->|yes| C[Process]
B -->|no| D[(Database)]
C --> E[[Subroutine]]
D -.-> F{{Prepare}}
E ==> G((Done))
F --> G
A --> H[/Input/]
H --x B"
rm -f "$PPTX"
officecli create "$PPTX"
title() { # $1=slide $2=text
officecli add "$PPTX" "/slide[$1]" --type textbox \
--prop text="$2" --prop size=24 --prop bold=true \
--prop x=0.5in --prop y=0.3in --prop width=12.3in --prop height=0.6in
}
# ─────────────────────────────────────────────────────────────────────────────
# Slide 1 — Title
# ─────────────────────────────────────────────────────────────────────────────
officecli add "$PPTX" / --type slide
officecli add "$PPTX" '/slide[1]' --type textbox \
--prop text="Mermaid Diagrams" --prop size=44 --prop bold=true \
--prop x=1in --prop y=2.5in --prop width=11.3in --prop height=1in --prop align=center
officecli add "$PPTX" '/slide[1]' --type textbox \
--prop text="native editable shapes · full-fidelity PNG for every mermaid type" \
--prop size=20 --prop color=595959 \
--prop x=1in --prop y=3.6in --prop width=11.3in --prop height=0.6in --prop align=center
# ─────────────────────────────────────────────────────────────────────────────
# Slide 2 — NATIVE flowchart (mermaid= source). Editable shapes + connectors,
# fitted and CENTRED in the placement box.
# ─────────────────────────────────────────────────────────────────────────────
officecli add "$PPTX" / --type slide
title 2 "render=native — flowchart (editable shapes + connectors)"
officecli add "$PPTX" '/slide[2]' --type diagram --prop render=native --prop mermaid="$FLOW" "${BOX[@]}"
# The whole native diagram is ONE group at the returned path — read its box back.
# `set /slide[2]/group[1] --prop width=…` resizes it as a unit (fonts re-bake);
# `remove /slide[2]/group[1]` deletes the group and every child.
officecli get "$PPTX" '/slide[2]/group[1]'
# ─────────────────────────────────────────────────────────────────────────────
# Slide 3 — IMAGE of the SAME flowchart (dsl= alias). Real mermaid.js → PNG.
# Apples-to-apples comparison with slide 2.
# ─────────────────────────────────────────────────────────────────────────────
officecli add "$PPTX" / --type slide
title 3 "render=image — the same flowchart as a full-fidelity PNG"
officecli add "$PPTX" '/slide[3]' --type diagram --prop render=image --prop dsl="$FLOW" "${BOX[@]}"
# ─────────────────────────────────────────────────────────────────────────────
# Slide 4 — NATIVE sequenceDiagram (text= alias). The 2nd native-supported type.
# ─────────────────────────────────────────────────────────────────────────────
officecli add "$PPTX" / --type slide
title 4 "render=native — sequenceDiagram"
officecli add "$PPTX" '/slide[4]' --type diagram --prop render=native --prop text="sequenceDiagram
participant U as User
participant S as Server
participant D as Database
U->>S: Login request
S->>D: Validate credentials
D-->>S: OK
S-->>U: Session token" "${BOX[@]}"
# ─────────────────────────────────────────────────────────────────────────────
# Slides 5+ — IMAGE gallery: every other mermaid type, proving render=image
# covers the full mermaid surface (these have no native synthesizer).
# ─────────────────────────────────────────────────────────────────────────────
# The pie source is written to a .mmd file and loaded with src= (alias path=).
cat > "$MMD" << 'EOF'
pie showData title Traffic Sources
"Organic Search" : 45
"Direct" : 30
"Referral" : 15
"Social" : 10
EOF
# One helper per gallery slide (macOS ships bash 3.2 — NO associative arrays, so
# we use plain functions, not `declare -A`). `n` tracks the current slide number.
n=4
img() { # $1=title suffix $2=mermaid source (inline)
n=$((n + 1))
officecli add "$PPTX" / --type slide
title "$n" "render=image — $1"
officecli add "$PPTX" "/slide[$n]" --type diagram --prop render=image --prop text="$2" "${BOX[@]}"
}
img_src() { # $1=title suffix $2=.mmd file path (loaded with src=, alias path=)
n=$((n + 1))
officecli add "$PPTX" / --type slide
title "$n" "render=image — $1"
officecli add "$PPTX" "/slide[$n]" --type diagram --prop render=image --prop src="$2" "${BOX[@]}"
}
img_src "pie — proportions" "$MMD"
img "classDiagram — UML classes" "classDiagram
class Animal { +int age +run() }
class Dog { +bark() }
Animal <|-- Dog"
img "stateDiagram-v2 — states" "stateDiagram-v2
[*] --> Idle
Idle --> Running: start
Running --> Idle: pause
Running --> [*]: stop"
img "erDiagram — entities & relations" "erDiagram
CUSTOMER ||--o{ ORDER : places
ORDER ||--|{ LINE_ITEM : contains"
img "gantt — project schedule" "gantt
title Project Plan
dateFormat YYYY-MM-DD
axisFormat %b %d
tickInterval 1week
weekday monday
todayMarker off
section Design
Research :a1, 2024-01-01, 5d
Draft :after a1, 4d
section Build
Code :2024-01-12, 6d"
img "journey — user journey" "journey
title My working day
section Morning
Standup: 3: Me, Team
Code: 5: Me
section Afternoon
Review: 2: Me"
img "gitGraph — branch/merge" "gitGraph
commit
branch develop
commit
checkout main
merge develop
commit"
img "mindmap — hierarchy" "mindmap
root((mermaid))
Origins
History
Uses
Docs
Diagrams"
img "timeline — events" "timeline
title Release History
2019 : v1
2021 : v2 : v2.1
2023 : v3"
img "quadrantChart — 2x2 matrix" "quadrantChart
title Reach vs Engagement
x-axis Low Reach --> High Reach
y-axis Low Engagement --> High Engagement
quadrant-1 Expand
quadrant-2 Promote
quadrant-3 Re-evaluate
quadrant-4 Improve
Campaign A: [0.3, 0.6]
Campaign B: [0.45, 0.23]"
img "requirementDiagram — requirements" "requirementDiagram
requirement test_req {
id: 1
text: the test text
risk: high
verifymethod: test
}
element test_entity {
type: simulation
}
test_entity - satisfies -> test_req"
img "C4Context — system context" "C4Context
title System Context
Person(customer, \"Customer\")
System(banking, \"Internet Banking\")
Rel(customer, banking, \"Uses\")"
img "sankey-beta — flow volumes" "sankey-beta
Agricultural,Bio-conversion,124
Bio-conversion,Losses,26
Bio-conversion,Solid,280
Bio-conversion,Gas,81"
img "xychart-beta — bar/line" "xychart-beta
title \"Monthly Revenue\"
x-axis [jan, feb, mar, apr]
y-axis \"Revenue (k\$)\" 0 --> 100
bar [30, 50, 65, 80]
line [30, 50, 65, 80]"
img "block-beta — block layout" "block-beta
columns 3
a[\"Ingest\"] b[\"Process\"] c[\"Store\"]
d[\"Log\"]"
img "packet-beta — byte layout" "packet-beta
0-15: \"Source Port\"
16-31: \"Destination Port\"
32-63: \"Sequence Number\""
img "kanban — board" "kanban
Todo
t1[Design]
In Progress
t2[Build]
Done
t3[Ship]"
img "architecture-beta — cloud services" "architecture-beta
group api(cloud)[API]
service db(database)[Database] in api
service server(server)[Server] in api
db:L -- R:server"
img "radar-beta — multi-axis scores" "radar-beta
title Skill Assessment
axis a[\"Coding\"], b[\"Design\"], c[\"Testing\"], d[\"Docs\"]
curve x{80, 60, 70, 50}"
# poster= is deck-wide: pptx has a single presentation slide size, so poster=true
# grows the WHOLE deck to the diagram's natural size (export-a-diagram-as-a-slide).
# It is mutually exclusive with a multi-slide showcase — use it in a single-diagram
# file: officecli add poster.pptx '/slide[1]' --type diagram --prop poster=true \
# --prop mermaid="flowchart LR; A --> B --> C"
officecli validate "$PPTX"
echo "Created: $PPTX ($n slides)"
Binary file not shown.
Binary file not shown.
Binary file not shown.
+162
View File
@@ -0,0 +1,162 @@
# PPT OLE Embedded Objects
Embed whole Office files (a .xlsx workbook, a .docx document) *inside* a slide
as OLE objects. Double-clicking the object in PowerPoint opens the embedded
payload in-place. This demo consists of four files that work together:
- **ole-embed.sh** — CLI script. Builds two source payloads (`data.xlsx`, `data.docx`) with `officecli`, synthesizes two preview thumbnails, then embeds them into the deck via `add --type ole`.
- **ole-embed.py** — Python SDK twin. Same output via the officecli Python SDK.
- **ole-embed.pptx** — The generated 2-slide deck.
- **ole-embed.md** — This file.
The two payloads (`data.xlsx`, `data.docx`) and the thumbnails (`thumb-xlsx.png`,
`thumb-docx.png`) are the demo inputs the embed step consumes; they are kept
in-dir next to the deck.
> **You must supply `preview=` to see anything.** officecli does **not**
> auto-generate the Office live-preview image for an embedded OLE object.
> Without `preview=`, the object embeds and validates correctly, but real
> PowerPoint renders it as a **blank rectangle** in static / print view — it
> only becomes visible once the user double-clicks to activate it. Supply a
> `preview=` thumbnail for any OLE object you want visible in a static view.
## Regenerate
```bash
cd examples/ppt/ole
pip install Pillow # required for the preview thumbnails
bash ole-embed.sh
# → ole-embed.pptx (+ data.xlsx, data.docx, thumb-xlsx.png, thumb-docx.png)
```
## Build the payloads first
An OLE embed needs a real source file. Build a tiny spreadsheet and a tiny
Word memo with officecli, then embed them.
```bash
# A tiny .xlsx payload
officecli create data.xlsx
officecli open data.xlsx
officecli set data.xlsx '/sheet[1]/A1' --prop value="Q1 Revenue"
officecli set data.xlsx '/sheet[1]/A2' --prop value="North"
officecli set data.xlsx '/sheet[1]/B2' --prop value="1200"
officecli close data.xlsx
# A tiny .docx payload
officecli create data.docx
officecli open data.docx
officecli add data.docx /body --type paragraph --prop text="Quarterly Memo" --prop bold=true --prop size=16
officecli add data.docx /body --type paragraph --prop text="Revenue is up 12% quarter over quarter."
officecli close data.docx
```
## Slides
### Slide 1 — Embed .xlsx and .docx (each with a preview=)
Two OLE objects side by side, each carrying a full Office package. `progId`
tells PowerPoint which application owns the object (usually inferred from the
`src` extension, shown here explicitly). Each embed also gets its own
`preview=` thumbnail so it renders as a visible, intentional object rather than
a blank box.
```bash
officecli create ole-embed.pptx
officecli open ole-embed.pptx
officecli add ole-embed.pptx / --type slide
# Embed the spreadsheet — progId=Excel.Sheet.12 (modern .xlsx package)
officecli add ole-embed.pptx '/slide[1]' --type ole \
--prop src=data.xlsx \
--prop progId=Excel.Sheet.12 \
--prop preview=thumb-xlsx.png \
--prop x=1.5in --prop y=1.8in --prop width=3.5in --prop height=2.5in
# Embed the Word memo — progId=Word.Document.12 (modern .docx)
officecli add ole-embed.pptx '/slide[1]' --type ole \
--prop src=data.docx \
--prop progId=Word.Document.12 \
--prop preview=thumb-docx.png \
--prop x=6.5in --prop y=1.8in --prop width=3.5in --prop height=2.5in
```
**Features:** `--type ole`, `src` (embedded payload — file path / URL / data-URI; alias `path`), `progId` (`Excel.Sheet.12`, `Word.Document.12`, … — usually inferred from the `src` extension), `preview` (thumbnail image so the object is visible in static view), `x`/`y`/`width`/`height` (position and size, EMU-parseable; readback in cm)
---
### Slide 2 — `preview=` vs no `preview=` (teaching contrast)
The same payload embedded twice: once WITH a `preview=` thumbnail, once
WITHOUT. `preview=` supplies the image drawn in the object frame; it is
**add-time only**`set` ignores this key. The no-preview object embeds and
validates fine but renders **blank** in static view until it is activated in
PowerPoint.
```bash
officecli add ole-embed.pptx / --type slide
# WITH an explicit preview thumbnail — renders visibly
officecli add ole-embed.pptx '/slide[2]' --type ole \
--prop src=data.xlsx \
--prop progId=Excel.Sheet.12 \
--prop preview=thumb-xlsx.png \
--prop x=1.5in --prop y=1.8in --prop width=3.5in --prop height=2.5in
# WITHOUT preview — embeds + validates, but blank until opened in PowerPoint
officecli add ole-embed.pptx '/slide[2]' --type ole \
--prop src=data.xlsx \
--prop progId=Excel.Sheet.12 \
--prop x=6.5in --prop y=1.8in --prop width=3.5in --prop height=2.5in
officecli close ole-embed.pptx
officecli validate ole-embed.pptx
```
**Features:** `preview` (thumbnail image source; add-time only — `set` ignores it). Without it, the object is present and valid but shows blank in static / print view until double-clicked to activate.
---
## Complete Feature Coverage
| Feature | Slide |
|---------|-------|
| **--type ole:** embed an Office package on a slide | 1, 2 |
| **src=:** embedded payload (file path / URL / data-URI; alias `path`) | 1, 2 |
| **progId=:** `Excel.Sheet.12` (embedded .xlsx) | 1, 2 |
| **progId=:** `Word.Document.12` (embedded .docx) | 1 |
| **preview=:** custom thumbnail image (add-time only; required for a visible static-view face) | 1, 2 |
| **no preview=:** embeds + validates, but blank until activated in PowerPoint | 2 |
| **x / y / width / height:** position and size | 1, 2 |
## Inspect the Generated File
`Get` surfaces read-only readbacks about the embedded part. Note `src` is **not**
echoed by `Get` — the embedded relationship is exposed under `relId` instead.
```bash
# List every OLE object across all slides
officecli query ole-embed.pptx ole
# Full readback — progId / contentType / fileSize / relId / position
officecli get ole-embed.pptx '/slide[1]/ole[1]' # the .xlsx
officecli get ole-embed.pptx '/slide[1]/ole[2]' # the .docx
```
Example readback for the embedded .xlsx:
```
/slide[1]/ole[1] (ole) "Excel.Sheet.12" objectType=ole progId=Excel.Sheet.12 \
display=icon x=3.81cm y=129.6pt width=8.89cm height=6.35cm \
relId=R079cd9d005e64b19 \
contentType=application/vnd.openxmlformats-officedocument.spreadsheetml.sheet \
fileSize=3936
```
**Get-only readbacks:** `contentType` (MIME type of the embedded part),
`fileSize` (embedded payload bytes), `objectType` (literal `ole`),
`relId` (the embedded relationship id — inspect the part behind the object),
`progId` (also settable).
> `src` is accepted on `add`/`set` only and is **not** echoed by `Get`. Use
> `relId` to identify the embedded part.
Binary file not shown.
+197
View File
@@ -0,0 +1,197 @@
#!/usr/bin/env python3
"""
PowerPoint OLE embedded objects — embed .xlsx / .docx binary payloads in a deck.
SDK twin of ole-embed.sh (officecli CLI). Both produce an equivalent
ole-embed.pptx. This one drives the **officecli Python SDK**
(`pip install officecli-sdk`): a resident is started per file and every element
is shipped over the named pipe. Each item is the same
`{"command","parent","type","props"}` dict you'd put in an `officecli batch`
list; `doc.send(...)` ships one and returns its envelope.
This script:
1. Builds two source payloads with officecli: a tiny .xlsx and a .docx
2. Synthesizes two distinct preview thumbnail PNGs (Pillow)
3. Builds a 2-slide PPTX demoing OLE embedding:
- slide 1: embed the .xlsx (Excel.Sheet.12) and the .docx (Word.Document.12),
each with an explicit preview= thumbnail so they render visibly
- slide 2: WITH preview= vs WITHOUT — a deliberate teaching contrast
4. Reads back contentType / fileSize / progId / relId via `get`
IMPORTANT: officecli does NOT auto-generate the Office live-preview image for an
embedded OLE object. Without preview=, the object embeds and validates fine, but
real PowerPoint renders it as a BLANK rectangle in static/print view — it only
becomes visible after the user double-clicks to activate it. Supply preview= for
any OLE object you want visible in a static view.
The embedded source files (data.xlsx, data.docx) and the preview PNGs live in
this example dir alongside the deck — they are the meaningful inputs the embed
step consumes.
Requirements:
pip install Pillow officecli-sdk # plus the `officecli` binary on PATH
Usage:
python3 ole-embed.py
"""
import os
import sys
try:
from PIL import Image, ImageDraw
except ImportError:
print("ERROR: Pillow not installed. Run: pip install Pillow")
sys.exit(1)
# --- 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
HERE = os.path.dirname(os.path.abspath(__file__))
FILE = os.path.join(HERE, "ole-embed.pptx")
XLSX = os.path.join(HERE, "data.xlsx")
DOCX = os.path.join(HERE, "data.docx")
THUMB_XLSX = os.path.join(HERE, "thumb-xlsx.png")
THUMB_DOCX = os.path.join(HERE, "thumb-docx.png")
def add(doc, parent, typ, **props):
"""Ship one `add` item over the pipe; return the parsed envelope."""
return doc.send({"command": "add", "parent": parent, "type": typ, "props": props})
def make_thumbs(xlsx_path, docx_path):
# Excel-styled thumbnail (green) for the .xlsx embed
img = Image.new("RGB", (240, 160), (33, 115, 70))
d = ImageDraw.Draw(img)
d.rectangle((8, 8, 231, 151), outline=(255, 255, 255), width=4)
d.text((30, 40), "Q1 Revenue", fill=(255, 255, 255))
d.text((30, 90), "(embedded .xlsx)", fill=(200, 230, 210))
img.save(xlsx_path)
# Word-styled thumbnail (blue) for the .docx embed
img = Image.new("RGB", (240, 160), (43, 87, 154))
d = ImageDraw.Draw(img)
d.rectangle((8, 8, 231, 151), outline=(255, 255, 255), width=4)
d.text((30, 40), "Quarterly Memo", fill=(255, 255, 255))
d.text((30, 90), "(embedded .docx)", fill=(205, 218, 240))
img.save(docx_path)
def build_xlsx(path):
"""A tiny spreadsheet payload."""
if os.path.exists(path):
os.remove(path)
with officecli.create(path, "--force") as x:
x.send({"command": "set", "path": "/sheet[1]/A1", "props": {"value": "Q1 Revenue"}})
x.send({"command": "set", "path": "/sheet[1]/A2", "props": {"value": "North"}})
x.send({"command": "set", "path": "/sheet[1]/B2", "props": {"value": "1200"}})
x.send({"command": "set", "path": "/sheet[1]/A3", "props": {"value": "South"}})
x.send({"command": "set", "path": "/sheet[1]/B3", "props": {"value": "980"}})
x.send({"command": "save"})
def build_docx(path):
"""A tiny Word memo payload."""
if os.path.exists(path):
os.remove(path)
with officecli.create(path, "--force") as w:
add(w, "/body", "paragraph", text="Quarterly Memo", bold="true", size="16")
add(w, "/body", "paragraph", text="Revenue is up 12% quarter over quarter.")
w.send({"command": "save"})
def main():
if os.path.exists(FILE):
os.remove(FILE)
build_xlsx(XLSX)
build_docx(DOCX)
make_thumbs(THUMB_XLSX, THUMB_DOCX)
print(f"Building {FILE} ...")
with officecli.create(FILE, "--force") as doc:
# ── Slide 1: embed an .xlsx and a .docx, each with a preview= ─────────
add(doc, "/", "slide")
add(doc, "/slide[1]", "textbox",
text="Embedded OLE objects — Excel + Word packages",
size="24", bold="true",
x="0.5in", y="0.3in", width="12in", height="0.6in")
# Embed the spreadsheet. Double-clicking the object opens it in-place.
# progId=Excel.Sheet.12 marks it as a modern .xlsx package.
# preview= gives it a visible face in static view (officecli won't bake one).
add(doc, "/slide[1]", "ole",
src=XLSX,
progId="Excel.Sheet.12",
preview=THUMB_XLSX,
x="1.5in", y="1.8in", width="3.5in", height="2.5in")
add(doc, "/slide[1]", "textbox",
text="src=data.xlsx progId=Excel.Sheet.12 preview=thumb-xlsx.png",
size="12", italic="true",
x="1.5in", y="4.4in", width="5in", height="0.4in")
# Embed the Word memo. progId=Word.Document.12 marks it as a modern .docx.
# preview= gives it a visible face in static view (officecli won't bake one).
add(doc, "/slide[1]", "ole",
src=DOCX,
progId="Word.Document.12",
preview=THUMB_DOCX,
x="6.5in", y="1.8in", width="3.5in", height="2.5in")
add(doc, "/slide[1]", "textbox",
text="src=data.docx progId=Word.Document.12 preview=thumb-docx.png",
size="12", italic="true",
x="6.5in", y="4.4in", width="5in", height="0.4in")
# ── Slide 2: WITH preview= vs WITHOUT — a deliberate teaching contrast ─
add(doc, "/", "slide")
add(doc, "/slide[2]", "textbox",
text="preview= is the reliable path to a visible OLE object",
size="24", bold="true",
x="0.5in", y="0.3in", width="12in", height="0.6in")
# WITH preview= — the thumbnail is drawn in the object frame in static
# view. add-time only (Set ignores this key).
add(doc, "/slide[2]", "ole",
src=XLSX,
progId="Excel.Sheet.12",
preview=THUMB_XLSX,
x="1.5in", y="1.8in", width="3.5in", height="2.5in")
add(doc, "/slide[2]", "textbox",
text="src=data.xlsx preview=thumb-xlsx.png (renders visibly)",
size="12", italic="true",
x="1.5in", y="4.4in", width="4.5in", height="0.4in")
# WITHOUT preview= — embeds and validates fine, but real PowerPoint
# renders a BLANK rectangle in static view; it only appears once
# double-clicked/activated. officecli does NOT bake the live preview.
add(doc, "/slide[2]", "ole",
src=XLSX,
progId="Excel.Sheet.12",
x="6.5in", y="1.8in", width="3.5in", height="2.5in")
add(doc, "/slide[2]", "textbox",
text="src=data.xlsx (no preview — blank until opened in PowerPoint)",
size="12", italic="true",
x="6.5in", y="4.4in", width="5in", height="0.4in")
doc.send({"command": "save"})
# ── Inspect: Get surfaces read-only readbacks (src is NOT echoed) ─────
for path in ("/slide[1]/ole[1]", "/slide[1]/ole[2]"):
env = doc.send({"command": "get", "path": path})
print(f"{path}: {env.get('data') if isinstance(env, dict) else env}")
# context exit closes the resident, flushing the deck to disk.
print(f"Created: {FILE}")
if __name__ == "__main__":
main()
+173
View File
@@ -0,0 +1,173 @@
#!/bin/bash
# PowerPoint OLE embedded objects — embed .xlsx / .docx binary payloads in a deck.
#
# CLI twin of ole-embed.py (officecli Python SDK). Both produce an equivalent
# ole-embed.pptx. This one drives the officecli binary directly: one
# `officecli add ... --type ole --prop k=v` invocation per embedded object.
#
# - build tiny source docs first (a spreadsheet + a Word memo) via officecli
# - slide 1: embed the .xlsx (Excel.Sheet.12) and the .docx (Word.Document.12),
# each with an explicit preview= thumbnail so they render visibly
# - slide 2: WITH preview= vs WITHOUT — a deliberate teaching contrast
# - each ole object is read back with `get` (contentType / fileSize / progId / relId)
#
# IMPORTANT: officecli does NOT auto-generate the Office live-preview image for
# an embedded OLE object. Without preview=, the object embeds and validates
# fine, but real PowerPoint renders it as a BLANK rectangle in static/print
# view — it only becomes visible after the user double-clicks to activate it.
# Supply preview= for any OLE object you want visible in a static view.
#
# The embedded source files (data.xlsx, data.docx) and the preview PNGs live in
# this example dir alongside the deck — they are the meaningful inputs the embed
# step consumes, kept in-dir.
#
# Requirements: Pillow (pip install Pillow) to synthesize the preview thumbnails.
# Usage: ./ole-embed.sh [officecli path]
# NOTE: intentionally NO `set -e`. Like the SDK twin's doc.batch, this script
# tolerates forward-compat 'UNSUPPORTED props' warnings (officecli exit 2) and
# keeps building so the full document is produced.
CLI="${1:-officecli}"
DIR="$(dirname "$0")"
FILE="$DIR/ole-embed.pptx"
# Source payloads embedded into the deck (kept in-dir — they are the demo inputs).
XLSX="$DIR/data.xlsx"
DOCX="$DIR/data.docx"
THUMB_XLSX="$DIR/thumb-xlsx.png"
THUMB_DOCX="$DIR/thumb-docx.png"
# ── Build the .xlsx payload (a tiny spreadsheet) ──────────────────────────────
rm -f "$XLSX"
$CLI create "$XLSX"
$CLI open "$XLSX"
$CLI set "$XLSX" '/sheet[1]/A1' --prop value="Q1 Revenue"
$CLI set "$XLSX" '/sheet[1]/A2' --prop value="North"
$CLI set "$XLSX" '/sheet[1]/B2' --prop value="1200"
$CLI set "$XLSX" '/sheet[1]/A3' --prop value="South"
$CLI set "$XLSX" '/sheet[1]/B3' --prop value="980"
$CLI close "$XLSX"
# ── Build the .docx payload (a tiny Word memo) ────────────────────────────────
rm -f "$DOCX"
$CLI create "$DOCX"
$CLI open "$DOCX"
$CLI add "$DOCX" /body --type paragraph \
--prop text="Quarterly Memo" --prop bold=true --prop size=16
$CLI add "$DOCX" /body --type paragraph \
--prop text="Revenue is up 12% quarter over quarter."
$CLI close "$DOCX"
# ── Synthesize two distinct preview thumbnails (Excel-green, Word-blue) ───────
python3 - "$THUMB_XLSX" "$THUMB_DOCX" <<'PY'
import sys
from PIL import Image, ImageDraw
xlsx_path, docx_path = sys.argv[1], sys.argv[2]
# Excel-styled thumbnail (green) for the .xlsx embed
img = Image.new("RGB", (240, 160), (33, 115, 70))
d = ImageDraw.Draw(img)
d.rectangle((8, 8, 231, 151), outline=(255, 255, 255), width=4)
d.text((30, 40), "Q1 Revenue", fill=(255, 255, 255))
d.text((30, 90), "(embedded .xlsx)", fill=(200, 230, 210))
img.save(xlsx_path)
# Word-styled thumbnail (blue) for the .docx embed
img = Image.new("RGB", (240, 160), (43, 87, 154))
d = ImageDraw.Draw(img)
d.rectangle((8, 8, 231, 151), outline=(255, 255, 255), width=4)
d.text((30, 40), "Quarterly Memo", fill=(255, 255, 255))
d.text((30, 90), "(embedded .docx)", fill=(205, 218, 240))
img.save(docx_path)
PY
rm -f "$FILE"
$CLI create "$FILE"
$CLI open "$FILE"
# ══════════════════════════════════════════════════════════════════════════════
# Slide 1: embed an .xlsx and a .docx, each with a preview= so they render
# ══════════════════════════════════════════════════════════════════════════════
$CLI add "$FILE" / --type slide
$CLI add "$FILE" "/slide[1]" --type textbox \
--prop text="Embedded OLE objects — Excel + Word packages" \
--prop size=24 --prop bold=true \
--prop x=0.5in --prop y=0.3in --prop width=12in --prop height=0.6in
# Embed the spreadsheet. Double-clicking the object in PowerPoint opens the
# workbook in-place. progId=Excel.Sheet.12 marks it as a modern .xlsx package.
# preview= gives it a visible face in static view (officecli won't bake one).
# Features: --type ole, src (embedded payload), progId, preview, x/y/width/height
$CLI add "$FILE" "/slide[1]" --type ole \
--prop src="$XLSX" \
--prop progId=Excel.Sheet.12 \
--prop preview="$THUMB_XLSX" \
--prop x=1.5in --prop y=1.8in --prop width=3.5in --prop height=2.5in
$CLI add "$FILE" "/slide[1]" --type textbox \
--prop text="src=data.xlsx progId=Excel.Sheet.12 preview=thumb-xlsx.png" \
--prop size=12 --prop italic=true \
--prop x=1.5in --prop y=4.4in --prop width=5in --prop height=0.4in
# Embed the Word memo. progId=Word.Document.12 marks it as a modern .docx.
# preview= gives it a visible face in static view (officecli won't bake one).
# Features: --type ole, src (embedded payload), progId, preview, x/y/width/height
$CLI add "$FILE" "/slide[1]" --type ole \
--prop src="$DOCX" \
--prop progId=Word.Document.12 \
--prop preview="$THUMB_DOCX" \
--prop x=6.5in --prop y=1.8in --prop width=3.5in --prop height=2.5in
$CLI add "$FILE" "/slide[1]" --type textbox \
--prop text="src=data.docx progId=Word.Document.12 preview=thumb-docx.png" \
--prop size=12 --prop italic=true \
--prop x=6.5in --prop y=4.4in --prop width=5in --prop height=0.4in
# ══════════════════════════════════════════════════════════════════════════════
# Slide 2: WITH preview= vs WITHOUT — a deliberate teaching contrast
# ══════════════════════════════════════════════════════════════════════════════
$CLI add "$FILE" / --type slide
$CLI add "$FILE" "/slide[2]" --type textbox \
--prop text="preview= is the reliable path to a visible OLE object" \
--prop size=24 --prop bold=true \
--prop x=0.5in --prop y=0.3in --prop width=12in --prop height=0.6in
# WITH preview= — the thumbnail is drawn in the object frame in static view.
# add-time only (Set ignores this key).
# Features: --type ole, src, progId, preview (thumbnail image), x/y/width/height
$CLI add "$FILE" "/slide[2]" --type ole \
--prop src="$XLSX" \
--prop progId=Excel.Sheet.12 \
--prop preview="$THUMB_XLSX" \
--prop x=1.5in --prop y=1.8in --prop width=3.5in --prop height=2.5in
$CLI add "$FILE" "/slide[2]" --type textbox \
--prop text="src=data.xlsx preview=thumb-xlsx.png (renders visibly)" \
--prop size=12 --prop italic=true \
--prop x=1.5in --prop y=4.4in --prop width=4.5in --prop height=0.4in
# WITHOUT preview= — embeds and validates fine, but real PowerPoint renders a
# BLANK rectangle in static view; it only appears once double-clicked/activated.
# officecli does NOT auto-generate the Office live-preview image.
# Features: --type ole (no preview — blank until activated)
$CLI add "$FILE" "/slide[2]" --type ole \
--prop src="$XLSX" \
--prop progId=Excel.Sheet.12 \
--prop x=6.5in --prop y=1.8in --prop width=3.5in --prop height=2.5in
$CLI add "$FILE" "/slide[2]" --type textbox \
--prop text="src=data.xlsx (no preview — blank until opened in PowerPoint)" \
--prop size=12 --prop italic=true \
--prop x=6.5in --prop y=4.4in --prop width=5in --prop height=0.4in
$CLI close "$FILE"
# ══════════════════════════════════════════════════════════════════════════════
# Inspect: Get surfaces read-only readbacks (src is NOT echoed — use relId).
# ══════════════════════════════════════════════════════════════════════════════
echo "── query all OLE objects ──"
$CLI query "$FILE" ole
echo "── get slide 1 / ole 1 (the .xlsx) ──"
$CLI get "$FILE" "/slide[1]/ole[1]"
echo "── get slide 1 / ole 2 (the .docx) ──"
$CLI get "$FILE" "/slide[1]/ole[2]"
$CLI validate "$FILE"
echo "Generated: $FILE"
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

+296
View File
@@ -0,0 +1,296 @@
# Basic PPT Pictures
This demo consists of three files that work together:
- **pictures-basic.py** — Python script that generates 3 sample PNGs (gradient, geometric, photo-like) and calls `officecli` commands to build the deck.
- **pictures-basic.pptx** — The generated 5-slide deck (src= forms, crop variants, rotation, hyperlinks, Set-only effects).
- **pictures-basic.md** — This file. Maps each slide to the features it demonstrates.
## Regenerate
```bash
cd examples/ppt
pip install Pillow # required for sample image generation
python3 pictures/pictures-basic.py
# → pictures/pictures-basic.pptx
```
## Slides
### Slide 1 — Three Ways to Supply src=
Three pictures side by side, each using a different `src=` input form.
```bash
officecli create pictures-basic.pptx
officecli open pictures-basic.pptx
officecli add pictures-basic.pptx / --type slide
# 1a. File path — most common form; image is embedded at Add time
officecli add pictures-basic.pptx '/slide[1]' --type picture \
--prop src="/path/to/gradient.png" \
--prop x=0.5in --prop y=1.3in \
--prop width=3.5in --prop height=2.6in \
--prop alt="gradient image from disk"
# 1b. data-URI — inline base64; avoids external file dependency at run time
officecli add pictures-basic.pptx '/slide[1]' --type picture \
--prop src="data:image/png;base64,<base64data>" \
--prop x=4.5in --prop y=1.3in \
--prop width=3.5in --prop height=2.6in \
--prop alt="geometric shapes embedded as data-URI"
# 1c. File path + name= + compressionState=print
officecli add pictures-basic.pptx '/slide[1]' --type picture \
--prop src="/path/to/photo.png" \
--prop x=8.5in --prop y=1.3in \
--prop width=3.5in --prop height=2.6in \
--prop alt="pseudo-photo gradient" \
--prop name=hero-photo \
--prop compressionState=print
```
**Features:** `--type picture`, `src` (file path or `data:image/…;base64,…` data-URI), `x`/`y`/`width`/`height` (position and size), `alt` (accessibility alt text), `name` (stable @name identifier), `compressionState` (print, hqprint, screen — controls DPI stored in OOXML)
---
### Slide 2 — Crop Variants
Six pictures showing every crop form: symmetric, two-value (vertical/horizontal), four-value (L,T,R,B), and per-edge named props.
```bash
officecli add pictures-basic.pptx / --type slide
# Original — no crop (reference)
officecli add pictures-basic.pptx '/slide[2]' --type picture \
--prop src="/path/to/geometric.png" \
--prop x=0.5in --prop y=1.3in --prop width=3in --prop height=2.2in
# crop=20 — same 20% trimmed from all four edges
officecli add pictures-basic.pptx '/slide[2]' --type picture \
--prop src="/path/to/geometric.png" \
--prop crop=20 \
--prop x=4in --prop y=1.3in --prop width=3in --prop height=2.2in
# crop=10,30 — 10% off top/bottom, 30% off left/right (vertical,horizontal)
officecli add pictures-basic.pptx '/slide[2]' --type picture \
--prop src="/path/to/geometric.png" \
--prop crop=10,30 \
--prop x=7.5in --prop y=1.3in --prop width=3in --prop height=2.2in
# Per-edge named props: cropLeft + cropTop independently
officecli add pictures-basic.pptx '/slide[2]' --type picture \
--prop src="/path/to/geometric.png" \
--prop cropLeft=25 --prop cropTop=25 \
--prop x=0.5in --prop y=4.3in --prop width=3in --prop height=2.2in
# Four-value crop: crop=L,T,R,B (left, top, right, bottom percentages)
officecli add pictures-basic.pptx '/slide[2]' --type picture \
--prop src="/path/to/geometric.png" \
--prop crop=5,10,40,20 \
--prop x=4in --prop y=4.3in --prop width=3in --prop height=2.2in
```
**Features:** `crop` (symmetric: single value; vertical+horizontal: two values; L,T,R,B: four values), `cropLeft`, `cropTop`, `cropRight`, `cropBottom` (per-edge named form; all values in percentage of original image dimension)
---
### Slide 3 — Rotation
Six pictures of the same image at different rotation angles.
```bash
officecli add pictures-basic.pptx / --type slide
# rotation= degrees clockwise (positive) or counter-clockwise (negative)
officecli add pictures-basic.pptx '/slide[3]' --type picture \
--prop src="/path/to/geometric.png" \
--prop x=0.5in --prop y=1.5in --prop width=3in --prop height=2.2in \
--prop rotation=0
officecli add pictures-basic.pptx '/slide[3]' --type picture \
--prop src="/path/to/geometric.png" \
--prop x=4.5in --prop y=1.5in --prop width=3in --prop height=2.2in \
--prop rotation=30
officecli add pictures-basic.pptx '/slide[3]' --type picture \
--prop src="/path/to/geometric.png" \
--prop x=8.5in --prop y=1.5in --prop width=3in --prop height=2.2in \
--prop rotation=90
officecli add pictures-basic.pptx '/slide[3]' --type picture \
--prop src="/path/to/geometric.png" \
--prop x=0.5in --prop y=4.5in --prop width=3in --prop height=2.2in \
--prop rotation=180
officecli add pictures-basic.pptx '/slide[3]' --type picture \
--prop src="/path/to/geometric.png" \
--prop x=4.5in --prop y=4.5in --prop width=3in --prop height=2.2in \
--prop rotation=270
officecli add pictures-basic.pptx '/slide[3]' --type picture \
--prop src="/path/to/geometric.png" \
--prop x=8.5in --prop y=4.5in --prop width=3in --prop height=2.2in \
--prop rotation=-45
```
**Features:** `rotation` (degrees clockwise; negative values rotate counter-clockwise; 0360 range, also accepts negative)
---
### Slide 4 — Clickable Pictures (link= and tooltip=)
Three pictures demonstrating all three `link=` target types: external URL, in-deck slide jump, and named action.
```bash
officecli add pictures-basic.pptx / --type slide
# External URL — opens in browser on click
officecli add pictures-basic.pptx '/slide[4]' --type picture \
--prop src="/path/to/gradient.png" \
--prop x=0.5in --prop y=1.5in --prop width=3.5in --prop height=2.6in \
--prop link=https://example.com \
--prop tooltip="Open example.com"
# In-deck slide jump — link to another slide by path syntax
officecli add pictures-basic.pptx '/slide[4]' --type picture \
--prop src="/path/to/geometric.png" \
--prop x=4.5in --prop y=1.5in --prop width=3.5in --prop height=2.6in \
--prop link="slide[1]" \
--prop tooltip="Back to slide 1"
# Named action — PowerPoint built-in presentation control
officecli add pictures-basic.pptx '/slide[4]' --type picture \
--prop src="/path/to/photo.png" \
--prop x=8.5in --prop y=1.5in --prop width=3.5in --prop height=2.6in \
--prop link=nextslide \
--prop tooltip="Advance one slide"
```
**Features:** `link` (URL for external; `slide[N]` for in-deck jump; named actions: nextslide, previousslide, firstslide, lastslide, endshow), `tooltip` (hover text shown in presentation mode)
---
### Slide 5 — Set-Only Effects (brightness / contrast / glow / shadow)
These four properties are declared `add:false / set:true` in the schema — add the picture first, then apply effects via `set`. Also demonstrates `cropRight` / `cropBottom` by-name form.
```bash
officecli add pictures-basic.pptx / --type slide
# Add pictures without effects first; capture their DOM paths
# (officecli prints "Added picture at /slide[N]/picture[@id=M]")
P_REF=$(officecli add pictures-basic.pptx '/slide[5]' --type picture \
--prop src="/path/to/photo.png" \
--prop x=0.5in --prop y=1.2in --prop width=2.8in --prop height=2.1in \
| awk '/Added picture at/ {print $NF}')
P_BRIGHT=$(officecli add pictures-basic.pptx '/slide[5]' --type picture \
--prop src="/path/to/photo.png" \
--prop x=3.6in --prop y=1.2in --prop width=2.8in --prop height=2.1in \
| awk '/Added picture at/ {print $NF}')
P_CON=$(officecli add pictures-basic.pptx '/slide[5]' --type picture \
--prop src="/path/to/photo.png" \
--prop x=6.7in --prop y=1.2in --prop width=2.8in --prop height=2.1in \
| awk '/Added picture at/ {print $NF}')
P_COMBO=$(officecli add pictures-basic.pptx '/slide[5]' --type picture \
--prop src="/path/to/photo.png" \
--prop x=9.8in --prop y=1.2in --prop width=2.8in --prop height=2.1in \
| awk '/Added picture at/ {print $NF}')
# Apply effects via set — brightness: -100..100 (%)
officecli set pictures-basic.pptx "$P_BRIGHT" --prop brightness=40
officecli set pictures-basic.pptx "$P_CON" --prop contrast=-30
officecli set pictures-basic.pptx "$P_COMBO" --prop brightness=-20 --prop contrast=40
# glow — "color-radius-opacity" compound
P_GLOW=$(officecli add pictures-basic.pptx '/slide[5]' --type picture \
--prop src="/path/to/photo.png" \
--prop x=0.5in --prop y=4.2in --prop width=2.8in --prop height=2.1in \
| awk '/Added picture at/ {print $NF}')
officecli set pictures-basic.pptx "$P_GLOW" --prop glow=FFD700-12-75
# shadow — "color-blur-angle-dist-opacity" compound
P_SHADOW=$(officecli add pictures-basic.pptx '/slide[5]' --type picture \
--prop src="/path/to/photo.png" \
--prop x=3.6in --prop y=4.2in --prop width=2.8in --prop height=2.1in \
| awk '/Added picture at/ {print $NF}')
officecli set pictures-basic.pptx "$P_SHADOW" --prop shadow=000000-10-45-6-50
# cropRight + cropBottom by-name at Add time (no set needed — these are add-capable)
officecli add pictures-basic.pptx '/slide[5]' --type picture \
--prop src="/path/to/photo.png" \
--prop x=6.7in --prop y=4.2in --prop width=2.8in --prop height=2.1in \
--prop cropRight=25 --prop cropBottom=15
# All effects combined on one picture
P_ALL=$(officecli add pictures-basic.pptx '/slide[5]' --type picture \
--prop src="/path/to/photo.png" \
--prop x=9.8in --prop y=4.2in --prop width=2.8in --prop height=2.1in \
--prop cropLeft=10 --prop cropTop=10 --prop cropRight=10 --prop cropBottom=10 \
| awk '/Added picture at/ {print $NF}')
officecli set pictures-basic.pptx "$P_ALL" \
--prop brightness=15 --prop contrast=20 \
--prop glow=4472C4-8-60 \
--prop shadow=000000-6-135-3-40
officecli close pictures-basic.pptx
officecli validate pictures-basic.pptx
```
**Features:** `brightness` (Set-only; -100..100 — lifts/darkens mid-tones), `contrast` (Set-only; -100..100 — expands/compresses tone range), `glow` (Set-only; `color-radius-opacity`), `shadow` (Set-only; `color-blur-angle-dist-opacity`)
> `brightness`, `contrast`, `glow`, and `shadow` are `add:false / set:true` — they cannot be passed at `add` time; use `set` on the captured picture path.
---
## Complete Feature Coverage
| Feature | Slide |
|---------|-------|
| **src=:** file path | 1 |
| **src=:** data:image/…;base64,… URI | 1 |
| **alt=:** accessibility alt text | 1 |
| **name=:** stable @name identifier | 1 |
| **compressionState:** print, hqprint, screen | 1 |
| **crop=N:** symmetric (one value) | 2 |
| **crop=V,H:** vertical + horizontal (two values) | 2 |
| **crop=L,T,R,B:** per-edge (four values) | 2 |
| **cropLeft / cropTop / cropRight / cropBottom:** named per-edge | 2, 5 |
| **rotation=:** degrees clockwise (negative = counter-clockwise) | 3 |
| **link=:** external URL | 4 |
| **link=slide[N]:** in-deck slide jump | 4 |
| **link=nextslide / …:** named action | 4 |
| **tooltip=:** hover text in presentation mode | 4 |
| **brightness=:** Set-only; -100..100 | 5 |
| **contrast=:** Set-only; -100..100 | 5 |
| **glow=:** Set-only; `color-radius-opacity` | 5 |
| **shadow=:** Set-only; `color-blur-angle-dist-opacity` | 5 |
## Inspect the Generated File
```bash
# List pictures on slide 1
officecli query pictures-basic.pptx '/slide[1]' picture
# Get full properties including src, alt, name on slide 1
officecli get pictures-basic.pptx '/slide[1]/picture[1]'
officecli get pictures-basic.pptx '/slide[1]/picture[3]'
# Inspect crop values on slide 2
officecli get pictures-basic.pptx '/slide[2]/picture[2]'
officecli get pictures-basic.pptx '/slide[2]/picture[4]'
# Check rotation values on slide 3
officecli get pictures-basic.pptx '/slide[3]/picture[2]'
# Verify link and tooltip on slide 4
officecli get pictures-basic.pptx '/slide[4]/picture[1]'
officecli get pictures-basic.pptx '/slide[4]/picture[3]'
# Get effect properties on slide 5 (after set)
officecli get pictures-basic.pptx '/slide[5]/picture[2]'
officecli get pictures-basic.pptx '/slide[5]/picture[5]'
```
Binary file not shown.
+378
View File
@@ -0,0 +1,378 @@
#!/usr/bin/env python3
"""
Basic PowerPoint pictures — embed images, position/resize, crop, rotate, hyperlink.
SDK twin of pictures-basic.sh (officecli CLI). Both produce an equivalent
pictures-basic.pptx. This one drives the **officecli Python SDK**
(`pip install officecli-sdk`): one resident is started and every picture and
textbox is shipped over the named pipe. Each item is the same
`{"command","parent","type","props"}` dict you'd put in an `officecli batch`
list; `doc.send(...)` ships one and returns its envelope (used on slide 5 to
recover the just-added picture's DOM path before a Set-only effect is applied).
This script:
1. Generates 3 sample PNGs (gradient, geometric, photo-like) in a temp dir
2. Builds a multi-slide PPTX demoing different picture properties:
- slide 1: src= file vs URL vs data-URI (three ways to supply an image)
- slide 2: crop variants — symmetric, vertical/horizontal, per-edge
- slide 3: rotation
- slide 4: hyperlinks (click-to-open URL / jump to slide / next-slide action)
- slide 5: Set-only effects — brightness / contrast / glow / shadow
Requirements:
pip install Pillow officecli-sdk # plus the `officecli` binary on PATH
Usage:
python3 pictures-basic.py
"""
import base64
import os
import shutil
import sys
import tempfile
try:
from PIL import Image, ImageDraw
except ImportError:
print("ERROR: Pillow not installed. Run: pip install Pillow")
sys.exit(1)
# --- 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__)), "pictures-basic.pptx")
def make_gradient(path, w=400, h=300, c1=(231, 76, 60), c2=(52, 152, 219)):
img = Image.new("RGB", (w, h))
pix = img.load()
for y in range(h):
t = y / (h - 1)
r = int(c1[0] * (1 - t) + c2[0] * t)
g = int(c1[1] * (1 - t) + c2[1] * t)
b = int(c1[2] * (1 - t) + c2[2] * t)
for x in range(w):
pix[x, y] = (r, g, b)
d = ImageDraw.Draw(img)
d.text((20, 20), "gradient.png", fill=(255, 255, 255))
img.save(path)
def make_geometric(path, w=400, h=300):
img = Image.new("RGB", (w, h), (245, 245, 220))
d = ImageDraw.Draw(img)
d.ellipse((50, 50, 180, 180), fill=(231, 76, 60), outline=(0, 0, 0), width=3)
d.rectangle((200, 80, 350, 220), fill=(52, 152, 219), outline=(0, 0, 0), width=3)
d.polygon([(120, 200), (60, 270), (180, 270)],
fill=(241, 196, 15), outline=(0, 0, 0))
d.text((10, 10), "geometric.png", fill=(0, 0, 0))
img.save(path)
def make_photo(path, w=400, h=300):
"""A pseudo-photo (radial gradient + noise hint)."""
img = Image.new("RGB", (w, h))
cx, cy = w / 2, h / 2
maxd = (cx ** 2 + cy ** 2) ** 0.5
pix = img.load()
for y in range(h):
for x in range(w):
d = ((x - cx) ** 2 + (y - cy) ** 2) ** 0.5 / maxd
r = int(255 * (1 - d * 0.7))
g = int(180 * (1 - d * 0.5))
b = int(80 * (1 - d * 0.3))
pix[x, y] = (r, g, b)
draw = ImageDraw.Draw(img)
draw.text((10, 10), "photo.png", fill=(255, 255, 255))
img.save(path)
def png_to_data_uri(path):
with builtin_open(path, "rb") as f:
data = base64.b64encode(f.read()).decode()
return f"data:image/png;base64,{data}"
# officecli (the module) defines its own open(); keep the builtin for reading PNGs.
builtin_open = open
def add(doc, parent, typ, **props):
"""Ship one `add` item over the pipe; return the parsed envelope."""
return doc.send({"command": "add", "parent": parent, "type": typ, "props": props})
def add_pic_path(doc, parent, **props):
"""Add a picture and return its DOM path from the success envelope."""
env = add(doc, parent, "picture", **props)
# envelope: {"success": true, "data": "Added picture at /slide[5]/shape[@id=...]"}
msg = env.get("data") if isinstance(env, dict) else None
if not msg:
msg = env.get("message") if isinstance(env, dict) else None
if msg and "Added picture at" in msg:
return msg.split()[-1]
raise RuntimeError("Could not extract picture path from: " + repr(env))
def main():
if os.path.exists(FILE):
os.remove(FILE)
workdir = tempfile.mkdtemp(prefix="ocli-pics-")
try:
grad = os.path.join(workdir, "gradient.png")
geo = os.path.join(workdir, "geometric.png")
photo = os.path.join(workdir, "photo.png")
make_gradient(grad)
make_geometric(geo)
make_photo(photo)
print(f"Building {FILE} ...")
with officecli.create(FILE, "--force") as doc:
# ── Slide 1: three src= forms ─────────────────────────────────────
add(doc, "/", "slide")
add(doc, "/slide[1]", "textbox",
text="Three ways to supply src= (file path / data-URI)",
size="24", bold="true",
x="0.5in", y="0.3in", width="12in", height="0.6in")
# 1a. File path
add(doc, "/slide[1]", "picture",
src=grad,
x="0.5in", y="1.3in", width="3.5in", height="2.6in",
alt="gradient image from disk")
add(doc, "/slide[1]", "textbox",
text="src=<file path>",
size="12", italic="true",
x="0.5in", y="4in", width="3.5in", height="0.4in")
# 1b. data-URI
uri = png_to_data_uri(geo)
add(doc, "/slide[1]", "picture",
src=uri,
x="4.5in", y="1.3in", width="3.5in", height="2.6in",
alt="geometric shapes embedded as data-URI")
add(doc, "/slide[1]", "textbox",
text="src=data:image/png;base64,...",
size="12", italic="true",
x="4.5in", y="4in", width="3.5in", height="0.4in")
# 1c. Another file (use the photo)
add(doc, "/slide[1]", "picture",
src=photo,
x="8.5in", y="1.3in", width="3.5in", height="2.6in",
alt="pseudo-photo gradient",
name="hero-photo",
compressionState="print")
add(doc, "/slide[1]", "textbox",
text='src=<file> + name="hero-photo" + compressionState=print',
size="12", italic="true",
x="8.5in", y="4in", width="3.5in", height="0.4in")
# ── Slide 2: crop variants ────────────────────────────────────────
add(doc, "/", "slide")
add(doc, "/slide[2]", "textbox",
text="Crop — symmetric / vertical,horizontal / per-edge",
size="24", bold="true",
x="0.5in", y="0.3in", width="12in", height="0.6in")
# Original (uncropped reference)
add(doc, "/slide[2]", "picture",
src=geo,
x="0.5in", y="1.3in", width="3in", height="2.2in")
add(doc, "/slide[2]", "textbox",
text="original (no crop)", size="12",
x="0.5in", y="3.6in", width="3in", height="0.4in")
# crop=20 — symmetric all edges
add(doc, "/slide[2]", "picture",
src=geo, crop="20",
x="4in", y="1.3in", width="3in", height="2.2in")
add(doc, "/slide[2]", "textbox",
text="crop=20 (20% off each edge)", size="12",
x="4in", y="3.6in", width="3in", height="0.4in")
# crop=10,30 — vertical 10%, horizontal 30%
add(doc, "/slide[2]", "picture",
src=geo, crop="10,30",
x="7.5in", y="1.3in", width="3in", height="2.2in")
add(doc, "/slide[2]", "textbox",
text="crop=10,30 (10% top/bot, 30% left/right)",
size="12",
x="7.5in", y="3.6in", width="3.5in", height="0.4in")
# Per-edge: cropLeft + cropTop
add(doc, "/slide[2]", "picture",
src=geo,
cropLeft="25", cropTop="25",
x="0.5in", y="4.3in", width="3in", height="2.2in")
add(doc, "/slide[2]", "textbox",
text="cropLeft=25 + cropTop=25",
size="12",
x="0.5in", y="6.6in", width="3in", height="0.4in")
# 4-value crop: left,top,right,bottom
add(doc, "/slide[2]", "picture",
src=geo, crop="5,10,40,20",
x="4in", y="4.3in", width="3in", height="2.2in")
add(doc, "/slide[2]", "textbox",
text="crop=5,10,40,20 (L,T,R,B)",
size="12",
x="4in", y="6.6in", width="3in", height="0.4in")
# ── Slide 3: rotation ─────────────────────────────────────────────
add(doc, "/", "slide")
add(doc, "/slide[3]", "textbox",
text="Rotation — degrees clockwise",
size="24", bold="true",
x="0.5in", y="0.3in", width="12in", height="0.6in")
positions = [
(0.5, 1.5, 0),
(4.5, 1.5, 30),
(8.5, 1.5, 90),
(0.5, 4.5, 180),
(4.5, 4.5, 270),
(8.5, 4.5, -45),
]
for x, y, deg in positions:
add(doc, "/slide[3]", "picture",
src=geo,
x=f"{x}in", y=f"{y}in", width="3in", height="2.2in",
rotation=str(deg))
add(doc, "/slide[3]", "textbox",
text=f"rotation={deg}",
size="12",
x=f"{x}in", y=f"{y + 2.3}in", width="3in", height="0.4in")
# ── Slide 4: clickable hyperlinks on pictures ─────────────────────
add(doc, "/", "slide")
add(doc, "/slide[4]", "textbox",
text="Clickable Pictures — link= and tooltip=",
size="24", bold="true",
x="0.5in", y="0.3in", width="12in", height="0.6in")
# External URL
add(doc, "/slide[4]", "picture",
src=grad,
x="0.5in", y="1.5in", width="3.5in", height="2.6in",
link="https://example.com",
tooltip="Open example.com")
add(doc, "/slide[4]", "textbox",
text="link=https://example.com",
size="12",
x="0.5in", y="4.2in", width="3.5in", height="0.4in")
# In-deck slide jump
add(doc, "/slide[4]", "picture",
src=geo,
x="4.5in", y="1.5in", width="3.5in", height="2.6in",
link="slide[1]",
tooltip="Back to slide 1")
add(doc, "/slide[4]", "textbox",
text="link=slide[1] (jump to slide 1)",
size="12",
x="4.5in", y="4.2in", width="3.5in", height="0.4in")
# Named action: nextslide
add(doc, "/slide[4]", "picture",
src=photo,
x="8.5in", y="1.5in", width="3.5in", height="2.6in",
link="nextslide",
tooltip="Advance one slide")
add(doc, "/slide[4]", "textbox",
text="link=nextslide (named action)",
size="12",
x="8.5in", y="4.2in", width="3.5in", height="0.4in")
# ── Slide 5: Set-only effects — brightness, contrast, glow, shadow ─
# These four props are schema-declared add:false / set:true. Pattern:
# Add the picture, then Set the effect on the captured path. Also
# exercises cropBottom / cropRight by their named form (vs the
# 4-value crop= shape).
add(doc, "/", "slide")
add(doc, "/slide[5]", "textbox",
text="Picture effects (Set-only) — brightness / contrast / glow / shadow",
size="24", bold="true",
x="0.5in", y="0.3in", width="13in", height="0.6in")
def add_pic_and_get_path(slide, x, y, **extra):
"""Add a picture and return its DOM path from the envelope."""
return add_pic_path(
doc, f"/slide[{slide}]",
src=photo,
x=f"{x}in", y=f"{y}in", width="2.8in", height="2.1in",
**{k: str(v) for k, v in extra.items()})
def label(slide, x, y, text):
add(doc, f"/slide[{slide}]", "textbox",
text=text,
size="11", italic="true",
x=f"{x}in", y=f"{y}in", width="2.8in", height="0.4in")
def set_(path, **props):
doc.send({"command": "set", "path": path, "props": props})
# Reference (untouched)
add_pic_and_get_path(5, 0.5, 1.2)
label(5, 0.5, 3.4, "(reference)")
# brightness +40 — lifts mid-tones
p_bright = add_pic_and_get_path(5, 3.6, 1.2)
set_(p_bright, brightness="40")
label(5, 3.6, 3.4, "brightness=40")
# contrast -30 — flattens
p_con = add_pic_and_get_path(5, 6.7, 1.2)
set_(p_con, contrast="-30")
label(5, 6.7, 3.4, "contrast=-30")
# brightness + contrast together
p_combo = add_pic_and_get_path(5, 9.8, 1.2)
set_(p_combo, brightness="-20", contrast="40")
label(5, 9.8, 3.4, "brightness=-20 + contrast=40")
# glow — `color-radius-opacity`
p_glow = add_pic_and_get_path(5, 0.5, 4.2)
set_(p_glow, glow="FFD700-12-75")
label(5, 0.5, 6.4, "glow=FFD700-12-75")
# shadow — `color-blur-angle-dist-opacity`
p_shadow = add_pic_and_get_path(5, 3.6, 4.2)
set_(p_shadow, shadow="000000-10-45-6-50")
label(5, 3.6, 6.4, "shadow=000000-10-45-6-50")
# cropRight + cropBottom — by-name form (vs the 4-value crop=)
add_pic_and_get_path(5, 6.7, 4.2, cropRight=25, cropBottom=15)
label(5, 6.7, 6.4, "cropRight=25 + cropBottom=15")
# Everything together: trim corners + brightness + glow + shadow
p_all = add_pic_and_get_path(5, 9.8, 4.2, cropLeft=10, cropTop=10,
cropRight=10, cropBottom=10)
set_(p_all,
brightness="15",
contrast="20",
glow="4472C4-8-60",
shadow="000000-6-135-3-40")
label(5, 9.8, 6.4, "trimmed + bright + contrast + glow + shadow")
doc.send({"command": "save"})
# context exit closes the resident, flushing the deck to disk.
print(f"Created: {FILE}")
finally:
shutil.rmtree(workdir, ignore_errors=True)
if __name__ == "__main__":
main()
+305
View File
@@ -0,0 +1,305 @@
#!/bin/bash
# Basic PowerPoint pictures — embed images, position/resize, crop, rotate, hyperlink.
#
# CLI twin of pictures-basic.py (officecli Python SDK). Both produce an
# equivalent pictures-basic.pptx. This one drives the officecli binary directly:
# one `officecli ... --prop k=v` invocation per element.
#
# - slide 1: src= file vs data-URI (ways to supply an image)
# - slide 2: crop variants — symmetric, vertical/horizontal, per-edge
# - slide 3: rotation
# - slide 4: hyperlinks (click-to-open URL / jump to slide / next-slide action)
# - slide 5: Set-only effects — brightness / contrast / glow / shadow
#
# Requirements: Pillow (pip install Pillow) to synthesize the sample PNGs.
# Usage: ./pictures-basic.sh [officecli path]
# NOTE: intentionally NO `set -e`. Like the SDK twin's doc.batch, this script
# tolerates forward-compat 'UNSUPPORTED props' warnings (officecli exit 2) and
# keeps building so the full document is produced.
CLI="${1:-officecli}"
FILE="$(dirname "$0")/pictures-basic.pptx"
WORKDIR="$(mktemp -d -t ocli-pics-XXXXXX)"
trap 'rm -rf "$WORKDIR"' EXIT
GRAD="$WORKDIR/gradient.png"
GEO="$WORKDIR/geometric.png"
PHOTO="$WORKDIR/photo.png"
# ── Synthesize the three sample PNGs (gradient, geometric, photo-like) ─────────
python3 - "$GRAD" "$GEO" "$PHOTO" <<'PY'
import sys
from PIL import Image, ImageDraw
grad, geo, photo = sys.argv[1:4]
def make_gradient(path, w=400, h=300, c1=(231, 76, 60), c2=(52, 152, 219)):
img = Image.new("RGB", (w, h)); pix = img.load()
for y in range(h):
t = y / (h - 1)
r = int(c1[0] * (1 - t) + c2[0] * t)
g = int(c1[1] * (1 - t) + c2[1] * t)
b = int(c1[2] * (1 - t) + c2[2] * t)
for x in range(w):
pix[x, y] = (r, g, b)
ImageDraw.Draw(img).text((20, 20), "gradient.png", fill=(255, 255, 255))
img.save(path)
def make_geometric(path, w=400, h=300):
img = Image.new("RGB", (w, h), (245, 245, 220)); d = ImageDraw.Draw(img)
d.ellipse((50, 50, 180, 180), fill=(231, 76, 60), outline=(0, 0, 0), width=3)
d.rectangle((200, 80, 350, 220), fill=(52, 152, 219), outline=(0, 0, 0), width=3)
d.polygon([(120, 200), (60, 270), (180, 270)], fill=(241, 196, 15), outline=(0, 0, 0))
d.text((10, 10), "geometric.png", fill=(0, 0, 0))
img.save(path)
def make_photo(path, w=400, h=300):
img = Image.new("RGB", (w, h)); cx, cy = w / 2, h / 2
maxd = (cx ** 2 + cy ** 2) ** 0.5; pix = img.load()
for y in range(h):
for x in range(w):
dd = ((x - cx) ** 2 + (y - cy) ** 2) ** 0.5 / maxd
pix[x, y] = (int(255 * (1 - dd * 0.7)), int(180 * (1 - dd * 0.5)), int(80 * (1 - dd * 0.3)))
ImageDraw.Draw(img).text((10, 10), "photo.png", fill=(255, 255, 255))
img.save(path)
make_gradient(grad); make_geometric(geo); make_photo(photo)
PY
# data-URI form for the geometric image (slide 1b)
GEO_URI="data:image/png;base64,$(base64 < "$GEO" | tr -d '\n')"
rm -f "$FILE"
$CLI create "$FILE"
$CLI open "$FILE"
# ══════════════════════════════════════════════════════════════════════════════
# Slide 1: three src= forms (file path / data-URI)
# ══════════════════════════════════════════════════════════════════════════════
$CLI add "$FILE" / --type slide
$CLI add "$FILE" "/slide[1]" --type textbox \
--prop text="Three ways to supply src= (file path / data-URI)" \
--prop size=24 --prop bold=true \
--prop x=0.5in --prop y=0.3in --prop width=12in --prop height=0.6in
# 1a. File path
$CLI add "$FILE" "/slide[1]" --type picture \
--prop src="$GRAD" \
--prop x=0.5in --prop y=1.3in --prop width=3.5in --prop height=2.6in \
--prop alt="gradient image from disk"
$CLI add "$FILE" "/slide[1]" --type textbox \
--prop text="src=<file path>" \
--prop size=12 --prop italic=true \
--prop x=0.5in --prop y=4in --prop width=3.5in --prop height=0.4in
# 1b. data-URI
$CLI add "$FILE" "/slide[1]" --type picture \
--prop src="$GEO_URI" \
--prop x=4.5in --prop y=1.3in --prop width=3.5in --prop height=2.6in \
--prop alt="geometric shapes embedded as data-URI"
$CLI add "$FILE" "/slide[1]" --type textbox \
--prop text="src=data:image/png;base64,..." \
--prop size=12 --prop italic=true \
--prop x=4.5in --prop y=4in --prop width=3.5in --prop height=0.4in
# 1c. Another file (use the photo)
$CLI add "$FILE" "/slide[1]" --type picture \
--prop src="$PHOTO" \
--prop x=8.5in --prop y=1.3in --prop width=3.5in --prop height=2.6in \
--prop alt="pseudo-photo gradient" \
--prop name="hero-photo" \
--prop compressionState=print
$CLI add "$FILE" "/slide[1]" --type textbox \
--prop text='src=<file> + name="hero-photo" + compressionState=print' \
--prop size=12 --prop italic=true \
--prop x=8.5in --prop y=4in --prop width=3.5in --prop height=0.4in
# ══════════════════════════════════════════════════════════════════════════════
# Slide 2: crop variants
# ══════════════════════════════════════════════════════════════════════════════
$CLI add "$FILE" / --type slide
$CLI add "$FILE" "/slide[2]" --type textbox \
--prop text="Crop — symmetric / vertical,horizontal / per-edge" \
--prop size=24 --prop bold=true \
--prop x=0.5in --prop y=0.3in --prop width=12in --prop height=0.6in
# Original (uncropped reference)
$CLI add "$FILE" "/slide[2]" --type picture \
--prop src="$GEO" \
--prop x=0.5in --prop y=1.3in --prop width=3in --prop height=2.2in
$CLI add "$FILE" "/slide[2]" --type textbox \
--prop text="original (no crop)" --prop size=12 \
--prop x=0.5in --prop y=3.6in --prop width=3in --prop height=0.4in
# crop=20 — symmetric all edges
$CLI add "$FILE" "/slide[2]" --type picture \
--prop src="$GEO" --prop crop=20 \
--prop x=4in --prop y=1.3in --prop width=3in --prop height=2.2in
$CLI add "$FILE" "/slide[2]" --type textbox \
--prop text="crop=20 (20% off each edge)" --prop size=12 \
--prop x=4in --prop y=3.6in --prop width=3in --prop height=0.4in
# crop=10,30 — vertical 10%, horizontal 30%
$CLI add "$FILE" "/slide[2]" --type picture \
--prop src="$GEO" --prop crop=10,30 \
--prop x=7.5in --prop y=1.3in --prop width=3in --prop height=2.2in
$CLI add "$FILE" "/slide[2]" --type textbox \
--prop text="crop=10,30 (10% top/bot, 30% left/right)" --prop size=12 \
--prop x=7.5in --prop y=3.6in --prop width=3.5in --prop height=0.4in
# Per-edge: cropLeft + cropTop
$CLI add "$FILE" "/slide[2]" --type picture \
--prop src="$GEO" \
--prop cropLeft=25 --prop cropTop=25 \
--prop x=0.5in --prop y=4.3in --prop width=3in --prop height=2.2in
$CLI add "$FILE" "/slide[2]" --type textbox \
--prop text="cropLeft=25 + cropTop=25" --prop size=12 \
--prop x=0.5in --prop y=6.6in --prop width=3in --prop height=0.4in
# 4-value crop: left,top,right,bottom
$CLI add "$FILE" "/slide[2]" --type picture \
--prop src="$GEO" --prop crop=5,10,40,20 \
--prop x=4in --prop y=4.3in --prop width=3in --prop height=2.2in
$CLI add "$FILE" "/slide[2]" --type textbox \
--prop text="crop=5,10,40,20 (L,T,R,B)" --prop size=12 \
--prop x=4in --prop y=6.6in --prop width=3in --prop height=0.4in
# ══════════════════════════════════════════════════════════════════════════════
# Slide 3: rotation
# ══════════════════════════════════════════════════════════════════════════════
$CLI add "$FILE" / --type slide
$CLI add "$FILE" "/slide[3]" --type textbox \
--prop text="Rotation — degrees clockwise" \
--prop size=24 --prop bold=true \
--prop x=0.5in --prop y=0.3in --prop width=12in --prop height=0.6in
# positions: x y degrees ; ylabel = y + 2.3
for spec in "0.5 1.5 0 3.8" "4.5 1.5 30 3.8" "8.5 1.5 90 3.8" \
"0.5 4.5 180 6.8" "4.5 4.5 270 6.8" "8.5 4.5 -45 6.8"; do
set -- $spec
X="$1"; Y="$2"; DEG="$3"; YLAB="$4"
$CLI add "$FILE" "/slide[3]" --type picture \
--prop src="$GEO" \
--prop x="${X}in" --prop y="${Y}in" --prop width=3in --prop height=2.2in \
--prop rotation="$DEG"
$CLI add "$FILE" "/slide[3]" --type textbox \
--prop text="rotation=$DEG" --prop size=12 \
--prop x="${X}in" --prop y="${YLAB}in" --prop width=3in --prop height=0.4in
done
# ══════════════════════════════════════════════════════════════════════════════
# Slide 4: clickable hyperlinks on pictures
# ══════════════════════════════════════════════════════════════════════════════
$CLI add "$FILE" / --type slide
$CLI add "$FILE" "/slide[4]" --type textbox \
--prop text="Clickable Pictures — link= and tooltip=" \
--prop size=24 --prop bold=true \
--prop x=0.5in --prop y=0.3in --prop width=12in --prop height=0.6in
# External URL
$CLI add "$FILE" "/slide[4]" --type picture \
--prop src="$GRAD" \
--prop x=0.5in --prop y=1.5in --prop width=3.5in --prop height=2.6in \
--prop link="https://example.com" \
--prop tooltip="Open example.com"
$CLI add "$FILE" "/slide[4]" --type textbox \
--prop text="link=https://example.com" --prop size=12 \
--prop x=0.5in --prop y=4.2in --prop width=3.5in --prop height=0.4in
# In-deck slide jump
$CLI add "$FILE" "/slide[4]" --type picture \
--prop src="$GEO" \
--prop x=4.5in --prop y=1.5in --prop width=3.5in --prop height=2.6in \
--prop link="slide[1]" \
--prop tooltip="Back to slide 1"
$CLI add "$FILE" "/slide[4]" --type textbox \
--prop text="link=slide[1] (jump to slide 1)" --prop size=12 \
--prop x=4.5in --prop y=4.2in --prop width=3.5in --prop height=0.4in
# Named action: nextslide
$CLI add "$FILE" "/slide[4]" --type picture \
--prop src="$PHOTO" \
--prop x=8.5in --prop y=1.5in --prop width=3.5in --prop height=2.6in \
--prop link="nextslide" \
--prop tooltip="Advance one slide"
$CLI add "$FILE" "/slide[4]" --type textbox \
--prop text="link=nextslide (named action)" --prop size=12 \
--prop x=8.5in --prop y=4.2in --prop width=3.5in --prop height=0.4in
# ══════════════════════════════════════════════════════════════════════════════
# Slide 5: Set-only effects — brightness / contrast / glow / shadow
# These four props are schema-declared add:false / set:true. Pattern: Add the
# picture, capture its DOM path from the "Added picture at ..." message, then
# Set the effect. Also exercises cropBottom / cropRight by their named form.
# ══════════════════════════════════════════════════════════════════════════════
$CLI add "$FILE" / --type slide
$CLI add "$FILE" "/slide[5]" --type textbox \
--prop text="Picture effects (Set-only) — brightness / contrast / glow / shadow" \
--prop size=24 --prop bold=true \
--prop x=0.5in --prop y=0.3in --prop width=13in --prop height=0.6in
# add_pic <x> <y> [extra --prop args...] ; echoes the picture's DOM path
add_pic() {
local x="$1" y="$2"; shift 2
local out
out=$($CLI add "$FILE" "/slide[5]" --type picture \
--prop src="$PHOTO" \
--prop x="${x}in" --prop y="${y}in" --prop width=2.8in --prop height=2.1in \
"$@")
# "Added picture at /slide[5]/shape[@id=...]" → last token
echo "$out" | grep "Added picture at" | tail -1 | awk '{print $NF}'
}
label() { # label <x> <y> <text>
$CLI add "$FILE" "/slide[5]" --type textbox \
--prop text="$3" --prop size=11 --prop italic=true \
--prop x="${1}in" --prop y="${2}in" --prop width=2.8in --prop height=0.4in
}
# Reference (untouched)
add_pic 0.5 1.2 >/dev/null
label 0.5 3.4 "(reference)"
# brightness +40 — lifts mid-tones
P_BRIGHT=$(add_pic 3.6 1.2)
$CLI set "$FILE" "$P_BRIGHT" --prop brightness=40
label 3.6 3.4 "brightness=40"
# contrast -30 — flattens
P_CON=$(add_pic 6.7 1.2)
$CLI set "$FILE" "$P_CON" --prop contrast=-30
label 6.7 3.4 "contrast=-30"
# brightness + contrast together
P_COMBO=$(add_pic 9.8 1.2)
$CLI set "$FILE" "$P_COMBO" --prop brightness=-20 --prop contrast=40
label 9.8 3.4 "brightness=-20 + contrast=40"
# glow — color-radius-opacity
P_GLOW=$(add_pic 0.5 4.2)
$CLI set "$FILE" "$P_GLOW" --prop glow=FFD700-12-75
label 0.5 6.4 "glow=FFD700-12-75"
# shadow — color-blur-angle-dist-opacity
P_SHADOW=$(add_pic 3.6 4.2)
$CLI set "$FILE" "$P_SHADOW" --prop shadow=000000-10-45-6-50
label 3.6 6.4 "shadow=000000-10-45-6-50"
# cropRight + cropBottom — by-name form (vs the 4-value crop=)
add_pic 6.7 4.2 --prop cropRight=25 --prop cropBottom=15 >/dev/null
label 6.7 6.4 "cropRight=25 + cropBottom=15"
# Everything together: trim corners + brightness + contrast + glow + shadow
P_ALL=$(add_pic 9.8 4.2 --prop cropLeft=10 --prop cropTop=10 --prop cropRight=10 --prop cropBottom=10)
$CLI set "$FILE" "$P_ALL" \
--prop brightness=15 \
--prop contrast=20 \
--prop glow=4472C4-8-60 \
--prop shadow=000000-6-135-3-40
label 9.8 6.4 "trimmed + bright + contrast + glow + shadow"
$CLI close "$FILE"
$CLI validate "$FILE"
echo "Generated: $FILE"
+5
View File
@@ -0,0 +1,5 @@
pie showData title Traffic Sources
"Organic Search" : 45
"Direct" : 30
"Referral" : 15
"Social" : 10
+129
View File
@@ -0,0 +1,129 @@
# Presentation Settings Showcase
Exercises the pptx `presentation` property surface — the deck-level settings with
no per-slide or per-shape equivalent. Four files work together:
- **presentation-settings.sh** — builds the deck via the `officecli` CLI (this file walks through it).
- **presentation-settings.py** — the same build via the **officecli Python SDK** (one `doc.send()` per command, mirroring the `.sh` line for line).
- **presentation-settings.pptx** — the generated deck (either script produces it).
- **presentation-settings.md** — this file.
The CLI commands shown below are exactly what `presentation-settings.sh` runs;
the `.py` issues the identical sequence over the SDK pipe.
## The `presentation` container
`presentation` is a read-only container addressed at path `/` — you never `add`
or `remove` it, only `set`/`get`:
```bash
officecli set file.pptx / --prop title="Q4 Review" --prop slideSize=widescreen
officecli get file.pptx /
```
> A blank pptx has a master + layouts but **no slides**. The script adds one
> (`add / --type slide`) before placing the title shape — `add /slide[1] …` on a
> deck with zero slides is a no-op.
## Regenerate
```bash
cd examples/ppt
bash presentation-settings.sh # via the CLI
# — or —
pip install officecli-sdk # the SDK (officecli binary still required)
python3 presentation-settings.py # via the SDK, same result
# → presentation-settings.pptx
```
## Property groups
### 1. Metadata (core + extended properties)
```bash
officecli set file.pptx / --prop author="Jane Author" --prop title="Q4 Business Review" \
--prop subject=Strategy --prop keywords="q4,review,strategy" \
--prop description="Quarterly business review deck." --prop category=Marketing \
--prop lastModifiedBy=Editorial --prop revisionNumber=3
officecli set file.pptx / --prop extended.company="Acme Corp" \
--prop extended.manager="Dana Lead" --prop extended.template="Widescreen.potx"
```
### 2. Slide setup
```bash
officecli set file.pptx / --prop slideSize=widescreen \ # 4:3 | widescreen | onscreen16x10 | a4 | letter
--prop firstSlideNum=1 --prop rtl=false --prop compatMode=false
```
`slideSize` is a named preset. Setting explicit `slideWidth`/`slideHeight`
instead makes the deck a **custom** size (the two are mutually exclusive):
```bash
officecli set file.pptx / --prop slideWidth=25.4cm --prop slideHeight=19.05cm # custom 4:3
```
### 3. Print setup
```bash
officecli set file.pptx / \
--prop print.what=slides \ # slides | handouts | notes | outline
--prop print.colorMode=color \ # color | gray | bw
--prop print.frameSlides=true \
--prop print.hiddenSlides=false \
--prop print.scaleToFitPaper=true
```
### 4. Slideshow behaviour
```bash
officecli set file.pptx / \
--prop show.loop=false --prop show.narration=true \
--prop show.animation=true --prop show.useTimings=true
```
### 5. Privacy
```bash
officecli set file.pptx / --prop removePersonalInfo=false
```
### 6. Theme — palette accents and major/minor fonts
A blank pptx ships a theme part, so theme edits resolve. The title shape uses
`fill=accent1`, so remapping `theme.color.accent1` recolours it — the rendered
deck shows the title bar in the new accent, not the Office default:
```bash
officecli set file.pptx / \
--prop theme.color.accent1=1F6FEB --prop theme.color.accent2=E3572A \
--prop theme.color.hlink=0969DA
officecli set file.pptx / \
--prop theme.font.major.latin=Georgia --prop theme.font.minor.latin=Calibri
```
## Complete feature coverage
| Group | Keys |
|---|---|
| Metadata | `author`, `title`, `subject`, `keywords`, `description`, `category`, `lastModifiedBy`, `revisionNumber`, `extended.*` |
| Slide setup | `slideSize`, `slideWidth`, `slideHeight`, `firstSlideNum`, `rtl`, `compatMode` |
| Print | `print.what`, `print.colorMode`, `print.frameSlides`, `print.hiddenSlides`, `print.scaleToFitPaper` |
| Slideshow | `show.loop`, `show.narration`, `show.animation`, `show.useTimings` |
| Privacy | `removePersonalInfo` |
| Theme | `theme.color.accent1..6/dk/lt/hlink/folHlink`, `theme.font.major/minor.latin/eastAsia` |
Full list: `officecli help pptx presentation`. (A separate `/theme` element —
`officecli help pptx theme` — exposes the same palette under shorter keys.)
## Set → Get round-trip
```
author = Jane Author
title = Q4 Business Review
slideSize = widescreen
print.what = slides
show.useTimings = True
theme.color.accent1 = #1F6FEB
theme.font.major.latin = Georgia
```
Binary file not shown.
+107
View File
@@ -0,0 +1,107 @@
#!/usr/bin/env python3
"""
Presentation Settings Showcase — generates presentation-settings.pptx exercising
the full pptx `presentation` property surface
(schemas/help/pptx/presentation.json): the deck-level settings with no per-slide
or per-shape equivalent.
`presentation` is a read-only container at path "/"; you only set/get it. Six
groups: metadata, slide setup, print, slideshow, privacy, theme.
SDK twin of presentation-settings.sh, mapped one-for-one:
officecli.create(...) ≈ officecli create + open
doc.send({...}) ≈ one officecli set/add (one call each, no batch)
doc.close() ≈ officecli close
Usage:
pip install officecli-sdk
python3 presentation-settings.py
"""
import os
import officecli # pip install officecli-sdk
FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)), "presentation-settings.pptx")
print("\n==========================================")
print(f"Generating presentation-settings showcase: {FILE}")
print("==========================================")
doc = officecli.create(FILE, "--force") # create the .pptx + start its resident
def pres(**props): # one presentation-container `set`
doc.send({"command": "set", "path": "/", "props": props})
def add(parent, type_, **props): # one `officecli add`
doc.send({"command": "add", "parent": parent, "type": type_, "props": props})
# --- A title slide (blank pptx has master + layouts but no slides) ---
print("\n--- Title slide ---")
add("/", "slide") # add the first slide
add("/slide[1]", "shape", geometry="rect", left="2cm", top="3cm",
width="26cm", height="4cm", fill="accent1", # fill references theme accent1
text="Presentation Settings", fontSize="40", color="FFFFFF", bold="true")
# --- 1. Metadata (core + extended) ---
print("--- Metadata ---")
pres(author="Jane Author", title="Q4 Business Review", subject="Strategy",
keywords="q4,review,strategy", description="Quarterly business review deck.",
category="Marketing", lastModifiedBy="Editorial", revisionNumber="3")
pres(**{"extended.company": "Acme Corp", "extended.manager": "Dana Lead",
"extended.template": "Widescreen.potx"})
# --- 2. Slide setup (slideSize preset; explicit slideWidth/Height = custom) ---
print("--- Slide setup ---")
pres(slideSize="widescreen", # 4:3 | widescreen | onscreen16x10 | a4 | letter
firstSlideNum="1", rtl="false", compatMode="false")
# --- 3. Print ---
print("--- Print ---")
pres(**{"print.what": "slides", # slides | handouts | notes | outline
"print.colorMode": "color", # color | gray | bw
"print.frameSlides": "true",
"print.hiddenSlides": "false",
"print.scaleToFitPaper": "true"})
# --- 4. Slideshow behaviour ---
print("--- Slideshow ---")
pres(**{"show.loop": "false", "show.narration": "true",
"show.animation": "true", "show.useTimings": "true"})
# --- 5. Privacy ---
print("--- Privacy ---")
pres(removePersonalInfo="false") # keep document properties on save
# --- 6. Theme — palette (dk/lt + accent1..6) and major/minor fonts ---
print("--- Theme ---")
pres(**{"theme.color.dk1": "1A1A1A", "theme.color.lt1": "FFFFFF",
"theme.color.dk2": "2F3640", "theme.color.lt2": "EEF1F5",
"theme.color.accent1": "1F6FEB", "theme.color.accent2": "E3572A",
"theme.color.accent3": "2DA44E", "theme.color.accent4": "BF8700",
"theme.color.accent5": "8250DF", "theme.color.accent6": "1B7C83",
"theme.color.hlink": "0969DA", "theme.color.folHlink": "8250DF"})
pres(**{"theme.font.major.latin": "Georgia", "theme.font.minor.latin": "Calibri",
"theme.font.major.eastAsia": "SimHei", "theme.font.minor.eastAsia": "SimSun"})
# --- Get round-trip: confirm canonical keys read back ---
print("\n--- Round-trip readback (get / ) ---")
node = doc.send({"command": "get", "path": "/"})
fmt = node.get("data", {}).get("results", [{}])[0].get("format", {})
for k in ["author", "title", "category", "slideSize", "firstSlideNum",
"print.what", "show.useTimings", "theme.color.accent1",
"theme.font.major.latin"]:
if k in fmt:
print(f" {k} = {fmt[k]}")
# --- Validate over the pipe (in-session, no extra process) ---
print("\n--- Validate ---")
v = doc.send({"command": "validate"})
print(" Validation passed: no errors found." if v.get("success")
else f" {v.get('warnings')}")
doc.close() # stop the resident (flushes to disk)
print(f"\nCreated: {FILE}")
+62
View File
@@ -0,0 +1,62 @@
#!/bin/bash
# presentation-settings.sh — exercise the full pptx `presentation` property
# surface (schemas/help/pptx/presentation.json) using the officecli CLI directly.
#
# `presentation` is a read-only container at path "/"; you only set/get it. Six
# groups: metadata, slide setup, print, slideshow, privacy, theme. CLI twin of
# presentation-settings.py (officecli SDK); both produce an equivalent
# presentation-settings.pptx.
# NOTE: intentionally NO `set -e`. Like the SDK twin's doc.batch, this script
# tolerates forward-compat 'UNSUPPORTED props' warnings (officecli exit 2) and
# keeps building so the full document is produced.
FILE="$(dirname "$0")/presentation-settings.pptx"
echo "Building $FILE ..."
rm -f "$FILE"
officecli create "$FILE"
officecli open "$FILE"
# --- A title slide (blank pptx has master+layouts but no slides) ---
officecli add "$FILE" / --type slide
officecli add "$FILE" "/slide[1]" --type shape --prop geometry=rect \
--prop left=2cm --prop top=3cm --prop width=26cm --prop height=4cm \
--prop fill=accent1 --prop text="Presentation Settings" \
--prop fontSize=40 --prop color=FFFFFF --prop bold=true
# --- 1. Metadata (core + extended) ---
officecli set "$FILE" / --prop author="Jane Author" --prop title="Q4 Business Review" \
--prop subject=Strategy --prop keywords="q4,review,strategy" \
--prop description="Quarterly business review deck." --prop category=Marketing \
--prop lastModifiedBy=Editorial --prop revisionNumber=3
officecli set "$FILE" / --prop extended.company="Acme Corp" \
--prop extended.manager="Dana Lead" --prop extended.template="Widescreen.potx"
# --- 2. Slide setup (slideSize preset; explicit slideWidth/Height = custom) ---
officecli set "$FILE" / --prop slideSize=widescreen \
--prop firstSlideNum=1 --prop rtl=false --prop compatMode=false
# --- 3. Print ---
officecli set "$FILE" / --prop print.what=slides --prop print.colorMode=color \
--prop print.frameSlides=true --prop print.hiddenSlides=false --prop print.scaleToFitPaper=true
# --- 4. Slideshow ---
officecli set "$FILE" / --prop show.loop=false --prop show.narration=true \
--prop show.animation=true --prop show.useTimings=true
# --- 5. Privacy ---
officecli set "$FILE" / --prop removePersonalInfo=false
# --- 6. Theme — palette (dk/lt + accent1..6) and major/minor fonts ---
officecli set "$FILE" / \
--prop theme.color.dk1=1A1A1A --prop theme.color.lt1=FFFFFF \
--prop theme.color.dk2=2F3640 --prop theme.color.lt2=EEF1F5 \
--prop theme.color.accent1=1F6FEB --prop theme.color.accent2=E3572A \
--prop theme.color.accent3=2DA44E --prop theme.color.accent4=BF8700 \
--prop theme.color.accent5=8250DF --prop theme.color.accent6=1B7C83 \
--prop theme.color.hlink=0969DA --prop theme.color.folHlink=8250DF
officecli set "$FILE" / \
--prop theme.font.major.latin=Georgia --prop theme.font.minor.latin=Calibri \
--prop theme.font.major.eastAsia=SimHei --prop theme.font.minor.eastAsia=SimSun
officecli close "$FILE"
officecli validate "$FILE"
echo "Created: $FILE"
+442
View File
@@ -0,0 +1,442 @@
# Presentation Showcase
This demo consists of three files that work together:
- **presentation.sh** — Shell script that calls `officecli raw-set` to build all slides. Raw XML is injected per-element for full design control.
- **presentation.pptx** — The generated 6-slide deck: title, pillars, data, quote, process, closing.
- **presentation.md** — This file. Maps each slide to the techniques it demonstrates.
## Regenerate
```bash
cd examples/ppt
bash presentation.sh
# → presentation.pptx
```
## Slides
### Slide 1 — Title Slide
Full-bleed 3-stop dark gradient background, two decorative semi-transparent circles, a gradient accent line, main title, two-paragraph subtitle, and a tiny rotated diamond.
```bash
officecli add presentation.pptx /presentation --type slide
# 3-stop vertical gradient background (dark navy)
officecli raw-set presentation.pptx /slide[1] \
--xpath "//p:cSld" --action prepend --xml '
<p:bg><p:bgPr>
<a:gradFill rotWithShape="0">
<a:gsLst>
<a:gs pos="0"><a:srgbClr val="0D1B2A"/></a:gs>
<a:gs pos="50000"><a:srgbClr val="1B2838"/></a:gs>
<a:gs pos="100000"><a:srgbClr val="0A1628"/></a:gs>
</a:gsLst>
<a:lin ang="5400000" scaled="1"/>
</a:gradFill><a:effectLst/>
</p:bgPr></p:bg>'
# Decorative teal ellipse, top-right (alpha=8000 ≈ 31% opacity)
officecli raw-set presentation.pptx /slide[1] \
--xpath "//p:cSld/p:spTree" --action append --xml '
<p:sp>
<p:nvSpPr><p:cNvPr id="100" name="Deco Circle 1"/><p:cNvSpPr/><p:nvPr/></p:nvSpPr>
<p:spPr>
<a:xfrm><a:off x="8500000" y="-1200000"/><a:ext cx="4800000" cy="4800000"/></a:xfrm>
<a:prstGeom prst="ellipse"><a:avLst/></a:prstGeom>
<a:solidFill><a:srgbClr val="00B4D8"><a:alpha val="8000"/></a:srgbClr></a:solidFill>
<a:ln><a:noFill/></a:ln>
</p:spPr>
<p:txBody><a:bodyPr/><a:lstStyle/><a:p><a:endParaRPr/></a:p></p:txBody>
</p:sp>'
# Gradient accent line (teal → lavender, horizontal)
officecli raw-set presentation.pptx /slide[1] \
--xpath "//p:cSld/p:spTree" --action append --xml '
<p:sp>
<p:nvSpPr><p:cNvPr id="102" name="Accent Line"/><p:cNvSpPr/><p:nvPr/></p:nvSpPr>
<p:spPr>
<a:xfrm><a:off x="800000" y="4200000"/><a:ext cx="5000000" cy="0"/></a:xfrm>
<a:prstGeom prst="line"><a:avLst/></a:prstGeom>
<a:ln w="28575">
<a:gradFill>
<a:gsLst>
<a:gs pos="0"><a:srgbClr val="00B4D8"/></a:gs>
<a:gs pos="100000"><a:srgbClr val="E0AAFF"/></a:gs>
</a:gsLst>
<a:lin ang="0" scaled="1"/>
</a:gradFill>
</a:ln>
</p:spPr>
<p:txBody><a:bodyPr/><a:lstStyle/><a:p><a:endParaRPr/></a:p></p:txBody>
</p:sp>'
# Main title: sz=5400 bold white, Segoe UI, anchor=b
officecli raw-set presentation.pptx /slide[1] \
--xpath "//p:cSld/p:spTree" --action append --xml '
<p:sp>
<p:nvSpPr><p:cNvPr id="103" name="Title"/><p:cNvSpPr txBox="1"/><p:nvPr/></p:nvSpPr>
<p:spPr>
<a:xfrm><a:off x="800000" y="1600000"/><a:ext cx="8000000" cy="1200000"/></a:xfrm>
<a:prstGeom prst="rect"><a:avLst/></a:prstGeom>
<a:noFill/><a:ln><a:noFill/></a:ln>
</p:spPr>
<p:txBody>
<a:bodyPr wrap="square" anchor="b"/>
<a:lstStyle/>
<a:p>
<a:pPr algn="l"/>
<a:r>
<a:rPr lang="en-US" sz="5400" b="1" dirty="0">
<a:solidFill><a:srgbClr val="FFFFFF"/></a:solidFill>
<a:latin typeface="Segoe UI"/>
</a:rPr>
<a:t>The Art of Design</a:t>
</a:r>
</a:p>
</p:txBody>
</p:sp>'
# Subtitle: paragraph 1 = sz=2000 cyan; paragraph 2 = sz=1400 grey, spc=600
officecli raw-set presentation.pptx /slide[1] \
--xpath "//p:cSld/p:spTree" --action append --xml '
<p:sp>
<p:nvSpPr><p:cNvPr id="104" name="Subtitle"/><p:cNvSpPr txBox="1"/><p:nvPr/></p:nvSpPr>
<p:spPr>
<a:xfrm><a:off x="800000" y="2900000"/><a:ext cx="8000000" cy="1100000"/></a:xfrm>
<a:prstGeom prst="rect"><a:avLst/></a:prstGeom>
<a:noFill/><a:ln><a:noFill/></a:ln>
</p:spPr>
<p:txBody>
<a:bodyPr wrap="square" anchor="t"/>
<a:lstStyle/>
<a:p>
<a:pPr algn="l"/>
<a:r>
<a:rPr lang="en-US" sz="2000" dirty="0">
<a:solidFill><a:srgbClr val="90E0EF"/></a:solidFill>
<a:latin typeface="Segoe UI"/>
</a:rPr>
<a:t>Crafting Beautiful Experiences</a:t>
</a:r>
</a:p>
<a:p>
<a:pPr algn="l"/>
<a:r>
<a:rPr lang="en-US" sz="1400" dirty="0" spc="600">
<a:solidFill><a:srgbClr val="8B95A2"/></a:solidFill>
<a:latin typeface="Segoe UI"/>
</a:rPr>
<a:t>SIMPLICITY · ELEGANCE · FUNCTION</a:t>
</a:r>
</a:p>
</p:txBody>
</p:sp>'
# Diamond accent: rot=2700000 (45°) tiny rect, teal fill
officecli raw-set presentation.pptx /slide[1] \
--xpath "//p:cSld/p:spTree" --action append --xml '
<p:sp>
<p:nvSpPr><p:cNvPr id="105" name="Diamond"/><p:cNvSpPr/><p:nvPr/></p:nvSpPr>
<p:spPr>
<a:xfrm rot="2700000"><a:off x="600000" y="4050000"/><a:ext cx="200000" cy="200000"/></a:xfrm>
<a:prstGeom prst="rect"><a:avLst/></a:prstGeom>
<a:solidFill><a:srgbClr val="00B4D8"/></a:solidFill>
<a:ln><a:noFill/></a:ln>
</p:spPr>
<p:txBody><a:bodyPr/><a:lstStyle/><a:p><a:endParaRPr/></a:p></p:txBody>
</p:sp>'
```
**Features:** `raw-set --action prepend` (background), `raw-set --action append` (shapes), 3-stop `gradFill` background, `solidFill` with `alpha`, gradient line stroke (`a:ln/a:gradFill`), `prstGeom prst="ellipse"/"line"/"rect"`, `txBox="1"`, `bodyPr anchor="b"/"t"`, `sz` (hundredths of a point), `b="1"` bold, `spc` letter-spacing, `rot` rotation, `a:latin typeface=`
### Slide 2 — Three Pillars
Dark solid background with three rounded-rectangle cards side by side, each containing a Unicode symbol icon, bold title, and body text.
```bash
officecli add presentation.pptx /presentation --type slide
# Solid background
officecli raw-set presentation.pptx /slide[2] \
--xpath "//p:cSld" --action prepend --xml '
<p:bg><p:bgPr>
<a:solidFill><a:srgbClr val="0D1B2A"/></a:solidFill>
<a:effectLst/>
</p:bgPr></p:bg>'
# Section title: sz=3200 bold white centered
# Sub-line: sz=1400 grey centered
officecli raw-set presentation.pptx /slide[2] \
--xpath "//p:cSld/p:spTree" --action append --xml '...'
# Card 1 — Simplicity: roundRect adj=8000, solidFill 152238, ln 1E3A5F
# Icon: sz=4800 teal ○; Title: sz=2400 bold white; Body: sz=1200 grey
officecli raw-set presentation.pptx /slide[2] \
--xpath "//p:cSld/p:spTree" --action append --xml '
<p:sp>
<p:nvSpPr><p:cNvPr id="210" name="Card1"/><p:cNvSpPr/><p:nvPr/></p:nvSpPr>
<p:spPr>
<a:xfrm><a:off x="900000" y="2000000"/><a:ext cx="3200000" cy="4200000"/></a:xfrm>
<a:prstGeom prst="roundRect">
<a:avLst><a:gd name="adj" fmla="val 8000"/></a:avLst>
</a:prstGeom>
<a:solidFill><a:srgbClr val="152238"/></a:solidFill>
<a:ln w="12700"><a:solidFill><a:srgbClr val="1E3A5F"/></a:solidFill></a:ln>
</p:spPr>
<p:txBody>
<a:bodyPr wrap="square" lIns="228600" tIns="228600" rIns="228600" bIns="228600" anchor="t"/>
<a:lstStyle/>
<!-- paragraph: icon ○ sz=4800 teal -->
<!-- paragraph: empty spacer -->
<!-- paragraph: "Simplicity" sz=2400 bold white -->
<!-- paragraph: body text sz=1200 grey -->
</p:txBody>
</p:sp>'
# Card 2 — Hierarchy: same structure, lavender △ icon
# Card 3 — Harmony: same structure, amber ◇ icon
```
**Features:** `solidFill` background, `prstGeom prst="roundRect"` with `a:gd name="adj" fmla="val 8000"` (corner rounding ≈8%), `a:ln w=` border thickness, `bodyPr lIns/tIns/rIns/bIns` padding, `anchor="t"`, mixed `sz` paragraphs, Unicode in `a:t` (`&#x25CB;` ○, `&#x25B3;` △, `&#x25C7;` ◇), `algn="ctr"` paragraph alignment
### Slide 3 — Data Showcase
Left-to-right gradient background, title, thin gradient accent bar, three stat cards with gradient borders.
```bash
officecli add presentation.pptx /presentation --type slide
# 2-stop diagonal gradient background
officecli raw-set presentation.pptx /slide[3] \
--xpath "//p:cSld" --action prepend --xml '
<p:bg><p:bgPr>
<a:gradFill rotWithShape="0">
<a:gsLst>
<a:gs pos="0"><a:srgbClr val="0D1B2A"/></a:gs>
<a:gs pos="100000"><a:srgbClr val="152238"/></a:gs>
</a:gsLst>
<a:lin ang="2700000" scaled="1"/>
</a:gradFill><a:effectLst/>
</p:bgPr></p:bg>'
# Thin gradient accent bar (rect, no text, gradFill fill)
officecli raw-set presentation.pptx /slide[3] \
--xpath "//p:cSld/p:spTree" --action append --xml '
<p:sp>
<!-- off y=1050000, ext cx=3000000 cy=50000 — purely decorative horizontal bar -->
<!-- gradFill: 00B4D8 → E0AAFF, ang=0 (left→right) -->
</p:sp>'
# Stat card 1 — "98%": roundRect solidFill 0E2540, gradient border stroke
officecli raw-set presentation.pptx /slide[3] \
--xpath "//p:cSld/p:spTree" --action append --xml '
<p:sp>
<p:spPr>
<a:ln w="19050">
<a:gradFill>
<a:gsLst>
<a:gs pos="0"><a:srgbClr val="00B4D8"/></a:gs>
<a:gs pos="100000"><a:srgbClr val="0077B6"/></a:gs>
</a:gsLst>
<a:lin ang="5400000" scaled="1"/>
</a:gradFill>
</a:ln>
</p:spPr>
<!-- sz=5600 bold teal big number; sz=1400 grey label -->
</p:sp>'
```
**Features:** 2-stop `gradFill` at 270° (`ang="2700000"`), thin decorative rect (height `cy=50000`), gradient line/border (`a:ln/a:gradFill`), `anchor="ctr"` vertical centering, mixed font sizes in single `txBody`
### Slide 4 — Quote Slide
3-stop gradient background, very large low-alpha quote-mark glyph, italic Georgia quote text, teal attribution, and a fade-center accent line.
```bash
officecli add presentation.pptx /presentation --type slide
# 3-stop gradient background
# Large quote mark: sz=12000, solidFill alpha=20000 (very transparent)
officecli raw-set presentation.pptx /slide[4] \
--xpath "//p:cSld/p:spTree" --action append --xml '
<p:sp>
<p:nvSpPr><p:cNvPr id="400" name="QuoteMark"/><p:cNvSpPr txBox="1"/><p:nvPr/></p:nvSpPr>
<p:txBody>
<a:bodyPr wrap="square" anchor="t"/>
<a:lstStyle/>
<a:p>
<a:pPr algn="l"/>
<a:r>
<a:rPr lang="en-US" sz="12000" dirty="0">
<a:solidFill><a:srgbClr val="00B4D8"><a:alpha val="20000"/></a:srgbClr></a:solidFill>
<a:latin typeface="Georgia"/>
</a:rPr>
<a:t>&#x201C;</a:t>
</a:r>
</a:p>
</p:txBody>
</p:sp>'
# Quote text: sz=2800 italic Georgia, 2 paragraphs
officecli raw-set presentation.pptx /slide[4] \
--xpath "//p:cSld/p:spTree" --action append --xml '
<p:sp>
<!-- i="1" italic, Georgia, sz=2800, anchor=ctr -->
</p:sp>'
# Attribution line: sz=1600 teal 00B4D8, en-dash prefix
# Fading accent line: 3-stop gradFill (alpha=0 at ends, full at 50%)
officecli raw-set presentation.pptx /slide[4] \
--xpath "//p:cSld/p:spTree" --action append --xml '
<p:sp>
<!-- line shape, ln gradFill: pos=0 alpha=0, pos=50000 full, pos=100000 alpha=0 -->
</p:sp>'
```
**Features:** `sz=12000` giant glyph, `a:alpha val="20000"` (low opacity ≈8%), `i="1"` italic, `a:latin typeface="Georgia"`, 3-stop gradient line fading at both ends (creating a center-glow effect), `&#x201C;` left double quote, `&#x2014;` em-dash
### Slide 5 — Process / Timeline
Dark solid background, title, 4-stop rainbow horizontal connector line, four numbered ellipse steps (semi-transparent fill + colored border), and four text labels below.
```bash
officecli add presentation.pptx /presentation --type slide
# Title: sz=3200 bold white centered
# 4-stop rainbow gradient connector line (horizontal)
officecli raw-set presentation.pptx /slide[5] \
--xpath "//p:cSld/p:spTree" --action append --xml '
<p:sp>
<p:spPr>
<a:xfrm><a:off x="1800000" y="2800000"/><a:ext cx="8600000" cy="0"/></a:xfrm>
<a:prstGeom prst="line"><a:avLst/></a:prstGeom>
<a:ln w="25400">
<a:gradFill>
<a:gsLst>
<a:gs pos="0"><a:srgbClr val="00B4D8"/></a:gs>
<a:gs pos="33000"><a:srgbClr val="E0AAFF"/></a:gs>
<a:gs pos="66000"><a:srgbClr val="FFD166"/></a:gs>
<a:gs pos="100000"><a:srgbClr val="06D6A0"/></a:gs>
</a:gsLst>
<a:lin ang="0" scaled="1"/>
</a:gradFill>
</a:ln>
</p:spPr>
<p:txBody><a:bodyPr/><a:lstStyle/><a:p><a:endParaRPr/></a:p></p:txBody>
</p:sp>'
# Loop: 4 step circles (ellipse, fill alpha=15000, border solid color)
LABELS=("Research" "Ideate" "Design" "Validate")
COLORS=("00B4D8" "E0AAFF" "FFD166" "06D6A0")
XPOS=(1400000 3600000 5800000 8000000)
for i in 0 1 2 3; do
officecli raw-set presentation.pptx "/slide[5]" \
--xpath "//p:cSld/p:spTree" --action append --xml "
<p:sp>
<p:spPr>
<a:xfrm><a:off x=\"${XPOS[$i]}\" y=\"2200000\"/><a:ext cx=\"1200000\" cy=\"1200000\"/></a:xfrm>
<a:prstGeom prst=\"ellipse\"><a:avLst/></a:prstGeom>
<a:solidFill><a:srgbClr val=\"${COLORS[$i]}\"><a:alpha val=\"15000\"/></a:srgbClr></a:solidFill>
<a:ln w=\"38100\"><a:solidFill><a:srgbClr val=\"${COLORS[$i]}\"/></a:solidFill></a:ln>
</p:spPr>
<p:txBody>
<a:bodyPr wrap=\"square\" anchor=\"ctr\"/>
<a:lstStyle/>
<a:p><a:pPr algn=\"ctr\"/><a:r><a:rPr lang=\"en-US\" sz=\"2400\" b=\"1\" dirty=\"0\">
<a:solidFill><a:srgbClr val=\"${COLORS[$i]}\"/></a:solidFill>
</a:rPr><a:t>0$((i+1))</a:t></a:r></a:p>
</p:txBody>
</p:sp>"
done
```
**Features:** 4-stop rainbow gradient line stroke, `prstGeom prst="ellipse"`, very low fill alpha (`val="15000"` ≈ 6%), thick border `a:ln w="38100"`, `anchor="ctr"` for centered number label, bash loop for repeated shape generation
### Slide 6 — Closing
Gradient ring (ellipse with gradient stroke, no fill), large "Thank You" heading, closing subtitle, three tiny diamond accent shapes.
```bash
officecli add presentation.pptx /presentation --type slide
# 3-stop diagonal gradient background
# Gradient ring: large ellipse, noFill, ln w=12700 gradFill 3-stop with alpha
officecli raw-set presentation.pptx /slide[6] \
--xpath "//p:cSld/p:spTree" --action append --xml '
<p:sp>
<p:spPr>
<a:xfrm><a:off x="3596000" y="800000"/><a:ext cx="5000000" cy="5000000"/></a:xfrm>
<a:prstGeom prst="ellipse"><a:avLst/></a:prstGeom>
<a:noFill/>
<a:ln w="12700">
<a:gradFill>
<a:gsLst>
<a:gs pos="0"><a:srgbClr val="00B4D8"><a:alpha val="30000"/></a:srgbClr></a:gs>
<a:gs pos="50000"><a:srgbClr val="E0AAFF"><a:alpha val="30000"/></a:srgbClr></a:gs>
<a:gs pos="100000"><a:srgbClr val="FFD166"><a:alpha val="30000"/></a:srgbClr></a:gs>
</a:gsLst>
<a:lin ang="2700000" scaled="1"/>
</a:gradFill>
</a:ln>
</p:spPr>
<p:txBody><a:bodyPr/><a:lstStyle/><a:p><a:endParaRPr/></a:p></p:txBody>
</p:sp>'
# "Thank You": sz=4800 bold white centered
# Closing subtitle: sz=1600 light-teal 90E0EF
# Three tiny diamonds: rot=2700000 rects, cx=cy=120000, teal/lavender/amber
officecli raw-set presentation.pptx /slide[6] \
--xpath "//p:cSld/p:spTree" --action append --xml '
<p:sp>
<p:spPr>
<a:xfrm rot="2700000"><a:off x="5850000" y="4700000"/><a:ext cx="120000" cy="120000"/></a:xfrm>
<a:prstGeom prst="rect"><a:avLst/></a:prstGeom>
<a:solidFill><a:srgbClr val="00B4D8"/></a:solidFill>
<a:ln><a:noFill/></a:ln>
</p:spPr>
<p:txBody><a:bodyPr/><a:lstStyle/><a:p><a:endParaRPr/></a:p></p:txBody>
</p:sp>'
```
**Features:** `a:noFill` (transparent shape body), gradient stroke ring effect (`a:ln/a:gradFill` with alpha), tiny rotated rect (`cx=cy=120000` EMU, `rot=2700000`), three-color accent trio (teal/lavender/amber)
## Complete Feature Coverage
| Feature | Slides |
|---------|--------|
| **Backgrounds:** solid, 2-stop gradient, 3-stop gradient | 2, 3, 1/4/6 |
| **Gradient angles:** 0° horizontal, 270° vertical, 90° inverted | 1, 3, 5 |
| **Alpha / transparency on fills** (`a:alpha val=`) | 1, 4, 5 |
| **Alpha / transparency on stroke** | 6 |
| **Gradient fill stroke** (`a:ln/a:gradFill`) | 1, 5, 6 |
| **Gradient fill as shape body** | 3 (accent bar) |
| **prstGeom:** ellipse, line, rect, roundRect | all |
| **roundRect adj corner radius** (`a:gd name="adj"`) | 2, 3 |
| **noFill** (transparent shape body) | 1, 4, 6 |
| **txBox="1"** text-only box | 1, 4 |
| **bodyPr anchor:** t / b / ctr | all |
| **bodyPr padding:** lIns/tIns/rIns/bIns | 2 |
| **Font sizes** 120012000 hundredths-of-point range | all |
| **Bold** (`b="1"`), **italic** (`i="1"`) | 1, 4 |
| **Letter-spacing** (`spc=`) | 1 |
| **Typefaces:** Segoe UI, Georgia | 1, 4, 5 |
| **Per-run solidFill** | all |
| **Multi-paragraph txBody with mixed sizes** | 1, 2, 3, 4 |
| **Paragraph alignment** (`algn="l"/"ctr"`) | all |
| **Rotation** (`a:xfrm rot=2700000`) | 1, 6 |
| **Unicode glyphs in a:t** | 1, 2, 4 |
| **Bash loop for repeated shapes** | 5, 6 |
| **raw-set --action prepend** (background injection) | all |
| **raw-set --action append** (shape injection) | all |
| **Decorative non-text shapes** (accent bars, rings, diamonds) | 1, 3, 4, 6 |
## Inspect the Generated File
```bash
officecli query presentation.pptx slide
officecli get presentation.pptx /slide[1]
officecli get presentation.pptx "/slide[2]/shape[3]"
officecli get presentation.pptx "/slide[5]/shape[2]"
```
Binary file not shown.
+686
View File
@@ -0,0 +1,686 @@
#!/usr/bin/env python3
"""
The Art of Design — generates presentation.pptx, a visually rich 6-slide deck
built entirely from raw OOXML shape trees: deep gradient backgrounds, decorative
circles, gradient accent lines, stat cards, a quote slide, a process timeline,
and a closing slide.
SDK twin of presentation.sh (officecli CLI). Both produce an equivalent
presentation.pptx. This one drives the **officecli Python SDK**
(`pip install officecli-sdk`): one resident is started and every slide + every
raw-set shape injection is shipped over the named pipe in a single
`doc.batch(...)` round-trip.
The deck is built with the `raw-set` escape hatch (the same one the .sh uses):
each item is a batch dict whose `part` names the target slide and whose
`xpath`/`action`/`xml` fields drive `IDocumentHandler.RawSet` — exactly the
fields you'd pass to `officecli raw-set`. Slides themselves are plain
`add slide` items under `/presentation`.
Usage:
pip install officecli-sdk # plus the `officecli` binary on PATH
python3 presentation.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__)), "presentation.pptx")
def slide():
"""One `add slide` item in batch-shape. Slides hang off the presentation
root, so the parent is "/" (the resident/batch model; the CLI's positional
/presentation maps to the same root)."""
return {"command": "add", "parent": "/", "type": "slide"}
def bg(n, xml):
"""raw-set: prepend a <p:bg> into slide n's <p:cSld>."""
return {"command": "raw-set", "part": f"/slide[{n}]",
"xpath": "//p:cSld", "action": "prepend", "xml": xml}
def shape(n, xml):
"""raw-set: append a shape <p:sp> into slide n's <p:cSld>/<p:spTree>."""
return {"command": "raw-set", "part": f"/slide[{n}]",
"xpath": "//p:cSld/p:spTree", "action": "append", "xml": xml}
print(f"Building {FILE} ...")
with officecli.create(FILE, "--force") as doc:
items = []
# =========================================================================
# SLIDE 1 — Title Slide
# =========================================================================
items.append(slide())
# Full-bleed dark gradient background
items.append(bg(1, '''
<p:bg>
<p:bgPr>
<a:gradFill rotWithShape="0">
<a:gsLst>
<a:gs pos="0"><a:srgbClr val="0D1B2A"/></a:gs>
<a:gs pos="50000"><a:srgbClr val="1B2838"/></a:gs>
<a:gs pos="100000"><a:srgbClr val="0A1628"/></a:gs>
</a:gsLst>
<a:lin ang="5400000" scaled="1"/>
</a:gradFill>
<a:effectLst/>
</p:bgPr>
</p:bg>'''))
# Decorative circle — top right (large, semi-transparent teal)
items.append(shape(1, '''
<p:sp>
<p:nvSpPr><p:cNvPr id="100" name="Deco Circle 1"/><p:cNvSpPr/><p:nvPr/></p:nvSpPr>
<p:spPr>
<a:xfrm><a:off x="8500000" y="-1200000"/><a:ext cx="4800000" cy="4800000"/></a:xfrm>
<a:prstGeom prst="ellipse"><a:avLst/></a:prstGeom>
<a:solidFill><a:srgbClr val="00B4D8"><a:alpha val="8000"/></a:srgbClr></a:solidFill>
<a:ln><a:noFill/></a:ln>
</p:spPr>
<p:txBody><a:bodyPr/><a:lstStyle/><a:p><a:endParaRPr/></a:p></p:txBody>
</p:sp>'''))
# Decorative circle — bottom left (lavender)
items.append(shape(1, '''
<p:sp>
<p:nvSpPr><p:cNvPr id="101" name="Deco Circle 2"/><p:cNvSpPr/><p:nvPr/></p:nvSpPr>
<p:spPr>
<a:xfrm><a:off x="-800000" y="4500000"/><a:ext cx="3200000" cy="3200000"/></a:xfrm>
<a:prstGeom prst="ellipse"><a:avLst/></a:prstGeom>
<a:solidFill><a:srgbClr val="E0AAFF"><a:alpha val="6000"/></a:srgbClr></a:solidFill>
<a:ln><a:noFill/></a:ln>
</p:spPr>
<p:txBody><a:bodyPr/><a:lstStyle/><a:p><a:endParaRPr/></a:p></p:txBody>
</p:sp>'''))
# Gradient accent line
items.append(shape(1, '''
<p:sp>
<p:nvSpPr><p:cNvPr id="102" name="Accent Line"/><p:cNvSpPr/><p:nvPr/></p:nvSpPr>
<p:spPr>
<a:xfrm><a:off x="800000" y="4200000"/><a:ext cx="5000000" cy="0"/></a:xfrm>
<a:prstGeom prst="line"><a:avLst/></a:prstGeom>
<a:ln w="28575">
<a:gradFill>
<a:gsLst>
<a:gs pos="0"><a:srgbClr val="00B4D8"/></a:gs>
<a:gs pos="100000"><a:srgbClr val="E0AAFF"/></a:gs>
</a:gsLst>
<a:lin ang="0" scaled="1"/>
</a:gradFill>
</a:ln>
</p:spPr>
<p:txBody><a:bodyPr/><a:lstStyle/><a:p><a:endParaRPr/></a:p></p:txBody>
</p:sp>'''))
# Main title
items.append(shape(1, '''
<p:sp>
<p:nvSpPr><p:cNvPr id="103" name="Title"/><p:cNvSpPr txBox="1"/><p:nvPr/></p:nvSpPr>
<p:spPr>
<a:xfrm><a:off x="800000" y="1600000"/><a:ext cx="8000000" cy="1200000"/></a:xfrm>
<a:prstGeom prst="rect"><a:avLst/></a:prstGeom>
<a:noFill/><a:ln><a:noFill/></a:ln>
</p:spPr>
<p:txBody>
<a:bodyPr wrap="square" anchor="b"/>
<a:lstStyle/>
<a:p>
<a:pPr algn="l"/>
<a:r>
<a:rPr lang="en-US" sz="5400" b="1" dirty="0">
<a:solidFill><a:srgbClr val="FFFFFF"/></a:solidFill>
<a:latin typeface="Segoe UI"/>
</a:rPr>
<a:t>The Art of Design</a:t>
</a:r>
</a:p>
</p:txBody>
</p:sp>'''))
# Subtitle
items.append(shape(1, '''
<p:sp>
<p:nvSpPr><p:cNvPr id="104" name="Subtitle"/><p:cNvSpPr txBox="1"/><p:nvPr/></p:nvSpPr>
<p:spPr>
<a:xfrm><a:off x="800000" y="2900000"/><a:ext cx="8000000" cy="1100000"/></a:xfrm>
<a:prstGeom prst="rect"><a:avLst/></a:prstGeom>
<a:noFill/><a:ln><a:noFill/></a:ln>
</p:spPr>
<p:txBody>
<a:bodyPr wrap="square" anchor="t"/>
<a:lstStyle/>
<a:p>
<a:pPr algn="l"/>
<a:r>
<a:rPr lang="en-US" sz="2000" dirty="0">
<a:solidFill><a:srgbClr val="90E0EF"/></a:solidFill>
<a:latin typeface="Segoe UI"/>
</a:rPr>
<a:t>Crafting Beautiful Experiences</a:t>
</a:r>
</a:p>
<a:p>
<a:pPr algn="l"/>
<a:r>
<a:rPr lang="en-US" sz="1400" dirty="0" spc="600">
<a:solidFill><a:srgbClr val="8B95A2"/></a:solidFill>
<a:latin typeface="Segoe UI"/>
</a:rPr>
<a:t>SIMPLICITY &#xB7; ELEGANCE &#xB7; FUNCTION</a:t>
</a:r>
</a:p>
</p:txBody>
</p:sp>'''))
# Diamond accent
items.append(shape(1, '''
<p:sp>
<p:nvSpPr><p:cNvPr id="105" name="Diamond"/><p:cNvSpPr/><p:nvPr/></p:nvSpPr>
<p:spPr>
<a:xfrm rot="2700000"><a:off x="600000" y="4050000"/><a:ext cx="200000" cy="200000"/></a:xfrm>
<a:prstGeom prst="rect"><a:avLst/></a:prstGeom>
<a:solidFill><a:srgbClr val="00B4D8"/></a:solidFill>
<a:ln><a:noFill/></a:ln>
</p:spPr>
<p:txBody><a:bodyPr/><a:lstStyle/><a:p><a:endParaRPr/></a:p></p:txBody>
</p:sp>'''))
# =========================================================================
# SLIDE 2 — Three Pillars
# =========================================================================
items.append(slide())
items.append(bg(2,
'<p:bg><p:bgPr><a:solidFill><a:srgbClr val="0D1B2A"/></a:solidFill>'
'<a:effectLst/></p:bgPr></p:bg>'))
# Section title
items.append(shape(2, '''
<p:sp>
<p:nvSpPr><p:cNvPr id="200" name="Section Title"/><p:cNvSpPr txBox="1"/><p:nvPr/></p:nvSpPr>
<p:spPr>
<a:xfrm><a:off x="800000" y="400000"/><a:ext cx="10592000" cy="900000"/></a:xfrm>
<a:prstGeom prst="rect"><a:avLst/></a:prstGeom>
<a:noFill/><a:ln><a:noFill/></a:ln>
</p:spPr>
<p:txBody>
<a:bodyPr wrap="square" anchor="ctr"/>
<a:lstStyle/>
<a:p>
<a:pPr algn="ctr"/>
<a:r>
<a:rPr lang="en-US" sz="3200" b="1" dirty="0">
<a:solidFill><a:srgbClr val="FFFFFF"/></a:solidFill>
<a:latin typeface="Segoe UI"/>
</a:rPr>
<a:t>Three Pillars of Great Design</a:t>
</a:r>
</a:p>
</p:txBody>
</p:sp>'''))
# Subtitle
items.append(shape(2, '''
<p:sp>
<p:nvSpPr><p:cNvPr id="201" name="SubLine"/><p:cNvSpPr txBox="1"/><p:nvPr/></p:nvSpPr>
<p:spPr>
<a:xfrm><a:off x="800000" y="1200000"/><a:ext cx="10592000" cy="400000"/></a:xfrm>
<a:prstGeom prst="rect"><a:avLst/></a:prstGeom>
<a:noFill/><a:ln><a:noFill/></a:ln>
</p:spPr>
<p:txBody>
<a:bodyPr wrap="square" anchor="t"/>
<a:lstStyle/>
<a:p>
<a:pPr algn="ctr"/>
<a:r>
<a:rPr lang="en-US" sz="1400" dirty="0">
<a:solidFill><a:srgbClr val="8B95A2"/></a:solidFill>
<a:latin typeface="Segoe UI"/>
</a:rPr>
<a:t>Every exceptional design is built upon these core principles</a:t>
</a:r>
</a:p>
</p:txBody>
</p:sp>'''))
# Card 1 — Simplicity
items.append(shape(2, '''
<p:sp>
<p:nvSpPr><p:cNvPr id="210" name="Card1"/><p:cNvSpPr/><p:nvPr/></p:nvSpPr>
<p:spPr>
<a:xfrm><a:off x="900000" y="2000000"/><a:ext cx="3200000" cy="4200000"/></a:xfrm>
<a:prstGeom prst="roundRect"><a:avLst><a:gd name="adj" fmla="val 8000"/></a:avLst></a:prstGeom>
<a:solidFill><a:srgbClr val="152238"/></a:solidFill>
<a:ln w="12700"><a:solidFill><a:srgbClr val="1E3A5F"/></a:solidFill></a:ln>
</p:spPr>
<p:txBody>
<a:bodyPr wrap="square" lIns="228600" tIns="228600" rIns="228600" bIns="228600" anchor="t"/>
<a:lstStyle/>
<a:p><a:pPr algn="ctr"/><a:r><a:rPr lang="en-US" sz="4800" dirty="0"><a:solidFill><a:srgbClr val="00B4D8"/></a:solidFill></a:rPr><a:t>&#x25CB;</a:t></a:r></a:p>
<a:p><a:pPr algn="ctr"/><a:endParaRPr lang="en-US" sz="800"/></a:p>
<a:p><a:pPr algn="ctr"/><a:r><a:rPr lang="en-US" sz="2400" b="1" dirty="0"><a:solidFill><a:srgbClr val="FFFFFF"/></a:solidFill><a:latin typeface="Segoe UI"/></a:rPr><a:t>Simplicity</a:t></a:r></a:p>
<a:p><a:pPr algn="ctr"/><a:endParaRPr lang="en-US" sz="600"/></a:p>
<a:p><a:pPr algn="ctr"/><a:r><a:rPr lang="en-US" sz="1200" dirty="0"><a:solidFill><a:srgbClr val="8B95A2"/></a:solidFill><a:latin typeface="Segoe UI"/></a:rPr><a:t>Less is more. Strip away the unnecessary to let the essential shine through.</a:t></a:r></a:p>
</p:txBody>
</p:sp>'''))
# Card 2 — Hierarchy
items.append(shape(2, '''
<p:sp>
<p:nvSpPr><p:cNvPr id="211" name="Card2"/><p:cNvSpPr/><p:nvPr/></p:nvSpPr>
<p:spPr>
<a:xfrm><a:off x="4496000" y="2000000"/><a:ext cx="3200000" cy="4200000"/></a:xfrm>
<a:prstGeom prst="roundRect"><a:avLst><a:gd name="adj" fmla="val 8000"/></a:avLst></a:prstGeom>
<a:solidFill><a:srgbClr val="152238"/></a:solidFill>
<a:ln w="12700"><a:solidFill><a:srgbClr val="1E3A5F"/></a:solidFill></a:ln>
</p:spPr>
<p:txBody>
<a:bodyPr wrap="square" lIns="228600" tIns="228600" rIns="228600" bIns="228600" anchor="t"/>
<a:lstStyle/>
<a:p><a:pPr algn="ctr"/><a:r><a:rPr lang="en-US" sz="4800" dirty="0"><a:solidFill><a:srgbClr val="E0AAFF"/></a:solidFill></a:rPr><a:t>&#x25B3;</a:t></a:r></a:p>
<a:p><a:pPr algn="ctr"/><a:endParaRPr lang="en-US" sz="800"/></a:p>
<a:p><a:pPr algn="ctr"/><a:r><a:rPr lang="en-US" sz="2400" b="1" dirty="0"><a:solidFill><a:srgbClr val="FFFFFF"/></a:solidFill><a:latin typeface="Segoe UI"/></a:rPr><a:t>Hierarchy</a:t></a:r></a:p>
<a:p><a:pPr algn="ctr"/><a:endParaRPr lang="en-US" sz="600"/></a:p>
<a:p><a:pPr algn="ctr"/><a:r><a:rPr lang="en-US" sz="1200" dirty="0"><a:solidFill><a:srgbClr val="8B95A2"/></a:solidFill><a:latin typeface="Segoe UI"/></a:rPr><a:t>Guide the eye with size, color, and space. Create a clear visual flow.</a:t></a:r></a:p>
</p:txBody>
</p:sp>'''))
# Card 3 — Harmony
items.append(shape(2, '''
<p:sp>
<p:nvSpPr><p:cNvPr id="212" name="Card3"/><p:cNvSpPr/><p:nvPr/></p:nvSpPr>
<p:spPr>
<a:xfrm><a:off x="8092000" y="2000000"/><a:ext cx="3200000" cy="4200000"/></a:xfrm>
<a:prstGeom prst="roundRect"><a:avLst><a:gd name="adj" fmla="val 8000"/></a:avLst></a:prstGeom>
<a:solidFill><a:srgbClr val="152238"/></a:solidFill>
<a:ln w="12700"><a:solidFill><a:srgbClr val="1E3A5F"/></a:solidFill></a:ln>
</p:spPr>
<p:txBody>
<a:bodyPr wrap="square" lIns="228600" tIns="228600" rIns="228600" bIns="228600" anchor="t"/>
<a:lstStyle/>
<a:p><a:pPr algn="ctr"/><a:r><a:rPr lang="en-US" sz="4800" dirty="0"><a:solidFill><a:srgbClr val="FFD166"/></a:solidFill></a:rPr><a:t>&#x25C7;</a:t></a:r></a:p>
<a:p><a:pPr algn="ctr"/><a:endParaRPr lang="en-US" sz="800"/></a:p>
<a:p><a:pPr algn="ctr"/><a:r><a:rPr lang="en-US" sz="2400" b="1" dirty="0"><a:solidFill><a:srgbClr val="FFFFFF"/></a:solidFill><a:latin typeface="Segoe UI"/></a:rPr><a:t>Harmony</a:t></a:r></a:p>
<a:p><a:pPr algn="ctr"/><a:endParaRPr lang="en-US" sz="600"/></a:p>
<a:p><a:pPr algn="ctr"/><a:r><a:rPr lang="en-US" sz="1200" dirty="0"><a:solidFill><a:srgbClr val="8B95A2"/></a:solidFill><a:latin typeface="Segoe UI"/></a:rPr><a:t>Consistent color, type, and layout create a professional, cohesive experience.</a:t></a:r></a:p>
</p:txBody>
</p:sp>'''))
# =========================================================================
# SLIDE 3 — Data Showcase
# =========================================================================
items.append(slide())
items.append(bg(3,
'<p:bg><p:bgPr><a:gradFill rotWithShape="0"><a:gsLst>'
'<a:gs pos="0"><a:srgbClr val="0D1B2A"/></a:gs>'
'<a:gs pos="100000"><a:srgbClr val="152238"/></a:gs></a:gsLst>'
'<a:lin ang="2700000" scaled="1"/></a:gradFill><a:effectLst/></p:bgPr></p:bg>'))
# Title
items.append(shape(3, '''
<p:sp>
<p:nvSpPr><p:cNvPr id="300" name="DataTitle"/><p:cNvSpPr txBox="1"/><p:nvPr/></p:nvSpPr>
<p:spPr>
<a:xfrm><a:off x="800000" y="300000"/><a:ext cx="10592000" cy="700000"/></a:xfrm>
<a:prstGeom prst="rect"><a:avLst/></a:prstGeom><a:noFill/><a:ln><a:noFill/></a:ln>
</p:spPr>
<p:txBody>
<a:bodyPr wrap="square" anchor="ctr"/><a:lstStyle/>
<a:p><a:pPr algn="l"/><a:r><a:rPr lang="en-US" sz="2800" b="1" dirty="0"><a:solidFill><a:srgbClr val="FFFFFF"/></a:solidFill><a:latin typeface="Segoe UI"/></a:rPr><a:t>Data-Driven Design</a:t></a:r></a:p>
</p:txBody>
</p:sp>'''))
# Gradient accent bar
items.append(shape(3, '''
<p:sp>
<p:nvSpPr><p:cNvPr id="301" name="Bar"/><p:cNvSpPr/><p:nvPr/></p:nvSpPr>
<p:spPr>
<a:xfrm><a:off x="800000" y="1050000"/><a:ext cx="3000000" cy="50000"/></a:xfrm>
<a:prstGeom prst="rect"><a:avLst/></a:prstGeom>
<a:gradFill><a:gsLst><a:gs pos="0"><a:srgbClr val="00B4D8"/></a:gs><a:gs pos="100000"><a:srgbClr val="E0AAFF"/></a:gs></a:gsLst><a:lin ang="0" scaled="1"/></a:gradFill>
<a:ln><a:noFill/></a:ln>
</p:spPr>
<p:txBody><a:bodyPr/><a:lstStyle/><a:p><a:endParaRPr/></a:p></p:txBody>
</p:sp>'''))
# Stat card 1 — 98%
items.append(shape(3, '''
<p:sp>
<p:nvSpPr><p:cNvPr id="310" name="Stat1"/><p:cNvSpPr txBox="1"/><p:nvPr/></p:nvSpPr>
<p:spPr>
<a:xfrm><a:off x="800000" y="1500000"/><a:ext cx="3400000" cy="2200000"/></a:xfrm>
<a:prstGeom prst="roundRect"><a:avLst><a:gd name="adj" fmla="val 6000"/></a:avLst></a:prstGeom>
<a:solidFill><a:srgbClr val="0E2540"/></a:solidFill>
<a:ln w="19050"><a:gradFill><a:gsLst><a:gs pos="0"><a:srgbClr val="00B4D8"/></a:gs><a:gs pos="100000"><a:srgbClr val="0077B6"/></a:gs></a:gsLst><a:lin ang="5400000" scaled="1"/></a:gradFill></a:ln>
</p:spPr>
<p:txBody>
<a:bodyPr wrap="square" lIns="228600" tIns="182880" rIns="228600" bIns="182880" anchor="ctr"/><a:lstStyle/>
<a:p><a:pPr algn="ctr"/><a:r><a:rPr lang="en-US" sz="5600" b="1" dirty="0"><a:solidFill><a:srgbClr val="00B4D8"/></a:solidFill><a:latin typeface="Segoe UI"/></a:rPr><a:t>98%</a:t></a:r></a:p>
<a:p><a:pPr algn="ctr"/><a:r><a:rPr lang="en-US" sz="1400" dirty="0"><a:solidFill><a:srgbClr val="8B95A2"/></a:solidFill><a:latin typeface="Segoe UI"/></a:rPr><a:t>User Satisfaction</a:t></a:r></a:p>
</p:txBody>
</p:sp>'''))
# Stat card 2 — 2.5M
items.append(shape(3, '''
<p:sp>
<p:nvSpPr><p:cNvPr id="311" name="Stat2"/><p:cNvSpPr txBox="1"/><p:nvPr/></p:nvSpPr>
<p:spPr>
<a:xfrm><a:off x="4500000" y="1500000"/><a:ext cx="3400000" cy="2200000"/></a:xfrm>
<a:prstGeom prst="roundRect"><a:avLst><a:gd name="adj" fmla="val 6000"/></a:avLst></a:prstGeom>
<a:solidFill><a:srgbClr val="0E2540"/></a:solidFill>
<a:ln w="19050"><a:gradFill><a:gsLst><a:gs pos="0"><a:srgbClr val="E0AAFF"/></a:gs><a:gs pos="100000"><a:srgbClr val="9B5DE5"/></a:gs></a:gsLst><a:lin ang="5400000" scaled="1"/></a:gradFill></a:ln>
</p:spPr>
<p:txBody>
<a:bodyPr wrap="square" lIns="228600" tIns="182880" rIns="228600" bIns="182880" anchor="ctr"/><a:lstStyle/>
<a:p><a:pPr algn="ctr"/><a:r><a:rPr lang="en-US" sz="5600" b="1" dirty="0"><a:solidFill><a:srgbClr val="E0AAFF"/></a:solidFill><a:latin typeface="Segoe UI"/></a:rPr><a:t>2.5M</a:t></a:r></a:p>
<a:p><a:pPr algn="ctr"/><a:r><a:rPr lang="en-US" sz="1400" dirty="0"><a:solidFill><a:srgbClr val="8B95A2"/></a:solidFill><a:latin typeface="Segoe UI"/></a:rPr><a:t>Monthly Active Users</a:t></a:r></a:p>
</p:txBody>
</p:sp>'''))
# Stat card 3 — 47ms
items.append(shape(3, '''
<p:sp>
<p:nvSpPr><p:cNvPr id="312" name="Stat3"/><p:cNvSpPr txBox="1"/><p:nvPr/></p:nvSpPr>
<p:spPr>
<a:xfrm><a:off x="8200000" y="1500000"/><a:ext cx="3400000" cy="2200000"/></a:xfrm>
<a:prstGeom prst="roundRect"><a:avLst><a:gd name="adj" fmla="val 6000"/></a:avLst></a:prstGeom>
<a:solidFill><a:srgbClr val="0E2540"/></a:solidFill>
<a:ln w="19050"><a:gradFill><a:gsLst><a:gs pos="0"><a:srgbClr val="FFD166"/></a:gs><a:gs pos="100000"><a:srgbClr val="F48C06"/></a:gs></a:gsLst><a:lin ang="5400000" scaled="1"/></a:gradFill></a:ln>
</p:spPr>
<p:txBody>
<a:bodyPr wrap="square" lIns="228600" tIns="182880" rIns="228600" bIns="182880" anchor="ctr"/><a:lstStyle/>
<a:p><a:pPr algn="ctr"/><a:r><a:rPr lang="en-US" sz="5600" b="1" dirty="0"><a:solidFill><a:srgbClr val="FFD166"/></a:solidFill><a:latin typeface="Segoe UI"/></a:rPr><a:t>47ms</a:t></a:r></a:p>
<a:p><a:pPr algn="ctr"/><a:r><a:rPr lang="en-US" sz="1400" dirty="0"><a:solidFill><a:srgbClr val="8B95A2"/></a:solidFill><a:latin typeface="Segoe UI"/></a:rPr><a:t>Avg Response Time</a:t></a:r></a:p>
</p:txBody>
</p:sp>'''))
# Bottom description
items.append(shape(3, '''
<p:sp>
<p:nvSpPr><p:cNvPr id="320" name="Desc"/><p:cNvSpPr txBox="1"/><p:nvPr/></p:nvSpPr>
<p:spPr>
<a:xfrm><a:off x="800000" y="4200000"/><a:ext cx="10592000" cy="2200000"/></a:xfrm>
<a:prstGeom prst="rect"><a:avLst/></a:prstGeom><a:noFill/><a:ln><a:noFill/></a:ln>
</p:spPr>
<p:txBody>
<a:bodyPr wrap="square" anchor="t"/><a:lstStyle/>
<a:p><a:pPr algn="l"/><a:r><a:rPr lang="en-US" sz="1400" dirty="0"><a:solidFill><a:srgbClr val="8B95A2"/></a:solidFill><a:latin typeface="Segoe UI"/></a:rPr><a:t>Numbers tell stories. Through thoughtful visual design, every data point</a:t></a:r></a:p>
<a:p><a:pPr algn="l"/><a:r><a:rPr lang="en-US" sz="1400" dirty="0"><a:solidFill><a:srgbClr val="8B95A2"/></a:solidFill><a:latin typeface="Segoe UI"/></a:rPr><a:t>communicates its meaning at first glance.</a:t></a:r></a:p>
</p:txBody>
</p:sp>'''))
# =========================================================================
# SLIDE 4 — Quote Slide
# =========================================================================
items.append(slide())
items.append(bg(4,
'<p:bg><p:bgPr><a:gradFill rotWithShape="0"><a:gsLst>'
'<a:gs pos="0"><a:srgbClr val="1B2838"/></a:gs>'
'<a:gs pos="50000"><a:srgbClr val="0D1B2A"/></a:gs>'
'<a:gs pos="100000"><a:srgbClr val="1B2838"/></a:gs></a:gsLst>'
'<a:lin ang="2700000" scaled="1"/></a:gradFill><a:effectLst/></p:bgPr></p:bg>'))
# Large quote mark
items.append(shape(4, '''
<p:sp>
<p:nvSpPr><p:cNvPr id="400" name="QuoteMark"/><p:cNvSpPr txBox="1"/><p:nvPr/></p:nvSpPr>
<p:spPr>
<a:xfrm><a:off x="1000000" y="800000"/><a:ext cx="3000000" cy="2000000"/></a:xfrm>
<a:prstGeom prst="rect"><a:avLst/></a:prstGeom><a:noFill/><a:ln><a:noFill/></a:ln>
</p:spPr>
<p:txBody>
<a:bodyPr wrap="square" anchor="t"/><a:lstStyle/>
<a:p><a:pPr algn="l"/><a:r><a:rPr lang="en-US" sz="12000" dirty="0"><a:solidFill><a:srgbClr val="00B4D8"><a:alpha val="20000"/></a:srgbClr></a:solidFill><a:latin typeface="Georgia"/></a:rPr><a:t>&#x201C;</a:t></a:r></a:p>
</p:txBody>
</p:sp>'''))
# Quote text
items.append(shape(4, '''
<p:sp>
<p:nvSpPr><p:cNvPr id="401" name="Quote"/><p:cNvSpPr txBox="1"/><p:nvPr/></p:nvSpPr>
<p:spPr>
<a:xfrm><a:off x="1500000" y="2000000"/><a:ext cx="9192000" cy="2000000"/></a:xfrm>
<a:prstGeom prst="rect"><a:avLst/></a:prstGeom><a:noFill/><a:ln><a:noFill/></a:ln>
</p:spPr>
<p:txBody>
<a:bodyPr wrap="square" anchor="ctr"/><a:lstStyle/>
<a:p><a:pPr algn="ctr"/><a:r><a:rPr lang="en-US" sz="2800" i="1" dirty="0"><a:solidFill><a:srgbClr val="FFFFFF"/></a:solidFill><a:latin typeface="Georgia"/></a:rPr><a:t>Good design is obvious.</a:t></a:r></a:p>
<a:p><a:pPr algn="ctr"/><a:r><a:rPr lang="en-US" sz="2800" i="1" dirty="0"><a:solidFill><a:srgbClr val="FFFFFF"/></a:solidFill><a:latin typeface="Georgia"/></a:rPr><a:t>Great design is transparent.</a:t></a:r></a:p>
</p:txBody>
</p:sp>'''))
# Attribution
items.append(shape(4, '''
<p:sp>
<p:nvSpPr><p:cNvPr id="402" name="Author"/><p:cNvSpPr txBox="1"/><p:nvPr/></p:nvSpPr>
<p:spPr>
<a:xfrm><a:off x="1500000" y="4200000"/><a:ext cx="9192000" cy="600000"/></a:xfrm>
<a:prstGeom prst="rect"><a:avLst/></a:prstGeom><a:noFill/><a:ln><a:noFill/></a:ln>
</p:spPr>
<p:txBody>
<a:bodyPr wrap="square" anchor="t"/><a:lstStyle/>
<a:p><a:pPr algn="ctr"/><a:r><a:rPr lang="en-US" sz="1600" dirty="0"><a:solidFill><a:srgbClr val="00B4D8"/></a:solidFill><a:latin typeface="Segoe UI"/></a:rPr><a:t>&#x2014; Joe Sparano</a:t></a:r></a:p>
</p:txBody>
</p:sp>'''))
# Decorative line under quote
items.append(shape(4, '''
<p:sp>
<p:nvSpPr><p:cNvPr id="403" name="QuoteLine"/><p:cNvSpPr/><p:nvPr/></p:nvSpPr>
<p:spPr>
<a:xfrm><a:off x="5096000" y="5000000"/><a:ext cx="2000000" cy="0"/></a:xfrm>
<a:prstGeom prst="line"><a:avLst/></a:prstGeom>
<a:ln w="19050"><a:gradFill><a:gsLst><a:gs pos="0"><a:srgbClr val="00B4D8"><a:alpha val="0"/></a:srgbClr></a:gs><a:gs pos="50000"><a:srgbClr val="00B4D8"/></a:gs><a:gs pos="100000"><a:srgbClr val="00B4D8"><a:alpha val="0"/></a:srgbClr></a:gs></a:gsLst><a:lin ang="0" scaled="1"/></a:gradFill></a:ln>
</p:spPr>
<p:txBody><a:bodyPr/><a:lstStyle/><a:p><a:endParaRPr/></a:p></p:txBody>
</p:sp>'''))
# =========================================================================
# SLIDE 5 — Process / Timeline
# =========================================================================
items.append(slide())
items.append(bg(5,
'<p:bg><p:bgPr><a:solidFill><a:srgbClr val="0D1B2A"/></a:solidFill>'
'<a:effectLst/></p:bgPr></p:bg>'))
# Title
items.append(shape(5, '''
<p:sp>
<p:nvSpPr><p:cNvPr id="500" name="ProcessTitle"/><p:cNvSpPr txBox="1"/><p:nvPr/></p:nvSpPr>
<p:spPr>
<a:xfrm><a:off x="800000" y="300000"/><a:ext cx="10592000" cy="900000"/></a:xfrm>
<a:prstGeom prst="rect"><a:avLst/></a:prstGeom><a:noFill/><a:ln><a:noFill/></a:ln>
</p:spPr>
<p:txBody>
<a:bodyPr wrap="square" anchor="ctr"/><a:lstStyle/>
<a:p><a:pPr algn="ctr"/><a:r><a:rPr lang="en-US" sz="3200" b="1" dirty="0"><a:solidFill><a:srgbClr val="FFFFFF"/></a:solidFill><a:latin typeface="Segoe UI"/></a:rPr><a:t>Design Process</a:t></a:r></a:p>
</p:txBody>
</p:sp>'''))
# Horizontal rainbow connector
items.append(shape(5, '''
<p:sp>
<p:nvSpPr><p:cNvPr id="501" name="ConnLine"/><p:cNvSpPr/><p:nvPr/></p:nvSpPr>
<p:spPr>
<a:xfrm><a:off x="1800000" y="2800000"/><a:ext cx="8600000" cy="0"/></a:xfrm>
<a:prstGeom prst="line"><a:avLst/></a:prstGeom>
<a:ln w="25400"><a:gradFill><a:gsLst><a:gs pos="0"><a:srgbClr val="00B4D8"/></a:gs><a:gs pos="33000"><a:srgbClr val="E0AAFF"/></a:gs><a:gs pos="66000"><a:srgbClr val="FFD166"/></a:gs><a:gs pos="100000"><a:srgbClr val="06D6A0"/></a:gs></a:gsLst><a:lin ang="0" scaled="1"/></a:gradFill></a:ln>
</p:spPr>
<p:txBody><a:bodyPr/><a:lstStyle/><a:p><a:endParaRPr/></a:p></p:txBody>
</p:sp>'''))
# Step circles + labels (loop — mirrors the bash for-loop)
labels = ["Research", "Ideate", "Design", "Validate"]
colors = ["00B4D8", "E0AAFF", "FFD166", "06D6A0"]
xpos = [1400000, 3600000, 5800000, 8000000]
for i in range(4):
x = xpos[i]
c = colors[i]
label = labels[i]
n = i + 1
cid = 510 + i * 2
cid2 = 511 + i * 2
items.append(shape(5, f'''
<p:sp>
<p:nvSpPr><p:cNvPr id="{cid}" name="Step{n}"/><p:cNvSpPr/><p:nvPr/></p:nvSpPr>
<p:spPr>
<a:xfrm><a:off x="{x}" y="2200000"/><a:ext cx="1200000" cy="1200000"/></a:xfrm>
<a:prstGeom prst="ellipse"><a:avLst/></a:prstGeom>
<a:solidFill><a:srgbClr val="{c}"><a:alpha val="15000"/></a:srgbClr></a:solidFill>
<a:ln w="38100"><a:solidFill><a:srgbClr val="{c}"/></a:solidFill></a:ln>
</p:spPr>
<p:txBody>
<a:bodyPr wrap="square" anchor="ctr"/><a:lstStyle/>
<a:p><a:pPr algn="ctr"/><a:r><a:rPr lang="en-US" sz="2400" b="1" dirty="0"><a:solidFill><a:srgbClr val="{c}"/></a:solidFill></a:rPr><a:t>0{n}</a:t></a:r></a:p>
</p:txBody>
</p:sp>'''))
items.append(shape(5, f'''
<p:sp>
<p:nvSpPr><p:cNvPr id="{cid2}" name="Label{n}"/><p:cNvSpPr txBox="1"/><p:nvPr/></p:nvSpPr>
<p:spPr>
<a:xfrm><a:off x="{x}" y="3600000"/><a:ext cx="1200000" cy="800000"/></a:xfrm>
<a:prstGeom prst="rect"><a:avLst/></a:prstGeom><a:noFill/><a:ln><a:noFill/></a:ln>
</p:spPr>
<p:txBody>
<a:bodyPr wrap="square" anchor="t"/><a:lstStyle/>
<a:p><a:pPr algn="ctr"/><a:r><a:rPr lang="en-US" sz="1800" b="1" dirty="0"><a:solidFill><a:srgbClr val="FFFFFF"/></a:solidFill><a:latin typeface="Segoe UI"/></a:rPr><a:t>{label}</a:t></a:r></a:p>
</p:txBody>
</p:sp>'''))
# Bottom text
items.append(shape(5, '''
<p:sp>
<p:nvSpPr><p:cNvPr id="530" name="Bottom"/><p:cNvSpPr txBox="1"/><p:nvPr/></p:nvSpPr>
<p:spPr>
<a:xfrm><a:off x="800000" y="5000000"/><a:ext cx="10592000" cy="600000"/></a:xfrm>
<a:prstGeom prst="rect"><a:avLst/></a:prstGeom><a:noFill/><a:ln><a:noFill/></a:ln>
</p:spPr>
<p:txBody>
<a:bodyPr wrap="square" anchor="ctr"/><a:lstStyle/>
<a:p><a:pPr algn="ctr"/><a:r><a:rPr lang="en-US" sz="1200" dirty="0"><a:solidFill><a:srgbClr val="8B95A2"/></a:solidFill><a:latin typeface="Segoe UI"/></a:rPr><a:t>Every step is iterative. From research to validation, we refine until perfection.</a:t></a:r></a:p>
</p:txBody>
</p:sp>'''))
# =========================================================================
# SLIDE 6 — Closing
# =========================================================================
items.append(slide())
items.append(bg(6,
'<p:bg><p:bgPr><a:gradFill rotWithShape="0"><a:gsLst>'
'<a:gs pos="0"><a:srgbClr val="0A1628"/></a:gs>'
'<a:gs pos="50000"><a:srgbClr val="0D1B2A"/></a:gs>'
'<a:gs pos="100000"><a:srgbClr val="1B2838"/></a:gs></a:gsLst>'
'<a:lin ang="5400000" scaled="1"/></a:gradFill><a:effectLst/></p:bgPr></p:bg>'))
# Gradient ring
items.append(shape(6, '''
<p:sp>
<p:nvSpPr><p:cNvPr id="600" name="Ring"/><p:cNvSpPr/><p:nvPr/></p:nvSpPr>
<p:spPr>
<a:xfrm><a:off x="3596000" y="800000"/><a:ext cx="5000000" cy="5000000"/></a:xfrm>
<a:prstGeom prst="ellipse"><a:avLst/></a:prstGeom>
<a:noFill/>
<a:ln w="12700"><a:gradFill><a:gsLst><a:gs pos="0"><a:srgbClr val="00B4D8"><a:alpha val="30000"/></a:srgbClr></a:gs><a:gs pos="50000"><a:srgbClr val="E0AAFF"><a:alpha val="30000"/></a:srgbClr></a:gs><a:gs pos="100000"><a:srgbClr val="FFD166"><a:alpha val="30000"/></a:srgbClr></a:gs></a:gsLst><a:lin ang="2700000" scaled="1"/></a:gradFill></a:ln>
</p:spPr>
<p:txBody><a:bodyPr/><a:lstStyle/><a:p><a:endParaRPr/></a:p></p:txBody>
</p:sp>'''))
# Thank You
items.append(shape(6, '''
<p:sp>
<p:nvSpPr><p:cNvPr id="601" name="Thanks"/><p:cNvSpPr txBox="1"/><p:nvPr/></p:nvSpPr>
<p:spPr>
<a:xfrm><a:off x="1500000" y="2200000"/><a:ext cx="9192000" cy="1400000"/></a:xfrm>
<a:prstGeom prst="rect"><a:avLst/></a:prstGeom><a:noFill/><a:ln><a:noFill/></a:ln>
</p:spPr>
<p:txBody>
<a:bodyPr wrap="square" anchor="ctr"/><a:lstStyle/>
<a:p><a:pPr algn="ctr"/><a:r><a:rPr lang="en-US" sz="4800" b="1" dirty="0"><a:solidFill><a:srgbClr val="FFFFFF"/></a:solidFill><a:latin typeface="Segoe UI"/></a:rPr><a:t>Thank You</a:t></a:r></a:p>
</p:txBody>
</p:sp>'''))
# Closing subtitle
items.append(shape(6, '''
<p:sp>
<p:nvSpPr><p:cNvPr id="602" name="ClosingSub"/><p:cNvSpPr txBox="1"/><p:nvPr/></p:nvSpPr>
<p:spPr>
<a:xfrm><a:off x="1500000" y="3600000"/><a:ext cx="9192000" cy="800000"/></a:xfrm>
<a:prstGeom prst="rect"><a:avLst/></a:prstGeom><a:noFill/><a:ln><a:noFill/></a:ln>
</p:spPr>
<p:txBody>
<a:bodyPr wrap="square" anchor="t"/><a:lstStyle/>
<a:p><a:pPr algn="ctr"/><a:r><a:rPr lang="en-US" sz="1600" dirty="0"><a:solidFill><a:srgbClr val="90E0EF"/></a:solidFill><a:latin typeface="Segoe UI"/></a:rPr><a:t>Design is not just what it looks like &#x2014; it&#x2019;s how it works.</a:t></a:r></a:p>
</p:txBody>
</p:sp>'''))
# Three accent diamonds
items.append(shape(6, '''
<p:sp>
<p:nvSpPr><p:cNvPr id="603" name="D1"/><p:cNvSpPr/><p:nvPr/></p:nvSpPr>
<p:spPr>
<a:xfrm rot="2700000"><a:off x="5850000" y="4700000"/><a:ext cx="120000" cy="120000"/></a:xfrm>
<a:prstGeom prst="rect"><a:avLst/></a:prstGeom>
<a:solidFill><a:srgbClr val="00B4D8"/></a:solidFill><a:ln><a:noFill/></a:ln>
</p:spPr>
<p:txBody><a:bodyPr/><a:lstStyle/><a:p><a:endParaRPr/></a:p></p:txBody>
</p:sp>'''))
items.append(shape(6, '''
<p:sp>
<p:nvSpPr><p:cNvPr id="604" name="D2"/><p:cNvSpPr/><p:nvPr/></p:nvSpPr>
<p:spPr>
<a:xfrm rot="2700000"><a:off x="6100000" y="4700000"/><a:ext cx="120000" cy="120000"/></a:xfrm>
<a:prstGeom prst="rect"><a:avLst/></a:prstGeom>
<a:solidFill><a:srgbClr val="E0AAFF"/></a:solidFill><a:ln><a:noFill/></a:ln>
</p:spPr>
<p:txBody><a:bodyPr/><a:lstStyle/><a:p><a:endParaRPr/></a:p></p:txBody>
</p:sp>'''))
items.append(shape(6, '''
<p:sp>
<p:nvSpPr><p:cNvPr id="605" name="D3"/><p:cNvSpPr/><p:nvPr/></p:nvSpPr>
<p:spPr>
<a:xfrm rot="2700000"><a:off x="6350000" y="4700000"/><a:ext cx="120000" cy="120000"/></a:xfrm>
<a:prstGeom prst="rect"><a:avLst/></a:prstGeom>
<a:solidFill><a:srgbClr val="FFD166"/></a:solidFill><a:ln><a:noFill/></a:ln>
</p:spPr>
<p:txBody><a:bodyPr/><a:lstStyle/><a:p><a:endParaRPr/></a:p></p:txBody>
</p:sp>'''))
# One round-trip: 6 slides + every background and shape injection.
# stop_on_error so an out-of-order raw-set surfaces immediately (a slide
# must exist before its shapes can be appended to it).
resp = doc.batch(items, stop_on_error=True)
summary = resp.get("data", {}).get("summary", {}) if isinstance(resp, dict) else {}
print(f" shipped {len(items)} slide/raw-set items "
f"({summary.get('succeeded', '?')} ok, {summary.get('failed', '?')} failed)")
if summary.get("failed"):
for row in resp["data"]["results"]:
if not row.get("success"):
print(f" FAILED #{row['index']}: {row.get('error')}", file=sys.stderr)
raise SystemExit(1)
# context exit closes the resident, flushing the deck to disk.
print(f"Generated: {FILE}")
+624
View File
@@ -0,0 +1,624 @@
#!/bin/bash
# Generate a visually stunning presentation: "The Art of Design"
# Deep gradient backgrounds, geometric accents, clean typography
# NOTE: intentionally NO `set -e`. Like the SDK twin's doc.batch, this script
# tolerates forward-compat 'UNSUPPORTED props' warnings (officecli exit 2) and
# keeps building so the full document is produced.
OUT="$(dirname "$0")/presentation.pptx"
rm -f "$OUT"
officecli create "$OUT"
officecli open "$OUT"
# Slide dimensions: 12192000 x 6858000 EMU (16:9)
###############################################################################
# SLIDE 1 — Title Slide
###############################################################################
echo " -> Slide 1: Title"
officecli add "$OUT" / --type slide
# Full-bleed dark gradient background
officecli raw-set "$OUT" /slide[1] --xpath "//p:cSld" --action prepend --xml '
<p:bg>
<p:bgPr>
<a:gradFill rotWithShape="0">
<a:gsLst>
<a:gs pos="0"><a:srgbClr val="0D1B2A"/></a:gs>
<a:gs pos="50000"><a:srgbClr val="1B2838"/></a:gs>
<a:gs pos="100000"><a:srgbClr val="0A1628"/></a:gs>
</a:gsLst>
<a:lin ang="5400000" scaled="1"/>
</a:gradFill>
<a:effectLst/>
</p:bgPr>
</p:bg>'
# Decorative circle — top right (large, semi-transparent teal)
officecli raw-set "$OUT" /slide[1] --xpath "//p:cSld/p:spTree" --action append --xml '
<p:sp>
<p:nvSpPr><p:cNvPr id="100" name="Deco Circle 1"/><p:cNvSpPr/><p:nvPr/></p:nvSpPr>
<p:spPr>
<a:xfrm><a:off x="8500000" y="-1200000"/><a:ext cx="4800000" cy="4800000"/></a:xfrm>
<a:prstGeom prst="ellipse"><a:avLst/></a:prstGeom>
<a:solidFill><a:srgbClr val="00B4D8"><a:alpha val="8000"/></a:srgbClr></a:solidFill>
<a:ln><a:noFill/></a:ln>
</p:spPr>
<p:txBody><a:bodyPr/><a:lstStyle/><a:p><a:endParaRPr/></a:p></p:txBody>
</p:sp>'
# Decorative circle — bottom left (lavender)
officecli raw-set "$OUT" /slide[1] --xpath "//p:cSld/p:spTree" --action append --xml '
<p:sp>
<p:nvSpPr><p:cNvPr id="101" name="Deco Circle 2"/><p:cNvSpPr/><p:nvPr/></p:nvSpPr>
<p:spPr>
<a:xfrm><a:off x="-800000" y="4500000"/><a:ext cx="3200000" cy="3200000"/></a:xfrm>
<a:prstGeom prst="ellipse"><a:avLst/></a:prstGeom>
<a:solidFill><a:srgbClr val="E0AAFF"><a:alpha val="6000"/></a:srgbClr></a:solidFill>
<a:ln><a:noFill/></a:ln>
</p:spPr>
<p:txBody><a:bodyPr/><a:lstStyle/><a:p><a:endParaRPr/></a:p></p:txBody>
</p:sp>'
# Gradient accent line
officecli raw-set "$OUT" /slide[1] --xpath "//p:cSld/p:spTree" --action append --xml '
<p:sp>
<p:nvSpPr><p:cNvPr id="102" name="Accent Line"/><p:cNvSpPr/><p:nvPr/></p:nvSpPr>
<p:spPr>
<a:xfrm><a:off x="800000" y="4200000"/><a:ext cx="5000000" cy="0"/></a:xfrm>
<a:prstGeom prst="line"><a:avLst/></a:prstGeom>
<a:ln w="28575">
<a:gradFill>
<a:gsLst>
<a:gs pos="0"><a:srgbClr val="00B4D8"/></a:gs>
<a:gs pos="100000"><a:srgbClr val="E0AAFF"/></a:gs>
</a:gsLst>
<a:lin ang="0" scaled="1"/>
</a:gradFill>
</a:ln>
</p:spPr>
<p:txBody><a:bodyPr/><a:lstStyle/><a:p><a:endParaRPr/></a:p></p:txBody>
</p:sp>'
# Main title
officecli raw-set "$OUT" /slide[1] --xpath "//p:cSld/p:spTree" --action append --xml '
<p:sp>
<p:nvSpPr><p:cNvPr id="103" name="Title"/><p:cNvSpPr txBox="1"/><p:nvPr/></p:nvSpPr>
<p:spPr>
<a:xfrm><a:off x="800000" y="1600000"/><a:ext cx="8000000" cy="1200000"/></a:xfrm>
<a:prstGeom prst="rect"><a:avLst/></a:prstGeom>
<a:noFill/><a:ln><a:noFill/></a:ln>
</p:spPr>
<p:txBody>
<a:bodyPr wrap="square" anchor="b"/>
<a:lstStyle/>
<a:p>
<a:pPr algn="l"/>
<a:r>
<a:rPr lang="en-US" sz="5400" b="1" dirty="0">
<a:solidFill><a:srgbClr val="FFFFFF"/></a:solidFill>
<a:latin typeface="Segoe UI"/>
</a:rPr>
<a:t>The Art of Design</a:t>
</a:r>
</a:p>
</p:txBody>
</p:sp>'
# Subtitle
officecli raw-set "$OUT" /slide[1] --xpath "//p:cSld/p:spTree" --action append --xml '
<p:sp>
<p:nvSpPr><p:cNvPr id="104" name="Subtitle"/><p:cNvSpPr txBox="1"/><p:nvPr/></p:nvSpPr>
<p:spPr>
<a:xfrm><a:off x="800000" y="2900000"/><a:ext cx="8000000" cy="1100000"/></a:xfrm>
<a:prstGeom prst="rect"><a:avLst/></a:prstGeom>
<a:noFill/><a:ln><a:noFill/></a:ln>
</p:spPr>
<p:txBody>
<a:bodyPr wrap="square" anchor="t"/>
<a:lstStyle/>
<a:p>
<a:pPr algn="l"/>
<a:r>
<a:rPr lang="en-US" sz="2000" dirty="0">
<a:solidFill><a:srgbClr val="90E0EF"/></a:solidFill>
<a:latin typeface="Segoe UI"/>
</a:rPr>
<a:t>Crafting Beautiful Experiences</a:t>
</a:r>
</a:p>
<a:p>
<a:pPr algn="l"/>
<a:r>
<a:rPr lang="en-US" sz="1400" dirty="0" spc="600">
<a:solidFill><a:srgbClr val="8B95A2"/></a:solidFill>
<a:latin typeface="Segoe UI"/>
</a:rPr>
<a:t>SIMPLICITY &#xB7; ELEGANCE &#xB7; FUNCTION</a:t>
</a:r>
</a:p>
</p:txBody>
</p:sp>'
# Diamond accent
officecli raw-set "$OUT" /slide[1] --xpath "//p:cSld/p:spTree" --action append --xml '
<p:sp>
<p:nvSpPr><p:cNvPr id="105" name="Diamond"/><p:cNvSpPr/><p:nvPr/></p:nvSpPr>
<p:spPr>
<a:xfrm rot="2700000"><a:off x="600000" y="4050000"/><a:ext cx="200000" cy="200000"/></a:xfrm>
<a:prstGeom prst="rect"><a:avLst/></a:prstGeom>
<a:solidFill><a:srgbClr val="00B4D8"/></a:solidFill>
<a:ln><a:noFill/></a:ln>
</p:spPr>
<p:txBody><a:bodyPr/><a:lstStyle/><a:p><a:endParaRPr/></a:p></p:txBody>
</p:sp>'
###############################################################################
# SLIDE 2 — Three Pillars
###############################################################################
echo " -> Slide 2: Three Pillars"
officecli add "$OUT" / --type slide
officecli raw-set "$OUT" /slide[2] --xpath "//p:cSld" --action prepend --xml '
<p:bg><p:bgPr><a:solidFill><a:srgbClr val="0D1B2A"/></a:solidFill><a:effectLst/></p:bgPr></p:bg>'
# Section title
officecli raw-set "$OUT" /slide[2] --xpath "//p:cSld/p:spTree" --action append --xml '
<p:sp>
<p:nvSpPr><p:cNvPr id="200" name="Section Title"/><p:cNvSpPr txBox="1"/><p:nvPr/></p:nvSpPr>
<p:spPr>
<a:xfrm><a:off x="800000" y="400000"/><a:ext cx="10592000" cy="900000"/></a:xfrm>
<a:prstGeom prst="rect"><a:avLst/></a:prstGeom>
<a:noFill/><a:ln><a:noFill/></a:ln>
</p:spPr>
<p:txBody>
<a:bodyPr wrap="square" anchor="ctr"/>
<a:lstStyle/>
<a:p>
<a:pPr algn="ctr"/>
<a:r>
<a:rPr lang="en-US" sz="3200" b="1" dirty="0">
<a:solidFill><a:srgbClr val="FFFFFF"/></a:solidFill>
<a:latin typeface="Segoe UI"/>
</a:rPr>
<a:t>Three Pillars of Great Design</a:t>
</a:r>
</a:p>
</p:txBody>
</p:sp>'
# Subtitle
officecli raw-set "$OUT" /slide[2] --xpath "//p:cSld/p:spTree" --action append --xml '
<p:sp>
<p:nvSpPr><p:cNvPr id="201" name="SubLine"/><p:cNvSpPr txBox="1"/><p:nvPr/></p:nvSpPr>
<p:spPr>
<a:xfrm><a:off x="800000" y="1200000"/><a:ext cx="10592000" cy="400000"/></a:xfrm>
<a:prstGeom prst="rect"><a:avLst/></a:prstGeom>
<a:noFill/><a:ln><a:noFill/></a:ln>
</p:spPr>
<p:txBody>
<a:bodyPr wrap="square" anchor="t"/>
<a:lstStyle/>
<a:p>
<a:pPr algn="ctr"/>
<a:r>
<a:rPr lang="en-US" sz="1400" dirty="0">
<a:solidFill><a:srgbClr val="8B95A2"/></a:solidFill>
<a:latin typeface="Segoe UI"/>
</a:rPr>
<a:t>Every exceptional design is built upon these core principles</a:t>
</a:r>
</a:p>
</p:txBody>
</p:sp>'
# Card 1 — Simplicity
officecli raw-set "$OUT" /slide[2] --xpath "//p:cSld/p:spTree" --action append --xml '
<p:sp>
<p:nvSpPr><p:cNvPr id="210" name="Card1"/><p:cNvSpPr/><p:nvPr/></p:nvSpPr>
<p:spPr>
<a:xfrm><a:off x="900000" y="2000000"/><a:ext cx="3200000" cy="4200000"/></a:xfrm>
<a:prstGeom prst="roundRect"><a:avLst><a:gd name="adj" fmla="val 8000"/></a:avLst></a:prstGeom>
<a:solidFill><a:srgbClr val="152238"/></a:solidFill>
<a:ln w="12700"><a:solidFill><a:srgbClr val="1E3A5F"/></a:solidFill></a:ln>
</p:spPr>
<p:txBody>
<a:bodyPr wrap="square" lIns="228600" tIns="228600" rIns="228600" bIns="228600" anchor="t"/>
<a:lstStyle/>
<a:p><a:pPr algn="ctr"/><a:r><a:rPr lang="en-US" sz="4800" dirty="0"><a:solidFill><a:srgbClr val="00B4D8"/></a:solidFill></a:rPr><a:t>&#x25CB;</a:t></a:r></a:p>
<a:p><a:pPr algn="ctr"/><a:endParaRPr lang="en-US" sz="800"/></a:p>
<a:p><a:pPr algn="ctr"/><a:r><a:rPr lang="en-US" sz="2400" b="1" dirty="0"><a:solidFill><a:srgbClr val="FFFFFF"/></a:solidFill><a:latin typeface="Segoe UI"/></a:rPr><a:t>Simplicity</a:t></a:r></a:p>
<a:p><a:pPr algn="ctr"/><a:endParaRPr lang="en-US" sz="600"/></a:p>
<a:p><a:pPr algn="ctr"/><a:r><a:rPr lang="en-US" sz="1200" dirty="0"><a:solidFill><a:srgbClr val="8B95A2"/></a:solidFill><a:latin typeface="Segoe UI"/></a:rPr><a:t>Less is more. Strip away the unnecessary to let the essential shine through.</a:t></a:r></a:p>
</p:txBody>
</p:sp>'
# Card 2 — Hierarchy
officecli raw-set "$OUT" /slide[2] --xpath "//p:cSld/p:spTree" --action append --xml '
<p:sp>
<p:nvSpPr><p:cNvPr id="211" name="Card2"/><p:cNvSpPr/><p:nvPr/></p:nvSpPr>
<p:spPr>
<a:xfrm><a:off x="4496000" y="2000000"/><a:ext cx="3200000" cy="4200000"/></a:xfrm>
<a:prstGeom prst="roundRect"><a:avLst><a:gd name="adj" fmla="val 8000"/></a:avLst></a:prstGeom>
<a:solidFill><a:srgbClr val="152238"/></a:solidFill>
<a:ln w="12700"><a:solidFill><a:srgbClr val="1E3A5F"/></a:solidFill></a:ln>
</p:spPr>
<p:txBody>
<a:bodyPr wrap="square" lIns="228600" tIns="228600" rIns="228600" bIns="228600" anchor="t"/>
<a:lstStyle/>
<a:p><a:pPr algn="ctr"/><a:r><a:rPr lang="en-US" sz="4800" dirty="0"><a:solidFill><a:srgbClr val="E0AAFF"/></a:solidFill></a:rPr><a:t>&#x25B3;</a:t></a:r></a:p>
<a:p><a:pPr algn="ctr"/><a:endParaRPr lang="en-US" sz="800"/></a:p>
<a:p><a:pPr algn="ctr"/><a:r><a:rPr lang="en-US" sz="2400" b="1" dirty="0"><a:solidFill><a:srgbClr val="FFFFFF"/></a:solidFill><a:latin typeface="Segoe UI"/></a:rPr><a:t>Hierarchy</a:t></a:r></a:p>
<a:p><a:pPr algn="ctr"/><a:endParaRPr lang="en-US" sz="600"/></a:p>
<a:p><a:pPr algn="ctr"/><a:r><a:rPr lang="en-US" sz="1200" dirty="0"><a:solidFill><a:srgbClr val="8B95A2"/></a:solidFill><a:latin typeface="Segoe UI"/></a:rPr><a:t>Guide the eye with size, color, and space. Create a clear visual flow.</a:t></a:r></a:p>
</p:txBody>
</p:sp>'
# Card 3 — Harmony
officecli raw-set "$OUT" /slide[2] --xpath "//p:cSld/p:spTree" --action append --xml '
<p:sp>
<p:nvSpPr><p:cNvPr id="212" name="Card3"/><p:cNvSpPr/><p:nvPr/></p:nvSpPr>
<p:spPr>
<a:xfrm><a:off x="8092000" y="2000000"/><a:ext cx="3200000" cy="4200000"/></a:xfrm>
<a:prstGeom prst="roundRect"><a:avLst><a:gd name="adj" fmla="val 8000"/></a:avLst></a:prstGeom>
<a:solidFill><a:srgbClr val="152238"/></a:solidFill>
<a:ln w="12700"><a:solidFill><a:srgbClr val="1E3A5F"/></a:solidFill></a:ln>
</p:spPr>
<p:txBody>
<a:bodyPr wrap="square" lIns="228600" tIns="228600" rIns="228600" bIns="228600" anchor="t"/>
<a:lstStyle/>
<a:p><a:pPr algn="ctr"/><a:r><a:rPr lang="en-US" sz="4800" dirty="0"><a:solidFill><a:srgbClr val="FFD166"/></a:solidFill></a:rPr><a:t>&#x25C7;</a:t></a:r></a:p>
<a:p><a:pPr algn="ctr"/><a:endParaRPr lang="en-US" sz="800"/></a:p>
<a:p><a:pPr algn="ctr"/><a:r><a:rPr lang="en-US" sz="2400" b="1" dirty="0"><a:solidFill><a:srgbClr val="FFFFFF"/></a:solidFill><a:latin typeface="Segoe UI"/></a:rPr><a:t>Harmony</a:t></a:r></a:p>
<a:p><a:pPr algn="ctr"/><a:endParaRPr lang="en-US" sz="600"/></a:p>
<a:p><a:pPr algn="ctr"/><a:r><a:rPr lang="en-US" sz="1200" dirty="0"><a:solidFill><a:srgbClr val="8B95A2"/></a:solidFill><a:latin typeface="Segoe UI"/></a:rPr><a:t>Consistent color, type, and layout create a professional, cohesive experience.</a:t></a:r></a:p>
</p:txBody>
</p:sp>'
###############################################################################
# SLIDE 3 — Data Showcase
###############################################################################
echo " -> Slide 3: Data Showcase"
officecli add "$OUT" / --type slide
officecli raw-set "$OUT" /slide[3] --xpath "//p:cSld" --action prepend --xml '
<p:bg><p:bgPr><a:gradFill rotWithShape="0"><a:gsLst><a:gs pos="0"><a:srgbClr val="0D1B2A"/></a:gs><a:gs pos="100000"><a:srgbClr val="152238"/></a:gs></a:gsLst><a:lin ang="2700000" scaled="1"/></a:gradFill><a:effectLst/></p:bgPr></p:bg>'
# Title
officecli raw-set "$OUT" /slide[3] --xpath "//p:cSld/p:spTree" --action append --xml '
<p:sp>
<p:nvSpPr><p:cNvPr id="300" name="DataTitle"/><p:cNvSpPr txBox="1"/><p:nvPr/></p:nvSpPr>
<p:spPr>
<a:xfrm><a:off x="800000" y="300000"/><a:ext cx="10592000" cy="700000"/></a:xfrm>
<a:prstGeom prst="rect"><a:avLst/></a:prstGeom><a:noFill/><a:ln><a:noFill/></a:ln>
</p:spPr>
<p:txBody>
<a:bodyPr wrap="square" anchor="ctr"/><a:lstStyle/>
<a:p><a:pPr algn="l"/><a:r><a:rPr lang="en-US" sz="2800" b="1" dirty="0"><a:solidFill><a:srgbClr val="FFFFFF"/></a:solidFill><a:latin typeface="Segoe UI"/></a:rPr><a:t>Data-Driven Design</a:t></a:r></a:p>
</p:txBody>
</p:sp>'
# Gradient accent bar
officecli raw-set "$OUT" /slide[3] --xpath "//p:cSld/p:spTree" --action append --xml '
<p:sp>
<p:nvSpPr><p:cNvPr id="301" name="Bar"/><p:cNvSpPr/><p:nvPr/></p:nvSpPr>
<p:spPr>
<a:xfrm><a:off x="800000" y="1050000"/><a:ext cx="3000000" cy="50000"/></a:xfrm>
<a:prstGeom prst="rect"><a:avLst/></a:prstGeom>
<a:gradFill><a:gsLst><a:gs pos="0"><a:srgbClr val="00B4D8"/></a:gs><a:gs pos="100000"><a:srgbClr val="E0AAFF"/></a:gs></a:gsLst><a:lin ang="0" scaled="1"/></a:gradFill>
<a:ln><a:noFill/></a:ln>
</p:spPr>
<p:txBody><a:bodyPr/><a:lstStyle/><a:p><a:endParaRPr/></a:p></p:txBody>
</p:sp>'
# Stat card 1 — 98%
officecli raw-set "$OUT" /slide[3] --xpath "//p:cSld/p:spTree" --action append --xml '
<p:sp>
<p:nvSpPr><p:cNvPr id="310" name="Stat1"/><p:cNvSpPr txBox="1"/><p:nvPr/></p:nvSpPr>
<p:spPr>
<a:xfrm><a:off x="800000" y="1500000"/><a:ext cx="3400000" cy="2200000"/></a:xfrm>
<a:prstGeom prst="roundRect"><a:avLst><a:gd name="adj" fmla="val 6000"/></a:avLst></a:prstGeom>
<a:solidFill><a:srgbClr val="0E2540"/></a:solidFill>
<a:ln w="19050"><a:gradFill><a:gsLst><a:gs pos="0"><a:srgbClr val="00B4D8"/></a:gs><a:gs pos="100000"><a:srgbClr val="0077B6"/></a:gs></a:gsLst><a:lin ang="5400000" scaled="1"/></a:gradFill></a:ln>
</p:spPr>
<p:txBody>
<a:bodyPr wrap="square" lIns="228600" tIns="182880" rIns="228600" bIns="182880" anchor="ctr"/><a:lstStyle/>
<a:p><a:pPr algn="ctr"/><a:r><a:rPr lang="en-US" sz="5600" b="1" dirty="0"><a:solidFill><a:srgbClr val="00B4D8"/></a:solidFill><a:latin typeface="Segoe UI"/></a:rPr><a:t>98%</a:t></a:r></a:p>
<a:p><a:pPr algn="ctr"/><a:r><a:rPr lang="en-US" sz="1400" dirty="0"><a:solidFill><a:srgbClr val="8B95A2"/></a:solidFill><a:latin typeface="Segoe UI"/></a:rPr><a:t>User Satisfaction</a:t></a:r></a:p>
</p:txBody>
</p:sp>'
# Stat card 2 — 2.5M
officecli raw-set "$OUT" /slide[3] --xpath "//p:cSld/p:spTree" --action append --xml '
<p:sp>
<p:nvSpPr><p:cNvPr id="311" name="Stat2"/><p:cNvSpPr txBox="1"/><p:nvPr/></p:nvSpPr>
<p:spPr>
<a:xfrm><a:off x="4500000" y="1500000"/><a:ext cx="3400000" cy="2200000"/></a:xfrm>
<a:prstGeom prst="roundRect"><a:avLst><a:gd name="adj" fmla="val 6000"/></a:avLst></a:prstGeom>
<a:solidFill><a:srgbClr val="0E2540"/></a:solidFill>
<a:ln w="19050"><a:gradFill><a:gsLst><a:gs pos="0"><a:srgbClr val="E0AAFF"/></a:gs><a:gs pos="100000"><a:srgbClr val="9B5DE5"/></a:gs></a:gsLst><a:lin ang="5400000" scaled="1"/></a:gradFill></a:ln>
</p:spPr>
<p:txBody>
<a:bodyPr wrap="square" lIns="228600" tIns="182880" rIns="228600" bIns="182880" anchor="ctr"/><a:lstStyle/>
<a:p><a:pPr algn="ctr"/><a:r><a:rPr lang="en-US" sz="5600" b="1" dirty="0"><a:solidFill><a:srgbClr val="E0AAFF"/></a:solidFill><a:latin typeface="Segoe UI"/></a:rPr><a:t>2.5M</a:t></a:r></a:p>
<a:p><a:pPr algn="ctr"/><a:r><a:rPr lang="en-US" sz="1400" dirty="0"><a:solidFill><a:srgbClr val="8B95A2"/></a:solidFill><a:latin typeface="Segoe UI"/></a:rPr><a:t>Monthly Active Users</a:t></a:r></a:p>
</p:txBody>
</p:sp>'
# Stat card 3 — 47ms
officecli raw-set "$OUT" /slide[3] --xpath "//p:cSld/p:spTree" --action append --xml '
<p:sp>
<p:nvSpPr><p:cNvPr id="312" name="Stat3"/><p:cNvSpPr txBox="1"/><p:nvPr/></p:nvSpPr>
<p:spPr>
<a:xfrm><a:off x="8200000" y="1500000"/><a:ext cx="3400000" cy="2200000"/></a:xfrm>
<a:prstGeom prst="roundRect"><a:avLst><a:gd name="adj" fmla="val 6000"/></a:avLst></a:prstGeom>
<a:solidFill><a:srgbClr val="0E2540"/></a:solidFill>
<a:ln w="19050"><a:gradFill><a:gsLst><a:gs pos="0"><a:srgbClr val="FFD166"/></a:gs><a:gs pos="100000"><a:srgbClr val="F48C06"/></a:gs></a:gsLst><a:lin ang="5400000" scaled="1"/></a:gradFill></a:ln>
</p:spPr>
<p:txBody>
<a:bodyPr wrap="square" lIns="228600" tIns="182880" rIns="228600" bIns="182880" anchor="ctr"/><a:lstStyle/>
<a:p><a:pPr algn="ctr"/><a:r><a:rPr lang="en-US" sz="5600" b="1" dirty="0"><a:solidFill><a:srgbClr val="FFD166"/></a:solidFill><a:latin typeface="Segoe UI"/></a:rPr><a:t>47ms</a:t></a:r></a:p>
<a:p><a:pPr algn="ctr"/><a:r><a:rPr lang="en-US" sz="1400" dirty="0"><a:solidFill><a:srgbClr val="8B95A2"/></a:solidFill><a:latin typeface="Segoe UI"/></a:rPr><a:t>Avg Response Time</a:t></a:r></a:p>
</p:txBody>
</p:sp>'
# Bottom description
officecli raw-set "$OUT" /slide[3] --xpath "//p:cSld/p:spTree" --action append --xml '
<p:sp>
<p:nvSpPr><p:cNvPr id="320" name="Desc"/><p:cNvSpPr txBox="1"/><p:nvPr/></p:nvSpPr>
<p:spPr>
<a:xfrm><a:off x="800000" y="4200000"/><a:ext cx="10592000" cy="2200000"/></a:xfrm>
<a:prstGeom prst="rect"><a:avLst/></a:prstGeom><a:noFill/><a:ln><a:noFill/></a:ln>
</p:spPr>
<p:txBody>
<a:bodyPr wrap="square" anchor="t"/><a:lstStyle/>
<a:p><a:pPr algn="l"/><a:r><a:rPr lang="en-US" sz="1400" dirty="0"><a:solidFill><a:srgbClr val="8B95A2"/></a:solidFill><a:latin typeface="Segoe UI"/></a:rPr><a:t>Numbers tell stories. Through thoughtful visual design, every data point</a:t></a:r></a:p>
<a:p><a:pPr algn="l"/><a:r><a:rPr lang="en-US" sz="1400" dirty="0"><a:solidFill><a:srgbClr val="8B95A2"/></a:solidFill><a:latin typeface="Segoe UI"/></a:rPr><a:t>communicates its meaning at first glance.</a:t></a:r></a:p>
</p:txBody>
</p:sp>'
###############################################################################
# SLIDE 4 — Quote Slide
###############################################################################
echo " -> Slide 4: Quote"
officecli add "$OUT" / --type slide
officecli raw-set "$OUT" /slide[4] --xpath "//p:cSld" --action prepend --xml '
<p:bg><p:bgPr><a:gradFill rotWithShape="0"><a:gsLst><a:gs pos="0"><a:srgbClr val="1B2838"/></a:gs><a:gs pos="50000"><a:srgbClr val="0D1B2A"/></a:gs><a:gs pos="100000"><a:srgbClr val="1B2838"/></a:gs></a:gsLst><a:lin ang="2700000" scaled="1"/></a:gradFill><a:effectLst/></p:bgPr></p:bg>'
# Large quote mark
officecli raw-set "$OUT" /slide[4] --xpath "//p:cSld/p:spTree" --action append --xml '
<p:sp>
<p:nvSpPr><p:cNvPr id="400" name="QuoteMark"/><p:cNvSpPr txBox="1"/><p:nvPr/></p:nvSpPr>
<p:spPr>
<a:xfrm><a:off x="1000000" y="800000"/><a:ext cx="3000000" cy="2000000"/></a:xfrm>
<a:prstGeom prst="rect"><a:avLst/></a:prstGeom><a:noFill/><a:ln><a:noFill/></a:ln>
</p:spPr>
<p:txBody>
<a:bodyPr wrap="square" anchor="t"/><a:lstStyle/>
<a:p><a:pPr algn="l"/><a:r><a:rPr lang="en-US" sz="12000" dirty="0"><a:solidFill><a:srgbClr val="00B4D8"><a:alpha val="20000"/></a:srgbClr></a:solidFill><a:latin typeface="Georgia"/></a:rPr><a:t>&#x201C;</a:t></a:r></a:p>
</p:txBody>
</p:sp>'
# Quote text
officecli raw-set "$OUT" /slide[4] --xpath "//p:cSld/p:spTree" --action append --xml '
<p:sp>
<p:nvSpPr><p:cNvPr id="401" name="Quote"/><p:cNvSpPr txBox="1"/><p:nvPr/></p:nvSpPr>
<p:spPr>
<a:xfrm><a:off x="1500000" y="2000000"/><a:ext cx="9192000" cy="2000000"/></a:xfrm>
<a:prstGeom prst="rect"><a:avLst/></a:prstGeom><a:noFill/><a:ln><a:noFill/></a:ln>
</p:spPr>
<p:txBody>
<a:bodyPr wrap="square" anchor="ctr"/><a:lstStyle/>
<a:p><a:pPr algn="ctr"/><a:r><a:rPr lang="en-US" sz="2800" i="1" dirty="0"><a:solidFill><a:srgbClr val="FFFFFF"/></a:solidFill><a:latin typeface="Georgia"/></a:rPr><a:t>Good design is obvious.</a:t></a:r></a:p>
<a:p><a:pPr algn="ctr"/><a:r><a:rPr lang="en-US" sz="2800" i="1" dirty="0"><a:solidFill><a:srgbClr val="FFFFFF"/></a:solidFill><a:latin typeface="Georgia"/></a:rPr><a:t>Great design is transparent.</a:t></a:r></a:p>
</p:txBody>
</p:sp>'
# Attribution
officecli raw-set "$OUT" /slide[4] --xpath "//p:cSld/p:spTree" --action append --xml '
<p:sp>
<p:nvSpPr><p:cNvPr id="402" name="Author"/><p:cNvSpPr txBox="1"/><p:nvPr/></p:nvSpPr>
<p:spPr>
<a:xfrm><a:off x="1500000" y="4200000"/><a:ext cx="9192000" cy="600000"/></a:xfrm>
<a:prstGeom prst="rect"><a:avLst/></a:prstGeom><a:noFill/><a:ln><a:noFill/></a:ln>
</p:spPr>
<p:txBody>
<a:bodyPr wrap="square" anchor="t"/><a:lstStyle/>
<a:p><a:pPr algn="ctr"/><a:r><a:rPr lang="en-US" sz="1600" dirty="0"><a:solidFill><a:srgbClr val="00B4D8"/></a:solidFill><a:latin typeface="Segoe UI"/></a:rPr><a:t>&#x2014; Joe Sparano</a:t></a:r></a:p>
</p:txBody>
</p:sp>'
# Decorative line under quote
officecli raw-set "$OUT" /slide[4] --xpath "//p:cSld/p:spTree" --action append --xml '
<p:sp>
<p:nvSpPr><p:cNvPr id="403" name="QuoteLine"/><p:cNvSpPr/><p:nvPr/></p:nvSpPr>
<p:spPr>
<a:xfrm><a:off x="5096000" y="5000000"/><a:ext cx="2000000" cy="0"/></a:xfrm>
<a:prstGeom prst="line"><a:avLst/></a:prstGeom>
<a:ln w="19050"><a:gradFill><a:gsLst><a:gs pos="0"><a:srgbClr val="00B4D8"><a:alpha val="0"/></a:srgbClr></a:gs><a:gs pos="50000"><a:srgbClr val="00B4D8"/></a:gs><a:gs pos="100000"><a:srgbClr val="00B4D8"><a:alpha val="0"/></a:srgbClr></a:gs></a:gsLst><a:lin ang="0" scaled="1"/></a:gradFill></a:ln>
</p:spPr>
<p:txBody><a:bodyPr/><a:lstStyle/><a:p><a:endParaRPr/></a:p></p:txBody>
</p:sp>'
###############################################################################
# SLIDE 5 — Process / Timeline
###############################################################################
echo " -> Slide 5: Process"
officecli add "$OUT" / --type slide
officecli raw-set "$OUT" /slide[5] --xpath "//p:cSld" --action prepend --xml '
<p:bg><p:bgPr><a:solidFill><a:srgbClr val="0D1B2A"/></a:solidFill><a:effectLst/></p:bgPr></p:bg>'
# Title
officecli raw-set "$OUT" /slide[5] --xpath "//p:cSld/p:spTree" --action append --xml '
<p:sp>
<p:nvSpPr><p:cNvPr id="500" name="ProcessTitle"/><p:cNvSpPr txBox="1"/><p:nvPr/></p:nvSpPr>
<p:spPr>
<a:xfrm><a:off x="800000" y="300000"/><a:ext cx="10592000" cy="900000"/></a:xfrm>
<a:prstGeom prst="rect"><a:avLst/></a:prstGeom><a:noFill/><a:ln><a:noFill/></a:ln>
</p:spPr>
<p:txBody>
<a:bodyPr wrap="square" anchor="ctr"/><a:lstStyle/>
<a:p><a:pPr algn="ctr"/><a:r><a:rPr lang="en-US" sz="3200" b="1" dirty="0"><a:solidFill><a:srgbClr val="FFFFFF"/></a:solidFill><a:latin typeface="Segoe UI"/></a:rPr><a:t>Design Process</a:t></a:r></a:p>
</p:txBody>
</p:sp>'
# Horizontal rainbow connector
officecli raw-set "$OUT" /slide[5] --xpath "//p:cSld/p:spTree" --action append --xml '
<p:sp>
<p:nvSpPr><p:cNvPr id="501" name="ConnLine"/><p:cNvSpPr/><p:nvPr/></p:nvSpPr>
<p:spPr>
<a:xfrm><a:off x="1800000" y="2800000"/><a:ext cx="8600000" cy="0"/></a:xfrm>
<a:prstGeom prst="line"><a:avLst/></a:prstGeom>
<a:ln w="25400"><a:gradFill><a:gsLst><a:gs pos="0"><a:srgbClr val="00B4D8"/></a:gs><a:gs pos="33000"><a:srgbClr val="E0AAFF"/></a:gs><a:gs pos="66000"><a:srgbClr val="FFD166"/></a:gs><a:gs pos="100000"><a:srgbClr val="06D6A0"/></a:gs></a:gsLst><a:lin ang="0" scaled="1"/></a:gradFill></a:ln>
</p:spPr>
<p:txBody><a:bodyPr/><a:lstStyle/><a:p><a:endParaRPr/></a:p></p:txBody>
</p:sp>'
# Step circles + labels
LABELS=("Research" "Ideate" "Design" "Validate")
COLORS=("00B4D8" "E0AAFF" "FFD166" "06D6A0")
XPOS=(1400000 3600000 5800000 8000000)
for i in 0 1 2 3; do
X=${XPOS[$i]}
C=${COLORS[$i]}
L=${LABELS[$i]}
N=$((i+1))
ID=$((510 + i*2))
ID2=$((511 + i*2))
officecli raw-set "$OUT" /slide[5] --xpath "//p:cSld/p:spTree" --action append --xml "
<p:sp>
<p:nvSpPr><p:cNvPr id=\"${ID}\" name=\"Step${N}\"/><p:cNvSpPr/><p:nvPr/></p:nvSpPr>
<p:spPr>
<a:xfrm><a:off x=\"${X}\" y=\"2200000\"/><a:ext cx=\"1200000\" cy=\"1200000\"/></a:xfrm>
<a:prstGeom prst=\"ellipse\"><a:avLst/></a:prstGeom>
<a:solidFill><a:srgbClr val=\"${C}\"><a:alpha val=\"15000\"/></a:srgbClr></a:solidFill>
<a:ln w=\"38100\"><a:solidFill><a:srgbClr val=\"${C}\"/></a:solidFill></a:ln>
</p:spPr>
<p:txBody>
<a:bodyPr wrap=\"square\" anchor=\"ctr\"/><a:lstStyle/>
<a:p><a:pPr algn=\"ctr\"/><a:r><a:rPr lang=\"en-US\" sz=\"2400\" b=\"1\" dirty=\"0\"><a:solidFill><a:srgbClr val=\"${C}\"/></a:solidFill></a:rPr><a:t>0${N}</a:t></a:r></a:p>
</p:txBody>
</p:sp>"
officecli raw-set "$OUT" /slide[5] --xpath "//p:cSld/p:spTree" --action append --xml "
<p:sp>
<p:nvSpPr><p:cNvPr id=\"${ID2}\" name=\"Label${N}\"/><p:cNvSpPr txBox=\"1\"/><p:nvPr/></p:nvSpPr>
<p:spPr>
<a:xfrm><a:off x=\"${X}\" y=\"3600000\"/><a:ext cx=\"1200000\" cy=\"800000\"/></a:xfrm>
<a:prstGeom prst=\"rect\"><a:avLst/></a:prstGeom><a:noFill/><a:ln><a:noFill/></a:ln>
</p:spPr>
<p:txBody>
<a:bodyPr wrap=\"square\" anchor=\"t\"/><a:lstStyle/>
<a:p><a:pPr algn=\"ctr\"/><a:r><a:rPr lang=\"en-US\" sz=\"1800\" b=\"1\" dirty=\"0\"><a:solidFill><a:srgbClr val=\"FFFFFF\"/></a:solidFill><a:latin typeface=\"Segoe UI\"/></a:rPr><a:t>${L}</a:t></a:r></a:p>
</p:txBody>
</p:sp>"
done
# Bottom text
officecli raw-set "$OUT" /slide[5] --xpath "//p:cSld/p:spTree" --action append --xml '
<p:sp>
<p:nvSpPr><p:cNvPr id="530" name="Bottom"/><p:cNvSpPr txBox="1"/><p:nvPr/></p:nvSpPr>
<p:spPr>
<a:xfrm><a:off x="800000" y="5000000"/><a:ext cx="10592000" cy="600000"/></a:xfrm>
<a:prstGeom prst="rect"><a:avLst/></a:prstGeom><a:noFill/><a:ln><a:noFill/></a:ln>
</p:spPr>
<p:txBody>
<a:bodyPr wrap="square" anchor="ctr"/><a:lstStyle/>
<a:p><a:pPr algn="ctr"/><a:r><a:rPr lang="en-US" sz="1200" dirty="0"><a:solidFill><a:srgbClr val="8B95A2"/></a:solidFill><a:latin typeface="Segoe UI"/></a:rPr><a:t>Every step is iterative. From research to validation, we refine until perfection.</a:t></a:r></a:p>
</p:txBody>
</p:sp>'
###############################################################################
# SLIDE 6 — Closing
###############################################################################
echo " -> Slide 6: Closing"
officecli add "$OUT" / --type slide
officecli raw-set "$OUT" /slide[6] --xpath "//p:cSld" --action prepend --xml '
<p:bg><p:bgPr><a:gradFill rotWithShape="0"><a:gsLst><a:gs pos="0"><a:srgbClr val="0A1628"/></a:gs><a:gs pos="50000"><a:srgbClr val="0D1B2A"/></a:gs><a:gs pos="100000"><a:srgbClr val="1B2838"/></a:gs></a:gsLst><a:lin ang="5400000" scaled="1"/></a:gradFill><a:effectLst/></p:bgPr></p:bg>'
# Gradient ring
officecli raw-set "$OUT" /slide[6] --xpath "//p:cSld/p:spTree" --action append --xml '
<p:sp>
<p:nvSpPr><p:cNvPr id="600" name="Ring"/><p:cNvSpPr/><p:nvPr/></p:nvSpPr>
<p:spPr>
<a:xfrm><a:off x="3596000" y="800000"/><a:ext cx="5000000" cy="5000000"/></a:xfrm>
<a:prstGeom prst="ellipse"><a:avLst/></a:prstGeom>
<a:noFill/>
<a:ln w="12700"><a:gradFill><a:gsLst><a:gs pos="0"><a:srgbClr val="00B4D8"><a:alpha val="30000"/></a:srgbClr></a:gs><a:gs pos="50000"><a:srgbClr val="E0AAFF"><a:alpha val="30000"/></a:srgbClr></a:gs><a:gs pos="100000"><a:srgbClr val="FFD166"><a:alpha val="30000"/></a:srgbClr></a:gs></a:gsLst><a:lin ang="2700000" scaled="1"/></a:gradFill></a:ln>
</p:spPr>
<p:txBody><a:bodyPr/><a:lstStyle/><a:p><a:endParaRPr/></a:p></p:txBody>
</p:sp>'
# Thank You
officecli raw-set "$OUT" /slide[6] --xpath "//p:cSld/p:spTree" --action append --xml '
<p:sp>
<p:nvSpPr><p:cNvPr id="601" name="Thanks"/><p:cNvSpPr txBox="1"/><p:nvPr/></p:nvSpPr>
<p:spPr>
<a:xfrm><a:off x="1500000" y="2200000"/><a:ext cx="9192000" cy="1400000"/></a:xfrm>
<a:prstGeom prst="rect"><a:avLst/></a:prstGeom><a:noFill/><a:ln><a:noFill/></a:ln>
</p:spPr>
<p:txBody>
<a:bodyPr wrap="square" anchor="ctr"/><a:lstStyle/>
<a:p><a:pPr algn="ctr"/><a:r><a:rPr lang="en-US" sz="4800" b="1" dirty="0"><a:solidFill><a:srgbClr val="FFFFFF"/></a:solidFill><a:latin typeface="Segoe UI"/></a:rPr><a:t>Thank You</a:t></a:r></a:p>
</p:txBody>
</p:sp>'
# Closing subtitle
officecli raw-set "$OUT" /slide[6] --xpath "//p:cSld/p:spTree" --action append --xml '
<p:sp>
<p:nvSpPr><p:cNvPr id="602" name="ClosingSub"/><p:cNvSpPr txBox="1"/><p:nvPr/></p:nvSpPr>
<p:spPr>
<a:xfrm><a:off x="1500000" y="3600000"/><a:ext cx="9192000" cy="800000"/></a:xfrm>
<a:prstGeom prst="rect"><a:avLst/></a:prstGeom><a:noFill/><a:ln><a:noFill/></a:ln>
</p:spPr>
<p:txBody>
<a:bodyPr wrap="square" anchor="t"/><a:lstStyle/>
<a:p><a:pPr algn="ctr"/><a:r><a:rPr lang="en-US" sz="1600" dirty="0"><a:solidFill><a:srgbClr val="90E0EF"/></a:solidFill><a:latin typeface="Segoe UI"/></a:rPr><a:t>Design is not just what it looks like &#x2014; it&#x2019;s how it works.</a:t></a:r></a:p>
</p:txBody>
</p:sp>'
# Three accent diamonds
officecli raw-set "$OUT" /slide[6] --xpath "//p:cSld/p:spTree" --action append --xml '
<p:sp>
<p:nvSpPr><p:cNvPr id="603" name="D1"/><p:cNvSpPr/><p:nvPr/></p:nvSpPr>
<p:spPr>
<a:xfrm rot="2700000"><a:off x="5850000" y="4700000"/><a:ext cx="120000" cy="120000"/></a:xfrm>
<a:prstGeom prst="rect"><a:avLst/></a:prstGeom>
<a:solidFill><a:srgbClr val="00B4D8"/></a:solidFill><a:ln><a:noFill/></a:ln>
</p:spPr>
<p:txBody><a:bodyPr/><a:lstStyle/><a:p><a:endParaRPr/></a:p></p:txBody>
</p:sp>'
officecli raw-set "$OUT" /slide[6] --xpath "//p:cSld/p:spTree" --action append --xml '
<p:sp>
<p:nvSpPr><p:cNvPr id="604" name="D2"/><p:cNvSpPr/><p:nvPr/></p:nvSpPr>
<p:spPr>
<a:xfrm rot="2700000"><a:off x="6100000" y="4700000"/><a:ext cx="120000" cy="120000"/></a:xfrm>
<a:prstGeom prst="rect"><a:avLst/></a:prstGeom>
<a:solidFill><a:srgbClr val="E0AAFF"/></a:solidFill><a:ln><a:noFill/></a:ln>
</p:spPr>
<p:txBody><a:bodyPr/><a:lstStyle/><a:p><a:endParaRPr/></a:p></p:txBody>
</p:sp>'
officecli raw-set "$OUT" /slide[6] --xpath "//p:cSld/p:spTree" --action append --xml '
<p:sp>
<p:nvSpPr><p:cNvPr id="605" name="D3"/><p:cNvSpPr/><p:nvPr/></p:nvSpPr>
<p:spPr>
<a:xfrm rot="2700000"><a:off x="6350000" y="4700000"/><a:ext cx="120000" cy="120000"/></a:xfrm>
<a:prstGeom prst="rect"><a:avLst/></a:prstGeom>
<a:solidFill><a:srgbClr val="FFD166"/></a:solidFill><a:ln><a:noFill/></a:ln>
</p:spPr>
<p:txBody><a:bodyPr/><a:lstStyle/><a:p><a:endParaRPr/></a:p></p:txBody>
</p:sp>'
officecli close "$OUT"
echo ""
echo "=========================================="
echo "Beautiful presentation generated: $OUT"
echo "=========================================="
officecli view "$OUT" outline
+348
View File
@@ -0,0 +1,348 @@
# Basic PPT Shapes — Geometries, Fills, Outlines, Effects, Rotation
This demo consists of three files that work together:
- **shapes-basic.sh** — Shell script that calls `officecli` commands to generate the deck. Each slide's commands are shown as copyable blocks below.
- **shapes-basic.pptx** — The generated 5-slide deck (8 geometry presets, 8 fill types, 6 outline variants, 8 rotation angles, 3 effects, 6 stroke-geometry variants).
- **shapes-basic.md** — This file. Maps each slide to the features it demonstrates.
## Regenerate
```bash
cd examples/ppt
bash shapes/shapes-basic.sh
# → shapes/shapes-basic.pptx
```
## Slides
### Slide 1 — Geometry Preset Gallery
One row of 8 shapes, each rendered with a different `geometry=` preset.
Every supported schema-declared preset appears exactly once.
```bash
# Create the file and open a resident session
officecli create shapes-basic.pptx
officecli open shapes-basic.pptx
# Add the slide
officecli add shapes-basic.pptx / --type slide
# Title label
officecli add shapes-basic.pptx '/slide[1]' --type shape \
--prop text="Geometry Presets" --prop size=28 --prop bold=true \
--prop x=0.5in --prop y=0.3in --prop width=12in --prop height=0.6in
# One shape per preset — loop adds all 8 at columns 0..7
officecli add shapes-basic.pptx '/slide[1]' --type shape \
--prop geometry=rect \
--prop x=0.5in --prop y=1.5in --prop width=1.3in --prop height=1.3in \
--prop fill=4472C4 --prop color=FFFFFF \
--prop text="rect" --prop size=11 --prop bold=true
officecli add shapes-basic.pptx '/slide[1]' --type shape \
--prop geometry=roundRect \
--prop x=2.05in --prop y=1.5in --prop width=1.3in --prop height=1.3in \
--prop fill=4472C4 --prop color=FFFFFF \
--prop text="roundRect" --prop size=11 --prop bold=true
officecli add shapes-basic.pptx '/slide[1]' --type shape \
--prop geometry=ellipse \
--prop x=3.6in --prop y=1.5in --prop width=1.3in --prop height=1.3in \
--prop fill=4472C4 --prop color=FFFFFF \
--prop text="ellipse" --prop size=11 --prop bold=true
# … triangle, diamond, parallelogram, rightArrow, star5 follow the same pattern
officecli add shapes-basic.pptx '/slide[1]' --type shape \
--prop geometry=star5 \
--prop x=11.35in --prop y=1.5in --prop width=1.3in --prop height=1.3in \
--prop fill=4472C4 --prop color=FFFFFF \
--prop text="star5" --prop size=11 --prop bold=true
```
**Features:** `geometry` (rect, roundRect, ellipse, triangle, diamond, parallelogram, rightArrow, star5), `fill` (hex color), `color` (text color), `text`, `size`, `bold`, `x`/`y`/`width`/`height` (inch-suffixed dimensions)
---
### Slide 2 — Fill Variations
Eight `roundRect` shapes on one slide — every fill syntax demonstrated side by side.
```bash
officecli add shapes-basic.pptx / --type slide
# Solid hex fill
officecli add shapes-basic.pptx '/slide[2]' --type shape --prop geometry=roundRect \
--prop x=0.5in --prop y=1.3in --prop width=2.5in --prop height=1.5in \
--prop fill=E63946 --prop color=FFFFFF --prop bold=true \
--prop text='fill=E63946'
# Theme color (accent2 follows the deck's color theme)
officecli add shapes-basic.pptx '/slide[2]' --type shape --prop geometry=roundRect \
--prop x=3.3in --prop y=1.3in --prop width=2.5in --prop height=1.5in \
--prop fill=accent2 --prop color=FFFFFF --prop bold=true \
--prop text='fill=accent2'
# Linear gradient: COLOR1-COLOR2-ANGLE
officecli add shapes-basic.pptx '/slide[2]' --type shape --prop geometry=roundRect \
--prop x=6.1in --prop y=1.3in --prop width=2.5in --prop height=1.5in \
--prop gradient="FF6B6B-4ECDC4-45" --prop color=FFFFFF --prop bold=true \
--prop text='gradient linear 45°'
# Radial gradient: radial:CENTER-COLOR1-COLOR2
officecli add shapes-basic.pptx '/slide[2]' --type shape --prop geometry=roundRect \
--prop x=8.9in --prop y=1.3in --prop width=2.5in --prop height=1.5in \
--prop gradient="radial:FFE66D-FF6B35-center" --prop color=000000 --prop bold=true \
--prop text='gradient radial'
# Pattern fill: preset:foreground:background
officecli add shapes-basic.pptx '/slide[2]' --type shape --prop geometry=roundRect \
--prop x=0.5in --prop y=3.1in --prop width=2.5in --prop height=1.5in \
--prop pattern="diagBrick:1D3557:F1FAEE" --prop color=FFFFFF --prop bold=true \
--prop text='pattern diagBrick'
# Solid + opacity (opacity requires fill)
officecli add shapes-basic.pptx '/slide[2]' --type shape --prop geometry=roundRect \
--prop x=3.3in --prop y=3.1in --prop width=2.5in --prop height=1.5in \
--prop fill=2A9D8F --prop opacity=0.4 --prop color=000000 --prop bold=true \
--prop text='fill + opacity=0.4'
# No fill — outline only
officecli add shapes-basic.pptx '/slide[2]' --type shape --prop geometry=roundRect \
--prop x=6.1in --prop y=3.1in --prop width=2.5in --prop height=1.5in \
--prop fill=none --prop line="264653:2.5:solid" --prop color=264653 --prop bold=true \
--prop text='fill=none + outline'
# Per-stop gradient: COLOR@POSITION (0..100%)
officecli add shapes-basic.pptx '/slide[2]' --type shape --prop geometry=roundRect \
--prop x=8.9in --prop y=3.1in --prop width=2.5in --prop height=1.5in \
--prop gradient="FF0000@0-FFD700@40-0000FF@100" --prop color=FFFFFF --prop bold=true \
--prop text='gradient per-stop'
```
**Features:** `fill` (hex, theme color, none), `gradient` (linear `C1-C2-ANGLE`, radial `radial:C1-C2-center`, per-stop `C@POS-C@POS-C@POS`), `pattern` (`preset:fg:bg` — e.g. diagBrick, wave, dotGrid), `opacity` (0.01.0, requires fill), `line` (compound `color:widthPt:dash`)
---
### Slide 3 — Outline Styling
Six shapes demonstrating both the compound and per-attribute line forms, compound strokes, and arrowhead endpoints.
```bash
officecli add shapes-basic.pptx / --type slide
# Compound line form: "color:widthPt:dash"
officecli add shapes-basic.pptx '/slide[3]' --type shape --prop geometry=rect \
--prop x=0.5in --prop y=1.3in --prop width=3in --prop height=1.2in \
--prop fill=none --prop line="E63946:3:solid" \
--prop text='line="E63946:3:solid"' --prop size=12
officecli add shapes-basic.pptx '/slide[3]' --type shape --prop geometry=rect \
--prop x=4in --prop y=1.3in --prop width=3in --prop height=1.2in \
--prop fill=none --prop line="1D3557:2:dash" \
--prop text='line="1D3557:2:dash"' --prop size=12
officecli add shapes-basic.pptx '/slide[3]' --type shape --prop geometry=rect \
--prop x=7.5in --prop y=1.3in --prop width=3in --prop height=1.2in \
--prop fill=none --prop line="2A9D8F:2.5:dashDot" \
--prop text='line="2A9D8F:2.5:dashDot"' --prop size=12
# Per-attribute form: lineColor + lineWidth + lineDash separately
officecli add shapes-basic.pptx '/slide[3]' --type shape --prop geometry=ellipse \
--prop x=0.5in --prop y=2.9in --prop width=3in --prop height=1.4in \
--prop fill=FFE66D --prop lineColor=E63946 --prop lineWidth=4pt --prop lineDash=solid \
--prop text='separate lineColor/lineWidth/lineDash' --prop size=11
# Compound stroke: cmpd=dbl (double line)
officecli add shapes-basic.pptx '/slide[3]' --type shape --prop geometry=ellipse \
--prop x=4in --prop y=2.9in --prop width=3in --prop height=1.4in \
--prop fill=A8DADC --prop lineColor=1D3557 --prop lineWidth=6pt --prop cmpd=dbl \
--prop text='cmpd=dbl (double stroke)' --prop size=11
# Compound stroke: cmpd=tri (triple line)
officecli add shapes-basic.pptx '/slide[3]' --type shape --prop geometry=ellipse \
--prop x=7.5in --prop y=2.9in --prop width=3in --prop height=1.4in \
--prop fill=A8DADC --prop lineColor=1D3557 --prop lineWidth=8pt --prop cmpd=tri \
--prop text='cmpd=tri (triple stroke)' --prop size=11
# Arrowheads on shape outlines (headEnd / tailEnd)
officecli add shapes-basic.pptx '/slide[3]' --type shape --prop geometry=rect \
--prop x=0.5in --prop y=5.2in --prop width=4in --prop height=0.05in \
--prop fill=none --prop lineColor=000000 --prop lineWidth=2pt \
--prop headEnd=triangle --prop tailEnd=arrow
officecli add shapes-basic.pptx '/slide[3]' --type shape --prop geometry=rect \
--prop x=5in --prop y=5.2in --prop width=4in --prop height=0.05in \
--prop fill=none --prop lineColor=000000 --prop lineWidth=2pt \
--prop headEnd=diamond --prop tailEnd=oval
```
**Features:** `line` (compound `color:widthPt:dash`), `lineColor`, `lineWidth` (pt-suffixed), `lineDash` (solid, dash, dashDot, dot, lgDash, sysDash, sysDot), `cmpd` (dbl, tri), `headEnd` / `tailEnd` (none, triangle, arrow, diamond, oval, stealth)
---
### Slide 4 — Rotation + Effects
Eight right-arrow shapes show `rotation=0..270`. Three `roundRect` shapes demonstrate shadow, glow, and reflection effects.
```bash
officecli add shapes-basic.pptx / --type slide
# Rotation — degrees clockwise (0..360); each shape shows its angle as text
officecli add shapes-basic.pptx '/slide[4]' --type shape --prop geometry=rightArrow \
--prop x=0.5in --prop y=1.3in --prop width=1.4in --prop height=0.8in \
--prop fill=4472C4 --prop color=FFFFFF --prop bold=true \
--prop rotation=0 --prop text="0°" --prop size=11
officecli add shapes-basic.pptx '/slide[4]' --type shape --prop geometry=rightArrow \
--prop x=2.05in --prop y=1.3in --prop width=1.4in --prop height=0.8in \
--prop fill=4472C4 --prop color=FFFFFF --prop bold=true \
--prop rotation=30 --prop text="30°" --prop size=11
# … continues for 60, 90, 135, 180, 225, 270
# Shadow effect — color only; handler fills in blur/offset/direction defaults
officecli add shapes-basic.pptx '/slide[4]' --type shape --prop geometry=roundRect \
--prop x=1in --prop y=3in --prop width=3.5in --prop height=1.8in \
--prop fill=E63946 --prop color=FFFFFF --prop bold=true --prop size=14 \
--prop text='shadow=000000' \
--prop shadow=000000
# Glow effect — color; handler applies default radius
officecli add shapes-basic.pptx '/slide[4]' --type shape --prop geometry=roundRect \
--prop x=5.5in --prop y=3in --prop width=3.5in --prop height=1.8in \
--prop fill=2A9D8F --prop color=FFFFFF --prop bold=true --prop size=14 \
--prop text='glow=FFD700' \
--prop glow=FFD700
# Reflection effect — preset name
officecli add shapes-basic.pptx '/slide[4]' --type shape --prop geometry=roundRect \
--prop x=10in --prop y=3in --prop width=3in --prop height=1.8in \
--prop fill=F4A261 --prop color=000000 --prop bold=true --prop size=14 \
--prop text='reflection=tight' \
--prop reflection=tight
```
**Features:** `rotation` (degrees 0360), `shadow` (color or `true` for defaults; Get returns `#RRGGBB-blur-angle-dist-opacity`), `glow` (color or `color-radius-opacity`), `reflection` (tight, half, full)
---
### Slide 5 — Stroke Geometry Details
Six shapes demonstrating `lineCap`, `lineJoin` (incl. miterLimit), and `lineAlign`.
```bash
officecli add shapes-basic.pptx / --type slide
# lineCap — how stroke terminates at endpoints / dash gaps
# Thick dashed stroke makes the difference visible: round/square extend past
# the endpoint, flat cuts exactly at it.
officecli add shapes-basic.pptx '/slide[5]' --type shape --prop geometry=rect \
--prop x=0.5in --prop y=1.5in --prop width=4in --prop height=0.05in \
--prop fill=none --prop lineColor=1D3557 --prop lineWidth=10pt \
--prop lineDash=dash --prop lineCap=flat
officecli add shapes-basic.pptx '/slide[5]' --type shape --prop geometry=rect \
--prop x=4.8in --prop y=1.5in --prop width=4in --prop height=0.05in \
--prop fill=none --prop lineColor=1D3557 --prop lineWidth=10pt \
--prop lineDash=dash --prop lineCap=round
officecli add shapes-basic.pptx '/slide[5]' --type shape --prop geometry=rect \
--prop x=9.1in --prop y=1.5in --prop width=4in --prop height=0.05in \
--prop fill=none --prop lineColor=1D3557 --prop lineWidth=10pt \
--prop lineDash=dash --prop lineCap=square
# lineJoin — corner style on a stroked shape (thick triangle makes it obvious)
officecli add shapes-basic.pptx '/slide[5]' --type shape --prop geometry=triangle \
--prop x=0.5in --prop y=2.8in --prop width=2.5in --prop height=2in \
--prop fill=A8DADC --prop lineColor=E63946 --prop lineWidth=12pt \
--prop lineJoin=round
officecli add shapes-basic.pptx '/slide[5]' --type shape --prop geometry=triangle \
--prop x=3.5in --prop y=2.8in --prop width=2.5in --prop height=2in \
--prop fill=A8DADC --prop lineColor=E63946 --prop lineWidth=12pt \
--prop lineJoin=bevel
officecli add shapes-basic.pptx '/slide[5]' --type shape --prop geometry=triangle \
--prop x=6.5in --prop y=2.8in --prop width=2.5in --prop height=2in \
--prop fill=A8DADC --prop lineColor=E63946 --prop lineWidth=12pt \
--prop lineJoin=miter
# miterLimit — compound form sets join style + limit together
# Expressed in 1/1000ths of a percent; 800000 = 800%
officecli add shapes-basic.pptx '/slide[5]' --type shape --prop geometry=triangle \
--prop x=0.5in --prop y=5.5in --prop width=2.5in --prop height=1.8in \
--prop fill=A8DADC --prop lineColor=E63946 --prop lineWidth=8pt \
--prop lineJoin="miter:800000"
# lineAlign — stroke alignment: ctr (centered on path) vs in (fully inset)
officecli add shapes-basic.pptx '/slide[5]' --type shape --prop geometry=rect \
--prop x=9in --prop y=2.8in --prop width=2in --prop height=2in \
--prop fill=F4A261 --prop lineColor=1D3557 --prop lineWidth=12pt \
--prop lineAlign=ctr
officecli add shapes-basic.pptx '/slide[5]' --type shape --prop geometry=rect \
--prop x=11.5in --prop y=2.8in --prop width=2in --prop height=2in \
--prop fill=F4A261 --prop lineColor=1D3557 --prop lineWidth=12pt \
--prop lineAlign=in
officecli close shapes-basic.pptx
officecli validate shapes-basic.pptx
```
**Features:** `lineCap` (flat, round, square), `lineJoin` (round, bevel, miter), `lineJoin="miter:N"` (compound form sets join + miterLimit in one prop), `lineAlign` (ctr, in)
---
## Complete Feature Coverage
| Feature | Slide |
|---------|-------|
| **Geometry presets:** rect, roundRect, ellipse, triangle, diamond, parallelogram, rightArrow, star5 | 1 |
| **Solid fill:** hex color | 1, 2 |
| **Theme fill:** accent1..6, dark1/2, light1/2 | 2 |
| **Linear gradient:** `C1-C2-ANGLE` | 2 |
| **Radial gradient:** `radial:C1-C2-center` | 2 |
| **Per-stop gradient:** `C@POS-C@POS-C@POS` | 2 |
| **Pattern fill:** `preset:fg:bg` | 2 |
| **Opacity:** `opacity=0.01.0` (requires fill) | 2 |
| **No fill:** `fill=none` | 2 |
| **Compound line:** `line="color:widthPt:dash"` | 2, 3 |
| **Per-attribute line:** `lineColor`, `lineWidth`, `lineDash` | 3 |
| **Dash patterns:** solid, dash, dashDot, dot, lgDash, sysDash, sysDot | 3 |
| **Compound stroke:** `cmpd=dbl|tri` | 3 |
| **Arrowheads:** `headEnd` / `tailEnd` (triangle, arrow, diamond, oval, none) | 3 |
| **Rotation:** `rotation=0..360` | 4 |
| **Shadow effect:** `shadow=color` or `shadow=color-blur-angle-dist-opacity` | 4 |
| **Glow effect:** `glow=color` or `glow=color-radius-opacity` | 4 |
| **Reflection effect:** `reflection=tight|half|full` | 4 |
| **Line cap:** `lineCap=flat|round|square` | 5 |
| **Line join:** `lineJoin=round|bevel|miter` | 5 |
| **Miter limit:** `lineJoin="miter:N"` (compound) | 5 |
| **Line alignment:** `lineAlign=ctr|in` | 5 |
| **Text in shape:** `text`, `size`, `bold`, `color` | 15 |
| **Position/size:** `x`, `y`, `width`, `height` (in/cm/pt/emu) | 15 |
## Inspect the Generated File
```bash
# List all shapes on slide 1
officecli query shapes-basic.pptx '/slide[1]' shape
# Get the full property set for the ellipse (shape[3])
officecli get shapes-basic.pptx '/slide[1]/shape[3]'
# Check the fill and gradient on slide 2 shape[3] (linear gradient)
officecli get shapes-basic.pptx '/slide[2]/shape[3]'
# Inspect outline properties on slide 3 shape[2]
officecli get shapes-basic.pptx '/slide[3]/shape[2]'
# Check effects on the shadow shape (slide 4 shape[9])
officecli get shapes-basic.pptx '/slide[4]/shape[9]'
# Inspect stroke geometry on slide 5
officecli get shapes-basic.pptx '/slide[5]/shape[1]'
officecli get shapes-basic.pptx '/slide[5]/shape[4]'
```
Binary file not shown.
+263
View File
@@ -0,0 +1,263 @@
#!/usr/bin/env python3
"""
Basic PowerPoint shapes — generates shapes-basic.pptx exercising the pptx
`shape` element: geometry presets, solid/gradient/pattern/image fills, line
styling (color/width/dash/caps/joins/align/arrowheads), rotation, opacity, and
shadow/glow/reflection effects.
SDK twin of shapes-basic.sh (officecli CLI). Both produce an equivalent
shapes-basic.pptx. This one drives the **officecli Python SDK**
(`pip install officecli-sdk`): one resident is started and every slide and
shape is shipped over the named pipe in a single `doc.batch(...)` round-trip.
Each item is the same `{"command","parent","type","props"}` dict you'd put in
an `officecli batch` list.
Usage:
pip install officecli-sdk # plus the `officecli` binary on PATH
python3 shapes-basic.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__)), "shapes-basic.pptx")
def slide(**props):
"""One `add slide` item in batch-shape."""
return {"command": "add", "parent": "/", "type": "slide", "props": props}
def shape(slide_idx, **props):
"""One `add shape` item onto /slide[slide_idx] in batch-shape."""
return {"command": "add", "parent": f"/slide[{slide_idx}]", "type": "shape",
"props": props}
print(f"Building {FILE} ...")
with officecli.create(FILE, "--force") as doc:
items = []
# ─────────────────────────────────────────────────────────────────────────
# Slide 1 — Geometry preset gallery
# ─────────────────────────────────────────────────────────────────────────
items.append(slide())
items.append(shape(1, text="Geometry Presets", size="28", bold="true",
x="0.5in", y="0.3in", width="12in", height="0.6in"))
# Row of 8 shapes, one per supported preset.
# Schema-declared presets: rect, roundRect, ellipse, triangle, diamond,
# parallelogram, rightArrow, star5
presets = ["rect", "roundRect", "ellipse", "triangle", "diamond",
"parallelogram", "rightArrow", "star5"]
for col, preset in enumerate(presets):
x = 0.5 + col * 1.55
items.append(shape(1, geometry=preset,
x=f"{x}in", y="1.5in", width="1.3in", height="1.3in",
fill="4472C4", color="FFFFFF",
text=preset, size="11", bold="true"))
# ─────────────────────────────────────────────────────────────────────────
# Slide 2 — Fill variations on the same geometry
# ─────────────────────────────────────────────────────────────────────────
items.append(slide())
items.append(shape(2, text="Fill Variations", size="28", bold="true",
x="0.5in", y="0.3in", width="12in", height="0.6in"))
# Solid hex
items.append(shape(2, geometry="roundRect",
x="0.5in", y="1.3in", width="2.5in", height="1.5in",
fill="E63946", color="FFFFFF", bold="true",
text="fill=E63946"))
# Theme color (follows deck theme)
items.append(shape(2, geometry="roundRect",
x="3.3in", y="1.3in", width="2.5in", height="1.5in",
fill="accent2", color="FFFFFF", bold="true",
text="fill=accent2"))
# Linear gradient (color1-color2-angle)
items.append(shape(2, geometry="roundRect",
x="6.1in", y="1.3in", width="2.5in", height="1.5in",
gradient="FF6B6B-4ECDC4-45", color="FFFFFF", bold="true",
text="gradient linear 45°"))
# Radial gradient
items.append(shape(2, geometry="roundRect",
x="8.9in", y="1.3in", width="2.5in", height="1.5in",
gradient="radial:FFE66D-FF6B35-center", color="000000",
bold="true", text="gradient radial"))
# Pattern (preset:fg:bg)
items.append(shape(2, geometry="roundRect",
x="0.5in", y="3.1in", width="2.5in", height="1.5in",
pattern="diagBrick:1D3557:F1FAEE", color="FFFFFF",
bold="true", text="pattern diagBrick"))
# Opacity (requires a fill to attach to)
items.append(shape(2, geometry="roundRect",
x="3.3in", y="3.1in", width="2.5in", height="1.5in",
fill="2A9D8F", opacity="0.4", color="000000", bold="true",
text="fill + opacity=0.4"))
# No fill (outline only)
items.append(shape(2, geometry="roundRect",
x="6.1in", y="3.1in", width="2.5in", height="1.5in",
fill="none", line="264653:2.5:solid", color="264653",
bold="true", text="fill=none + outline"))
# Per-stop gradient positions
items.append(shape(2, geometry="roundRect",
x="8.9in", y="3.1in", width="2.5in", height="1.5in",
gradient="FF0000@0-FFD700@40-0000FF@100", color="FFFFFF",
bold="true", text="gradient per-stop"))
# ─────────────────────────────────────────────────────────────────────────
# Slide 3 — Outline styling (line color / width / dash / caps / arrowheads)
# ─────────────────────────────────────────────────────────────────────────
items.append(slide())
items.append(shape(3, text="Outline Styling", size="28", bold="true",
x="0.5in", y="0.3in", width="12in", height="0.6in"))
# Compound line form: color:width:dash
items.append(shape(3, geometry="rect",
x="0.5in", y="1.3in", width="3in", height="1.2in",
fill="none", line="E63946:3:solid",
text='line="E63946:3:solid"', size="12"))
items.append(shape(3, geometry="rect",
x="4in", y="1.3in", width="3in", height="1.2in",
fill="none", line="1D3557:2:dash",
text='line="1D3557:2:dash"', size="12"))
items.append(shape(3, geometry="rect",
x="7.5in", y="1.3in", width="3in", height="1.2in",
fill="none", line="2A9D8F:2.5:dashDot",
text='line="2A9D8F:2.5:dashDot"', size="12"))
# Per-attribute form: lineColor + lineWidth + lineDash
items.append(shape(3, geometry="ellipse",
x="0.5in", y="2.9in", width="3in", height="1.4in",
fill="FFE66D", lineColor="E63946", lineWidth="4pt",
lineDash="solid",
text="separate lineColor/lineWidth/lineDash", size="11"))
# Compound stroke (cmpd=dbl → double line)
items.append(shape(3, geometry="ellipse",
x="4in", y="2.9in", width="3in", height="1.4in",
fill="A8DADC", lineColor="1D3557", lineWidth="6pt",
cmpd="dbl", text="cmpd=dbl (double stroke)", size="11"))
# Triple stroke
items.append(shape(3, geometry="ellipse",
x="7.5in", y="2.9in", width="3in", height="1.4in",
fill="A8DADC", lineColor="1D3557", lineWidth="8pt",
cmpd="tri", text="cmpd=tri (triple stroke)", size="11"))
# Arrowheads on shape outlines (demo headEnd/tailEnd here)
items.append(shape(3,
text="headEnd / tailEnd work on any outline (not just connectors):",
size="12",
x="0.5in", y="4.7in", width="12in", height="0.4in"))
items.append(shape(3, geometry="rect",
x="0.5in", y="5.2in", width="4in", height="0.05in",
fill="none", lineColor="000000", lineWidth="2pt",
headEnd="triangle", tailEnd="arrow"))
items.append(shape(3, geometry="rect",
x="5in", y="5.2in", width="4in", height="0.05in",
fill="none", lineColor="000000", lineWidth="2pt",
headEnd="diamond", tailEnd="oval"))
# ─────────────────────────────────────────────────────────────────────────
# Slide 4 — Rotation, shadow effect, z-order via add order
# ─────────────────────────────────────────────────────────────────────────
items.append(slide())
items.append(shape(4, text="Rotation + Effects", size="28", bold="true",
x="0.5in", y="0.3in", width="12in", height="0.6in"))
# Rotation in degrees (0..360)
for col, r in enumerate([0, 30, 60, 90, 135, 180, 225, 270]):
x = 0.5 + col * 1.55
items.append(shape(4, geometry="rightArrow",
x=f"{x}in", y="1.3in", width="1.4in", height="0.8in",
fill="4472C4", color="FFFFFF", bold="true",
rotation=str(r), text=f"{r}°", size="11"))
# Shadow effect: shadow=color:blur:offset:direction (compound effect)
items.append(shape(4, geometry="roundRect",
x="1in", y="3in", width="3.5in", height="1.8in",
fill="E63946", color="FFFFFF", bold="true", size="14",
text="shadow=000000", shadow="000000"))
items.append(shape(4, geometry="roundRect",
x="5.5in", y="3in", width="3.5in", height="1.8in",
fill="2A9D8F", color="FFFFFF", bold="true", size="14",
text="glow=FFD700", glow="FFD700"))
items.append(shape(4, geometry="roundRect",
x="10in", y="3in", width="3in", height="1.8in",
fill="F4A261", color="000000", bold="true", size="14",
text="reflection=tight", reflection="tight"))
# ─────────────────────────────────────────────────────────────────────────
# Slide 5 — Stroke geometry details (lineCap / lineJoin / lineAlign)
# ─────────────────────────────────────────────────────────────────────────
items.append(slide())
items.append(shape(5,
text="Stroke Geometry — lineCap / lineJoin / lineAlign",
size="28", bold="true",
x="0.5in", y="0.3in", width="12in", height="0.6in"))
# lineCap — how the stroke terminates at endpoints / dash gaps.
# Most visible with a thick dashed stroke.
x = 0.5
for cap in ["flat", "round", "square"]:
items.append(shape(5, geometry="rect",
x=f"{x}in", y="1.5in", width="4in", height="0.05in",
fill="none", lineColor="1D3557", lineWidth="10pt",
lineDash="dash", lineCap=cap))
items.append(shape(5, text=f"lineCap={cap}", size="12",
x=f"{x}in", y="1.8in", width="4in", height="0.4in",
fill="none", line="000000:0:solid"))
x += 4.3
# lineJoin — corner style on a stroked shape.
# Most visible on a triangle outline with thick lines.
x = 0.5
for join in ["round", "bevel", "miter"]:
items.append(shape(5, geometry="triangle",
x=f"{x}in", y="2.8in", width="2.5in", height="2in",
fill="A8DADC", lineColor="E63946", lineWidth="12pt",
lineJoin=join))
items.append(shape(5, text=f"lineJoin={join}", size="12",
x=f"{x}in", y="4.9in", width="2.5in", height="0.4in",
fill="none", line="000000:0:solid"))
x += 3
# miterLimit — caps how far a miter join's spike extends before clipping.
# Expressed in 1/1000ths of a percent; 800000 = 800%. Supplied as the
# compound lineJoin=miter:<lim> form which sets both join + limit at once.
items.append(shape(5, geometry="triangle",
x="0.5in", y="5.1in", width="2.5in", height="1.6in",
fill="A8DADC", lineColor="E63946", lineWidth="8pt",
lineJoin="miter:800000"))
items.append(shape(5, text='lineJoin="miter:800000" (limit 800%)', size="12",
x="0.5in", y="6.9in", width="4in", height="0.4in",
fill="none", line="000000:0:solid"))
# lineAlign — stroke alignment relative to the path: ctr (centered) vs in.
# Same shape, same border width, only the alignment of the stroke differs.
x = 8.9
for algn in ["ctr", "in"]:
items.append(shape(5, geometry="rect",
x=f"{x}in", y="2.8in", width="1.9in", height="2in",
fill="F4A261", lineColor="1D3557", lineWidth="12pt",
lineAlign=algn))
items.append(shape(5, text=f"lineAlign={algn}", size="12",
x=f"{x}in", y="4.9in", width="2in", height="0.4in",
fill="none", line="000000:0:solid"))
x += 2.1
doc.batch(items)
print(f" added {len(items)} slides/shapes")
doc.send({"command": "save"})
# context exit closes the resident, flushing the deck to disk.
print(f"Generated: {FILE}")
+258
View File
@@ -0,0 +1,258 @@
#!/bin/bash
# Basic PowerPoint shapes — geometries, fills, outlines, effects, rotation, opacity.
# Demonstrates: --type shape with geometry preset, solid/gradient/pattern/image fills,
# line styling (color/width/dash/arrowheads), rotation, opacity, shadow effects.
# NOTE: intentionally NO `set -e`. Like the SDK twin's doc.batch, this script
# tolerates forward-compat 'UNSUPPORTED props' warnings (officecli exit 2) and
# keeps building so the full document is produced.
DIR="$(dirname "$0")"
PPTX="$DIR/shapes-basic.pptx"
rm -f "$PPTX"
officecli create "$PPTX"
officecli open "$PPTX"
# ─────────────────────────────────────────────────────────────────────────────
# Slide 1 — Geometry preset gallery
# ─────────────────────────────────────────────────────────────────────────────
officecli add "$PPTX" / --type slide
officecli add "$PPTX" '/slide[1]' --type shape \
--prop text="Geometry Presets" --prop size=28 --prop bold=true \
--prop x=0.5in --prop y=0.3in --prop width=12in --prop height=0.6in
# Row of 8 shapes, one per supported preset.
# Schema-declared presets: rect, roundRect, ellipse, triangle, diamond,
# parallelogram, rightArrow, star5
COL=0
for preset in rect roundRect ellipse triangle diamond parallelogram rightArrow star5; do
X=$(echo "0.5 + $COL * 1.55" | bc -l)
officecli add "$PPTX" '/slide[1]' --type shape \
--prop geometry="$preset" \
--prop x="${X}in" --prop y=1.5in --prop width=1.3in --prop height=1.3in \
--prop fill=4472C4 --prop color=FFFFFF \
--prop text="$preset" --prop size=11 --prop bold=true
COL=$((COL + 1))
done
# ─────────────────────────────────────────────────────────────────────────────
# Slide 2 — Fill variations on the same geometry
# ─────────────────────────────────────────────────────────────────────────────
officecli add "$PPTX" / --type slide
officecli add "$PPTX" '/slide[2]' --type shape \
--prop text="Fill Variations" --prop size=28 --prop bold=true \
--prop x=0.5in --prop y=0.3in --prop width=12in --prop height=0.6in
# Solid hex
officecli add "$PPTX" '/slide[2]' --type shape --prop geometry=roundRect \
--prop x=0.5in --prop y=1.3in --prop width=2.5in --prop height=1.5in \
--prop fill=E63946 --prop color=FFFFFF --prop bold=true \
--prop text='fill=E63946'
# Theme color (follows deck theme)
officecli add "$PPTX" '/slide[2]' --type shape --prop geometry=roundRect \
--prop x=3.3in --prop y=1.3in --prop width=2.5in --prop height=1.5in \
--prop fill=accent2 --prop color=FFFFFF --prop bold=true \
--prop text='fill=accent2'
# Linear gradient (color1-color2-angle)
officecli add "$PPTX" '/slide[2]' --type shape --prop geometry=roundRect \
--prop x=6.1in --prop y=1.3in --prop width=2.5in --prop height=1.5in \
--prop gradient="FF6B6B-4ECDC4-45" --prop color=FFFFFF --prop bold=true \
--prop text='gradient linear 45°'
# Radial gradient
officecli add "$PPTX" '/slide[2]' --type shape --prop geometry=roundRect \
--prop x=8.9in --prop y=1.3in --prop width=2.5in --prop height=1.5in \
--prop gradient="radial:FFE66D-FF6B35-center" --prop color=000000 --prop bold=true \
--prop text='gradient radial'
# Pattern (preset:fg:bg)
officecli add "$PPTX" '/slide[2]' --type shape --prop geometry=roundRect \
--prop x=0.5in --prop y=3.1in --prop width=2.5in --prop height=1.5in \
--prop pattern="diagBrick:1D3557:F1FAEE" --prop color=FFFFFF --prop bold=true \
--prop text='pattern diagBrick'
# Opacity (requires a fill to attach to)
officecli add "$PPTX" '/slide[2]' --type shape --prop geometry=roundRect \
--prop x=3.3in --prop y=3.1in --prop width=2.5in --prop height=1.5in \
--prop fill=2A9D8F --prop opacity=0.4 --prop color=000000 --prop bold=true \
--prop text='fill + opacity=0.4'
# No fill (outline only)
officecli add "$PPTX" '/slide[2]' --type shape --prop geometry=roundRect \
--prop x=6.1in --prop y=3.1in --prop width=2.5in --prop height=1.5in \
--prop fill=none --prop line="264653:2.5:solid" --prop color=264653 --prop bold=true \
--prop text='fill=none + outline'
# Per-stop gradient positions
officecli add "$PPTX" '/slide[2]' --type shape --prop geometry=roundRect \
--prop x=8.9in --prop y=3.1in --prop width=2.5in --prop height=1.5in \
--prop gradient="FF0000@0-FFD700@40-0000FF@100" --prop color=FFFFFF --prop bold=true \
--prop text='gradient per-stop'
# ─────────────────────────────────────────────────────────────────────────────
# Slide 3 — Outline styling (line color / width / dash / caps / arrowheads)
# ─────────────────────────────────────────────────────────────────────────────
officecli add "$PPTX" / --type slide
officecli add "$PPTX" '/slide[3]' --type shape \
--prop text="Outline Styling" --prop size=28 --prop bold=true \
--prop x=0.5in --prop y=0.3in --prop width=12in --prop height=0.6in
# Compound line form: color:width:dash
officecli add "$PPTX" '/slide[3]' --type shape --prop geometry=rect \
--prop x=0.5in --prop y=1.3in --prop width=3in --prop height=1.2in \
--prop fill=none --prop line="E63946:3:solid" \
--prop text='line="E63946:3:solid"' --prop size=12
officecli add "$PPTX" '/slide[3]' --type shape --prop geometry=rect \
--prop x=4in --prop y=1.3in --prop width=3in --prop height=1.2in \
--prop fill=none --prop line="1D3557:2:dash" \
--prop text='line="1D3557:2:dash"' --prop size=12
officecli add "$PPTX" '/slide[3]' --type shape --prop geometry=rect \
--prop x=7.5in --prop y=1.3in --prop width=3in --prop height=1.2in \
--prop fill=none --prop line="2A9D8F:2.5:dashDot" \
--prop text='line="2A9D8F:2.5:dashDot"' --prop size=12
# Per-attribute form: lineColor + lineWidth + lineDash
officecli add "$PPTX" '/slide[3]' --type shape --prop geometry=ellipse \
--prop x=0.5in --prop y=2.9in --prop width=3in --prop height=1.4in \
--prop fill=FFE66D --prop lineColor=E63946 --prop lineWidth=4pt --prop lineDash=solid \
--prop text='separate lineColor/lineWidth/lineDash' --prop size=11
# Compound stroke (cmpd=dbl → double line)
officecli add "$PPTX" '/slide[3]' --type shape --prop geometry=ellipse \
--prop x=4in --prop y=2.9in --prop width=3in --prop height=1.4in \
--prop fill=A8DADC --prop lineColor=1D3557 --prop lineWidth=6pt --prop cmpd=dbl \
--prop text='cmpd=dbl (double stroke)' --prop size=11
# Triple stroke
officecli add "$PPTX" '/slide[3]' --type shape --prop geometry=ellipse \
--prop x=7.5in --prop y=2.9in --prop width=3in --prop height=1.4in \
--prop fill=A8DADC --prop lineColor=1D3557 --prop lineWidth=8pt --prop cmpd=tri \
--prop text='cmpd=tri (triple stroke)' --prop size=11
# Arrowheads on shape outlines (rightArrow already arrow-shaped — demo headEnd/tailEnd here)
officecli add "$PPTX" '/slide[3]' --type shape \
--prop text="headEnd / tailEnd work on any outline (not just connectors):" \
--prop size=12 \
--prop x=0.5in --prop y=4.7in --prop width=12in --prop height=0.4in
officecli add "$PPTX" '/slide[3]' --type shape --prop geometry=rect \
--prop x=0.5in --prop y=5.2in --prop width=4in --prop height=0.05in \
--prop fill=none --prop lineColor=000000 --prop lineWidth=2pt \
--prop headEnd=triangle --prop tailEnd=arrow
officecli add "$PPTX" '/slide[3]' --type shape --prop geometry=rect \
--prop x=5in --prop y=5.2in --prop width=4in --prop height=0.05in \
--prop fill=none --prop lineColor=000000 --prop lineWidth=2pt \
--prop headEnd=diamond --prop tailEnd=oval
# ─────────────────────────────────────────────────────────────────────────────
# Slide 4 — Rotation, shadow effect, z-order via add order
# ─────────────────────────────────────────────────────────────────────────────
officecli add "$PPTX" / --type slide
officecli add "$PPTX" '/slide[4]' --type shape \
--prop text="Rotation + Effects" --prop size=28 --prop bold=true \
--prop x=0.5in --prop y=0.3in --prop width=12in --prop height=0.6in
# Rotation in degrees (0..360)
COL=0
for r in 0 30 60 90 135 180 225 270; do
X=$(echo "0.5 + $COL * 1.55" | bc -l)
officecli add "$PPTX" '/slide[4]' --type shape --prop geometry=rightArrow \
--prop x="${X}in" --prop y=1.3in --prop width=1.4in --prop height=0.8in \
--prop fill=4472C4 --prop color=FFFFFF --prop bold=true \
--prop rotation="$r" --prop text="${r}°" --prop size=11
COL=$((COL + 1))
done
# Shadow effect: shadow=color:blur:offset:direction (handler's compound effect)
officecli add "$PPTX" '/slide[4]' --type shape --prop geometry=roundRect \
--prop x=1in --prop y=3in --prop width=3.5in --prop height=1.8in \
--prop fill=E63946 --prop color=FFFFFF --prop bold=true --prop size=14 \
--prop text='shadow=000000' \
--prop shadow=000000
officecli add "$PPTX" '/slide[4]' --type shape --prop geometry=roundRect \
--prop x=5.5in --prop y=3in --prop width=3.5in --prop height=1.8in \
--prop fill=2A9D8F --prop color=FFFFFF --prop bold=true --prop size=14 \
--prop text='glow=FFD700' \
--prop glow=FFD700
officecli add "$PPTX" '/slide[4]' --type shape --prop geometry=roundRect \
--prop x=10in --prop y=3in --prop width=3in --prop height=1.8in \
--prop fill=F4A261 --prop color=000000 --prop bold=true --prop size=14 \
--prop text='reflection=tight' \
--prop reflection=tight
# ─────────────────────────────────────────────────────────────────────────────
# Slide 5 — Stroke geometry details (lineCap / lineJoin / lineAlign)
# ─────────────────────────────────────────────────────────────────────────────
officecli add "$PPTX" / --type slide
officecli add "$PPTX" '/slide[5]' --type shape \
--prop text="Stroke Geometry — lineCap / lineJoin / lineAlign" \
--prop size=28 --prop bold=true \
--prop x=0.5in --prop y=0.3in --prop width=12in --prop height=0.6in
# lineCap — how the stroke terminates at line endpoints / dash gaps.
# Most visible with a thick dashed stroke.
X=0.5
for cap in flat round square; do
officecli add "$PPTX" '/slide[5]' --type shape --prop geometry=rect \
--prop x="${X}in" --prop y=1.5in --prop width=4in --prop height=0.05in \
--prop fill=none --prop lineColor=1D3557 --prop lineWidth=10pt \
--prop lineDash=dash --prop lineCap="$cap"
officecli add "$PPTX" '/slide[5]' --type shape \
--prop text="lineCap=$cap" --prop size=12 \
--prop x="${X}in" --prop y=1.8in --prop width=4in --prop height=0.4in \
--prop fill=none --prop line="000000:0:solid"
X=$(echo "$X + 4.3" | bc -l)
done
# lineJoin — corner style on a stroked shape.
# Most visible on a triangle outline with thick lines.
X=0.5
for join in round bevel miter; do
officecli add "$PPTX" '/slide[5]' --type shape --prop geometry=triangle \
--prop x="${X}in" --prop y=2.8in --prop width=2.5in --prop height=2in \
--prop fill=A8DADC --prop lineColor=E63946 --prop lineWidth=12pt \
--prop lineJoin="$join"
officecli add "$PPTX" '/slide[5]' --type shape \
--prop text="lineJoin=$join" --prop size=12 \
--prop x="${X}in" --prop y=4.9in --prop width=2.5in --prop height=0.4in \
--prop fill=none --prop line="000000:0:solid"
X=$(echo "$X + 3" | bc -l)
done
# miterLimit — caps how far a miter join's spike extends before it's clipped.
# Expressed in 1/1000ths of a percent; 800000 = 800%. Supplied as the compound
# lineJoin=miter:<lim> form which sets both join style and limit in one prop.
officecli add "$PPTX" '/slide[5]' --type shape --prop geometry=triangle \
--prop x=0.5in --prop y=5.1in --prop width=2.5in --prop height=1.6in \
--prop fill=A8DADC --prop lineColor=E63946 --prop lineWidth=8pt \
--prop lineJoin="miter:800000"
officecli add "$PPTX" '/slide[5]' --type shape \
--prop text='lineJoin="miter:800000" (limit 800%)' --prop size=12 \
--prop x=0.5in --prop y=6.9in --prop width=4in --prop height=0.4in \
--prop fill=none --prop line="000000:0:solid"
# lineAlign — stroke alignment relative to the path: ctr (centered) vs in (inset).
# Same shape, same border width, only the alignment of the stroke differs.
X=8.9
for algn in ctr in; do
officecli add "$PPTX" '/slide[5]' --type shape --prop geometry=rect \
--prop x="${X}in" --prop y=2.8in --prop width=1.9in --prop height=2in \
--prop fill=F4A261 --prop lineColor=1D3557 --prop lineWidth=12pt \
--prop lineAlign="$algn"
officecli add "$PPTX" '/slide[5]' --type shape \
--prop text="lineAlign=$algn" --prop size=12 \
--prop x="${X}in" --prop y=4.9in --prop width=2in --prop height=0.4in \
--prop fill=none --prop line="000000:0:solid"
X=$(echo "$X + 2.1" | bc -l)
done
officecli close "$PPTX"
officecli validate "$PPTX"
echo "Created: $PPTX"
+253
View File
@@ -0,0 +1,253 @@
# Connectors and Groups
This demo consists of three files that work together:
- **shapes-connectors.sh** — Shell script that calls `officecli` commands to generate the deck.
- **shapes-connectors.pptx** — The generated 4-slide deck (3 connector presets, 1 flowchart, 1 group, headEnd/lineJoin/miterLimit combos).
- **shapes-connectors.md** — This file. Maps each slide to the features it demonstrates.
## Regenerate
```bash
cd examples/ppt
bash shapes/shapes-connectors.sh
# → shapes/shapes-connectors.pptx
```
## Slides
### Slide 1 — Connector Geometry Presets
Three pairs of anchor shapes tied together with connectors — one per geometry preset: `straight`, `elbow`, `curve`.
```bash
officecli create shapes-connectors.pptx
officecli open shapes-connectors.pptx
officecli add shapes-connectors.pptx / --type slide
# Capture the added shape's stable @id path (from "Added shape at /slide[N]/shape[@id=M]")
A1=$(officecli add shapes-connectors.pptx '/slide[1]' --type shape --prop geometry=ellipse \
--prop x=0.5in --prop y=1.5in --prop width=2in --prop height=1.2in \
--prop fill=4472C4 --prop color=FFFFFF --prop bold=true --prop text="A" \
| awk '/Added/ {print $NF}')
B1=$(officecli add shapes-connectors.pptx '/slide[1]' --type shape --prop geometry=ellipse \
--prop x=4.5in --prop y=1.5in --prop width=2in --prop height=1.2in \
--prop fill=E63946 --prop color=FFFFFF --prop bold=true --prop text="B" \
| awk '/Added/ {print $NF}')
# Straight connector — direct line between anchor shapes
officecli add shapes-connectors.pptx '/slide[1]' --type connector \
--prop shape=straight --prop from="$A1" --prop to="$B1" \
--prop color=1D3557 --prop lineWidth=2pt --prop tailEnd=triangle
# Elbow connector — 90° right-angle bends
A2=... B2=... # (second pair of anchor shapes at staggered Y positions)
officecli add shapes-connectors.pptx '/slide[1]' --type connector \
--prop shape=elbow --prop from="$A2" --prop to="$B2" \
--prop color=1D3557 --prop lineWidth=2pt --prop tailEnd=triangle
# Curve connector — smooth Bezier arc
A3=... B3=...
officecli add shapes-connectors.pptx '/slide[1]' --type connector \
--prop shape=curve --prop from="$A3" --prop to="$B3" \
--prop color=2A9D8F --prop lineWidth=3pt --prop tailEnd=arrow
```
**Features:** `--type connector`, `shape` (straight, elbow, curve), `from` / `to` (captured `@id` paths), `color`, `lineWidth`, `tailEnd` (triangle, arrow)
> Capture the path that `add` prints on stdout — `awk '/Added/ {print $NF}'` extracts the last token from the "Added shape at /slide[N]/shape[@id=M]" message. The `@id` form is stable across re-numbering: if you later add a group, positional indices may shift but `@id` paths keep working.
---
### Slide 2 — Mini Flowchart with Attached Connectors
Four process boxes (Start, Valid?, End, Retry) connected with a real flowchart topology: straight connectors for the happy path, dashed elbow connectors for the loopback branch.
```bash
officecli add shapes-connectors.pptx / --type slide
# Process boxes — capture paths for connector endpoints
P1=$(officecli add shapes-connectors.pptx '/slide[2]' --type shape \
--prop geometry=roundRect \
--prop x=0.8in --prop y=2.5in --prop width=2.2in --prop height=1.2in \
--prop fill=2A9D8F --prop color=FFFFFF --prop bold=true --prop size=16 \
--prop text="Start" | awk '/Added/ {print $NF}')
P2=$(officecli add shapes-connectors.pptx '/slide[2]' --type shape \
--prop geometry=diamond \
--prop x=4.5in --prop y=2.3in --prop width=2.8in --prop height=1.6in \
--prop fill=F4A261 --prop color=000000 --prop bold=true --prop size=14 \
--prop text="Valid?" | awk '/Added/ {print $NF}')
P3=$(officecli add shapes-connectors.pptx '/slide[2]' --type shape \
--prop geometry=roundRect \
--prop x=9in --prop y=2.5in --prop width=2.2in --prop height=1.2in \
--prop fill=E63946 --prop color=FFFFFF --prop bold=true --prop size=16 \
--prop text="End" | awk '/Added/ {print $NF}')
P4=$(officecli add shapes-connectors.pptx '/slide[2]' --type shape \
--prop geometry=roundRect \
--prop x=4.7in --prop y=5in --prop width=2.4in --prop height=1in \
--prop fill=A8DADC --prop color=000000 --prop bold=true --prop size=14 \
--prop text="Retry" | awk '/Added/ {print $NF}')
# Happy path: Start → Valid? → End (solid black)
officecli add shapes-connectors.pptx '/slide[2]' --type connector \
--prop shape=straight --prop from="$P1" --prop to="$P2" \
--prop color=1D3557 --prop lineWidth=2pt --prop tailEnd=triangle
officecli add shapes-connectors.pptx '/slide[2]' --type connector \
--prop shape=straight --prop from="$P2" --prop to="$P3" \
--prop color=1D3557 --prop lineWidth=2pt --prop tailEnd=triangle
# Loopback: Valid? → Retry → Start (dashed red elbow)
officecli add shapes-connectors.pptx '/slide[2]' --type connector \
--prop shape=elbow --prop from="$P2" --prop to="$P4" \
--prop color=E63946 --prop lineWidth=2pt --prop lineDash=dash --prop tailEnd=triangle
officecli add shapes-connectors.pptx '/slide[2]' --type connector \
--prop shape=elbow --prop from="$P4" --prop to="$P1" \
--prop color=E63946 --prop lineWidth=2pt --prop lineDash=dash --prop tailEnd=triangle
# Branch labels — bare textboxes with no fill (floating text over canvas)
officecli add shapes-connectors.pptx '/slide[2]' --type textbox \
--prop x=7.4in --prop y=2.7in --prop width=1.3in --prop height=0.5in \
--prop text="yes" --prop size=12 --prop bold=true --prop color=2A9D8F
officecli add shapes-connectors.pptx '/slide[2]' --type textbox \
--prop x=6in --prop y=4in --prop width=1.3in --prop height=0.5in \
--prop text="no" --prop size=12 --prop bold=true --prop color=E63946
```
**Features:** `--type connector` with `from` / `to` shape paths, `shape=straight|elbow`, `lineDash=dash` (dashed connector for loopback), `tailEnd=triangle`, `--type textbox` (no-fill floating labels)
---
### Slide 3 — Grouping Shapes
Three overlapping ellipses grouped into a single unit via `--type group`, compared to three ungrouped rectangles on the right.
```bash
officecli add shapes-connectors.pptx / --type slide
# Three overlapping ellipses with partial opacity
G1=$(officecli add shapes-connectors.pptx '/slide[3]' --type shape \
--prop geometry=ellipse \
--prop x=1.5in --prop y=2in --prop width=1.4in --prop height=1.4in \
--prop fill=E63946 | awk '/Added/ {print $NF}')
G2=$(officecli add shapes-connectors.pptx '/slide[3]' --type shape \
--prop geometry=ellipse \
--prop x=2.4in --prop y=2in --prop width=1.4in --prop height=1.4in \
--prop fill=F4A261 --prop opacity=0.75 | awk '/Added/ {print $NF}')
G3=$(officecli add shapes-connectors.pptx '/slide[3]' --type shape \
--prop geometry=ellipse \
--prop x=3.3in --prop y=2in --prop width=1.4in --prop height=1.4in \
--prop fill=2A9D8F --prop opacity=0.75 | awk '/Added/ {print $NF}')
# Group the three shapes — shapes= is a comma-separated list of captured paths
officecli add shapes-connectors.pptx '/slide[3]' --type group \
--prop shapes="$G1,$G2,$G3" --prop name="Logo"
```
**Features:** `--type group`, `shapes` (comma-separated `@id` or positional paths), `name` (stable identifier for the group), `opacity` (0.01.0) on individual shapes before grouping
> After `add group` the handler re-numbers remaining shapes. This is why the `@id`-form paths captured at add-time are essential — they survive the re-numbering that positional paths do not.
---
### Slide 4 — headEnd / lineJoin / miterLimit on Connectors
Demonstrates all `headEnd`/`tailEnd` combinations and all `lineJoin` modes on connectors.
```bash
officecli add shapes-connectors.pptx / --type slide
# headEnd + tailEnd arrowhead combinations on straight connectors
officecli add shapes-connectors.pptx '/slide[4]' --type connector \
--prop shape=straight \
--prop x=0.5in --prop y=1.8in --prop width=5in --prop height=0in \
--prop color=1D3557 --prop lineWidth=2pt \
--prop headEnd=triangle --prop tailEnd=oval
officecli add shapes-connectors.pptx '/slide[4]' --type connector \
--prop shape=straight \
--prop x=0.5in --prop y=2.6in --prop width=5in --prop height=0in \
--prop color=1D3557 --prop lineWidth=2pt \
--prop headEnd=diamond --prop tailEnd=arrow
officecli add shapes-connectors.pptx '/slide[4]' --type connector \
--prop shape=straight \
--prop x=0.5in --prop y=3.4in --prop width=5in --prop height=0in \
--prop color=1D3557 --prop lineWidth=2pt \
--prop headEnd=arrow --prop tailEnd=arrow
# lineJoin on elbow connectors (affects the bend corner geometry)
officecli add shapes-connectors.pptx '/slide[4]' --type connector \
--prop shape=elbow \
--prop x=0.5in --prop y=5.2in --prop width=3.4in --prop height=1.6in \
--prop color=E63946 --prop lineWidth=5pt \
--prop lineJoin=round
officecli add shapes-connectors.pptx '/slide[4]' --type connector \
--prop shape=elbow \
--prop x=4.7in --prop y=5.2in --prop width=3.4in --prop height=1.6in \
--prop color=E63946 --prop lineWidth=5pt \
--prop lineJoin=bevel
# Third column uses the compound lineJoin=miter:<lim> form (1/1000ths of %)
# to set the join style AND the miter limit in one prop.
officecli add shapes-connectors.pptx '/slide[4]' --type connector \
--prop shape=elbow \
--prop x=8.9in --prop y=5.2in --prop width=3.4in --prop height=1.6in \
--prop color=2A9D8F --prop lineWidth=5pt \
--prop lineJoin="miter:800000"
officecli close shapes-connectors.pptx
officecli validate shapes-connectors.pptx
```
**Features:** `headEnd` / `tailEnd` (none, triangle, stealth, diamond, oval, arrow), `lineJoin` on connectors (round, bevel, miter), `lineJoin="miter:N"` (compound miter+limit), `lineWidth`
---
## Complete Feature Coverage
| Feature | Slide |
|---------|-------|
| **Connector presets:** straight, elbow, curve | 1 |
| **Attached endpoints:** `from=` / `to=` with captured `@id` paths | 1, 2 |
| **Tail arrowheads:** `tailEnd=triangle|arrow|oval` | 1, 2, 4 |
| **Head arrowheads:** `headEnd=triangle|diamond|oval|arrow` | 4 |
| **Dash pattern:** `lineDash=dash` (dashed loopback connectors) | 2 |
| **Line width:** `lineWidth=Npt` | 14 |
| **Color:** `color=hex` | 14 |
| **Flowchart topology:** mixed shapes + connectors | 2 |
| **Floating labels:** `--type textbox` with no fill | 2 |
| **Group:** `--type group` with `shapes=path1,path2,...` | 3 |
| **Group name:** `name=` (stable @name addressing) | 3 |
| **Opacity on grouped shapes:** `opacity=0.01.0` | 3 |
| **lineJoin on connectors:** round, bevel, miter | 4 |
| **miterLimit:** `lineJoin="miter:N"` compound form | 4 |
## Inspect the Generated File
```bash
# List all elements on slide 1 (shapes + connectors)
officecli query shapes-connectors.pptx '/slide[1]' shape
# Get the straight connector details
officecli get shapes-connectors.pptx '/slide[1]/connector[1]'
# Inspect flowchart connectors on slide 2
officecli query shapes-connectors.pptx '/slide[2]' connector
# Get the group on slide 3
officecli get shapes-connectors.pptx '/slide[3]/group[1]'
# Inspect headEnd/tailEnd on slide 4 connectors
officecli get shapes-connectors.pptx '/slide[4]/connector[1]'
officecli get shapes-connectors.pptx '/slide[4]/connector[4]'
```
Binary file not shown.
+224
View File
@@ -0,0 +1,224 @@
#!/usr/bin/env python3
"""
Connectors and groups — generates shapes-connectors.pptx exercising the pptx
`connector` element (straight / elbow / curve presets, head/tail arrowheads,
lineJoin / miterLimit) and the `group` element (comma-separated shape indices).
SDK twin of shapes-connectors.sh (officecli CLI). Both produce an equivalent
shapes-connectors.pptx. This one drives the **officecli Python SDK**
(`pip install officecli-sdk`): one resident is started and every command is
shipped over the named pipe. Each item is the same
`{"command","parent","type","props"}` dict you'd put in an `officecli batch`
list.
Connectors attach to shapes via from=/to= shape *paths*, and a group is built
from a comma-separated list of shape paths — so the shapes those refer to must
be added first and their returned `@id` path captured. `add_shape` does exactly
that: it `send`s one add and parses the path out of the response envelope
("Added shape at /slide[N]/shape[@id=M]" → the last whitespace-delimited token).
Usage:
pip install officecli-sdk # plus the `officecli` binary on PATH
python3 shapes-connectors.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__)), "shapes-connectors.pptx")
def _path_from_add(resp):
"""officecli prints "Added shape at /slide[N]/shape[@id=M]"; the path is the
last whitespace-delimited token of the response's data/message string."""
msg = ""
if isinstance(resp, dict):
msg = resp.get("data") or resp.get("message") or ""
else:
msg = str(resp)
return msg.split()[-1] if msg else ""
print(f"Building {FILE} ...")
with officecli.create(FILE, "--force") as doc:
def add(parent, type_, **props):
"""Send one `add` and return the parsed envelope."""
return doc.send({"command": "add", "parent": parent, "type": type_,
"props": {k: str(v) for k, v in props.items()}})
def add_shape(parent, **props):
"""Add a shape and return its captured @id path (for from=/to=/shapes=)."""
return _path_from_add(add(parent, "shape", **props))
# ─────────────────────────────────────────────────────────────────────────
# Slide 1 — Connector geometry presets (straight / elbow / curve)
# ─────────────────────────────────────────────────────────────────────────
add("/", "slide")
add("/slide[1]", "shape", text="Connector Presets", size=28, bold="true",
x="0.5in", y="0.3in", width="12in", height="0.6in")
A1 = add_shape("/slide[1]", geometry="ellipse",
x="0.5in", y="1.5in", width="2in", height="1.2in",
fill="4472C4", color="FFFFFF", bold="true", text="A")
B1 = add_shape("/slide[1]", geometry="ellipse",
x="4.5in", y="1.5in", width="2in", height="1.2in",
fill="E63946", color="FFFFFF", bold="true", text="B")
add("/slide[1]", "connector", shape="straight", **{"from": A1}, to=B1,
color="1D3557", lineWidth="2pt", tailEnd="triangle")
add("/slide[1]", "shape", text="straight (default)", size=12,
x="0.5in", y="2.8in", width="6in", height="0.4in")
A2 = add_shape("/slide[1]", geometry="ellipse",
x="0.5in", y="3.6in", width="2in", height="1.2in",
fill="4472C4", color="FFFFFF", bold="true", text="A")
B2 = add_shape("/slide[1]", geometry="ellipse",
x="4.5in", y="5in", width="2in", height="1.2in",
fill="E63946", color="FFFFFF", bold="true", text="B")
add("/slide[1]", "connector", shape="elbow", **{"from": A2}, to=B2,
color="1D3557", lineWidth="2pt", tailEnd="triangle")
add("/slide[1]", "shape", text="elbow (bent, 90° turns)", size=12,
x="0.5in", y="6.3in", width="6in", height="0.4in")
A3 = add_shape("/slide[1]", geometry="ellipse",
x="8in", y="1.5in", width="2in", height="1.2in",
fill="4472C4", color="FFFFFF", bold="true", text="A")
B3 = add_shape("/slide[1]", geometry="ellipse",
x="11.5in", y="4.5in", width="2in", height="1.2in",
fill="E63946", color="FFFFFF", bold="true", text="B")
add("/slide[1]", "connector", shape="curve", **{"from": A3}, to=B3,
color="2A9D8F", lineWidth="3pt", tailEnd="arrow")
add("/slide[1]", "shape", text="curve (smooth Bezier)", size=12,
x="7.5in", y="6in", width="6in", height="0.4in")
# ─────────────────────────────────────────────────────────────────────────
# Slide 2 — Mini flowchart with attached connectors
# ─────────────────────────────────────────────────────────────────────────
add("/", "slide")
add("/slide[2]", "shape", text="Flowchart with Attached Connectors",
size=28, bold="true",
x="0.5in", y="0.3in", width="12in", height="0.6in")
P1 = add_shape("/slide[2]", geometry="roundRect",
x="0.8in", y="2.5in", width="2.2in", height="1.2in",
fill="2A9D8F", color="FFFFFF", bold="true", size=16, text="Start")
P2 = add_shape("/slide[2]", geometry="diamond",
x="4.5in", y="2.3in", width="2.8in", height="1.6in",
fill="F4A261", color="000000", bold="true", size=14, text="Valid?")
P3 = add_shape("/slide[2]", geometry="roundRect",
x="9in", y="2.5in", width="2.2in", height="1.2in",
fill="E63946", color="FFFFFF", bold="true", size=16, text="End")
P4 = add_shape("/slide[2]", geometry="roundRect",
x="4.7in", y="5in", width="2.4in", height="1in",
fill="A8DADC", color="000000", bold="true", size=14, text="Retry")
# Connect Start → Valid? → End, plus the loopback Valid? → Retry → Start
add("/slide[2]", "connector", shape="straight", **{"from": P1}, to=P2,
color="1D3557", lineWidth="2pt", tailEnd="triangle")
add("/slide[2]", "connector", shape="straight", **{"from": P2}, to=P3,
color="1D3557", lineWidth="2pt", tailEnd="triangle")
add("/slide[2]", "connector", shape="elbow", **{"from": P2}, to=P4,
color="E63946", lineWidth="2pt", lineDash="dash", tailEnd="triangle")
add("/slide[2]", "connector", shape="elbow", **{"from": P4}, to=P1,
color="E63946", lineWidth="2pt", lineDash="dash", tailEnd="triangle")
# Branch labels (textbox-style; no fill, transparent outline)
add("/slide[2]", "textbox", x="7.4in", y="2.7in", width="1.3in", height="0.5in",
text="yes", size=12, bold="true", color="2A9D8F")
add("/slide[2]", "textbox", x="6in", y="4in", width="1.3in", height="0.5in",
text="no", size=12, bold="true", color="E63946")
# ─────────────────────────────────────────────────────────────────────────
# Slide 3 — Grouping shapes
# ─────────────────────────────────────────────────────────────────────────
add("/", "slide")
add("/slide[3]", "shape", text="Grouping Shapes", size=28, bold="true",
x="0.5in", y="0.3in", width="12in", height="0.6in")
# Three logo-like shapes that we'll group together.
G1 = add_shape("/slide[3]", geometry="ellipse",
x="1.5in", y="2in", width="1.4in", height="1.4in", fill="E63946")
G2 = add_shape("/slide[3]", geometry="ellipse",
x="2.4in", y="2in", width="1.4in", height="1.4in",
fill="F4A261", opacity="0.75")
G3 = add_shape("/slide[3]", geometry="ellipse",
x="3.3in", y="2in", width="1.4in", height="1.4in",
fill="2A9D8F", opacity="0.75")
# Group them by passing the captured shape paths (comma-separated)
add("/slide[3]", "group", shapes=f"{G1},{G2},{G3}", name="Logo")
add("/slide[3]", "textbox",
text=f"Three ellipses grouped (shapes={G1},{G2},{G3}).", size=12,
x="0.5in", y="4in", width="12in", height="0.5in")
# Three independent boxes for comparison
add("/slide[3]", "shape", geometry="rect",
x="8in", y="2in", width="1.4in", height="1.4in", fill="4472C4")
add("/slide[3]", "shape", geometry="rect",
x="9.5in", y="2in", width="1.4in", height="1.4in", fill="4472C4")
add("/slide[3]", "shape", geometry="rect",
x="11in", y="2in", width="1.4in", height="1.4in", fill="4472C4")
add("/slide[3]", "textbox",
text="Three independent boxes (no group — each addressed separately).",
size=12, x="7in", y="4in", width="6in", height="0.5in")
# ─────────────────────────────────────────────────────────────────────────
# Slide 4 — headEnd / lineJoin / miterLimit on connectors
# ─────────────────────────────────────────────────────────────────────────
add("/", "slide")
add("/slide[4]", "shape",
text="headEnd / lineJoin / miterLimit on Connectors",
size=24, bold="true",
x="0.5in", y="0.3in", width="12in", height="0.6in")
# headEnd — arrowhead at the START of the connector (the 'head' = from-side)
# tailEnd — arrowhead at the END of the connector (the 'tail' = to-side)
add("/slide[4]", "textbox", text="headEnd + tailEnd arrowhead combinations:",
size=14, bold="true",
x="0.5in", y="1.1in", width="12in", height="0.4in")
y = 1.8
for hv, tv in [("triangle", "oval"), ("diamond", "arrow"), ("arrow", "arrow")]:
add("/slide[4]", "connector", shape="straight",
x="0.5in", y=f"{y}in", width="5in", height="0in",
color="1D3557", lineWidth="2pt", headEnd=hv, tailEnd=tv)
add("/slide[4]", "textbox", text=f"headEnd={hv} tailEnd={tv}", size=12,
x="5.8in", y=f"{y}in", width="6in", height="0.4in")
y += 0.8
# lineJoin — connector joins: round / bevel / miter, visible at the elbow bend.
add("/slide[4]", "textbox", text="lineJoin on elbow connectors:",
size=14, bold="true",
x="0.5in", y="4.6in", width="12in", height="0.4in")
# Three elbow connectors, one per column. The third uses the compound
# lineJoin=miter:<lim> form (limit in 1/1000ths of a percent) to also
# exercise miterLimit.
def add_elbow(x_in, color, line_join, label):
add("/slide[4]", "connector", shape="elbow",
x=f"{x_in}in", y="5.2in", width="3.4in", height="1.6in",
color=color, lineWidth="5pt", lineJoin=line_join)
add("/slide[4]", "textbox", text=label, size=12,
x=f"{x_in}in", y="7.0in", width="4in", height="0.4in")
add_elbow(0.5, "E63946", "round", "lineJoin=round")
add_elbow(4.7, "E63946", "bevel", "lineJoin=bevel")
add_elbow(8.9, "2A9D8F", "miter:800000", "lineJoin=miter:800000 (800% limit)")
doc.send({"command": "save"})
print(f"Generated: {FILE}")
+227
View File
@@ -0,0 +1,227 @@
#!/bin/bash
# Connectors and groups — flowchart-style shapes with attached arrows, then grouped.
# Demonstrates: --type connector with from=/to= shape references, straight/elbow/curve
# presets, arrowheads, --type group with comma-separated shape indices.
# NOTE: intentionally NO `set -e`. Like the SDK twin's doc.batch, this script
# tolerates forward-compat 'UNSUPPORTED props' warnings (officecli exit 2) and
# keeps building so the full document is produced.
DIR="$(dirname "$0")"
PPTX="$DIR/shapes-connectors.pptx"
# Helper — Add a shape and echo the returned @id path on stdout.
# (officecli prints "Added shape at /slide[N]/shape[@id=M]" — last whitespace-delimited token is the path.)
add_shape_get_path() {
officecli add "$PPTX" "$@" | awk '/Added/ {print $NF; exit}'
}
rm -f "$PPTX"
officecli create "$PPTX"
officecli open "$PPTX"
# ─────────────────────────────────────────────────────────────────────────────
# Slide 1 — Connector geometry presets (straight / elbow / curve)
# ─────────────────────────────────────────────────────────────────────────────
officecli add "$PPTX" / --type slide
officecli add "$PPTX" '/slide[1]' --type shape \
--prop text="Connector Presets" --prop size=28 --prop bold=true \
--prop x=0.5in --prop y=0.3in --prop width=12in --prop height=0.6in
A1=$(add_shape_get_path '/slide[1]' --type shape --prop geometry=ellipse \
--prop x=0.5in --prop y=1.5in --prop width=2in --prop height=1.2in \
--prop fill=4472C4 --prop color=FFFFFF --prop bold=true --prop text="A")
B1=$(add_shape_get_path '/slide[1]' --type shape --prop geometry=ellipse \
--prop x=4.5in --prop y=1.5in --prop width=2in --prop height=1.2in \
--prop fill=E63946 --prop color=FFFFFF --prop bold=true --prop text="B")
officecli add "$PPTX" '/slide[1]' --type connector \
--prop shape=straight --prop from="$A1" --prop to="$B1" \
--prop color=1D3557 --prop lineWidth=2pt --prop tailEnd=triangle
officecli add "$PPTX" '/slide[1]' --type shape \
--prop text='straight (default)' --prop size=12 \
--prop x=0.5in --prop y=2.8in --prop width=6in --prop height=0.4in
A2=$(add_shape_get_path '/slide[1]' --type shape --prop geometry=ellipse \
--prop x=0.5in --prop y=3.6in --prop width=2in --prop height=1.2in \
--prop fill=4472C4 --prop color=FFFFFF --prop bold=true --prop text="A")
B2=$(add_shape_get_path '/slide[1]' --type shape --prop geometry=ellipse \
--prop x=4.5in --prop y=5in --prop width=2in --prop height=1.2in \
--prop fill=E63946 --prop color=FFFFFF --prop bold=true --prop text="B")
officecli add "$PPTX" '/slide[1]' --type connector \
--prop shape=elbow --prop from="$A2" --prop to="$B2" \
--prop color=1D3557 --prop lineWidth=2pt --prop tailEnd=triangle
officecli add "$PPTX" '/slide[1]' --type shape \
--prop text='elbow (bent, 90° turns)' --prop size=12 \
--prop x=0.5in --prop y=6.3in --prop width=6in --prop height=0.4in
A3=$(add_shape_get_path '/slide[1]' --type shape --prop geometry=ellipse \
--prop x=8in --prop y=1.5in --prop width=2in --prop height=1.2in \
--prop fill=4472C4 --prop color=FFFFFF --prop bold=true --prop text="A")
B3=$(add_shape_get_path '/slide[1]' --type shape --prop geometry=ellipse \
--prop x=11.5in --prop y=4.5in --prop width=2in --prop height=1.2in \
--prop fill=E63946 --prop color=FFFFFF --prop bold=true --prop text="B")
officecli add "$PPTX" '/slide[1]' --type connector \
--prop shape=curve --prop from="$A3" --prop to="$B3" \
--prop color=2A9D8F --prop lineWidth=3pt --prop tailEnd=arrow
officecli add "$PPTX" '/slide[1]' --type shape \
--prop text='curve (smooth Bezier)' --prop size=12 \
--prop x=7.5in --prop y=6in --prop width=6in --prop height=0.4in
# ─────────────────────────────────────────────────────────────────────────────
# Slide 2 — Mini flowchart with attached connectors
# ─────────────────────────────────────────────────────────────────────────────
officecli add "$PPTX" / --type slide
officecli add "$PPTX" '/slide[2]' --type shape \
--prop text="Flowchart with Attached Connectors" --prop size=28 --prop bold=true \
--prop x=0.5in --prop y=0.3in --prop width=12in --prop height=0.6in
P1=$(add_shape_get_path '/slide[2]' --type shape --prop geometry=roundRect \
--prop x=0.8in --prop y=2.5in --prop width=2.2in --prop height=1.2in \
--prop fill=2A9D8F --prop color=FFFFFF --prop bold=true --prop size=16 \
--prop text="Start")
P2=$(add_shape_get_path '/slide[2]' --type shape --prop geometry=diamond \
--prop x=4.5in --prop y=2.3in --prop width=2.8in --prop height=1.6in \
--prop fill=F4A261 --prop color=000000 --prop bold=true --prop size=14 \
--prop text="Valid?")
P3=$(add_shape_get_path '/slide[2]' --type shape --prop geometry=roundRect \
--prop x=9in --prop y=2.5in --prop width=2.2in --prop height=1.2in \
--prop fill=E63946 --prop color=FFFFFF --prop bold=true --prop size=16 \
--prop text="End")
P4=$(add_shape_get_path '/slide[2]' --type shape --prop geometry=roundRect \
--prop x=4.7in --prop y=5in --prop width=2.4in --prop height=1in \
--prop fill=A8DADC --prop color=000000 --prop bold=true --prop size=14 \
--prop text="Retry")
# Connect Start → Valid? → End, plus the loopback Valid? → Retry → back to Start
officecli add "$PPTX" '/slide[2]' --type connector \
--prop shape=straight --prop from="$P1" --prop to="$P2" \
--prop color=1D3557 --prop lineWidth=2pt --prop tailEnd=triangle
officecli add "$PPTX" '/slide[2]' --type connector \
--prop shape=straight --prop from="$P2" --prop to="$P3" \
--prop color=1D3557 --prop lineWidth=2pt --prop tailEnd=triangle
officecli add "$PPTX" '/slide[2]' --type connector \
--prop shape=elbow --prop from="$P2" --prop to="$P4" \
--prop color=E63946 --prop lineWidth=2pt --prop lineDash=dash --prop tailEnd=triangle
officecli add "$PPTX" '/slide[2]' --type connector \
--prop shape=elbow --prop from="$P4" --prop to="$P1" \
--prop color=E63946 --prop lineWidth=2pt --prop lineDash=dash --prop tailEnd=triangle
# Branch labels (textbox-style; no fill, transparent outline)
officecli add "$PPTX" '/slide[2]' --type textbox \
--prop x=7.4in --prop y=2.7in --prop width=1.3in --prop height=0.5in \
--prop text="yes" --prop size=12 --prop bold=true --prop color=2A9D8F
officecli add "$PPTX" '/slide[2]' --type textbox \
--prop x=6in --prop y=4in --prop width=1.3in --prop height=0.5in \
--prop text="no" --prop size=12 --prop bold=true --prop color=E63946
# ─────────────────────────────────────────────────────────────────────────────
# Slide 3 — Grouping shapes
# ─────────────────────────────────────────────────────────────────────────────
officecli add "$PPTX" / --type slide
officecli add "$PPTX" '/slide[3]' --type shape \
--prop text="Grouping Shapes" --prop size=28 --prop bold=true \
--prop x=0.5in --prop y=0.3in --prop width=12in --prop height=0.6in
# Three logo-like shapes that we'll group together.
G1=$(add_shape_get_path '/slide[3]' --type shape --prop geometry=ellipse \
--prop x=1.5in --prop y=2in --prop width=1.4in --prop height=1.4in \
--prop fill=E63946)
G2=$(add_shape_get_path '/slide[3]' --type shape --prop geometry=ellipse \
--prop x=2.4in --prop y=2in --prop width=1.4in --prop height=1.4in \
--prop fill=F4A261 --prop opacity=0.75)
G3=$(add_shape_get_path '/slide[3]' --type shape --prop geometry=ellipse \
--prop x=3.3in --prop y=2in --prop width=1.4in --prop height=1.4in \
--prop fill=2A9D8F --prop opacity=0.75)
# Group them by passing the captured shape paths (comma-separated)
officecli add "$PPTX" '/slide[3]' --type group \
--prop shapes="$G1,$G2,$G3" --prop name="Logo"
officecli add "$PPTX" '/slide[3]' --type textbox \
--prop text='Three ellipses grouped (shapes='"$G1,$G2,$G3"').' \
--prop size=12 \
--prop x=0.5in --prop y=4in --prop width=12in --prop height=0.5in
# Three independent boxes for comparison
officecli add "$PPTX" '/slide[3]' --type shape --prop geometry=rect \
--prop x=8in --prop y=2in --prop width=1.4in --prop height=1.4in \
--prop fill=4472C4
officecli add "$PPTX" '/slide[3]' --type shape --prop geometry=rect \
--prop x=9.5in --prop y=2in --prop width=1.4in --prop height=1.4in \
--prop fill=4472C4
officecli add "$PPTX" '/slide[3]' --type shape --prop geometry=rect \
--prop x=11in --prop y=2in --prop width=1.4in --prop height=1.4in \
--prop fill=4472C4
officecli add "$PPTX" '/slide[3]' --type textbox \
--prop text='Three independent boxes (no group — each addressed separately).' \
--prop size=12 \
--prop x=7in --prop y=4in --prop width=6in --prop height=0.5in
# ─────────────────────────────────────────────────────────────────────────────
# Slide 4 — headEnd / lineJoin / miterLimit on connectors
# ─────────────────────────────────────────────────────────────────────────────
officecli add "$PPTX" / --type slide
officecli add "$PPTX" '/slide[4]' --type shape \
--prop text="headEnd / lineJoin / miterLimit on Connectors" \
--prop size=24 --prop bold=true \
--prop x=0.5in --prop y=0.3in --prop width=12in --prop height=0.6in
# headEnd — arrowhead at the START of the connector (the 'head' = from-side)
# tailEnd — arrowhead at the END of the connector (the 'tail' = to-side)
officecli add "$PPTX" '/slide[4]' --type textbox \
--prop text="headEnd + tailEnd arrowhead combinations:" \
--prop size=14 --prop bold=true \
--prop x=0.5in --prop y=1.1in --prop width=12in --prop height=0.4in
Y=1.8
for combo in "headEnd=triangle tailEnd=oval" "headEnd=diamond tailEnd=arrow" "headEnd=arrow tailEnd=arrow"; do
read -r h t <<< "$combo"
hv="${h#headEnd=}"; tv="${t#tailEnd=}"
officecli add "$PPTX" '/slide[4]' --type connector \
--prop shape=straight \
--prop x=0.5in --prop "y=${Y}in" --prop width=5in --prop height=0in \
--prop color=1D3557 --prop lineWidth=2pt \
--prop headEnd="$hv" --prop tailEnd="$tv"
officecli add "$PPTX" '/slide[4]' --type textbox \
--prop text="headEnd=$hv tailEnd=$tv" --prop size=12 \
--prop x=5.8in --prop "y=${Y}in" --prop width=6in --prop height=0.4in
Y=$(echo "$Y + 0.8" | bc -l)
done
# lineJoin — connector joins: round / bevel / miter
# lineJoin on connectors affects the joint where the connector bends (elbow)
officecli add "$PPTX" '/slide[4]' --type textbox \
--prop text="lineJoin on elbow connectors:" \
--prop size=14 --prop bold=true \
--prop x=0.5in --prop y=4.6in --prop width=12in --prop height=0.4in
# Three elbow connectors, one per column, so each join style at the bend is
# clearly visible. The third uses the compound lineJoin=miter:<lim> form
# (limit in 1/1000ths of a percent) to also exercise miterLimit.
add_elbow() { # $1=x(in) $2=color $3=lineJoin $4=label
officecli add "$PPTX" '/slide[4]' --type connector \
--prop shape=elbow \
--prop x="${1}in" --prop y=5.2in --prop width=3.4in --prop height=1.6in \
--prop color="$2" --prop lineWidth=5pt \
--prop lineJoin="$3"
officecli add "$PPTX" '/slide[4]' --type textbox \
--prop text="$4" --prop size=12 \
--prop x="${1}in" --prop y=7.0in --prop width=4in --prop height=0.4in
}
add_elbow 0.5 E63946 round "lineJoin=round"
add_elbow 4.7 E63946 bevel "lineJoin=bevel"
add_elbow 8.9 2A9D8F "miter:800000" "lineJoin=miter:800000 (800% limit)"
officecli close "$PPTX"
officecli validate "$PPTX"
echo "Created: $PPTX"
+266
View File
@@ -0,0 +1,266 @@
# Shape Effects and Meta
This demo consists of three files that work together:
- **shapes-effects.sh** — Shell script that calls `officecli` commands to generate the deck. It generates a sample PNG inline via a Python heredoc — no external image file is needed.
- **shapes-effects.pptx** — The generated 5-slide deck (autoFit, flipH/V, image fill, 3D bevel/depth/lighting/material, softEdge/link/name/zorder).
- **shapes-effects.md** — This file. Covers shape properties not found in shapes-basic or shapes-connectors.
## Regenerate
```bash
cd examples/ppt
bash shapes/shapes-effects.sh
# → shapes/shapes-effects.pptx
```
## Slides
### Slide 1 — autoFit: Text Overflow Behavior
Three textboxes with the same long text and a fixed height, each using a different `autoFit=` mode.
```bash
officecli create shapes-effects.pptx
officecli open shapes-effects.pptx
officecli add shapes-effects.pptx / --type slide
LONGTEXT='Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris.'
# autoFit=none — text runs off the box boundary (no shrink, no clip)
officecli add shapes-effects.pptx '/slide[1]' --type textbox \
--prop x=0.5in --prop y=1.5in --prop width=4in --prop height=1.5in \
--prop fill=F1FAEE --prop size=18 --prop text="$LONGTEXT" \
--prop autoFit=none
# autoFit=normal — font size shrinks until all text fits inside the fixed box
officecli add shapes-effects.pptx '/slide[1]' --type textbox \
--prop x=5in --prop y=1.5in --prop width=4in --prop height=1.5in \
--prop fill=A8DADC --prop size=18 --prop text="$LONGTEXT" \
--prop autoFit=normal
# autoFit=shape — box grows taller to accommodate the text at the declared font size
officecli add shapes-effects.pptx '/slide[1]' --type textbox \
--prop x=9.5in --prop y=1.5in --prop width=4in --prop height=1.5in \
--prop fill=F4A261 --prop size=18 --prop text="$LONGTEXT" \
--prop autoFit=shape
```
**Features:** `autoFit` (none — overflows, normal — text shrinks, shape — box grows)
---
### Slide 2 — flipH / flipV: Mirror
Four `rightArrow` shapes showing all combinations of horizontal and vertical flipping.
```bash
officecli add shapes-effects.pptx / --type slide
# Original — no flip flags
officecli add shapes-effects.pptx '/slide[2]' --type shape --prop geometry=rightArrow \
--prop x=0.5in --prop y=2in --prop width=2.8in --prop height=1.5in \
--prop fill=4472C4 --prop color=FFFFFF --prop bold=true --prop text="original"
# flipH=true — mirror horizontally (arrow points left)
officecli add shapes-effects.pptx '/slide[2]' --type shape --prop geometry=rightArrow \
--prop x=4in --prop y=2in --prop width=2.8in --prop height=1.5in \
--prop fill=E63946 --prop color=FFFFFF --prop bold=true --prop text="flipH=true" \
--prop flipH=true
# flipV=true — mirror vertically (arrow points down-right)
officecli add shapes-effects.pptx '/slide[2]' --type shape --prop geometry=rightArrow \
--prop x=7.5in --prop y=2in --prop width=2.8in --prop height=1.5in \
--prop fill=2A9D8F --prop color=FFFFFF --prop bold=true --prop text="flipV=true" \
--prop flipV=true
# flipH + flipV together — visually 180° rotation, stored as flip flags not rotation
officecli add shapes-effects.pptx '/slide[2]' --type shape --prop geometry=rightArrow \
--prop x=11in --prop y=2in --prop width=2.8in --prop height=1.5in \
--prop fill=F4A261 --prop color=000000 --prop bold=true --prop text="flipH + flipV" \
--prop flipH=true --prop flipV=true
```
**Features:** `flipH` (alias: flipHorizontal), `flipV` (alias: flipVertical). Flip flags are stored independently of `rotation=`, so `flipH=true` + `rotation=90` chains predictably.
---
### Slide 3 — image=: Picture as Shape Fill (blipFill)
Three shapes with different geometries all filled with an image. The geometry preset clips the bitmap to its outline.
```bash
officecli add shapes-effects.pptx / --type slide
# Ellipse with image fill + outline border — image clipped to ellipse shape
officecli add shapes-effects.pptx '/slide[3]' --type shape --prop geometry=ellipse \
--prop x=0.5in --prop y=1.5in --prop width=3.5in --prop height=3.5in \
--prop image="$SAMPLE_PNG" \
--prop lineColor=1D3557 --prop lineWidth=3pt
# Star5 — image clipped to a 5-pointed star
officecli add shapes-effects.pptx '/slide[3]' --type shape --prop geometry=star5 \
--prop x=4.5in --prop y=1.5in --prop width=3.5in --prop height=3.5in \
--prop image="$SAMPLE_PNG"
# Diamond with image fill + outline
officecli add shapes-effects.pptx '/slide[3]' --type shape --prop geometry=diamond \
--prop x=8.5in --prop y=1.5in --prop width=3.5in --prop height=3.5in \
--prop image="$SAMPLE_PNG" \
--prop lineColor=1D3557 --prop lineWidth=3pt
```
**Features:** `image` (file path to PNG/JPG — embeds the image as a blipFill inside the shape geometry; the geometry clips the image). This is distinct from `--type picture`, which embeds the bitmap with its native bounding box.
---
### Slide 4 — 3D Effects: Bevel / Depth / Lighting / Material
Six shapes demonstrating bevel types, extrusion depth, and lighting/material combinations.
```bash
officecli add shapes-effects.pptx / --type slide
# bevel=circle — top bevel only, default size
officecli add shapes-effects.pptx '/slide[4]' --type shape --prop geometry=roundRect \
--prop x=0.5in --prop y=1.4in --prop width=3in --prop height=1.8in \
--prop fill=4472C4 --prop color=FFFFFF --prop bold=true --prop size=14 \
--prop text='bevel=circle' \
--prop bevel=circle
# bevel with explicit dimensions + separate bottom bevel
# bevel=TYPE-W-H: bevel type, width in pt, height in pt
officecli add shapes-effects.pptx '/slide[4]' --type shape --prop geometry=roundRect \
--prop x=4in --prop y=1.4in --prop width=3in --prop height=1.8in \
--prop fill=E63946 --prop color=FFFFFF --prop bold=true --prop size=14 \
--prop text='bevel=angle-8-4 + bevelBottom=circle-4-4' \
--prop bevel=angle-8-4 --prop bevelBottom=circle-4-4
# depth= — extrusion thickness (pt-suffixed)
officecli add shapes-effects.pptx '/slide[4]' --type shape --prop geometry=roundRect \
--prop x=7.5in --prop y=1.4in --prop width=3in --prop height=1.8in \
--prop fill=2A9D8F --prop color=FFFFFF --prop bold=true --prop size=14 \
--prop text='depth=14pt + bevel=softRound' \
--prop depth=14pt --prop bevel=softRound
# lighting=threePt material=metal
officecli add shapes-effects.pptx '/slide[4]' --type shape --prop geometry=ellipse \
--prop x=0.5in --prop y=3.7in --prop width=3in --prop height=1.8in \
--prop fill=F4A261 --prop color=000000 --prop bold=true --prop size=12 \
--prop text='lighting=threePt material=metal' \
--prop bevel=circle-8 --prop depth=10 --prop lighting=threePt --prop material=metal
# lighting=balanced material=plastic
officecli add shapes-effects.pptx '/slide[4]' --type shape --prop geometry=ellipse \
--prop x=4in --prop y=3.7in --prop width=3in --prop height=1.8in \
--prop fill=A8DADC --prop color=000000 --prop bold=true --prop size=12 \
--prop text='lighting=balanced material=plastic' \
--prop bevel=circle-6 --prop depth=8 --prop lighting=balanced --prop material=plastic
# lighting=harsh material=warmMatte
officecli add shapes-effects.pptx '/slide[4]' --type shape --prop geometry=ellipse \
--prop x=7.5in --prop y=3.7in --prop width=3in --prop height=1.8in \
--prop fill=FFD700 --prop color=000000 --prop bold=true --prop size=12 \
--prop text='lighting=harsh material=warmMatte' \
--prop bevel=circle-6 --prop depth=8 --prop lighting=harsh --prop material=warmMatte
```
**Features:** `bevel` (TYPE or `TYPE-W` or `TYPE-W-H`; preset types: circle, angle, softRound, convex, coolSlant, cross, divot, hardEdge, relaxedInset, riblet, slope), `bevelBottom` (same syntax, sets the bottom face bevel), `depth` (extrusion in pt), `lighting` (threePt, balanced, harsh, flat, softAmbient, …), `material` (metal, plastic, warmMatte, matte, powder, translucentPowder, …)
---
### Slide 5 — softEdge / link / name / zorder
Feathered edges, clickable hyperlinks with tooltip, named addressable shapes, and explicit z-order stacking.
```bash
officecli add shapes-effects.pptx / --type slide
# softEdge — feathered/blurred edge in points; 0 = sharp
officecli add shapes-effects.pptx '/slide[5]' --type shape --prop geometry=ellipse \
--prop x=0.5in --prop y=1.5in --prop width=3in --prop height=2in \
--prop fill=E63946 --prop color=FFFFFF --prop bold=true \
--prop text='softEdge=0 (sharp)' --prop softEdge=0
officecli add shapes-effects.pptx '/slide[5]' --type shape --prop geometry=ellipse \
--prop x=4in --prop y=1.5in --prop width=3in --prop height=2in \
--prop fill=E63946 --prop color=FFFFFF --prop bold=true \
--prop text='softEdge=8pt' --prop softEdge=8pt
officecli add shapes-effects.pptx '/slide[5]' --type shape --prop geometry=ellipse \
--prop x=7.5in --prop y=1.5in --prop width=3in --prop height=2in \
--prop fill=E63946 --prop color=FFFFFF --prop bold=true \
--prop text='softEdge=20pt (heavy feather)' --prop softEdge=20pt
# link + tooltip — makes the entire shape a clickable hyperlink
officecli add shapes-effects.pptx '/slide[5]' --type shape --prop geometry=roundRect \
--prop x=0.5in --prop y=4in --prop width=4in --prop height=1in \
--prop fill=2A9D8F --prop color=FFFFFF --prop bold=true --prop size=16 \
--prop text="Click me → example.com" \
--prop link=https://example.com --prop tooltip="Open example.com" \
--prop name="cta-button"
# zorder — three overlapping rects with explicit stack depth
officecli add shapes-effects.pptx '/slide[5]' --type shape --prop geometry=rect \
--prop x=8in --prop y=4in --prop width=2.5in --prop height=2.5in \
--prop fill=4472C4 --prop name="back" --prop zorder=1 \
--prop color=FFFFFF --prop bold=true --prop text="back (zorder=1)"
officecli add shapes-effects.pptx '/slide[5]' --type shape --prop geometry=rect \
--prop x=9in --prop y=4.5in --prop width=2.5in --prop height=2.5in \
--prop fill=E63946 --prop name="middle" --prop zorder=2 \
--prop color=FFFFFF --prop bold=true --prop text="middle (zorder=2)"
officecli add shapes-effects.pptx '/slide[5]' --type shape --prop geometry=rect \
--prop x=10in --prop y=5in --prop width=2.5in --prop height=2.5in \
--prop fill=F4A261 --prop name="front" --prop zorder=3 \
--prop color=000000 --prop bold=true --prop text="front (zorder=3)"
officecli close shapes-effects.pptx
officecli validate shapes-effects.pptx
```
**Features:** `softEdge` (pt-suffixed radius; 0 = sharp), `link` (URL, `slide[N]` in-deck jump, or named action like `nextslide`), `tooltip` (hover text on hyperlinked shapes), `name` (stable identifier; addressable as `/slide[N]/shape[@name=...]`), `zorder` (integer stack depth; aliases: z-order, order)
---
## Complete Feature Coverage
| Feature | Slide |
|---------|-------|
| **autoFit:** none (overflow), normal (shrink text), shape (grow box) | 1 |
| **flipH / flipV:** mirror horizontal/vertical, independent of rotation | 2 |
| **image=:** blipFill — image clipped to any geometry preset | 3 |
| **bevel:** circle, angle, softRound, convex, and more (`TYPE-W-H` form) | 4 |
| **bevelBottom:** separate bottom-face bevel | 4 |
| **depth=:** 3D extrusion thickness in pt | 4 |
| **lighting:** threePt, balanced, harsh, flat, softAmbient | 4 |
| **material:** metal, plastic, warmMatte, matte, powder | 4 |
| **softEdge=:** feathered boundary radius in pt | 5 |
| **link=:** URL / `slide[N]` jump / named action | 5 |
| **tooltip=:** hover text for hyperlinked shapes | 5 |
| **name=:** stable @name addressing | 5 |
| **zorder=:** explicit stack depth (aliases: z-order, order) | 5 |
## Inspect the Generated File
```bash
# Check autoFit mode on each textbox (slide 1)
officecli get shapes-effects.pptx '/slide[1]/shape[1]'
officecli get shapes-effects.pptx '/slide[1]/shape[3]'
# Read back flip flags on slide 2
officecli get shapes-effects.pptx '/slide[2]/shape[2]'
officecli get shapes-effects.pptx '/slide[2]/shape[4]'
# Get bevel/depth/lighting details on slide 4
officecli get shapes-effects.pptx '/slide[4]/shape[1]'
officecli get shapes-effects.pptx '/slide[4]/shape[4]'
# Verify link, tooltip, name on the CTA button
officecli get shapes-effects.pptx '/slide[5]/shape[@name=cta-button]'
# Check zorder stack on slide 5
officecli get shapes-effects.pptx '/slide[5]/shape[@name=back]'
officecli get shapes-effects.pptx '/slide[5]/shape[@name=front]'
```
Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More