【2026年版・コード全文】Claude Code × Excel × PowerPoint で月次KPIから取締役会pptxを自動生成する完全手順(openpyxl + python-pptx)

この記事をシェア:
目次 クリックで開く

「経営企画はExcelで数字を更新する」「広報・経営層はPowerPointで報告を見る」——この2つを毎月の取締役会前夜に手転記でつないでいる組織は珍しくありません。本記事では Claude Code × python-pptx × openpyxl で、Excelの月次KPIから取締役会用 PowerPoint をワンコマンドで生成する仕組みを解説します。

この記事のゴールmonthly_kpi.xlsx(経営企画が更新する1ファイル)に対し python build_excel_to_pptx.py を実行するだけで、表紙・KPIサマリー(カード+グラフ)・ハイライト/リスクスライドの3枚の .pptx が自動生成される再現可能な構成を理解する。
目次

  1. 「Excel数字 → PowerPoint転記」の隠れた工数
  2. 完成イメージ
  3. 処理フロー:openpyxl で読み、python-pptx で書く
  4. 守るべき3つの原則(Excel側)
  5. 完成スクリプト全文
  6. 応用:BIダッシュボード連動・自動配布・差分通知
  7. FAQ

1. 「Excel数字 → PowerPoint転記」の隠れた工数

取締役会前日の典型的な作業:

  • Excelで集計した売上・粗利・受注件数をPowerPoint表紙にコピペ
  • 5か月推移をグラフにし、PowerPointへ画像貼付(解像度劣化)
  • 当月コメント(ハイライト/リスク)をテキストボックスに転記
  • 翌月、最新月分を全部やり直し

1セットあたり約60〜90分。年間12回 × 全社部署で計算すると、無視できない工数になります。

2. 完成イメージ

monthly_kpi.xlsx を入力に Claude Code が3スライドの月次取締役会pptxを自動生成するフロー
左:経営企画が更新する monthly_kpi.xlsx(KPIシート + コメントシート)/右:自動生成された monthly_board_report.pptx の3スライド。

3. 処理フロー

ステップ 処理 ライブラリ
1 monthly_kpi.xlsx の KPI / コメントシートを読み込み pandas + openpyxl
2 表紙スライド:当月の売上・粗利率を強調表示 python-pptx
3 KPIスライド:4枚カード + 5か月クラスタ縦棒 python-pptx (CategoryChartData)
4 コメントスライド:ハイライト緑 / リスク黄 python-pptx (Rounded Rectangle)
5 監査用に生成日時・ソースファイル名をフッター挿入 標準ライブラリ

4. 守るべき3つの原則(Excel側)

  1. シート名と列名は固定:「KPI」「コメント」シート、列名 月 / 売上(千円) / 粗利率 / 新規受注 / 解約率 を変えない
  2. 1行 = 1か月のロングフォーマット:転記時にピボットしないで済む
  3. コメントは末尾行を最新:スクリプトは iloc[-1] で当月分を取得

Excel側を「データの単一の真実」として扱うことで、以後はスクリプトを叩くだけで PowerPoint が更新されます。

5. 完成スクリプト全文

"""Excel → PowerPoint:月次KPIをExcelから読んで月次報告pptxを自動生成する。

Real-world flow:
  1. 経営企画が monthly_kpi.xlsx を更新
  2. python build_excel_to_pptx.py を実行
  3. 月次取締役会pptxが自動でできあがる(数字・グラフ・コメント反映済み)
"""
from pathlib import Path
import pandas as pd
import openpyxl
from pptx import Presentation
from pptx.util import Inches, Pt, Emu
from pptx.dml.color import RGBColor
from pptx.chart.data import CategoryChartData
from pptx.enum.chart import XL_CHART_TYPE
from pptx.enum.shapes import MSO_SHAPE

ROOT = Path(__file__).parent
XLSX = ROOT / "monthly_kpi.xlsx"
PPTX = ROOT / "monthly_board_report.pptx"


