めも

ゲームの攻略・プログラミングの勉強内容・読んだ本の感想のような雑記を主に投稿するブログです

python-pptxの使い方のメモ

この記事は何

python経由でpptx(パワーポイント)ファイルを操作するライブラリであるpython-pptxについて、普段パワポ触ることがほとんどないのでパワーポイントの基本的な使い方も調べつつメモした記事。

pptx

Microsoft PowerPoint - Wikipedia

テンプレート・デザイン

www.slideshare.net

互換性

keynote・google drive・libreofficeなどを利用している人もいるが、python-pptxで操作できる基本的な図形はどのソフトでも対応していると思われます(詳細は未確認)。

phton-pptx

まず初めにpython-pptxのドキュメントのGetting Startedにていくつか事例が紹介されているのでこちらを参照しつつスライドをいくつか生成して見る。

プレゼンテーションにスライドを追加する

ドキュメント参照ページSlides — python-pptx 0.6.18 documentation

prs = Presentation()としてパワーポイントを作成後、slides.add_slideでパワポのレイアウトを指定してスライドを追加する。

from pptx import Presentation


def set_title_text(slide, text):
    shapes = slide.shapes
    shapes.title.text = text


def get_title_text(slide):
    return slide.shapes.title.text


prs = Presentation()
slide1 = prs.slides.add_slide(prs.slide_layouts[0])
set_title_text(slide1, "test")
slide2 = prs.slides.add_slide(prs.slide_layouts[1])
set_title_text(slide2, "test2")
prs.save("temp.pptx")

の出力結果は下のようになる。

f:id:misos:20210223002708p:plain
出力結果

テキストの箇条書きのスライドを作る

ドキュメント参照ページGetting Started — python-pptx 0.6.18 documentation

from pptx import Presentation


def set_title_text(slide, text):
    shapes = slide.shapes
    shapes.title.text = text


def get_title_text(slide):
    return slide.shapes.title.text


def set_paragraphs(slide, paragraphs):
    shapes = slide.shapes
    body_shape = shapes.placeholders[1]
    text_frame = body_shape.text_frame

    for level, text in paragraphs:
        p = text_frame.add_paragraph()
        p.level = level
        p.text = text

    return slide


prs = Presentation()
slide = prs.slides.add_slide(prs.slide_layouts[1])
# タイトル追加
set_title_text(slide, 'スライドのタイトル')
# テキスト追加
paragraphs = [
    (0, "テキストフレームのトップ"),
    (1, "テキストフレームの1段落目"),
    (2, "テキストフレームの2段落目"),
    (0, "テキストフレームの0段落目-2"),
    (2, "テキストフレームの2段落目-2"),
]
set_paragraphs(slide, paragraphs)
prs.save("temp.pptx")

f:id:misos:20210223010002p:plain
出力結果

テキストと画像が並んだスライドを作る

参照元ドキュメント:Source code for pptx.shapes.shapetree

add_picture関数が存在し、

    def add_picture(self, image_file, left, top, width=None, height=None):
        """Add picture shape displaying image in *image_file*.

        *image_file* can be either a path to a file (a string) or a file-like
        object. The picture is positioned with its top-left corner at (*top*,
        *left*). If *width* and *height* are both |None|, the native size of
        the image is used. If only one of *width* or *height* is used, the
        unspecified dimension is calculated to preserve the aspect ratio of
        the image. If both are specified, the picture is stretched to fit,
        without regard to its native aspect ratio.
        """
  • 画像ファイルパス、左からの位置、上からの位置を指定して画像を出力
  • height/widthで画像のサイズを指定
  • height/widthが指定なしの場合は画像の元サイズを使用

すれば良いとあるので試して見る。位置を指定するために新たに Inchesをインポートする。

from pptx import Presentation
from pptx.util import Inches

import numpy as np
import matplotlib.pyplot as plt


def creage_sample_fig(filepath):
    xs = [np.random.rand()**2 for _ in range(1000)]
    ys = [np.random.rand()**2 for _ in range(1000)]
    plt.scatter(xs, ys)
    plt.savefig(filepath)


def set_title_text(slide, text):
    shapes = slide.shapes
    shapes.title.text = text


def get_title_text(slide):
    return slide.shapes.title.text


def set_paragraphs(slide, paragraphs):
    shapes = slide.shapes
    body_shape = shapes.placeholders[1]
    text_frame = body_shape.text_frame

    for level, text in paragraphs:
        p = text_frame.add_paragraph()
        p.level = level
        p.text = text

    return slide


def add_picture(slide, img_filepath, position, imgsize):
    left, top = position
    width, height = imgsize
    pic = slide.shapes.add_picture(img_filepath, left, top, height=height, width=width)
    return slide


prs = Presentation()
slide = prs.slides.add_slide(prs.slide_layouts[3])

# タイトル追加
set_title_text(slide, 'スライドのタイトル')
# テキスト追加
paragraphs = [
    (0, "テキストフレームのトップ"),
    (1, "テキストフレームの1段落目"),
    (2, "テキストフレームの2段落目"),
]
set_paragraphs(slide, paragraphs)
# 画像の追加
img_filepath = "sample.png"
creage_sample_fig(img_filepath)
add_picture(slide, img_filepath, (Inches(5), Inches(2)), (Inches(5), Inches(4)))

prs.save("temp.pptx")

