---
name: generacion-powerpoint-python-pptx
description: Referencia completa para crear, editar y manipular ficheros .pptx de forma programatica con python-pptx. Cubre generacion desde datos, actualizacion de plantillas, extraccion de contenido, graficos, tablas e imagenes sin necesidad de tener PowerPoint instalado.
license: Apache-2.0
metadata:
  id: b29b22a2
  slug: generacion-powerpoint-python-pptx
  titulo: "Generacion de PowerPoint con python-pptx"
  servicio: Automatizaciones
  categoria_recurso: Plantillas-Documentos
  tipo: referencia
  nivel: intermedio
  idioma: es
  idioma_original: en
  acceso: gratis
  precio_eur: 0
  plataformas: [Python, CLI]
  dependencias: [python-pptx]
  licencia: { spdx: Apache-2.0, redistribuible: true, uso_comercial: true }
  fuente:
    repo: TerminalSkills/skills
    url: https://github.com/TerminalSkills/skills/tree/main/skills/powerpoint
    commit: 77fa015
    autor: TerminalSkills
    nombre_original: powerpoint
    duplicados_en: []
  seguridad: { veredicto: seguro, riesgo: bajo, escaneado: "2026-06-14", motor: "grep-estatico+auditor-llm" }
  ficha:
    que_hace: "Genera y edita presentaciones PowerPoint (.pptx) de forma programatica a partir de datos, plantillas o contenido estructurado."
    como_lo_hace: "Utiliza la libreria python-pptx para manipular el formato Open XML directamente, con patrones de codigo listos para slides, graficos, tablas, imagenes y notas de orador."
  content_hash: "b29b22a2c56976e274e80b929c8da67db19d0abd336b3e156df686a92bbd504d"
  version: 1.0.0
---

# PowerPoint

## Overview

Create, read, and edit PowerPoint (.pptx) files programmatically using the python-pptx library. Handles slide creation, text formatting, images, tables, charts, shapes, slide layouts, and speaker notes. Works without PowerPoint installed — reads and writes the Open XML format directly.

## Instructions

### Setup

```bash
pip install python-pptx
```

**Alternative — AI-generated PPTX:** For fully automated slide generation from text prompts, Presenton (`github.com/presenton/presenton`) is an open-source tool that produces PPTX using OpenAI, Gemini, Claude, or Ollama. Runs locally via Docker. Use python-pptx (below) when you need precise control over content, formatting, and programmatic data-driven generation.

### Object model

```
Presentation
├── slide_layouts[]    # Layout variants (title, content, blank, etc.)
├── slides[]           # Actual slides
│   ├── shapes[]       # Text boxes, images, charts, tables
│   │   ├── text_frame → paragraphs[] → runs[]  # Text with formatting
│   │   └── table      # Table object (if table shape)
│   └── notes_slide    # Speaker notes
└── core_properties    # Title, author, subject
```

Layout indices vary by template. Always verify first:
```python
for i, layout in enumerate(prs.slide_layouts):
    print(i, layout.name)
```

Common defaults: 0 = Title Slide, 1 = Title and Content, 5 = Title Only, 6 = Blank.

### Creating a presentation

```python
from pptx import Presentation
from pptx.util import Inches, Pt
from pptx.dml.color import RGBColor
from pptx.enum.text import PP_ALIGN

prs = Presentation()

# Title slide
slide = prs.slides.add_slide(prs.slide_layouts[0])
slide.shapes.title.text = "Q4 Revenue Report"
slide.placeholders[1].text = "Finance Team — January 2025"

# Content slide with bullets
slide = prs.slides.add_slide(prs.slide_layouts[1])
slide.shapes.title.text = "Key Highlights"
tf = slide.placeholders[1].text_frame
tf.text = "Revenue up 23% year-over-year"
p = tf.add_paragraph()
p.text = "New enterprise clients: 14"
p.level = 1

prs.save("report.pptx")
```

### Editing existing files (template fill)