# 1) Build sample monthly_kpi.xlsx ---------------------------------------
def build_kpi_xlsx():
    wb = openpyxl.Workbook()
    ws = wb.active; ws.title = "KPI"
    ws.append(["月", "売上(千円)", "粗利率", "新規受注", "解約率"])
    rows = [
        ("2026-01", 142_300, 0.421, 18, 0.018),
        ("2026-02", 138_900, 0.418, 15, 0.022),
        ("2026-03", 156_700, 0.435, 22, 0.015),
        ("2026-04", 168_400, 0.442, 25, 0.013),
        ("2026-05", 175_200, 0.448, 28, 0.012),
    ]
    for r in rows: ws.append(r)
    ws2 = wb.create_sheet("コメント")
    ws2.append(["月", "ハイライト", "リスク"])
    ws2.append(["2026-05",
                "新規受注 28件で過去最高、製造業セグメントが牽引",
                "Software B 解約率は低下したが、契約更新時期が6月に集中"])
    wb.save(XLSX)
    print(f"[gen] {XLSX.name}")


# 2) Build pptx from xlsx ------------------------------------------------
NAVY = RGBColor(0x1E, 0x3A, 0x8A)
SLATE = RGBColor(0x0F, 0x17, 0x2A)
GRAY = RGBColor(0x64, 0x74, 0x8B)


def add_title_slide(prs, kpi_df, comments):
    slide = prs.slides.add_slide(prs.slide_layouts[6])  # blank
    bg = slide.shapes.add_shape(MSO_SHAPE.RECTANGLE, 0, 0, prs.slide_width, prs.slide_height)
    bg.fill.solid(); bg.fill.fore_color.rgb = NAVY
    bg.line.fill.background()
    tx = slide.shapes.add_textbox(Inches(0.6), Inches(2.2), Inches(12), Inches(1.2)).text_frame
    tx.text = "月次取締役会 報告  2026年5月"
    tx.paragraphs[0].runs[0].font.size = Pt(40)
    tx.paragraphs[0].runs[0].font.color.rgb = RGBColor(0xFF, 0xFF, 0xFF)
    tx.paragraphs[0].runs[0].font.bold = True
    tx2 = slide.shapes.add_textbox(Inches(0.6), Inches(3.6), Inches(12), Inches(0.8)).text_frame
    last_row = kpi_df.iloc[-1]
    tx2.text = f"売上 ¥{int(last_row['売上(千円)']*1000):,}  ・  粗利率 {last_row['粗利率']*100:.1f}%  ・  新規受注 {int(last_row['新規受注'])}件"
    tx2.paragraphs[0].runs[0].font.size = Pt(20)
    tx2.paragraphs[0].runs[0].font.color.rgb = RGBColor(0xC7, 0xD2, 0xFE)


def add_kpi_slide(prs, kpi_df):
    slide = prs.slides.add_slide(prs.slide_layouts[6])
    title = slide.shapes.add_textbox(Inches(0.4), Inches(0.2), Inches(12), Inches(0.7)).text_frame
    title.text = "1. 主要KPI 推移(5か月)"
    title.paragraphs[0].runs[0].font.size = Pt(26); title.paragraphs[0].runs[0].font.bold = True
    title.paragraphs[0].runs[0].font.color.rgb = SLATE
    # KPI cards (4)
    last = kpi_df.iloc[-1]; prev = kpi_df.iloc[-2]
    cards = [
        ("売上", f"¥{int(last['売上(千円)']*1000):,}", f"前月比 +{(last['売上(千円)']/prev['売上(千円)']-1)*100:.1f}%"),
        ("粗利率", f"{last['粗利率']*100:.1f}%", f"前月差 +{(last['粗利率']-prev['粗利率'])*100:.1f}pt"),
        ("新規受注", f"{int(last['新規受注'])}件", f"前月差 +{int(last['新規受注']-prev['新規受注'])}件"),
        ("解約率", f"{last['解約率']*100:.1f}%", f"前月差 −{(prev['解約率']-last['解約率'])*100:.1f}pt"),
    ]
    for i, (label, value, delta) in enumerate(cards):
        x = Inches(0.4 + i*3.15); y = Inches(1.1)
        box = slide.shapes.add_shape(MSO_SHAPE.ROUNDED_RECTANGLE, x, y, Inches(3.0), Inches(1.6))
        box.fill.solid(); box.fill.fore_color.rgb = RGBColor(0xF1, 0xF5, 0xF9)
        box.line.color.rgb = RGBColor(0xCB, 0xD5, 0xE1)
        tf = box.text_frame; tf.text = label
        tf.paragraphs[0].runs[0].font.size = Pt(11); tf.paragraphs[0].runs[0].font.color.rgb = GRAY
        p = tf.add_paragraph(); p.text = value
        p.runs[0].font.size = Pt(22); p.runs[0].font.bold = True; p.runs[0].font.color.rgb = SLATE
        p2 = tf.add_paragraph(); p2.text = delta
        p2.runs[0].font.size = Pt(10); p2.runs[0].font.color.rgb = RGBColor(0x05, 0x96, 0x69)
    # Bar chart
    chart_data = CategoryChartData()
    chart_data.categories = list(kpi_df["月"])
    chart_data.add_series("売上 (千円)", list(kpi_df["売上(千円)"]))
    cx, cy = Inches(0.4), Inches(3.0); cw, ch = Inches(12.4), Inches(4.2)
    slide.shapes.add_chart(XL_CHART_TYPE.COLUMN_CLUSTERED, cx, cy, cw, ch, chart_data)


