askill
skill-powerpoint-deck-generation

skill-powerpoint-deck-generationSafety 95Repository

This skill covers patterns for programmatically generating branded PowerPoint presentations using `python-pptx`, including chart insertion, template handling, and PDF export.

0 stars
1.2k downloads
Updated 2/7/2026

Package Files

Loading files...
SKILL.md

Skill: PowerPoint Deck Generation

This skill covers patterns for programmatically generating branded PowerPoint presentations using python-pptx, including chart insertion, template handling, and PDF export.

1. Context & Use Cases

Trigger: User requests to:

  • Generate a PowerPoint deck from data (CSVs, DataFrames, charts)
  • Apply corporate branding/templates to slides
  • Build executive summaries with KPI visualizations
  • Export presentations to PDF

Tools:

  • python-pptx — Core library for PPTX manipulation
  • matplotlib/seaborn — Chart generation (saved as PNG, inserted into slides)
  • soffice (LibreOffice) — PDF export and template conversion

2. Template Handling

2.1 Corporate Templates (.potx)

Corporate templates are often distributed as .potx (PowerPoint Template) files. python-pptx can open these, but sometimes requires conversion.

Conversion pattern (change content type):

import zipfile
from pathlib import Path

def convert_potx_to_pptx(src_path: Path, dst_path: Path) -> Path:
    """Convert .potx to .pptx by rewriting the content type."""
    old_type = "application/vnd.openxmlformats-officedocument.presentationml.template.main+xml"
    new_type = "application/vnd.openxmlformats-officedocument.presentationml.presentation.main+xml"

    with zipfile.ZipFile(src_path, "r") as zin:
        with zipfile.ZipFile(dst_path, "w", compression=zipfile.ZIP_DEFLATED) as zout:
            for info in zin.infolist():
                data = zin.read(info.filename)
                if info.filename == "[Content_Types].xml":
                    text = data.decode("utf-8")
                    text = text.replace(old_type, new_type)
                    data = text.encode("utf-8")
                zout.writestr(info, data)
    return dst_path

2.2 Template Location

Store templates in templates/ at repo root for reusability:

templates/
├── Premier_Standard_Legal.dotx    # Word template
└── Premier_FY25_16x9.potx         # PowerPoint template

Or in run-local folders for project-specific templates:

runs/<RUN_ID>/ge-pipeline/brand/
└── Premier-FY25-PPT 16x9-Feb25.potx

3. Slide Creation Patterns

3.1 Remove Existing Slides (Start Fresh)

from pptx import Presentation

def remove_all_slides(prs: Presentation) -> None:
    """Remove all slides from presentation."""
    for i in range(len(prs.slides) - 1, -1, -1):
        rId = prs.slides._sldIdLst[i].rId
        prs.part.drop_rel(rId)
        del prs.slides._sldIdLst[i]

3.2 Find Layouts by Name

def find_layout(prs: Presentation, layout_names: list[str]):
    """Find first matching layout by name."""
    for layout in prs.slide_layouts:
        if layout.name in layout_names:
            return layout
    # Fallback to first layout
    return prs.slide_layouts[0]

# Common layout names (vary by template)
LAYOUT_MAP = {
    "TITLE": ["Premier Title Dark", "Title Slide"],
    "TITLE_CONTENT": ["Title and Content", "Premier Two Content"],
    "SECTION": ["Section Header", "Premier Section"],
    "BLANK": ["Blank"],
}

3.3 Normalized Positioning

Use normalized (0-1) coordinates for consistent placement across slide sizes:

from pptx.util import Pt

EMU_PER_INCH = 914400

def place_normalized(slide, x: float, y: float, w: float, h: float):
    """Add textbox using normalized (0..1) coords."""
    presentation = slide.part.package.presentation_part.presentation
    sw, sh = presentation.slide_width, presentation.slide_height
    left = int(sw * x)
    top = int(sh * y)
    width = int(sw * w)
    height = int(sh * h)
    return slide.shapes.add_textbox(left, top, width, height)

3.4 Insert Images (Charts)

def add_picture_fit(slide, image_path: str, x: float, y: float, w: float, h: float):
    """Insert image at normalized position."""
    presentation = slide.part.package.presentation_part.presentation
    sw, sh = presentation.slide_width, presentation.slide_height
    left, top = int(sw * x), int(sh * y)
    width, height = int(sw * w), int(sh * h)
    return slide.shapes.add_picture(image_path, left, top, width=width, height=height)

4. Chart Generation Patterns

4.1 Executive-Style Charts (seaborn/matplotlib)

import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd

def generate_market_share_chart(df: pd.DataFrame, output_path: Path) -> None:
    """Generate a stacked bar chart for market share."""
    # Consistent manufacturer colors across all charts
    COLORS = {
        "GE": "#1f77b4",
        "SIEMENS": "#ff7f0e",
        "PHILIPS": "#2ca02c",
        "CANON": "#d62728",
        "OTHER": "#9467bd",
    }
    
    sns.set_theme(style="whitegrid")
    plt.figure(figsize=(10, 6))
    
    # ... chart logic ...
    
    plt.tight_layout()
    plt.savefig(output_path, dpi=300, bbox_inches='tight')
    plt.close()

