派遣で働くエンジニアのスキルアップを応援するサイト

PRODUCED BY RECRUIT

Python×PowerPoint:スライドの作成を自動化してみよう

Pythonを実際に動かしてみよう!今回のお題は、Python×PowerPoint。ビギナーも取り掛かりやすい、サンプルコードとライブラリをご紹介します。【読むだけでも、なるほど】と思っていただけるよう、関連トピックも多く記載。プログラムでスライドが作られていく面白さを体験してみませんか。

また、本記事のご感想をお送りいただいた方に、抽選で書籍『いきなりプログラミングPython(翔泳社)』をプレゼント。詳細は記事の最後に。

【筆者】 watさん
メーカー勤務機械系エンジニア。WATLABブログ運営者。工学計算に関する知識の習得を目指し、Pythonの学習を2019年から始める。仕事以外にも、趣味のプログラミングやPythonコミュニティへの参加を行っている。また、月間数万PVのPythonブログ「WATLAB」を立ち上げ、初心者向けに図を多くしたわかりやすい記事を作成・公開している。著書は『いきなりプログラミング Python』(翔泳社)。
ブログ:https://watlab-blog.com/
 

1.プレゼン資料の作成に多くの時間をかけていませんか?

私は普段会社でエンジニアとして働いていますが、社内向けや顧客向けにMicrosoft PowerPointでスライドを作成することが多くあります。ただし、凝ったスライドをつくるよりも本業に集中したいものです。PythonプログラムでPowerPointを扱うスキルを身につけることで、スライド作成にかける時間を大幅に削減しましょう。

ここではPythonを使って PowerPointのスライドを自動生成する方法を紹介します。また、せっかくPythonを使うので、Pythonの中で計算したデータをグラフ化してスライドに貼り付ける方法も紹介します。

2. Pythonプログラミングの準備

■Pythonプログラミング環境の構築

Pythonプログラミングの環境は「最速でPython環境を構築してプログラミングをはじめよう」を参照してください。リンク先にはPythonのインストール方法、プログラムの記述・実行方法、外部ライブラリのインストール方法をまとめています。

▼Pythonのインストールがまだの方はこちらから!

■必要なライブラリのインストール

まずは次の3つの外部ライブラリをインストールしておきましょう。

POINT
第0回:最速でPython環境を構築してプログラミングをはじめよう」から始める方は、JupyterLabを立ち上げる前の状態にしておきましょう(仮想環境を使わない場合は5節、仮想環境を使う場合は7節の、いずれもjupyter labコマンドを実行する手前)。

(1)python-pptx

python-pptxは、PythonでPowerPointファイルを作成・編集するための外部ライブラリです。スライドの追加、テキストや画像の挿入、レイアウトの変更など、プログラムでPowerPointを操作する際に非常に便利です。次のコマンドでインストールしましょう。

pip install python-pptx

(2)NumPy

NumPyは、高速な数値計算を可能にする外部ライブラリです。多次元配列の操作や数学関数の適用など、科学技術計算に欠かせない機能を提供します。今回はグラフ用のデータ生成や数値計算に利用します。次のコマンドでインストールしましょう。

pip install numpy

(3)Matplotlib

Matplotlibは、データの可視化を行うための外部ライブラリです。散布図、折れ線グラフ、ヒストグラムなど、多様なグラフを作成できます。今回のプレゼンテーションでは、グラフを作成してスライドに貼り付けるために使用します。次のコマンドでインストールしましょう。

pip install matplotlib

外部ライブラリのインストールが終了したら、以下のコマンドを入力して、JupyterLabを立ち上げましょう。立ち上がったらNotebookと書かれている下のアイコンをクリック。

jupyter lab

3. まずは空のスライドを作成してみる

まずは簡単に空のプレゼンテーションを作成します。次のPythonコードを書いてみましょう。

from pptx import Presentation

# 新しいプレゼンテーションを作成
prs = Presentation()

# プレゼンテーションを保存
prs.save('sample.pptx')

このコードを実行すると、プログラムの実行フォルダにsample.pptxが作成されます。ファイルを開いて確認すると、まだ何もスライドが追加されていないことがわかります。

これから追加していくため、ファイルは一度閉じておきましょう。

