MATLABでfigureの中のグラフにアノテーション(矢印)をつける方法を書きます。
ほとんど忘備録であり、他にも方法はあるのかもしれません。
###1.手で張る
いきなり何を言うのかと思うでしょうが、大多数の人はこれでしのいでいるのではないでしょうか。Figureをパワポか何かにコピーして、パワポの上で矢印をつける方法です。
MATLABのノウハウも不要であり、ある意味、無敵と言えます。
やり方がわからず時間もない場合は、ためらわず、これをやることをお勧めします(マジ)。
###2.まともな方法
では、まじめにMATLAB上でアノテーションをつける方法を説明します。
MathWorksのドキュメントには、構文は、
annotation(lineType,x,y)
こうなっています。
説明を読んで分かった気になり、スクリプトを書いてみます。
サイン波を1周期分描いて、180度の点にアノテーションをつけてみましょう。
まず、グラフを描きます。
t=0:100;
A=sin(2*pi*t/100);%正弦波1周期分
figure(1);
plot(t,A,'r');
これにアノテーションをつけてみます。座標はデフォルトでは正規化されているので、座標の指定は0~1の範囲でなければなりません。
1/2周期の部分(50,0)はグラフの真ん中ですから、[0.5 0.5]でよいのでしょうか。
t=0:100;
A=sin(2*pi*t/100);%正弦波1周期分
figure(1);
plot(t,A,'r');
x = [0.3 0.5];%右側が矢印の先
y = [0.6 0.5];%右側が矢印の先
annotation('arrow',x,y);
矢印がずれます。
これは、なぜかというと、figure全体で座標が0~1に割り振られており、グラフを描く領域(Axes)は、その一部であることによります。
では、Axesの座標はどこからどこまでなのでしょうか。
これは、下記のようにするとわかります。
t=0:100;
A=sin(2*pi*t/100);%正弦波1周期分
figure(1);
plot(t,A,'r');
%-------Axesの範囲を調べる ------
AxesHandle=findobj(gcf,'Type','axes');
pt1 = get(AxesHandle,{'Position'});
cell2mat(pt1)%cell配列を数値配列に変換
こうしますと、コマンドウィンドウに、
ans =
0.1300 0.1100 0.7750 0.8150
このように出力されていると思います。この意味は、
こうなります。
###3.アノテーションの座標を計算するfunctionを作ってみました。
以上のようになっていることがわかれば、正しい位置にアノテーションを表示することができるはずです。が、いちいち計算するのは面倒なので、functionを作成してみました。
%% Numfig:figureの中の図面領域の数(1か2)
%% Orderfig:figureの中のどちらのaxesについて計算するか
%% Left:対象のAxesの左端の数値
%% Bottom:対象のAxesの下端の数値
%% Width:対象のAxesの表示幅
%% Height:対象のAxesの表示高さ
%% x: アノテーションをつける場所のx座標
%% y: アノテーションをつける場所のy座標
%% Xpos: アノテーションの正規化されたX座標
%% Ypos: アノテーションの正規化されたY座標
function [Xpos, Ypos] = PositionCalc(Numfig,Orderfig,Left,Bottom,Width,Height,x,y)
if Numfig == 1
AxesPos = [0.1300 0.1100 0.7750 0.8150];
elseif Numfig == 2
if Orderfig == 1
AxesPos = [0.1300 0.5838 0.7750 0.3412];
else
AxesPos = [0.1300 0.1100 0.7750 0.3412];
end
end
X_Ratio = (x-Left) / Width * AxesPos(3);
Y_Ratio = (y-Bottom) / Height * AxesPos(4);
Xpos = X_Ratio + AxesPos(1);
Ypos = Y_Ratio + AxesPos(2);
Axesの座標はデフォルトの座標で固定にしています。
例として、下図の点にアノテーションをつける場合をやってみます。
functionに渡すパラメータですが、
Numfig=1 (Axesは1つ)
Orderfig=1 (1番目のAxesを操作したい)
Left=0 (Axesの左端の座標)
Bottom= -1 (Axesの下端の座標)
Width=100 (Axesの横幅)
Height=2 (Axesの高さ)
x=42 (アノテーションのx座標)
y=0.4818 (アノテーションのY座標)
t=0:100;
A=sin(2*pi*t/100);%正弦波1周期分
figure(1);
plot(t,A,'r');
Numfig=1;% (Axesは1つ)
Orderfig=1;% (1番目のAxesを操作したい)
Left=0;% (Axesの左端の座標)
Bottom= -1;% (Axesの下端の座標)
Width=100;% (Axesの横幅)
Height=2;% (Axesの高さ)
x=42;% (アノテーションのx座標)
y=0.4818;% (アノテーションのY座標)
[Xpos, Ypos] = PositionCalc(Numfig,Orderfig,Left,Bottom,Width,Height,x,y);
x = [Xpos+0.2 Xpos];% 右側の座標が矢印の先
y = [Ypos Ypos];
annotation('textarrow',x,y,'String','できた!')
このように描画されているかと思います。
矢印の形や大きさなどは変えられます。詳細は MathWorksのドキュメントを見てください。
###追記:矢印か、テキストか、それが問題
コメントをいただいたので、少し追記します。
テキストでアノテーションを入れるのも出来て、前に載せたI2C解析の記事では、テキストでアノテーションを入れています(下図の下の文字部分)。
これだと、わりとアバウトな範囲しか示せないですが、ご指摘にあったとおり、矢印がtexで追加できて、グラフ上にドットも打てます。
t=0:360;
%A=sin(2*pi*t/100);
A=sind(t);
figure(1);
subplot(2,1,1);
plot(t,A,'r');
xlim([0 360]);
%アノテーションを入れる
txt = '\bullet \leftarrow ここが 180度';
text(t(180),A(180),txt);
xlabel('[deg]');
ylabel('Amplitude');
しかし、もっと混み入った表示をする場合、例えば、下記のような場合、
グラフに曲線がプロットされていて(緑色)、なにかイベントが発生したところに矢印でアノテーションを入れる。かつ、イベントの種類で矢印の色を変え、さらにイベントの大きさで矢印の長さを変える、というような内容を直感的に図示するとなると、やはり、このような表記になってしまうのでは、と思います。
(追記ここまで)。
###おまけ:Qiitaに動画を埋め込むには
MATLAB EXPOのデモを動画して、Qiitaに埋め込もうとしたところ、多くの先人が指摘しているように、動画はアップロードもできないことがわかりました。
Youtubeだと埋め込みはできないようです。
GIFアニメは画質が汚いし。
なんのかんので、Twitterに動画をアップロードし、Qiitaにリンクを張ると動画埋め込みができることがわかり、それを採用しました。
Twitterで動画をQiita上で公開し、評判はよかったのですが、1つ問題が起こりました。
Twitterのアカウントがフォローされてしまったのです。しかもビミョーな範囲に。
ということで、下手なことはつぶやけないし、来年のMATLAB EXPOの動画を先にTwitterに上げてしまえばネタバレするし。
(ただ、Qiitaの記事をストックするならQiitaのアカウントが必要だけど持ってないし、Twitterのアカウントは大半の人が持っているので、Twitterにフォローかけてしまうのは理解はできます。公開したときに自分がそこまで計算してなかったわけですね)
ということで、お返事は書けませんが、見てはおりますので。
以上でMATLABのプロットでアノテーションを終わります。
おつかれさまでした。