def add_comment_slide(prs, comments):
    slide = prs.slides.add_slide(prs.slide_layouts[6])
    title = slide.shapes.add_textbox(Inches(0.4), Inches(0.2), Inches(12), Inches(0.7)).text_frame
    title.text = "2. 当月ハイライト & リスク"
    title.paragraphs[0].runs[0].font.size = Pt(26); title.paragraphs[0].runs[0].font.bold = True
    title.paragraphs[0].runs[0].font.color.rgb = SLATE

    # Highlights box
    hb = slide.shapes.add_shape(MSO_SHAPE.ROUNDED_RECTANGLE,
                                Inches(0.4), Inches(1.2), Inches(6.2), Inches(5.8))
    hb.fill.solid(); hb.fill.fore_color.rgb = RGBColor(0xEC, 0xFE, 0xF0)
    hb.line.color.rgb = RGBColor(0x86, 0xEF, 0xAC)
    htf = hb.text_frame; htf.word_wrap = True
    htf.text = "■ ハイライト"
    htf.paragraphs[0].runs[0].font.size = Pt(16); htf.paragraphs[0].runs[0].font.bold = True
    htf.paragraphs[0].runs[0].font.color.rgb = RGBColor(0x05, 0x96, 0x69)
    p = htf.add_paragraph(); p.text = comments["ハイライト"]
    p.runs[0].font.size = Pt(14); p.runs[0].font.color.rgb = SLATE

    # Risk box
    rb = slide.shapes.add_shape(MSO_SHAPE.ROUNDED_RECTANGLE,
                                Inches(6.8), Inches(1.2), Inches(6.2), Inches(5.8))
    rb.fill.solid(); rb.fill.fore_color.rgb = RGBColor(0xFE, 0xF3, 0xC7)
    rb.line.color.rgb = RGBColor(0xFB, 0xBF, 0x24)
    rtf = rb.text_frame; rtf.word_wrap = True
    rtf.text = "■ リスク・注意点"
    rtf.paragraphs[0].runs[0].font.size = Pt(16); rtf.paragraphs[0].runs[0].font.bold = True
    rtf.paragraphs[0].runs[0].font.color.rgb = RGBColor(0xD9, 0x77, 0x06)
    p = rtf.add_paragraph(); p.text = comments["リスク"]
    p.runs[0].font.size = Pt(14); p.runs[0].font.color.rgb = SLATE