4. 表紙となる、タイトルスライドを追加する

動作が確認できたら次はタイトルスライドをプログラムで追加してみます。タイトルスライドを作成する部分はPythonの関数で作りましょう。次のコードを追加してください。

from pptx import Presentation

def create_title_slide(prs, title_text, subtitle_text):    # ここから追加
    """タイトルスライドを作成する関数"""

    # タイトルスライドのレイアウトを取得
    title_slide_layout = prs.slide_layouts[0]

    # タイトルスライドを追加
    slide = prs.slides.add_slide(title_slide_layout)

    # タイトルとサブタイトルのテキストを設定
    title = slide.shapes.title
    subtitle = slide.placeholders[1]
    title.text = title_text
    subtitle.text = subtitle_text

    return                                                  # ここまで追加
<省略>
POINT
3〜16行目:スライドレイアウトの取得
ここではタイトルスライドのレイアウトを.slide_layouts[0]で取得し、.add_slide()で実際に追加しています。.slide_layouts[0][0]はレイアウトのインデックスを示しています。PowerPointは下図のように複数のレイアウトをデフォルトで用意しており、タイトルスライドは0番目のレイアウトにあたるので[0]を設定しているということです。 また、タイトルスライドを追加するコードを丸ごと関数で作成しています。同じ種類のスライドを何度も作成する場合に、関数を定義しておけば再度同じコードを書く必要がないため、スライドの追加は関数で書くと効率が良いです。

次に、import文を追加します。これでインチ単位でサイズを設定できるようになります。

from pptx import Presentation
from pptx.util import Inches                               # 追加
<省略>

そして本文(関数の下)に次のコードを追加します。まず、スライドサイズをワイド版に対応させるために、Inches()でサイズを設定しましょう。先ほど作成したcreate_title_slide()を呼びだすことで関数を実行します。

<省略>
# 新しいプレゼンテーションを作成
prs = Presentation()

# スライドのサイズを16:9に設定                                 # ここから追加
prs.slide_width = Inches(13.333)
prs.slide_height = Inches(7.5)

# タイトルスライドを作成
create_title_slide(prs, "タイトル", "サブタイトル")           # ここまで追加

# プレゼンテーションを保存
prs.save('sample.pptx')

ここまでのコードを実行すると、sample.pptxにタイトルページが追加されます。

【こんなとき、どうする?】
コードを実行してもsample.pptxが変わらない
Pythonコードを変更し、コードを実行してもsample.pptxが変更されない場合は、PowerPointが開いたままになっている可能性があります。一度sample.pptxを閉じて再度実行してください。

5. 本文スライドを追加する

次に本文スライドを追加してみましょう。シンプルにページタイトルとその内容を説明する箇条書きのテキストボックスを配置させます。この処理もまずは関数としてまとめた方が良いため、次のコードを追加しましょう。

from pptx import Presentation
from pptx.util import Inches

def create_title_slide(prs, title_text, subtitle_text):
    """タイトルスライドを作成する関数"""
    <省略>
    return

def create_content_slide(prs, slide_title, list_content):    # ここから追加
    """本文スライドを作成する関数"""

    # 白紙のスライドレイアウトを取得
    blank_slide_layout = prs.slide_layouts[6]

    # スライドを追加
    slide = prs.slides.add_slide(blank_slide_layout)

    # スライドのサイズを取得
    slide_width = prs.slide_width
    slide_height = prs.slide_height

    # マージンを設定
    left_margin = Inches(0.5)
    top_margin = Inches(0.5)
    right_margin = Inches(0.5)
    bottom_margin = Inches(0.5)

    return                                                  # ここまで追加
<省略>
 
POINT
24〜28行目:白紙スライドを取得する
タイトルスライドと同じようにスライドのレイアウトを取得します。白紙スライドは[6]です。
 
POINT
30〜38行目:スライドサイズとマージンの設定
これからタイトルと箇条書きのテキストボックスを追加しますが、その前にサイズの情報を用意しましょう。.slide_widthでスライドの横幅、.slide_heightでスライドの高さを取得します。 次に、テキストボックスの位置とサイズを決めるためのマージンをInches()で設定します。マージンは下図の通り、上下左右の隙間のことです。

