LoginSignup
12
4

MATLABからEXCELに書き出す

Last updated at Posted at 2023-12-02

はじめに

 昨年のアドベントカレンダーで、『MATLABにファイルデータを書き出す関数』を投稿したわけですが、早いもので、もう1年経ちました。
本記事は、その続編で、EXCELに書き出すことに特化してまとめてあります。一部、重複があるかもしれません。

1.xlswriteでできることできないこと

1-1 xlswriteの概要

 xlswriteは古い関数であり、公式ページでは「非推奨」になっています。しかしながら「xlswriteを削除する予定はありません」ということも書いてあります。
xlswriteが非推奨の理由は、速度が遅いということがあるようですが、ここでは(速度については置いておいて)xlswriteで何ができるかについて述べます。

1-2 xlswriteによるEXCEL書き込み

まず、ファイル名が指定できます。これは当たり前ですが、xls, xlsx, xlsm, xlsbの拡張子を持つエクセルファイルを作成し、データを書き出すことができます。
次に、エクセルのセルに書き込む変数ですが、数値のみ、文字列のみ、混合の配列を書き込むことができます。混合配列を書き込む場合は、cell配列を使ってください。cell配列は、ざっくり言うと{ }で囲うことで作成することができます。
また、シート名をつけることができます。
そして、エクセルシートのどのセルに書くか(Range)を指定することができます。
ここまでをまとめてスクリプトに書くと次のようになります。

filename= 'test.xlsx';% ファイル名 拡張子がないと自動的に".xls"になる
A=magic(5);% 書き込むデータ
sheet='ABC';%書き込むシート
Range='B2';書き込む位置 省略した場合は左上がA1になる
xlswrite(filename,A,sheet,Range);%エクセルファイルに書き出し

シート名については、任意の名前をつけることができるのですが、'Sheet1'が強制的に作成されてしまいます。

WS000415.JPG

シート名を数値の4とすると、'Sheet1'から'Sheet3'までが勝手に挿入されてしまいます。シート名が'Sheet4'ならば、'Sheet1'のみの追加で済みます。

シートを指定しない場合で、書き込む位置を指定したい場合は、書き込む配列の対角の左上と右下を指定する必要があります。左上だけを指定した場合は、'A1'から書き込まれます。

filename="test.xlsx";% ファイル名 拡張子がないと自動的に".xls"になる
A=magic(5);% 書き込むデータ
Range='B2:F7';%書き込む位置 対角をの2点を指定する
xlswrite(filename,A,Range);%エクセルファイルに書き出し

対角の値と配列の大きさが異なる場合にはエラーは出ず、このようになります。

WS000416.JPG

同じファイル名で異なるシートに追記することができます。
例えば次の例では、'Sheet1'と'Sheet2'にそれぞれ書き込みができます。

filename="test.xlsx";% ファイル名 拡張子がないと自動的に".xls"になる
A=magic(5);% 書き込むデータ
sheet=2;%書き込むシート
Range='B2';%書き込む位置 省略した場合は左上がA1になる
xlswrite(filename,A,sheet,Range);%エクセルファイルに書き出し

B=magic(6);% 書き込むデータ
sheet=1;%書き込むシート
Range='C3';%書き込む位置 省略した場合は左上がA1になる
xlswrite(filename,B,sheet,Range);%エクセルファイルに書き出し

また、同じシートを指定して2回xlswriteを実行すると、上書きされます。

xlswriteでできることは、ここまでです。

2.writetable, writematrix,writecellで,できること&できないこと

2-1 新しい関数の概要

R2019aからはwritetable, writematrix,writecellという新しい書き込み関数が使えるようになりました。これにより実行速度の向上や、クロスプラットホームでの使用が可能になっています。
また、writetableは、表データを目的としたtable変数を書き込むのに特化しています。
これらの新しい関数において、xlswriteで不可能だったことについて説明します。

2-2 新しい関数の使い方

ここではwritematrixを用いて、エクセルファイルに書き込んでみます。

filename='test2.xlsx';% ファイル名 拡張子がないと自動的に"txt"になる
A=magic(5);% 書き込むデータ
sheet_n='ABC';%書き込むシート
range_n='B2';%書き込む位置 省略した場合は左上がA1になる
writematrix(A,filename,'Sheet',sheet_n,'Range',range_n);%エクセルファイルに書き出し 

ファイル名の拡張子は、エクセル系の拡張子をつけます。つけないと.txtになります。
また、xlswriteでは、引数の順番が「ファイル名,データ」だったのが、新しい関数では「データ,ファイル名」と逆になります(だからmatrixwriteでなくてwritematrixなのかも)。
その他のオプションは、「オプション名,その値」となります。
公式ドキュメント見ると、オプション名の1文字目は大文字になっていますが、今、やったところだと小文字でも行けます。でも、大文字にしておいたほうが無難と思います。
(ちなみにロー&コラムの指定も'B4'でなく、'b4'でも行けます)。

WS000411.JPG

「なんだか密度が濃くなってしまった」というのは列幅が自動で調整されたからです。
AutoFitWidth というオプションがあり、デフォルトでオンになっています。
自動調整しない場合は下記のように、ゼロを指定する、もしくはfalseを指定します。

writematrix(A,filename,'Sheet',sheet_n,'Range',range_n,'AutoFitWidth',0);%エクセルファイルに書き出し 

WS000410.JPG

見慣れた(?)感じになりました。

2-3 追記が可能になった

xlswriteだとデータは上書きされます。データを書き込んで、後で、追加のデータを同じシートに追記しようとしたとき(書き込む位置を指定します)、追記の位置を間違えると上書きして消してしまいかねません。
writematrixを使うと、同じシートのデータの後ろに書き足すことができます。
'WriteMode'というオプションに'append'を指定すればOKです(通常の上書きの場合は'WriteMode'は'inplace'で、これがデフォルトです)。

