FC2ブログ

初心者によるMATLABメモ

3次元形状やってんのになぜかMATLABを使わされることになった人のメモ。

 

検索エンジンから来た方は読みたい記事が表示されていない可能性があります。
その場合、左メニューのフォームでブログ内を検索すると見たい記事を見れると思います。
もしくは、カテゴリー名をクリックしていただくと各カテゴリーの記事のリストが見れます。

[Graphics] FigureのメタファイルをWord2000で正しく表示させる

2007/02/03 よく考えるとパスに半角スペースとか混ざってると動かないことに気づいたので修正。ファイルも差し替えた。

なんだがよくわかりませんが,MATLABのFigureをメタファイル(EMF)形式でWord 2000に挿入すると、縦書き文字が文字化けします。
例えばFigureウインドウでこう↓表示されているものが…
FIGUREウインドウ

Word2000に挿入するとこう↓なってしまいます。
WORD2000にemf


これはこのように↓サイバネットのページにも書いてある問題で,解決策が載ってるのか?と思いきや,
MATLAB:テクニカルFAQ Figureウィンドウの表示結果をEMF形式でMicrosoft Word 2000に挿入すると、縦書き文字が文字化けしてしまいます。:サイバネットシステム

参照リンク↓を見るといちいち編集しろ!とのこと。
[WD2000] Word 97 文書を開くとグラフの Y 軸ラベルの文字の向きが変更される

しかし,いちいち編集しろというのも酷な話。
というか「今更Word2000使うなよ!」というのがもっともな話なんですが,僕みたいに未だにWord2000を使っている人もいるはず。

で,僕が解決策。
一応,コマンドラインで強制的にベーシックなwmfに変換してやると大丈夫(っぽい。というか僕はそれで困っていない…)
以下手順。(一応面倒な人はmファイルとかひとまとめでここにある1番のzipファイルに収めてありますのでDLしてください。)

まず準備として下記をしてください。(上記zipファイルをDLした人はsetup.cmdをダブルクリックすれば下記が実行されます.ペイントでout.wmfが開けばオッケー。saveaswmf.mをMATLABのパスが通ってるところに保存すればMATLAB上で動くはずです。)
  1. The Code Projectのemf2wmfをここからダウンロード。
    EMF to WMF conversion using GDI+ - The Code Project - GDI+
  2. 解凍して適当にWindowsのパスが通ってるところにemf2wmf.exeをコピー。(C:WINDOWSの下で問題ない。)
  3. emf2wmfが動くかを確認する。滞りなく実行できれば,emf2wmfがきちんと動くかと思います。
基本的には,これを実行するれば問題ありません。ただ,いちいちこんなのを実行していたらたまったものではありません。
そこで下記のようなmファイルを作ります。
保存先はMATLAB上でパスが通っているところがよいです。
(よくわからない人は例えばC:Program FilesMATLABR2006bworklib内にsaveaswmf.mを保存してaddpath('C:Program FilesMATLABR2006bworklib')とする。)
function saveaswmf(filepath, graphH)
%SAVEASWMF Windowsメタファイルとしてフィギュアを保存

% 引数のチェック
if nargin == 0 filepath = 'matlab.wmf'; end;
if ~ischar(filepath) error('第1引数のパスは文字列である必要があります。'); end;
if nargin < 2 graphH = get(0,'CurrentFigure'); end;
if isempty(graphH) error('カレントFigureがありません。'); end;

% パスを絶対パスに変換
[dirname, filename, ext, versn] = fileparts(filepath);
if isempty(regexpi(ext, 'wmf')) error('第1引数のパスは,拡張子がwmfもしくはWMFである必要があります。'); end;
[num,pathinfo] = fileattrib(dirname);
filepath = fullfile(pathinfo.Name, strcat([filename, ext]));

% 一時ファイルの作成
tmpfile = fullfile(matlabroot,'tmpfileforsaveaswmf.emf');
if exist(tmpfile,'file')~=0 delete(tmpfile); end;
saveas(graphH, tmpfile, 'emf');

% Windowsメタファイル形式で保存
if exist(filepath,'file')~=0 delete(filepath); end;
[s,w] = system(strcat(['emf2wmf "', tmpfile, '" "', filepath, '"']));

% 一時ファイルの削除
delete(tmpfile);

実際に使うときはこんな感じで。gcfのところは任意のグラフィックスハンドルで問題ない。
ちなみに第2引数がないのとgcfを与えるのは同じことです。
saveaswmf('保存先のパス', gcf)

例えば下記を実行すればカレントディレクトリにdemo.wmfが保存されるはずです。
saveaswmf('demo.wmf', plot([0:10]))