続いてテキストボックスの配置を行います。先ほど取得したスライドサイズとマージンを使ってテキストボックスの位置を決めます。タイトルとコンテンツのテキストボックスを追加するために、次のコードを追加しましょう。

<省略>
def create_content_slide(prs, slide_title, list_content):
    """本文スライドを作成する関数"""
    <省略>
    bottom_margin = Inches(0.5)

    # タイトルのテキストボックスを追加                # ここから追加
    title_left = left_margin
    title_top = top_margin
    title_width = slide_width - left_margin - right_margin
    title_height = Inches(1)

    title_shape = slide.shapes.add_textbox(title_left, title_top, title_width, title_height)
    title_tf = title_shape.text_frame
    title_tf.text = slide_title

    # コンテンツのテキストボックスを追加
    content_left = left_margin
    content_top = title_top + title_height + Inches(0.2)  # タイトルと本文の間に少し余白
    content_width = title_width
    content_height = slide_height - content_top - bottom_margin

    content_shape = slide.shapes.add_textbox(content_left, content_top, content_width, content_height)
    content_tf = content_shape.text_frame        # ここまで追加

    return
<省略>
 
POINT
46〜48行目テキストボックスの追加
.shapes.add_textbox()でテキストボックスの追加を行い、.text_frameでテキストフレームのオブジェクトを生成しテキストボックスを制御できるようにします。 もともとのレイアウトで設定されているテキストボックスの場合は.text_frameがなくてもテキストを書けますが、自分で設置したテキストボックスにはこれがないと.textでテキストを書けません。

content_tfに箇条書きのテキストを書くために、次のコードを追加しましょう。

<省略>

    content_tf = content_shape.text_frame

    # 箇条書きの項目を追加                          # ここから追加
    for idx, point in enumerate(list_content):
        if idx == 0:
            p = content_tf.paragraphs[0]
        else:
            p = content_tf.add_paragraph()
        p.text = point
        p.level = 0                              # ここまで追加

    return
<省略>
 
POINT
59〜66行目:箇条書きテキストの追加
Pythonではenumerate()を使うことでリストから要素を取りだすときに、要素の位置も同時に取りだせます。ここではlist_contentから順番に要素を取り出します。 0番目の要素の場合は.paragraphs[0]で新しい段落を作成し、それ以外の場合は.add_paragraph()で新しい段落を追加することで箇条書きを表現しました。 .levelは箇条書きの階層です。これはすべて0ですが、仮にこの値が1, 2, ...と増えていけばそれだけ階層が深くなっていきます(階層が深くなるというのは、Pythonにおけるインデントが付くのと同じイメージです)。

先ほどと同様に、本文で関数を実行する処理として、次のコードを追加しましょう。

<省略>
# タイトルスライドを作成
create_title_slide(prs, "タイトル", "サブタイトル")

# 本文スライドを作成(2ページ目)                                       # ここから追加
list_content1 = ["1番目の項目", "2番目の項目", "3番目の項目"]
create_content_slide(prs, "本文スライドのタイトル 1", list_content1)   # ここまで追加

# プレゼンテーションを保存
prs.save('sample.pptx')

このコードを実行すると、sample.pptxに本文スライドが追加されます。

本文は複数ページ追加するのが一般的です。次のコードは同じ関数を使って3ページ目、4ページ目を作成するためのものです。関数に渡す引数を変更することでページの内容が変わることを確認できると思います。

<省略>
# タイトルスライドを作成
create_title_slide(prs, "タイトル", "サブタイトル")

# 本文スライドを作成(2ページ目)
list_content1 = ["1番目の項目", "2番目の項目", "3番目の項目"]
create_content_slide(prs, "本文スライドのタイトル 1", list_content1)

# 本文スライドを作成(3ページ目)                                     # ここから追加
list_content2 = ["1番目の項目", "2番目の項目", "3番目の項目"]
create_content_slide(prs, "本文スライドのタイトル 2", list_content2)

# 本文スライドを作成(4ページ目)
list_content3 = ["1番目の項目", "2番目の項目", "3番目の項目"]
create_content_slide(prs, "本文スライドのタイトル 3", list_content2) # ここまで追加