```python
prs = Presentation("template.pptx")
for slide in prs.slides:
    for shape in slide.shapes:
        if shape.has_text_frame:
            for paragraph in shape.text_frame.paragraphs:
                for run in paragraph.runs:
                    if "{{COMPANY}}" in run.text:
                        run.text = run.text.replace("{{COMPANY}}", "Acme Corp")
prs.save("filled.pptx")
```

### Quick reference — adding elements

**Image:**
```python
slide.shapes.add_picture("photo.png", Inches(1), Inches(1.5), width=Inches(8))
```

**Table:**
```python
tbl = slide.shapes.add_table(rows, cols, Inches(1), Inches(2), Inches(8), Inches(3)).table
tbl.cell(0, 0).text = "Header"
```

**Chart:**
```python
from pptx.chart.data import CategoryChartData
from pptx.enum.chart import XL_CHART_TYPE

chart_data = CategoryChartData()
chart_data.categories = ["Q1", "Q2", "Q3", "Q4"]
chart_data.add_series("Revenue", (3.2, 3.8, 4.2, 5.1))
slide.shapes.add_chart(XL_CHART_TYPE.COLUMN_CLUSTERED, Inches(1), Inches(2), Inches(8), Inches(4.5), chart_data)
```

**Speaker notes:**
```python
slide.notes_slide.notes_text_frame.text = "Key talking point here."
```

**Text formatting:**
```python
run = paragraph.runs[0]
run.font.size = Pt(28)
run.font.bold = True
run.font.color.rgb = RGBColor(0x1A, 0x73, 0xE8)
run.font.name = "Calibri"
paragraph.alignment = PP_ALIGN.CENTER
```

### Design principles for generated slides

Apply these rules when building presentations programmatically:

**Typography:** Use Inter, Poppins, or Montserrat instead of default Calibri. One font family per presentation. Titles minimum 36pt, body minimum 24pt. Set line spacing to 1.2–1.3 for body text, 0.8–0.9 for large display text.

**Layout:** Left-align body text (center only for short titles). Use generous margins — `Inches(1)` minimum on all sides. Use multi-column layouts for readability. Vary slide designs while keeping a consistent style.

**Content density:** One idea per slide. Maximum 6 lines of text, 6 words per line. Split dense content across multiple slides (~30 seconds each). Replace bullet lists with visual hierarchy using font size, weight, and spacing.

**Whitespace:** Treat empty space as a design element, not wasted space. Apply padding inside boxes and shapes — at least `Inches(0.3)` internal margin.

**Visuals:** One hero image or chart per slide. Use high-contrast text on backgrounds. SVG icons from Noun Project (thenounproject.com) enhance slides without clutter. For professional templates as starting points, download PPTX files from Slidesgo (slidesgo.com) and load them with `Presentation("template.pptx")`.

## Examples

### Example 1: Generate a sales report from JSON data

**User request:** "Create a PowerPoint report from this sales data JSON file"

```python
import json
from pptx import Presentation
from pptx.util import Inches
from pptx.chart.data import CategoryChartData
from pptx.enum.chart import XL_CHART_TYPE

with open("sales_data.json") as f:
    data = json.load(f)

prs = Presentation()

# Title slide
slide = prs.slides.add_slide(prs.slide_layouts[0])
slide.shapes.title.text = f"Sales Report — {data['period']}"
slide.placeholders[1].text = f"Generated {data['generated_date']}"

# Summary slide
slide = prs.slides.add_slide(prs.slide_layouts[1])
slide.shapes.title.text = "Executive Summary"
tf = slide.placeholders[1].text_frame
tf.text = f"Total Revenue: ${data['total_revenue']:,.0f}"
p = tf.add_paragraph()
p.text = f"Units Sold: {data['units_sold']:,}"
p = tf.add_paragraph()
p.text = f"Top Region: {data['top_region']}"

# Chart slide — revenue by region
chart_data = CategoryChartData()
chart_data.categories = [r["name"] for r in data["regions"]]
chart_data.add_series("Revenue ($M)", [r["revenue"] for r in data["regions"]])
slide = prs.slides.add_slide(prs.slide_layouts[5])
slide.shapes.title.text = "Revenue by Region"
slide.shapes.add_chart(
    XL_CHART_TYPE.COLUMN_CLUSTERED,
    Inches(1), Inches(2), Inches(8), Inches(4.5), chart_data
)

# Table slide — product breakdown
products = data["products"]
slide = prs.slides.add_slide(prs.slide_layouts[5])
slide.shapes.title.text = "Product Performance"
tbl = slide.shapes.add_table(len(products) + 1, 3, Inches(1), Inches(2), Inches(8), Inches(3)).table
for j, h in enumerate(["Product", "Units", "Revenue"]):
    tbl.cell(0, j).text = h
for i, prod in enumerate(products):
    tbl.cell(i + 1, 0).text = prod["name"]
    tbl.cell(i + 1, 1).text = f"{prod['units']:,}"
    tbl.cell(i + 1, 2).text = f"${prod['revenue']:,.0f}"

prs.save("sales_report.pptx")
```

