Pythonからグラフと表の入ったパワポを自動生成する

## ライブラリのインポート
まずはパワポ操作に必要なライブラリをインポートします。

```
from pptx import Presentation
from pptx.util import Inches, Pt
from glob import glob #画像データの読み込み

import pandas as pd #パワポに載せる表のためのデータ操作
```

## パワポの作成
パワポに貼り付けるデータはすでに作成しているものとします。
![boxplot1.png](https://qiita-image-store.s3.amazonaws.com/0/195884/19f9be72-b3e9-49b3-3166-59a36fa43d50.png)

```
fnms = glob("./materials/*.png") #画像データのディレクトリ
prs = Presentation("./template/template.pptx") #テンプレートのパワポがあれば指定でき、スライドマスターを活用できます。

#タイトルスライドの挿入
title_slide_layout = prs.slide_layouts[0]
slide = prs.slides.add_slide(title_slide_layout)
#目次スライドの挿入
index_slide_layout = prs.slide_layouts[1]
slide = prs.slides.add_slide(index_slide_layout)
```
*prs.slide_layouts*ではスライドマスターからレイアウトを指定します。
slide_layouts[0]はスライドマスターの上から二個目のレイアウト、slide_layouts[1]は上から三個目のレイアウトです。
*prs.slides.add_slide*で指定したレイアウトのスライドを挿入します。

<img width="845" alt="スクリーンショット 2019-03-25 11.42.36.png" src="https://qiita-image-store.s3.amazonaws.com/0/195884/619406bb-8564-eea5-6a63-3a40b59b3ac5.png">


```
var = ['var1', 'var2', 'var3', 'var4', 'var5', 'var6',
       'var7', 'var8', 'var9', 'var10', 'var11', 'var12', 'var13', 'var14',
       'var15', 'var16', 'var17', 'var18', 'var19', 'var20', 'var21', 'var22',
       'var23', 'var24']

for i,t in zip(fnms,[var[:12],var[12:]]): 
 # 表に挿入する数値データに集計データを使用するため、集計列を指定しておきます。
 # 読み込んだ画像の１枚目と集計列の1つ目(var[:12])は同じデータを対象としています。２枚目はvar[12:]のデータ
 blank_slide_layout = prs.slide_layouts[2]
 slide = prs.slides.add_slide(blank_slide_layout)
 # 画像の挿入
 left = Inches(0.34) # スライドの左端からの距離（インチ）
 top = Inches(1.54) # スライドの上端からの距離（インチ）
 pic = slide.shapes.add_picture(i,left,top,width=Inches(6.8),height=Inches(2.9))
~
```
画像をスライドのどこに配置するかは*left*、*top*で指定します。
位置の指定が難しい場合は、パワポの図形の書式設定->位置から確認できますので、cmをインチに変換してください。
<img width="768" alt="スクリーンショット 2019-03-22 18.50.36.png" src="https://qiita-image-store.s3.amazonaws.com/0/195884/93facd70-a6ac-1306-1927-9cc08ce59a2b.png">

```
~
 # 表に挿入するデータ（中央値）の作成
 d=data.groupby("status")[t].median().loc[order]

 # 表の挿入
 shapes = slide.shapes
 rows = len(d)+1
 cols = len(d.columns)+1
 left = Inches(0.34)
 top = Inches(4.5)
 width = Inches(6.84)
 height = Inches(0.8)
 table = shapes.add_table(rows,cols,left,top,width,height).table
```
*shapes.add_table*でスライドにテーブルを挿入します。
*groupby*を使って表に挿入する数値データを作成しています。
集計対象の列は上のfor文で指定しています。
*groupby*した集計データのindexは事前に出力している箱ひげ図の順番に合わせた方が見やすいため、*.loc[]*を使って順番を指定しています。
```
 # ヘッダーの挿入
 run = table.cell(0,0).text_frame.paragraphs[0].add_run()
 table.cell(0,0).margin_left\
  = table.cell(0,0).margin_right\
  = table.cell(0,0).margin_top\
  = table.cell(0,0).margin_bottom\
  = 0

 run.text = "中央値"
 font = run.font
 font.name = "メイリオ"
 font.size = Pt(12)
```
テーブルに入れるテキストや書式は*run*オブジェクトを使ってセルごとに指定する必要があります。
*table.cell(0,0)*はテーブルの左上のセルを参照します。
タプルの左側は行、右側は列を指定します。
*margin_left(_right, _top, _bottom)はセル内の余白を指定します。
*run.font*でフォントやサイズを指定できます。

```
# ヘッダーの挿入続き
    for i,c in enumerate(d.columns):
        run = table.cell(0,i+1).text_frame.paragraphs[0].add_run() # 表の2列目から1行目を埋めていく
        table.cell(0,i+1).margin_left\
            = table.cell(0,i+1).margin_right\
            = table.cell(0,i+1).margin_top\
            = table.cell(0,i+1).margin_bottom\
            = 0
        run.text = c
        font = run.font
        font.name = "メイリオ"
        font.size = Pt(9)

        # 中央値の挿入
        for g in range(len(d)):
            run = table.cell(g+1,i+1).text_frame.paragraphs[0].add_run() # 表の2行2列目からデータを埋めていく
            table.cell(g+1,i+1).margin_left\
                = table.cell(g+1,i+1).margin_right\
                = table.cell(g+1,i+1).margin_top\
                = table.cell(g+1,i+1).margin_bottom\
                = 0
            run.text = "{:.3f}".format(d[c][g])
            font = run.font
            font.name = "メイリオ"
            font.size = Pt(9)
```
表のヘッダー（1行目）はgroupbyしたデータの列名を入れていきます。
表の2行2列目以降はgroupbyしたデータの数値を入れていきます。

```
# インデックスの挿入
    for j,k in enumerate(d.index):
        run = table.cell(j+1,0).text_frame.paragraphs[0].add_run() # 表の2行目から1列目を埋めていく
        table.cell(j+1,0).margin_left\
            = table.cell(j+1,0).margin_right\
            = table.cell(j+1,0).margin_top\
            = table.cell(j+1,0).margin_bottom\
            = 0
        run.text = k
        font = run.font
        font.name = "メイリオ"
        font.size = Pt(9)

# パワポの保存
prs.save("test.pptx")
```
表のインデックス（1列目）はgroupbyしたデータのインデックス名を入れていきます。
最後にファイル名を指定して保存します。

## 最終的なアプトプット
<img width="738" alt="スクリーンショット 2019-03-25 11.44.51.png" src="https://qiita-image-store.s3.amazonaws.com/0/195884/62f8406e-8ac5-018e-a1f6-caeff809732b.png">
読み込んだ箱ひげ図と各チームの中央値の入った表が貼り付けられた報告書が出来上がりました。

以上