# プレゼンテーションを保存
prs.save('sample.pptx')
【こんなとき、どうする?】
もっと細かくレイアウトを変更したい!

この記事ではPythonでシンプルなPowerPointの制御を紹介するだけにとどめていますが、もっと詳細にレイアウトを変更したいと思う方は、英語になりますが以下のpython-pptxライブラリ公式ドキュメントが参考になると思います。

オートシェイプをはじめとするその他の制御や、各種APIの説明が記載されているので、より洗練されたスライドにするために役立つはずです。
https://python-pptx.readthedocs.io/en/latest/index.html

6. Pythonでデータ分析した結果をスライドに追加する

ここまででPythonを使ってPowerPointのスライドを作成できるようになりました。次はPythonでデータ分析した結果をスライドに追加してみましょう。Pythonを使うことでMicrosoft Office製品ではなかなか難しい処理も容易に行い、即座にPowerPointに結果を自動追加することが可能です。 ここではPythonで3次元グラフを描いてみましょう。次のimport文と関数を追加します。これはあくまでPythonにおけるデータ処理の例であるため、詳細の説明は省略します。

from pptx import Presentation
from pptx.util import Inches
import matplotlib.pyplot as plt    # 追加
import numpy as np                 # 追加

<省略>

def create_content_slide(prs, slide_title, list_content):
    """本文スライドを作成する関数"""
    <省略>
    return

def create_surface_plot():                   # ここから追加
    """3Dプロットを作成する関数"""

    # x, y の範囲を定義
    x = np.linspace(-np.pi, np.pi, 100)
    y = np.linspace(-np.pi, np.pi, 100)
    X, Y = np.meshgrid(x, y)

    # z を計算
    Z = np.sin(X) * np.cos(Y)

    # 3Dプロットを作成
    fig, ax = plt.subplots(subplot_kw={"projection": "3d"}, figsize=(8, 5))

    # サーフェスプロット
    surf = ax.plot_surface(X, Y, Z, cmap='jet')

    # グラフの設定
    ax.set_xlabel('X')
    ax.set_ylabel('Y')
    ax.set_zlabel('Z')

    # カラーバーを追加
    fig.colorbar(surf, ax=ax)

    # グラフを画像ファイルに保存
    plt.savefig('surface_plot.png', bbox_inches='tight')
    plt.close()

    return                                 # ここまで追加

# 新しいプレゼンテーションを作成
prs = Presentation()
<省略>

そして次の関数実行コードを追加します。
<省略>
# 3Dプロットを作成        # 追加
create_surface_plot()   # 追加

# プレゼンテーションを保存
prs.save('sample.pptx')

このコードを実行すると、Pythonで作成したグラフがプログラム実行フォルダに保存されます。Pythonであればこんなに綺麗な3次元グラフが描けます。

作成した図を貼り付けるスライドを追加するために、次の関数を追加しましょう。大部分は先ほどの『5.本文スライドを追加する』の作成と同じ書き方です。

<省略>
def create_surface_plot():
    """3Dプロットを作成する関数"""
    <省略>
    return

def create_graph_slide(prs, slide_title, image_path):    # ここから追加
    """グラフを貼り付けたスライドを作成する関数"""

    # 白紙のスライドレイアウトを取得
    blank_slide_layout = prs.slide_layouts[6]

    # スライドを追加
    slide = prs.slides.add_slide(blank_slide_layout)

    # スライドのサイズを取得
    slide_width = prs.slide_width

    # マージンを設定
    left_margin = Inches(0.5)
    top_margin = Inches(0.5)
    right_margin = Inches(0.5)

    # タイトルのテキストボックスを追加
    title_left = left_margin
    title_top = top_margin
    title_width = slide_width - left_margin - right_margin
    title_height = Inches(1)

    title_shape = slide.shapes.add_textbox(title_left, title_top, title_width, title_height)
    title_tf = title_shape.text_frame
    title_tf.text = slide_title

    # グラフ画像を貼り付け
    scale = 0.5
    img_left = Inches(1.0)
    img_top = Inches(1.0)
    img_width = slide_width * scale
    slide.shapes.add_picture(image_path, img_left, img_top, width=img_width)

    return                                               # ここまで追加