4.2 Chart Naming Convention

Use descriptive names with prefixes for organization:

visuals/
├── exec_modality_trend.png        # Executive summary
├── exec_share_latest_quarter.png
├── qa_spend_vs_transactions.png   # QA/validation
└── market_trend_ct.png            # Category-specific

5. Slide Content Patterns

5.1 Big Number KPIs

def add_kpi_card(slide, value: str, label: str, x: float, y: float):
    """Add a KPI card (big number + label)."""
    box = place_normalized(slide, x, y, 0.25, 0.20)
    tf = box.text_frame
    tf.clear()
    
    # Value (big, bold)
    p1 = tf.paragraphs[0]
    p1.text = value
    p1.font.size = Pt(48)
    p1.font.bold = True
    p1.font.color.rgb = RGBColor(0, 82, 147)  # Premier Blue
    
    # Label (smaller)
    p2 = tf.add_paragraph()
    p2.text = label
    p2.font.size = Pt(14)

5.2 Data Tables

from pptx.util import Inches

def add_data_table(slide, df: pd.DataFrame, x: float, y: float, w: float, h: float):
    """Insert a DataFrame as a table."""
    presentation = slide.part.package.presentation_part.presentation
    sw, sh = presentation.slide_width, presentation.slide_height
    
    rows, cols = df.shape
    table = slide.shapes.add_table(
        rows + 1,  # +1 for header
        cols,
        int(sw * x), int(sh * y),
        int(sw * w), int(sh * h)
    ).table
    
    # Header row
    for j, col in enumerate(df.columns):
        table.cell(0, j).text = str(col)
    
    # Data rows
    for i, row in df.iterrows():
        for j, val in enumerate(row):
            table.cell(i + 1, j).text = str(val)
    
    return table

6. PDF Export

6.1 Using LibreOffice (soffice)

import subprocess
from pathlib import Path

def export_to_pdf(pptx_path: Path, output_dir: Path) -> Path:
    """Convert PPTX to PDF using LibreOffice."""
    cmd = [
        "soffice",
        "--headless",
        "--convert-to", "pdf",
        "--outdir", str(output_dir),
        str(pptx_path)
    ]
    subprocess.run(cmd, check=True)
    return output_dir / f"{pptx_path.stem}.pdf"

Prerequisite: LibreOffice must be installed:

# macOS
brew install --cask libreoffice

# Ubuntu
sudo apt install libreoffice

7. Deck Builder Architecture

For complex decks, use a modular builder pattern:

src/pptx_builder/
├── __init__.py
├── build_deck.py      # Main entry point
├── helpers.py         # Positioning, text formatting
├── layouts.py         # Layout discovery
├── slides.py          # Slide creation functions
├── charts_fallback.py # Chart generation helpers
└── style_tokens.py    # Colors, fonts, theme extraction

Usage pattern:

def build_deck(snapshot_dir: Path, template_path: Path, output_path: Path):
    # 1. Load template
    template = ensure_pptx_template(template_path, snapshot_dir)
    prs = Presentation(template)
    
    # 2. Clear existing slides
    remove_all_slides(prs)
    
    # 3. Add slides in order
    add_title_slide(prs, "Market Insights Report", "Q4 2025")
    add_section_slide(prs, "Market Trends")
    add_chart_slide(prs, snapshot_dir / "visuals/exec_trend.png", "Spend by Category")
    # ...
    
    # 4. Save
    prs.save(output_path)
    
    # 5. Export PDF
    export_to_pdf(output_path, snapshot_dir)

8. Recovery Rules

ProblemLikely CauseFix
KeyError: "no style named 'Title'"Template missing expected stylesUse layout discovery; fall back to first available
Template changes fail silently.potx content type not convertedUse convert_potx_to_pptx() helper
Charts look pixelatedLow DPI exportUse dpi=300 in plt.savefig()
Slides appear blankShapes added at wrong positionUse normalized positioning with slide dimensions
PDF export failsLibreOffice not installed or hung processInstall soffice; use --headless flag

9. Reference Implementation

See runs/2026-01-16__ge-market-insights/ge-pipeline/ for:

  • src/pptx_builder/ — Complete deck builder with theming
  • scripts/generate_capital_visuals.py — Chart generation patterns
  • scripts/run_full_pipeline.py — End-to-end pipeline with PDF export

Install

Download ZIP
Requires askill CLI v1.0+

AI Quality Score

96/100Analyzed 2/9/2026

An exceptional skill document providing deep technical patterns for PowerPoint automation, including non-trivial template conversion and layout management.

95
98
90
95
98

Metadata

Licenseunknown
Version-
Updated2/7/2026
Publishermbosseme

Tags

ci-cd