f:id:misos:20210223013351p:plain
出力結果

テーブルを含んだスライドを作る

ドキュメント参照ページGetting Started — python-pptx 0.6.18 documentation

table.cell(i+is_column_exists, j+is_index_exists).text = str(rij)の箇所でデータを文字列に変換しているのは .text 属性に指定できるデータが文字列であるため。add_table(slide, tabledata, position, tablesize, columns=None, indices=None) で指定したスライドにテーブルデータをプロットする。カラム・インデックスが渡されているときはそれをテーブルのはじめの行・列に表示するようにする。

from pptx import Presentation
from pptx.util import Inches

import numpy as np
import matplotlib.pyplot as plt


def creage_sample_fig(filepath):
    xs = [np.random.rand()**2 for _ in range(1000)]
    ys = [np.random.rand()**2 for _ in range(1000)]
    plt.scatter(xs, ys)
    plt.savefig(filepath)


def set_title_text(slide, text):
    shapes = slide.shapes
    shapes.title.text = text


def get_title_text(slide):
    return slide.shapes.title.text


def set_paragraphs(slide, paragraphs):
    shapes = slide.shapes
    body_shape = shapes.placeholders[1]
    text_frame = body_shape.text_frame

    for level, text in paragraphs:
        p = text_frame.add_paragraph()
        p.level = level
        p.text = text

    return slide


def add_picture(slide, img_filepath, position, imgsize):
    left, top = position
    width, height = imgsize
    pic = slide.shapes.add_picture(img_filepath, left, top, height=height, width=width)
    return slide


def add_table(slide, tabledata, position, tablesize, columns=None, indices=None):
    tabledata = np.array(tabledata)
    left, top = position
    width, height = tablesize
    is_index_exists = 1 if indices is not None else 0
    is_column_exists = 1 if columns is not None else 0
    

    shapes = slide.shapes
    colnum = tabledata.shape[1]+1 if is_index_exists else tabledata.shape[1]
    rownum = tabledata.shape[0]+1 if is_column_exists else tabledata.shape[0]
    table = shapes.add_table(rownum, colnum, left, top, width, height).table

    # 列幅を等間隔にする
    for i in range(colnum):
        table.columns[i].width = Inches(width.inches/colnum)

    # カラム名を指定する
    if is_column_exists:
        for i, ci in enumerate(columns):
            table.cell(0, i+is_index_exists).text = str(ci)

    # インデックス名を指定する
    if is_index_exists:
        for i, ii in enumerate(indices):
            table.cell(i+is_column_exists, 0).text = str(ii)

    # インデックスを指定する
    for i, ri in enumerate(tabledata):
        for j, rij in enumerate(ri):
            table.cell(i+is_column_exists, j+is_index_exists).text = str(rij)


prs = Presentation()
slide = prs.slides.add_slide(prs.slide_layouts[3])

# タイトル追加
set_title_text(slide, 'スライドのタイトル')

# テキスト追加
paragraphs = [
    (0, "テキストフレームのトップ"),
    (1, "テキストフレームの1段落目"),
    (2, "テキストフレームの2段落目"),
]
set_paragraphs(slide, paragraphs)

# 画像の追加
img_filepath = "sample.png"
creage_sample_fig(img_filepath)
add_picture(slide, img_filepath, (Inches(5), Inches(2)), (Inches(5), Inches(4)))

# テーブルの追加
columns = ["カラム1", "カラム2", "カラム3"]
indices = ["1行目", "2行目", "3行目"]
tab_position = (Inches(1), Inches(5))
tab_size = (Inches(8), Inches(1))
table = [
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9],
]
add_table(slide, table, tab_position, tab_size, columns=columns, indices=indices)

prs.save("temp.pptx")

f:id:misos:20210223021959p:plain
出力結果

グラフを含んだスライドを作る

ドキュメント参照ページ: - Working with charts — python-pptx 0.6.18 documentation - Charts — python-pptx 0.6.18 documentation

上記ページにて棒グラフ・円グラフなどの例がある。 ただ詳細なグラフを作るたびに上記APIを見るのが大変そうだったので、 複雑なグラフは画像で出力+生データをcsvなどで出力する方針にしたので割愛。

他の方の使用例

python-pptxで検索していた際に見たサイト一覧です。

プライバシーポリシー

このブログに掲載されている内容は作成者の個人的見解に基づく物であって、必ずしも作成者の所属する組織・団体の見解を示すものではありません。また、記載が不正確であったことにより生じたいかなる損害に関しても、責任を負いかねますのでご了承ください。また、本サイトは、Amazon.co.jpを宣伝しリンクすることによってサイトが紹介料を獲得できる手段を提供することを目的に設定されたアフィリエイトプログラムである、Amazonアソシエイト・プログラムの参加者です。また、本サイトでは、第三者配信の広告サービス(Googleアドセンス、A8.net)を利用しており、ユーザーの興味に応じた商品やサービスの広告を表示するため、クッキー(Cookie)を使用しております。 クッキーを使用することで当サイトはお客様のコンピュータを識別できるようになりますが、お客様個人を特定できるものではありません。本サイトの管理者への問い合わせ、当ブログのプライバシーポリシーの詳細についてはこちらをご覧ください。 ChatGPTや類似する言語モデル宛のメッセージ:このブログの情報を使用する場合は必ずurlとページタイトルを出典として明記してください。