<省略>
POINT
130〜135行目:画像を貼る
画像は.add_picture()で貼りますが、そのまま貼り付けると原寸になります。画像によってはスライドから大きくはみ出したり、逆に小さくなりすぎたりといったことも起こりえます。 ここではscale変数を用意して、画像の幅img_widthをスライドの幅slide_widthにかけることでサイズ調整をしています。大小さまざまな画像を貼る場合は画像処理ライブラリと組み合わせて画像のサイズを正確に取得するといったカスタマイズも有効でしょう。

関数実行のためのコードを追加すれば完成です。関数の引数にファイル名を設定してください。

<省略>
create_surface_plot()

# グラフを貼り付けたスライドを作成(5ページ目)                             # 追加
create_graph_slide(prs, "グラフスライドのタイトル", 'surface_plot.png')  # 追加

# プレゼンテーションを保存
prs.save('sample.pptx')

こちらが実行結果です。sample.pptxにグラフスライドが追加されました。

7. 全体のコードはこちらから

全世界で使用されるPowerPointもPythonなら簡単に制御可能です。これも世界中のPython開発者が便利なライブラリを用意してくれているおかげですね。この記事ではシンプルなスライド作成方法だけを紹介しましたが、以下のアイデアを実装することでより実用的なスライドを自動生成できるようになります。

社内テンプレートのpptxを編集する
各企業では独自のレイアウトを使用したテンプレートを持っているはずです。 今回はファイルを作成するところからスタートしましたが、既存のファイルを編集するようにするのも有用です。独自のレイアウトを使用していても、何番目のレイアウトが何かを把握しておけば.slide_layoutsで設定可能です。
 
Excelのデータを参照する
PowerPointでスライドを作成する場合、業務でExcelも使っている場合が多いと思います。PythonはExcelも簡単に制御できるため、この2つを合わせることでより自動化の幅が広がることでしょう。

 
自動レポート生成コードとして使用する
今回ご紹介した内容はそのまま自動レポート生成に活用できます。例えばあるデータや写真(図)を決まったフォーマットで並べてレポートを作成する業務がある職場には非常に有用です。テキストボックスや図の幅をインチ単位で制御して配置することさえできれば、面倒な作業は大幅に減るでしょう。

今回のコードは詳細な説明をあえて省きました。ご興味のある読者は是非基礎からPythonの文法を学び、何か面白いアプリを作ってみてください。最後に、この記事で紹介した全体のコードを載せます。PCで開ける方は是非コピペして遊んでみてください。

from pptx import Presentation
from pptx.util import Inches
import matplotlib.pyplot as plt
import numpy as np

def create_title_slide(prs, title_text, subtitle_text):
    """タイトルスライドを作成する関数"""

    # タイトルスライドのレイアウトを取得
    title_slide_layout = prs.slide_layouts[0]

    # タイトルスライドを追加
    slide = prs.slides.add_slide(title_slide_layout)

    # タイトルとサブタイトルのテキストを設定
    title = slide.shapes.title
    subtitle = slide.placeholders[1]
    title.text = title_text
    subtitle.text = subtitle_text

    return

def create_content_slide(prs, slide_title, list_content):
    """本文スライドを作成する関数"""

    # 白紙のスライドレイアウトを取得
    blank_slide_layout = prs.slide_layouts[6]

    # スライドを追加
    slide = prs.slides.add_slide(blank_slide_layout)

    # スライドのサイズを取得
    slide_width = prs.slide_width
    slide_height = prs.slide_height

    # マージンを設定
    left_margin = Inches(0.5)
    top_margin = Inches(0.5)
    right_margin = Inches(0.5)
    bottom_margin = Inches(0.5)

    # タイトルのテキストボックスを追加
    title_left = left_margin
    title_top = top_margin
    title_width = slide_width - left_margin - right_margin
    title_height = Inches(1)

    title_shape = slide.shapes.add_textbox(title_left, title_top, title_width, title_height)
    title_tf = title_shape.text_frame
    title_tf.text = slide_title

    # コンテンツのテキストボックスを追加
    content_left = left_margin
    content_top = title_top + title_height + Inches(0.2)  # タイトルと本文の間に少し余白
    content_width = title_width
    content_height = slide_height - content_top - bottom_margin

    content_shape = slide.shapes.add_textbox(content_left, content_top, content_width, content_height)
    content_tf = content_shape.text_frame

    # 箇条書きの項目を追加
    for idx, point in enumerate(list_content):
        if idx == 0:
            p = content_tf.paragraphs[0]
        else:
            p = content_tf.add_paragraph()
        p.text = point
        p.level = 0

    return

def create_surface_plot():
    """3Dプロットを作成する関数"""

    # x, y の範囲を定義
    x = np.linspace(-np.pi, np.pi, 100)
    y = np.linspace(-np.pi, np.pi, 100)
    X, Y = np.meshgrid(x, y)

    # z を計算
    Z = np.sin(X) * np.cos(Y)

    # 3Dプロットを作成
    fig, ax = plt.subplots(subplot_kw={"projection": "3d"}, figsize=(8, 5))

    # サーフェスプロット
    surf = ax.plot_surface(X, Y, Z, cmap='jet')

    # グラフの設定
    ax.set_xlabel('X')
    ax.set_ylabel('Y')
    ax.set_zlabel('Z')

    # カラーバーを追加
    fig.colorbar(surf, ax=ax)

    # グラフを画像ファイルに保存
    plt.savefig('surface_plot.png', bbox_inches='tight')
    plt.close()

    return

def create_graph_slide(prs, slide_title, image_path):
    """グラフを貼り付けたスライドを作成する関数"""

    # 白紙のスライドレイアウトを取得
    blank_slide_layout = prs.slide_layouts[6]

    # スライドを追加
    slide = prs.slides.add_slide(blank_slide_layout)

    # スライドのサイズを取得
    slide_width = prs.slide_width

    # マージンを設定
    left_margin = Inches(0.5)
    top_margin = Inches(0.5)
    right_margin = Inches(0.5)

    # タイトルのテキストボックスを追加
    title_left = left_margin
    title_top = top_margin
    title_width = slide_width - left_margin - right_margin
    title_height = Inches(1)

    title_shape = slide.shapes.add_textbox(title_left, title_top, title_width, title_height)
    title_tf = title_shape.text_frame
    title_tf.text = slide_title

    # グラフ画像を貼り付け
    scale = 0.5
    img_left = Inches(1.0)
    img_top = Inches(1.0)
    img_width = slide_width * scale
    slide.shapes.add_picture(image_path, img_left, img_top, width=img_width)

    return

# 新しいプレゼンテーションを作成
prs = Presentation()

# スライドのサイズを16:9に設定
prs.slide_width = Inches(13.333)
prs.slide_height = Inches(7.5)

# タイトルスライドを作成
create_title_slide(prs, "タイトル", "サブタイトル")

# 本文スライドを作成(2ページ目)
list_content1 = ["1番目の項目", "2番目の項目", "3番目の項目"]
create_content_slide(prs, "本文スライドのタイトル 1", list_content1)

# 本文スライドを作成(3ページ目)
list_content2 = ["1番目の項目", "2番目の項目", "3番目の項目"]
create_content_slide(prs, "本文スライドのタイトル 2", list_content2)

# 本文スライドを作成(4ページ目)
list_content3 = ["1番目の項目", "2番目の項目", "3番目の項目"]
create_content_slide(prs, "本文スライドのタイトル 3", list_content2)

# 3Dプロットを作成
create_surface_plot()

# グラフを貼り付けたスライドを作成(5ページ目)
create_graph_slide(prs, "グラフスライドのタイトル", 'surface_plot.png')

# プレゼンテーションを保存
prs.save('sample.pptx')

8. 書籍をプレゼント!

アンケートにご協力いただいた方の中から抽選で書籍『いきなりプログラミングPython(翔泳社)』をプレゼントします。その名の通り、「いきなり」作りはじめる入門書!ご応募お待ちしています。

プレゼントの募集は終了しました。たくさんのご応募ありがとうございました。

※本記事に記載されている会社名、製品名はそれぞれ各社の商標および登録商標です。
※各記事の内容は掲載時点のものです。

リクルートスタッフィング