【MATLAB】Excel 内での計算結果を更新させる方法


はじめに

Excel シートに MATLAB から何らかの値を出力して、Excel を開くことなくその値に対して Excel 内で何らかの計算処理を同時にさせたい。そんな時には 'UseExcel' オプションを使うといいよというお話。

Twitter で豆腐さんど (@tohu_sand) とのやり取りをしたので、Qiita にも備忘録としてまとめておくことにします。

'UseExcel' オプションは R2019b からはデフォルトで 'false' ですが、それまでは Excel が使える環境であれば 'true' であったという点には要注意。リリースノートへのはこちら: UseExcel。なので R2019a 以前を使っている場合は、特に意識する必要はないと思います。

この記事の Livescript 版(MATLAB)は GitHub: ActiveX-Excel-MATLAB1 に置いてあります。

使用環境

  • MATLAB R2020b

やりたいこと

例えばこんな感じ。

Code
data = rand(5,5);
writematrix(data,'example.xlsx','Range','A2:E6');

MATLAB から入力値を出力し、総和は Excel で計算する。(これくらいの計算であれば MATLAB でやってしまえ・・という話もありますがあくまで例です。)

Excel への出力の仕方によっては、改めて Excel ファイルを開かないと A9 の総和が更新されない。

値が更新されないとは?

A2:E6 の範囲にあたらしい値を MATLAB から出力しても、そのままでは Excel 側の A9 の値が変わらない現象です。

例えば新しいデータを書き出したあと Excel 内での処理結果(A9)を確認すると

Code
data = rand(5,5);
writematrix(data,'example.xlsx','Range','A2:E6');
readmatrix('example.xlsx','Range','A9:A9')
Output
ans = 12.6398
Code
sum(data,'all')
Output
ans = 12.0239

と値が異なるというか、A9 の値が更新されないという落とし穴。

もちろん Excel ファイルを開けば結果は更新されるんですが、いちいち開くのも面倒くさい場合もあると思います。

なんで更新されない?

最近は xlsread 関数xlswrite 関数は非推奨となっている(なんで xlswrite が非推奨?)いて、代わりに writematrix 関数writetable 関数 などの使用が薦められています。

ちなみに xlswrite 関数を使うとちゃんと更新されます。

Code
data = rand(5,5);
xlswrite('example.xlsx',data,'A2:E6');
readmatrix('example.xlsx','Range','A9:A9')
Output
ans = 11.9684
Code
sum(data,'all')
Output
ans = 11.9684

大丈夫ですね。

これは xlswrite 関数は(Excel がインストールされている環境であれば)実行時に Excel を起動するから。Excel が起動すると Excel 内の計算を実行することになります。xlswrite 関数が非推奨な大きな理由はこの Excel を起動する処理に時間がかかるためと見ています。writematrix 関数などの比較的新しい関数は(R2019b 以降のデフォルトの設定では) Excel アプリを介することなくデータを出力します。

参考:ちなみに自動計算を停止させるよう設定も可能 See. Anyway to turn off Excel automatic calculation by a MatLab command for faster export ?

ではどうするか

Excel を起動してしまえばよいのかなと。他にも良い方法があればコメントください。

方法1

writematrix 関数には 'UseExcel' というオプションがあり何も指定しなければ 'false'、すなわち Excel を使用しません。ここを 'true' に変更することで解決します。

Code
data = rand(5,5);
writematrix(data,'example.xlsx','Range','A2:E6','UseExcel',true);
readmatrix('example.xlsx','Range','A9:A9')
Output
ans = 13.7890
Code
sum(data,'all')
Output
ans = 13.7890

大丈夫ですね。総和(A9)もしっかり更新されています。

方法2

上で既にみた方法ですが xlswrite 関数も非推奨ではありますが必要があれば使ってもいいでしょう(個人的見解)。xlswrite 関数を使うことで Excel が起動され、計算結果も更新されます。

ここでは処理時間を比較してみます。

Code
tic
writematrix(data,'example.xlsx','Range','A2:E6','UseExcel',true);
toc
Output
経過時間は 0.390221 秒です。
Code
tic
xlswrite('example.xlsx',data,'A2:E6');
toc
Output
経過時間は 0.185799 秒です。

5x5 の行列であれば xlswrite 関数の方が速いみたいですね。

結果は載せていませんがデータ量が大きくなれば writematrix 関数の方が有利でした。同然の事ながら 'UseExcel' = false (既定の設定) の方がもちろん速いです。

Code
tic
writematrix(data,'example.xlsx','Range','A2:E6','UseExcel',false);
toc
Output
経過時間は 0.017237 秒です。

方法3

もう十分かと思いますが、他の選択肢も一応ご紹介します。ActiveX 経由で Excel を一度起動させてしまう・・。

Code
data = rand(5,5);
writematrix(data,'example.xlsx','Range','A2:E6');

tic
ExcelApp = actxserver('Excel.Application'); 
ExcelFile = ExcelApp.Workbooks.Open(fullfile(pwd,'\example.xlsx')); 
ExcelFile.Save; 
ExcelFile.Close; 
ExcelApp.Quit;
toc
Output
経過時間は 2.573898 秒です。
Code
readmatrix('example.xlsx','Range','A9:A9')
Output
ans = 11.5360
Code
sum(data,'all')
Output
ans = 11.5360

欲しい結果になっていますが、これは時間がかかるので NG ですね。

まとめ

データの出力には write* 系の関数がよさそうです。

MATLAB からファイルに出力する関数としては最近は

などが推奨されています。同様に csvwrite 関数も R2019a 以降「非推奨」の文字が出るようになりましたね。


  1. Livescript から markdown への変換は livescript2markdown​: MATLAB's live scripts to markdown を使っています。