この関数を使った場合,Word2000に図を挿入してもこのように↓Y軸のラベルが変になりません(ならないはず…)
WORD2000にwmf

よく考えたらこのエントリ「FigureをWindowsメタファイルとして保存する」でもよかったですね。

このエントリのmファイル
スポンサーサイト



このエントリに付けられたタグ|MATLABファイル操作グラフィックスFigureメタファイル

[興味本位] 割り算の余りを出力する標準関数modとrem

MATLABには割り算の余りを求めたいときに使用できる標準関数がmodとremの2つ用意されています。
しかし,この両関数,正の数÷正の数の時は同じ動きをしますが,符合が違うとびみょ~に違う動きをします。
なんとなく個人的には余りというと,自然数÷自然数のイメージしかないんで,どっちを使ってもいいんじゃないかと思ったりますが興味を持ったので一応メモっとく。

まず両者の実行例。自然数÷自然数だとこんな感じでremもmodも一緒。
>> A=round(100*rand(1,4))
A =
    20     2    75    45
>> mod(A,10)
ans =
     0     2     5     5
>> rem(A,10)
ans =
     0     2     5     5

続いて正の数÷負の数。remとmodで結果が違う。
>> mod(A,-10)
ans =
     0    -8    -5    -5
>> rem(A,-10)
ans =
     0     2     5     5

負の数÷正の数の場合もremとmodで結果が違う。
>> mod(-A,10)
ans =
     0     8     5     5
>> rem(-A,10)
ans =
     0    -2    -5    -5

で,この両者の違いはなんなのよ?と思いヘルプを見ると,
rem = 除算の剰余
mod = モジュラス(除算の符号付き剰余)
こんな感じで書いてあって意味不明(数学がちゃんと分かる人には意味不明ではないのかもしれないが…)

と遠回りしてみましたが結局根本的な違いは,両者の実装が↓だからです。
mod(X, Y) = X - floor(X./Y).*Y
rem(X, Y) = X - fix(X./Y).*Y
つまり
Y = mod (-X, Y) - rem(-X,Y) (X,Y>0)

個人的にはこれですっきりしたんですが,まぁわかりやすい説明を書いておくと要はfloorとfixの挙動の違いのせいで両関数の結果に違いが生まれるということ。

floorとfixの違いは,下記。
floor(A)は、AをA以下の最も近い整数に丸める。
fix(A)は、AをAよりも0に近くAに最も近い整数に丸める。

もっとわかりやすく書くとこんな感じか。つまりfloorは数直線上でより左側の整数に丸め,fixはより0に近い側の整数に丸めるってことです。
floorとfix

だから,結局remとmodはこんな感じの動きになります。図中の矢印の向きと長さでremとmodが表現されています。
modとrem


まぁこんだけ書いてみましたが,結局僕がすっきりするためのあまり意味のないエントリ。

mod (MATLAB Function Reference)
rem (MATLAB Function Reference)
fix (MATLAB Function Reference)
floor (MATLAB Function Reference)
このエントリに付けられたタグ|MATLAB剰余余り

[基本] 奇数と偶数の判別

奇数と偶数の判別
完全にメモエントリ。なんかどうもこのブログが奇数と偶数の判別のキーワードでHITするようなので書いておく。
一応modとremはこっち参照
mod(X,2) … 1なら奇数,0なら偶数
もしくは、
rem(X,2) … 1なら奇数,0なら偶数

例えば, 奇数かどうかを判別するならこう。一応Xが整数じゃない場合対応でroundで丸めてます。
if mod(round(X),2) 
    disp('奇数です');
else
    disp('奇数ではありません');
end;

で、偶数かどうかを判別するならこう。
if ~mod(round(X),2) 
    disp('偶数です');
else
    disp('偶数ではありません');
end;

mod (MATLAB Function Reference)
rem (MATLAB Function Reference)
round (MATLAB Function Reference)
このエントリに付けられたタグ|MATLAB偶数奇数

[基本] 行列(配列)から奇数(偶数)のみを取り出す

行列(配列)から奇数(偶数)のみを取り出す方法です。
奇数のみ:A(find(mod(A,2)))
偶数のみ:A(find(~mod(A,2)))
もしくは,
奇数のみ:A(mod(A,2)==1)
偶数のみ:A(mod(A,2)==0)

一応,例などを。例えば次のような整数の行列Aがあるとき
>> A=round(20*rand(3,5))
A =
    17    19     9    13    15
     0    20    10     6     8
    15    16     4    19    15