def main():
    build_kpi_xlsx()
    kpi = pd.read_excel(XLSX, sheet_name="KPI")
    cm = pd.read_excel(XLSX, sheet_name="コメント").iloc[-1].to_dict()

    prs = Presentation()
    prs.slide_width = Inches(13
# ... (略) ...

6. 応用パターン

6-1. BIダッシュボード連動

monthly_kpi.xlsx を BigQuery / Snowflake への SELECT 結果に置き換え、pandas-gbqsnowflake-connector-python で直接読み込めば、Excel配布も不要になります。

6-2. SharePoint / OneDrive 自動配布

生成 .pptx を requests + Microsoft Graph API で取締役会フォルダに自動アップロード。前月版は archive/ へ移動。Outlook通知とセットで運用すれば「取締役会前夜に資料を作る」作業そのものが消えます。

6-3. 差分通知(前月比サマリ)

当月生成と同時に、前月Excelとの差分(売上±◯%、解約率±◯pt)を Slack / Teams にWebhook通知。「数字を見る前にハイライトが届く」体験になります。

7. FAQ

Q1. PowerPointのテンプレ(社内ブランド)に合わせたい

A. Presentation("brand_template.pptx") で開いてレイアウト名で slide_layouts.get_by_name(...) 指定すれば、社内ブランドそのままに数字だけ流し込めます。

Q2. グラフは Excel 側で作って画像で貼ったほうが速いのでは?

A. CategoryChartData を使えば PowerPoint ネイティブのグラフが入り、後から色変更・データ修正が GUI 上で可能です。画像貼り付けと違って劣化しません。

Q3. 月次以外(週次・四半期)にも適用できる?

A. KPI シートの「月」列を「週」「四半期」に変えるだけで再利用可能です。グラフ軸ラベルも自動追従します。

Q4. PowerPoint Online でしか動かない要素(モーフ遷移など)は?

A. python-pptx は OOXML 構造を直接編集できるため、生成済み .pptx に対して PowerPoint Online で開いて遷移を加える運用がシンプル。テンプレ化しておけば、毎月の手作業はゼロのまま見栄えが上がります。

Q5. 監査要件で「いつ生成したか」を残したい

A. core_properties.author / created を python-pptx で書き込めます。本記事のスクリプトに prs.core_properties.author = "Auto-generated by Claude Code" を追加するだけで監査ログ要件を満たせます。

8. 上位記事との差別化:自動転記の運用品質

8-1. KPI閾値による自動コメント・自動色分け

「前月比+5%以上は緑」「-3%以下は赤」のような業務ルールを実装すると、人間がpptxを開く前に異常が一目で分かります。

delta = (this_month - last_month) / last_month
if delta > 0.05: color = RGBColor(0x05, 0x96, 0x69); comment = "好調"
elif delta < -0.03: color = RGBColor(0xDC, 0x26, 0x26); comment = "要対策"
else: color = RGBColor(0x64, 0x74, 0x8B); comment = "横這い"

8-2. ネイティブChart挿入 vs 画像貼付

方式 長所 短所
CategoryChartData(ネイティブ) 後からPowerPoint上で色変更可、解像度劣化なし 複雑なグラフは限定的
matplotlibでPNG生成→画像貼付 表現力高い(ヒートマップ・サンキー等) 後修正不可、解像度依存

8-3. 既存テンプレを壊さないプレースホルダー設計

会社標準の取締役会テンプレ(.pptx)を Presentation("brand_template.pptx") で開き、名前付きプレースホルダー(例 idx=10 = 売上数値)だけ書き換える設計だと、フォント・ロゴ・余白を壊しません。

8-4. 設定駆動(YAML/JSON)でKPI追加を非エンジニア化

# kpi_config.yaml
slides:
  - title: 主要KPI
    metrics:
      - {name: 売上, source: KPI!B, format: "¥{:,}k", threshold_up: 0.05}
      - {name: 粗利率, source: KPI!C, format: "{:.1%}", threshold_up: 0.01}

経営企画がKPIを追加する際、YAMLを編集するだけで pptx に新カードが追加されます。Pythonコードに触れさせないことで運用が継続します。

8-5. 数値の桁区切り・単位整形ルール

「¥48,000,000」「¥4,800万円」「¥0.48億円」のどれを採用するかは社内ルールに従い、format 文字列で統一。混在は読み手の認知負荷になります。

関連記事(クラスター)

本記事は「AI業務自動化完全ガイド」のクラスター記事です。Excel・PowerPoint・Outlook・Teams 各領域の Claude Code 実装サンプルを上記ガイドからまとめて参照できます。

AI・業務自動化

ChatGPT・Claude APIを活用したAIエージェント開発、n8n・Difyによるワークフロー自動化で繰り返し業務を削減します。まずはどの業務をAI化できるか診断します。

AT
aurant technologies 編集

上場企業からスタートアップまで、数多くのデータ分析基盤構築・AI導入プロジェクトを主導。単なる技術提供にとどまらず、MA/CRM(Salesforce, Hubspot, kintone, LINE)導入によるマーケティング最適化やバックオフィス業務の自動化など、常に「事業数値(売上・利益)」に直結する改善実績多数。

この記事が役に立ったらシェア: