【MATLAB】PowerPoint スライド作成自動化


# 概要

MATLAB の処理結果をまとめるのに PowerPoint を使う方向けのメモです。サンプルコードの1つとして役に立てばうれしいです。

:::note
PowerPoint のテンプレートを使った例はこちら：[テンプレート使って PowerPoint スライド作成自動化：MATLAB Report Generator 編](https://qiita.com/eigs/items/cb48fdcd741126d09def)
:::



この記事では、機械学習ではド定番のアヤメのデータを使って、複数のアルゴリズム検証結果をパワポに纏める ~~という体の~~ サンプルコードを紹介します。レポート作成に関わる単純な繰り返し作業を自動化する、そんな時のヒントになりますように。

自動生成したスライド例：
![Capture3.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149511/4b7ce491-156d-b2ce-c508-e46baaaf2a2c.png)


## 環境

- MATLAB R2019a
- Statistics and Machine Learning Toolbox*)

*) こちらは機械学習部分で使用しており、パワポの作成自体は MATLAB 本体だけでOKです。



# レポート生成作業は大変

処理結果を人に見せる資料にするときどうしていますか？

私は主に

- [Live Script (.mlx)](https://jp.mathworks.com/help/matlab/live-scripts-and-functions.html?s_eid=PSM_29435)のエクスポート
- [古いスクリプト（.m）のパブリッシュ](https://jp.mathworks.com/help/matlab/matlab_prog/publishing-matlab-code.html?s_eid=PSM_29435)

を使ってます。

どちらも MATLAB のコード・実行結果がそのまま反映されるので、コードとドキュメンテーションの管理が楽です。見せる相手によってはコードを隠して出力結果だけを表示するなどの設定にして PDF に出力＋メール添付が定番。~~これらを知る前はワードに１つ１つコピペしてました。~~


他にもパワポに図をまとめることが求められるケースありますが、コピペでやろうとするととにかく無駄が多い。プログラムを少し編集したら図も少し変わって、そのたびにコピペコピペ。。しまいにはどのバージョンのコードから出てきた図なのかわからないといった事態に。。とういうことで、パワポ作成を自動化する方法を調べてみました。

---

ちなみに Python では python-pptx というライブラリを使用して自動生成ができるようで、
以下の記事が MATLAB での方法をまとめてみようというきっかけになりました。

参照：[Qiita: Pythonを使ったレポートの自動作成【PowerPoint】【python-pptx】](https://qiita.com/kousakulog/items/34855cd8286bd4f33c08)

# いろんな選択肢があります

検索してみると既にいくつか COM サーバーを使った泥臭い方法が紹介されています。

- [MATLAB Answers: Mファイルスクリプト​によるPPTファイル​のスライドのコピー＆​ペースト](https://jp.mathworks.com/matlabcentral/answers/404115-m-ppt?s_eid=PSM_29435)
- [MATLAB Answers: PowerPoint へ画像を貼り付けるに​はどのようにすればよ​いですか？](https://jp.mathworks.com/matlabcentral/answers/99268-powerpoint?s_eid=PSM_29435)

他にもユーザー作成の関数も見つかりました。こちら中身をよく理解できていませんが、COMサーバーは使っていないみたいです。

- [File Exchange: MatLab tool for exporting data to PowerPoint 2007+ files without using COM-objects automation](https://jp.mathworks.com/matlabcentral/fileexchange/40277-exporttopptx?s_eid=PSM_29435)

組織内共通の方法で本格的にやるのであれば MATLAB Report Generator という選択肢もありますが・・・。

- [MATLAB Report Generator: プレゼンテーション ジェネレーターの作成](https://jp.mathworks.com/help/rptgen/ug/create-a-presentation-generator.html?s_eid=PSM_29435)


# Yet another example

特に新しい手法を紹介するわけじゃないんですが ~~例が多いに越したことはないと思いまして~~ ここでは泥臭く COM サーバーを使う方法で、各機械学習アルゴリズムの精度をパワポに纏めてみようと思います。


## 成果物：ExamplePresentation.pptx

パワポが張り付けられないので、キャプチャ画像でご勘弁を。同じ要領でループを回せば、何百ケース分でもパワポに結果をまとめることができます。


![Capture1.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149511/7bad6592-b364-db33-0d1f-494136209d52.png)

## コード

表示位置の調整が最初面倒です。h.Visible = 1 として出来栄えを確認しながら調整するのが吉かと。

```m:samplescript.m
%% PowerPointを開く
h = actxserver('PowerPoint.Application');
% PowerPointのウィンドウ表示（出来栄えの確認用）
h.Visible = 1; 

%% プレゼンテーションを追加
h.Presentation.invoke;
Presentation = h.Presentation.Add;

%% カスタムレイアウト読み込み
titleSlide = Presentation.SlideMaster.CustomLayouts.Item(1);
blankSlide = Presentation.SlideMaster.CustomLayouts.Item(2);

%% タイトルページ追加
Slide1 = Presentation.Slides.AddSlide(1,titleSlide);
Slide1.Shapes.Title.TextFrame.TextRange.Text = 'MATLAB -> PowerPoint 自動化';

%% 2ページ目以降、イメージを描画
methods = ["fitcnb","fitcsvm","fitctree","fitcknn"];
methodnames = ["ナイーブベイズ",...
    "サポートベクターマシン",...
    "決定木",...
    "ｋ近傍法"];
for ii=1:4
    newslide = Presentation.Slides.AddSlide(ii+1,blankSlide);
    newslide.Shapes.Title.TextFrame.TextRange.Text = [methodnames(ii) + "-" + methods(ii)];
    
    [loss, figH1, figH2] = checkClassificationPerformance(methods(ii));

    % 1つ目のFigureをコピペ
    print(figH1,'-dmeta','-r150')
  
    Image1 = newslide.Shapes.Paste;
    set(Image1, 'Left', 50) % 位置、大きさセット
    set(Image1, 'Top', 120)
    set(Image1, 'Width', 300)
    set(Image1, 'Height',300)
    
    % ２つ目のFigureをコピペ
    print(figH2,'-dmeta','-r150')
    
    Image2 = newslide.Shapes.Paste;
    set(Image2, 'Left',450)
    set(Image2, 'Top', 120)
    set(Image2, 'Width', 300)
    set(Image2, 'Height', 300)
    
    % Text 挿入 (Left, Top, Width, Height は TextBox の位置とサイズ)
    tmp = newslide.Shapes.AddTextbox('msoTextOrientationHorizontal',200,450,400,70);
    tmp.TextFrame.TextRange.Text = '混同行列';
    tmp = newslide.Shapes.AddTextbox('msoTextOrientationHorizontal',570,450,400,70);
    tmp.TextFrame.TextRange.Text = '散布図（ｘは不正解）';
    tmp = newslide.Shapes.AddTextbox('msoTextOrientationHorizontal',600,70,400,70);
    tmp.TextFrame.TextRange.Text = "Loss: " + string(loss);
end

%% プレゼンテーションを保存
Presentation.SaveAs([pwd '\ExamplePresentation.pptx']);

%% PowerPointを閉じる
h.Quit;
h.delete;
```

上記内で使っているのが以下、method に応じた（簡易的に4種類のみ）アルゴリズムをに対して5分割交差検定による混同行列、結果プロット、損失を返す関数

<details><summary>checkClassificationPerformance.m</summary><div>

```m:checkClassificationPerformance.m
function [loss, figH1, figH2] = checkClassificationPerformance(method)

% データ読み込み
s = load('fisheriris.mat');
X = s.meas(:,3:4);
Y = categorical(s.species);

switch method
    case 'fitcnb' % ナイーブベイズ
        Mdl = fitcnb(X,Y,...
            'ClassNames',{'setosa','versicolor','virginica'});
    case 'fitcsvm' % サポートベクタマシン
        Mdl = fitcecoc(X,Y,...
            'ClassNames',{'setosa','versicolor','virginica'});
    case 'fitctree' % 決定木
        Mdl = fitctree(X,Y,...
            'ClassNames',{'setosa','versicolor','virginica'});
    case 'fitcknn' % ｋ近傍法
        Mdl = fitcknn(X,Y,...
            'ClassNames',{'setosa','versicolor','virginica'});
    otherwise
        disp('not recognized');
end

% 交差検証済み (分割された) モデルを作成
CVMdl = crossval(Mdl,'KFold',5);
loss = kfoldLoss(CVMdl);
predictedLabels = kfoldPredict(CVMdl);

figH1 = figure(1); % 混同行列
cm = confusionchart(Y,categorical(predictedLabels));
cm.FontSize = 15;

figH2 = figure(2); % 散布図プロット
idx = Y == predictedLabels;
gscatter(X(~idx,1),X(~idx,2),Y(~idx),'rgb','x',8,'on');
hold on
gscatter(X(idx,1),X(idx,2),Y(idx),'rgb','.',18,'on');
hold off
title('Fisher''s Iris Data','FontSize',15);
xlabel('Petal Length (cm)','FontSize',13);
ylabel('Petal Width (cm)','FontSize',13);

grid on
```

</div></details>

# まとめ

COM サーバーを使う方法で機械学習アルゴリズムの精度をパワポに纏める例を紹介しました。

パワポのテンプレートを使うと位置合わせなどもうちょっと手軽にできると思いますが、それはまた今度。