2で割ったあまりを求めることで,奇数なら1,偶数なら0とできます。
>> mod(A,2)
ans =
     1     1     1     1     1
     0     0     0     0     0
     1     0     0     1     1

つまり,奇数のインデクスはこれで得られます。
>> find(mod(A,2))
ans =
     1
     3
     4
     7
    10
    12
    13
    15

で、偶数のインデクスはこれ。
>> find(~mod(A,2))
ans =
     2
     5
     6
     8
     9
    11
    14

よって下記で奇数と偶数が取り出せます。(見やすく転置してある)
% 奇数なら
>> A(find(mod(A,2)))'
ans =
    17    15    19     9    13    19    15    15
% 偶数なら
>> A(find(~mod(A,2)))'
ans =
     0    20    16    10     4     6     8

他の方法としてはこんなのもあります。(こっちも見やすく転置してある)
% 奇数なら
>> A(mod(A,2)==1)'
ans =
    17    15    19     9    13    19    15    15
% 偶数なら
>> A(mod(A,2)==0)'
ans =
     0    20    16    10     4     6     8

まぁあとアラカルト的ですが,行列Aの要素が全部奇数であるかを調べるならコレ。全部奇数なら1。
all(all(mod(A,2))) とか isempty(find(~mod(A,2)))

奇数を含むかを調べるならコレ。奇数を持つなら1。
any(any(mod(A,2))) とか ~isempty(find(mod(A,2)))

あとは偶数要素は0にするとか。
>> A(mod(A,2)==0)=0
A =
    17    19     9    13    15
     0     0     0     0     0
    15     0     0    19    15

奇数部と偶数部を切り分けるとか。
>> B=A;C=A;
>> B(mod(A,2)==0)=0
B =
    17    19     9    13    15
     0     0     0     0     0
    15     0     0    19    15

>> C(mod(A,2)==1)=0
C =
     0     0     0     0     0
     0    20    10     6     8
     0    16     4     0     0
>> B+C
ans =
    17    19     9    13    15
     0    20    10     6     8
    15    16     4    19    15
>> B+C-A
ans =
     0     0     0     0     0
     0     0     0     0     0
     0     0     0     0     0

any (MATLAB Function Reference)
all (MATLAB Function Reference)
find (MATLAB Function Reference)
mod (MATLAB Function Reference)
このエントリに付けられたタグ|MATLAB奇数偶数

[ファイル操作] 指定したディレクトリのファイルとディレクトリを再帰的に検索

※この記事の内容は古くなっています。2007bの日付フォーマット変更を考慮して,改良版のこちらの方法推奨です。

MATLABで用意されているdirでは,ファイルのリストを再帰的に取得することが出来ません.
それじゃ不便だということで指定したディレクトリのファイルとディレクトリを再帰的に検索してリストを取得する方法を。

まず,dirが返す構造体のリストをファイルのリストとディレクトリのリストに分別します。
これはisdirフィールドを使えば簡単に実装できます。こんな感じでやればFにファイルのリストが,Dにディレクトリのリストが返ります。
function [F, D] = dir2(path, hier) 

% 指定ディレクトリにdirを実行.
D = dir(path);

% "," と ".."を削除.
D = D(3:end);

% ファイルとディレクトリのリストに分別する.
F = D(find(~[D.isdir]));
D = D(find([D.isdir]));

また,dirが返す構造体のnameフィールドはパスを返してくれるわけではなく,それだといろいろと不便なのでpathという名前のフィールドに絶対パスを持たせます。
function [F, D] = dir2(path, hier) 

% 指定ディレクトリにdirを実行.
D = dir(path);

% "," と ".."を削除.
D = D(3:end);

% 構造体にpathフィールドを追加.
D = arrayfun(@(strc) setfield(strc, 'path', fullfile(path, strc.name)), D);

% ファイルとディレクトリのリストに分別する.
F = D(find(~[D.isdir]));
D = D(find([D.isdir]));

最後にこれを再帰的に呼び出すようにします。こんな感じ↓
一応,エラー処理も適当に書いたm.ファイルをここに置いてあるのでそっちを見てもらった方が見やすいかもしれません。
function [F, D] = dir2(path) 
% DIR2 : 指定したディレクトリのファイルとディレクトリを再帰的に検索し,リストを返す.

% 引数無しの場合はカレントディレクトリに対して実行.
if nargin == 0 path = pwd; end;

% 絶対パスに統一.
[num,pathinfo] = fileattrib(path);
if pathinfo.directory~=1 error('第1引数はディレクトリである必要があります。'); end;
path = pathinfo.Name;