### Example 2: Batch-update branding across PPTX templates

**User request:** "Update the company name and logo across all our PPTX templates"

```python
import glob
from pptx import Presentation
from pptx.util import Inches

old_name, new_name = "OldCorp Inc.", "NewBrand Technologies"
new_logo = "assets/newbrand_logo.png"

for filepath in glob.glob("templates/*.pptx"):
    prs = Presentation(filepath)
    for slide in prs.slides:
        to_remove = []
        for shape in slide.shapes:
            if shape.has_text_frame:
                for para in shape.text_frame.paragraphs:
                    for run in para.runs:
                        if old_name in run.text:
                            run.text = run.text.replace(old_name, new_name)
            if shape.shape_type == 13 and shape.name.startswith("Logo"):
                to_remove.append((shape, shape.left, shape.top, shape.width, shape.height))
                slide.shapes.add_picture(new_logo, shape.left, shape.top, shape.width, shape.height)
        for shape, *_ in to_remove:
            shape._element.getparent().remove(shape._element)

    output = filepath.replace("templates/", "updated/")
    prs.save(output)
    print(f"Updated: {output}")
```

### Example 3: Extract presentation content to markdown

**User request:** "Extract all content from this PowerPoint into a markdown file"

```python
from pptx import Presentation

prs = Presentation("presentation.pptx")
md_lines = [f"# {prs.core_properties.title or 'Presentation'}\n"]

for i, slide in enumerate(prs.slides):
    md_lines.append(f"\n## Slide {i + 1}")
    for shape in slide.shapes:
        if shape.has_text_frame:
            for para in shape.text_frame.paragraphs:
                text = para.text.strip()
                if not text:
                    continue
                if para.level == 0 and shape == slide.shapes.title:
                    md_lines.append(f"\n### {text}")
                else:
                    md_lines.append(f"{'  ' * para.level}- {text}")
    if slide.has_notes_slide:
        notes = slide.notes_slide.notes_text_frame.text.strip()
        if notes:
            md_lines.append(f"\n> **Notes:** {notes}")

with open("extracted.md", "w") as f:
    f.write("\n".join(md_lines))
```

## Guidelines

- Always use `from pptx.util import Inches, Pt` for positioning — never raw EMU values unless doing precise math.
- When editing existing files, iterate `paragraph.runs` to preserve formatting. Setting `text_frame.text` directly destroys all existing font styles.
- Check available layouts with `enumerate(prs.slide_layouts)` before using hardcoded indices — they vary by template.
- For template-based generation, use placeholder shapes (`slide.placeholders[idx]`) rather than adding new shapes. This preserves the template's design.
- Start from professional templates (e.g., Slidesgo PPTX downloads) rather than blank presentations — the design quality will be significantly higher.
- python-pptx does not support animations, transitions, or embedded video. Create the base PPTX and instruct the user to add those in PowerPoint.
- When building tables, set column widths explicitly — auto-sizing is not supported and defaults produce uneven columns.
- Set `font.name` explicitly on every run when generating from scratch — default Calibri looks generic. Inter, Poppins, and Montserrat are free alternatives available via Google Fonts.
- Save to a new filename when editing to avoid corrupting the source file during development.
