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
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:
@@ -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 4–8 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 2–7 — 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 4–7 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 | 1–8 |
|
||||
| **path=** (GLB file path) | 1–8 |
|
||||
| **name=** (morph pairing key) | 1–8 |
|
||||
| **rotx=** (X-axis tilt degrees) | 1, 3, 5, 7, 8 |
|
||||
| **roty=** (Y-axis orbit degrees) | 2–8 |
|
||||
| **x=/y=/width=/height=** in cm (model placement) | 1–8 |
|
||||
| **transition=morph** | 1–8 |
|
||||
| **background=** hex | 1–8 |
|
||||
| **fill=00000000** (transparent — no shape background) | 1–8 |
|
||||
| **font=Arial Black / Georgia / Calibri** | 1, 8 |
|
||||
| **bold=** / **italic=** | 1, 8 |
|
||||
| **align=right / align=left** | 2, 4, 6 |
|
||||
| **lineSpacing=2x** (line height multiplier) | 2–7 |
|
||||
| **text= with \n** multi-line | 2–7 |
|
||||
| **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.
@@ -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}")
|
||||
Executable
+205
@@ -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"
|
||||
@@ -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 (500–2000ms).
|
||||
|
||||
### 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 | 2–7 |
|
||||
| `effect=` entrance family | 2 |
|
||||
| `effect=` exit family | 3 |
|
||||
| `effect=` emphasis (motion + color) | 4 |
|
||||
| `class=entrance` / `exit` / `emphasis` / `motion` | 2 / 3 / 4 / 5 |
|
||||
| `duration=` (400–2000ms) | 2–7 |
|
||||
| `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) | 1–7 |
|
||||
|
||||
## 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.
@@ -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}")
|
||||
Executable
+261
@@ -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\""
|
||||
@@ -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 (0–500).
|
||||
|
||||
```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` (0–500, 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** (0–500) | 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.
@@ -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)")
|
||||
Executable
+104
@@ -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"
|
||||
@@ -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` (100–1000, 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 (1–48)
|
||||
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` (1–48 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** (1–48 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.
Executable
+305
@@ -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)")
|
||||
Executable
+307
@@ -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"
|
||||
@@ -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.
Executable
+179
@@ -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)")
|
||||
Executable
+99
@@ -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"
|
||||
@@ -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.
@@ -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()
|
||||
Executable
+100
@@ -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"
|
||||
@@ -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` (50–200, % 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** (50–200) | 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.
@@ -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)")
|
||||
Executable
+106
@@ -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"
|
||||
@@ -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` (0–100), `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` (0–500), `overlap` (-100–100), `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** (0–100) | 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.
@@ -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}")
|
||||
Executable
+107
@@ -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"
|
||||
@@ -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.
@@ -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)")
|
||||
Executable
+104
@@ -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"
|
||||
@@ -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 (10–90, % 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` (10–90), `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` (0–360°)
|
||||
|
||||
### 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** (10–90%) | 1 |
|
||||
| **varyColors** | 1 |
|
||||
| **Multi-ring** (concentric series) | 2 |
|
||||
| **firstSliceAngle** (0–360) | 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.
@@ -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}")
|
||||
Executable
+102
@@ -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"
|
||||
@@ -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.
@@ -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}")
|
||||
Executable
+102
@@ -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"
|
||||
@@ -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` (0–360°), `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` (0–100, % 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** (0–360) | 1, 6 |
|
||||
| **view3d** (pie3d) | 1 |
|
||||
| **explosion** (0–100%) | 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.
Executable
+187
@@ -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)")
|
||||
Executable
+97
@@ -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"
|
||||
@@ -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.
Executable
+206
@@ -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)")
|
||||
Executable
+98
@@ -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"
|
||||
@@ -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.
@@ -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)")
|
||||
Executable
+112
@@ -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"
|
||||
@@ -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.
@@ -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}")
|
||||
Executable
+101
@@ -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"
|
||||
@@ -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.
@@ -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)")
|
||||
Executable
+93
@@ -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"
|
||||
@@ -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) |
|
||||
| 6–23 | `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 5–23)
|
||||
|
||||
`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, 5–23 |
|
||||
| `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 & 5–23
|
||||
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.
Executable
+188
@@ -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}")
|
||||
Executable
+274
@@ -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.
@@ -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.
@@ -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()
|
||||
@@ -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 |
@@ -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; 0–360 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.
Executable
+378
@@ -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()
|
||||
Executable
+305
@@ -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"
|
||||
@@ -0,0 +1,5 @@
|
||||
pie showData title Traffic Sources
|
||||
"Organic Search" : 45
|
||||
"Direct" : 30
|
||||
"Referral" : 15
|
||||
"Social" : 10
|
||||
@@ -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.
@@ -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}")
|
||||
@@ -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"
|
||||
@@ -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` (`○` ○, `△` △, `◇` ◇), `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>“</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), `“` left double quote, `—` 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** 1200–12000 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.
@@ -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 · ELEGANCE · 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>○</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>△</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>◇</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>“</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>— 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 — it’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}")
|
||||
Executable
+624
@@ -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 · ELEGANCE · 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>○</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>△</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>◇</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>“</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>— 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 — it’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
|
||||
@@ -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.0–1.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 0–360), `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.0–1.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` | 1–5 |
|
||||
| **Position/size:** `x`, `y`, `width`, `height` (in/cm/pt/emu) | 1–5 |
|
||||
|
||||
## 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.
@@ -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}")
|
||||
Executable
+258
@@ -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"
|
||||
@@ -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.0–1.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` | 1–4 |
|
||||
| **Color:** `color=hex` | 1–4 |
|
||||
| **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.0–1.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.
@@ -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}")
|
||||
Executable
+227
@@ -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"
|
||||
@@ -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
Reference in New Issue
Block a user