% 指定ディレクトリにdirを実行.
D = dir(path);

% "," と ".."を削除.
D = D(3:end);

% 構造体にpathフィールドを追加.
D = arrayfun(@(strc) setfield(strc, 'path', fullfile(path, strc.name)), D);

% ファイルとディレクトリのリストに分別する.
F = D(find(~[D.isdir]));
D = D(find([D.isdir]));

% ディレクトリの名前を収集
dirnames = {D.name};

% 再帰的に検索
for ind=1:length(dirnames) 
[ff,dd] = dir2(fullfile(path, dirnames{ind}));

st = length(F) +1;
en = st + length(ff)-1;
F(st:en) = ff;

st = length(D) +1;
en = st + length(dd)-1;
D(st:en) = dd;
end;

で,最後に使い方ですが例えば,ファイルのパスだけが欲しいならこんな感じです。
F=dir2();
filepath_list = {F.path};

後はfindを使えば欲しいものだけを取り出せるかと思います。
その方法は適当気が向いたときに書くかもです。
よくわかんないですが,そういえばサブフォルダのショートカットとかあるとこけたりするかもしれません。
まぁ他にもいろいろ方法があるので気が向いたらまた書きます。

dir (MATLAB Function Reference)
このエントリのmファイル
このエントリに付けられたタグ|MATLABファイル操作ファイルリストdirファイル検索

[ファイル操作] サブディレクトリ(フォルダ)のリストを取得

指定したディレクトリ以下にあるディレクトリは,genpathを使うと「;」区切りの文字列で取得できます.
>> genpath(matlabroot)
ans =
C:Program FilesMATLABR2006b;C:Program FilesMATLABR2006bbin;C:Program FilesMATL...

なわけで,そいつを「;」でスプリットすることでサブディレクトリ(フォルダ)のリストを取得できます.
>> strread(genpath(matlabroot),'%s','delimiter',';')
ans = 
    'C:Program FilesMATLABR2006b'
    'C:Program FilesMATLABR2006bbin'
...


genpath (MATLAB Function Reference)
strread (MATLAB Function Reference)
このエントリに付けられたタグ|MATLABファイル操作サブディレクトリサブフォルダ

[ファイル操作] 指定したディレクトリを再帰的に正規表現で検索

この記事に続き,指定したディレクトリを再帰的に正規表現で検索する方法を。
この記事では関数を再帰的に呼び出して検索しましたが,よく考えるとgenpath使ったほうが楽だなと思って,ここではこの記事で書いた方法を使って階層を掘ってサブディレクトリ(サブフォルダ)を検索してます。
function F = dir_regexp(DIR_PATH, REGEXP)
% DIR_REGEXP  : 指定したディレクトリのファイルとディレクトリを再帰的に検索し,正規表現にマッチしたもののリストを返す.

% 引数無しの場合はカレントディレクトリに対して実行.
if nargin == 0 DIR_PATH = pwd; end;

% 絶対パスに統一. 
[num,pathinfo] = fileattrib(DIR_PATH);
DIR_PATH = pathinfo.Name;

% ディレクトリの取得
dirs = strread(genpath(DIR_PATH),'%s','delimiter',';');

F = [];

% 再帰的に検索 
for ind = 1:length(dirs) 
    path = dirs{ind};
    ff = dir(path);

    % 構造体にpathフィールドを追加.
    ff = arrayfun(@(strc) setfield(strc, 'path', fullfile(path, strc.name)), ff(3:end));

    if isempty(F) 
        F = ff;
    else 
        F(end+1:end+length(ff)) = ff;
    end;
end;

% 正規表現で絞り込む
if nargin > 1 F(find(cellfun(@isempty, regexpi({F.path}, REGEXP)))) = []; end;

使い方はまぁ見たまんまですが,例えばMATLABのルートディレクトリにあるabs.mファイルを検索するとこんな感じ↓
>> D=dir_regexp(matlabroot,'abs.m$');
>> {D(:).path}'
ans = 
    'C:Program FilesMATLABR2006btoolboxcompilermcrmatlabelfunabs.m'
    'C:Program FilesMATLABR2006btoolboxemllibmatlababs.m'
    'C:Program FilesMATLABR2006btoolboxmatlabelfunabs.m'
    'C:Program FilesMATLABR2006btoolboxmatlabelfunjaabs.m'

ちなみに第2引数を指定しない場合は,単にファイルのリストが返ります。

genpath (MATLAB Function Reference)
dir (MATLAB Function Reference)
このエントリのmファイル
このエントリに付けられたタグ|MATLABファイル操作正規表現ファイル検索