filename='test7.xlsx';% ファイル名 
A=magic(5);% 書き込むデータ
sheet_n='ABC';%書き込むシート
range_n='B2';%書き込む位置 省略した場合は左上がA1になる
writematrix(A,filename,'Sheet',sheet_n,'Range',range_n);%エクセルファイルに書き出し
% ここから追記
B=A+2;% 書き込むデータその2
writematrix(B,filename,'Sheet',sheet_n,'WriteMode','append');%エクセルファイルに書き出し 

ここで大事なのは、追記のときには'Range'オプションを指定しないことです。Rangeで指定された位置と、追記の位置のどちらに従えばよいかわからなくなるのでエラーが出ます。

2-4 余分なシートが追加されなくなる

新しい関数の場合には'Sheet1'が強制的に入ることはありません。必要なシートだけにできます。ここがxlswriteより進歩したところです。ただし、シートが1枚もないことは許されていません。
WS000410.JPG

3.新しい関数でのできないことへの対処

シート操作は、上記のことはできるようになりましたが、エクセル単体で普通にできる「シート名の変更」はできません。また、「特定のシートだけを削除」することもできません。
敢えて言うならエクセル上の全てのデータをMATLABに移して、新しいエクセルファイルに転記することになりますが、そこまでの大技は使わないでしょう。
この辺については、MATLABの中の人もいろいろ考えていると思うので、充実していくことを期待したいと思います。
とは言うものの、「今すぐにやりたいことがある」という方もおられるかと思います。
MATLAB公式ページを見ますと、activexを用いて、MATLABではできないところを補う方法が書かれています。
ここでは、足りないところ(具体的にはエクセルシートに画像を貼りこむ)をpythonの助けを用いてやる方法を説明します。

3-1 pythonの準備

やることを最低限書きますと、
 ・pythonのインストール
 ・openpyxlのインストール
です。この辺はpython関連のページをググっていただければと思います。凝った環境は不要で、最低限動けばよいです。openpyxlはpythonでエクセルを操作するライブラリです。
※一点、補足です。この記事執筆時点のpythonの最新バージョンは3.12ですが、MATLABの最新バージョンR2023bを使う場合には、3.11.x以前でないと動かないようです。

3-2 matlabとpythonのスクリプト

今、作業ディレクトリの中は、このようになっているとします。
image.png

MATLABとpythonのスクリプトがあり、fruitsフォルダの中には画像が入っています。
image.png

1)フォルダ名のfruitsというファイル名でエクセルファイルをつくる(fruits.xlsx)
2)シートを作成し、画像の名前をシート名とする
3)それぞれのシートに画像を貼りこむ
という内容を行ないます。

まず、MATLABのスクリプトです。

create_excel.m
foldername='fruits';% フォルダ名指定
DIRn=append(foldername,'\');
files=dir([DIRn '*.png']);% 中の.pngファイルをリストアップ

fnum=length(files);% 画像ファイルの数

xlsname=[foldername '.xlsx'];% 作成するエクセルの名前

for t=1:fnum % 画像ファイルの数だけ回す
    filefields=files(t);
    fname=[DIRn filefields.name];
    IMdisp=imread(fname);% 画像読み出し

    TextA = {fname};% シートに書き込む文字
    image_file=filefields.name;% 画像ファイルの名前
    dum=split(image_file,'.');
    fill_sheet=dum{1};% 書き込むシートの名前
    % ファイルオープン&¥シート作成&書き込み
    writecell(TextA,xlsname,'Sheet',fill_sheet,'Range','A3','AutoFitWidth',0);

    % コマンド発行&python実行
    comd=append("paint_image_excel.py ",xlsname," ",fill_sheet," ",image_file);
    pyrunfile(comd);
end

最後の部分で、"pyrunfile"という関数を使って、pythonスクリプトを呼び出しています。

続いて呼び出される側のpythonのスクリプトです。

paint_image_excel.py
## paint_image_excel.py
import os
import argparse
import openpyxl
from openpyxl.drawing.image import Image
from openpyxl.utils import get_column_letter


def main(excel_file_name, sheet_name, image_file): 
    # エクセルファイルの有無を確認
    if not os.path.isfile(excel_file_name):
        print(f"Error: '{excel_file_name}' not found")
        exit()

    # エクセルファイルを読み込む
    workbook = openpyxl.load_workbook(excel_file_name)

    # シート名の指定
    sheet = workbook[sheet_name]

    # セルに文字を書き込む場合は、このようにする
    directory = "fruits/" 
    # とりあえずrowを指定してみた
    row = 12
    sheet.cell(column=1, row=row).value = directory

    img = Image(os.path.join(directory, image_file))

    # 画像と位置を指定し、画像を貼りこむ(位置はB15)
    sheet.add_image(img, 'B15')

    # workbookの保存
    workbook.save(excel_file_name)

if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument("excel_file_name", help="使用する既存のExcelファイル名")
    parser.add_argument("sheet_name", help="画像を貼りこむシート名")
    parser.add_argument("image_name", help="画像名")
    args = parser.parse_args()
    main(args.excel_file_name, args.sheet_name, args.image_name)

3-3 スクリプトの実行

さて、MATLABのスクリプトを実行してみますと、エクセルのファイルが生成されます。

image.png

こんな感じにシートが生成できています。
ExcelMOV.gif

4.終わりに

以上、MATLABからEXCELに書き出す方法(その2)をまとめてみました。
間違いとか、「こんな使い方もある」がありましたら、お知らせいただけると幸いです。

12
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
4