MATLABのプロットでアノテーションをつける

MATLABでfigureの中のグラフにアノテーション（矢印）をつける方法を書きます。
ほとんど忘備録であり、他にも方法はあるのかもしれません。

###１．手で張る
いきなり何を言うのかと思うでしょうが、大多数の人はこれでしのいでいるのではないでしょうか。Figureをパワポか何かにコピーして、パワポの上で矢印をつける方法です。
MATLABのノウハウも不要であり、ある意味、無敵と言えます。
やり方がわからず時間もない場合は、ためらわず、これをやることをお勧めします（マジ）。

###２．まともな方法
では、まじめにMATLAB上でアノテーションをつける方法を説明します。
[MathWorksのドキュメント](https://jp.mathworks.com/help/matlab/ref/annotation.html)には、構文は、

　　annotation(lineType,x,y)

こうなっています。
説明を読んで分かった気になり、スクリプトを書いてみます。
サイン波を１周期分描いて、180度の点にアノテーションをつけてみましょう。
まず、グラフを描きます。

```matlab:annotationwrite.m
t=0:100;
A=sin(2*pi*t/100);%正弦波１周期分

figure(1);
plot(t,A,'r');
```

![figure1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/434947/e1f7302a-29de-af52-45de-8bfaff28ec69.jpeg)

これにアノテーションをつけてみます。座標はデフォルトでは正規化されているので、座標の指定は0～1の範囲でなければなりません。
1/2周期の部分(50,0)はグラフの真ん中ですから、[0.5 0.5]でよいのでしょうか。

```matlab:annotationwrite2.m
t=0:100;
A=sin(2*pi*t/100);%正弦波１周期分

figure(1);
plot(t,A,'r');

x = [0.3 0.5];%右側が矢印の先
y = [0.6 0.5];%右側が矢印の先
annotation('arrow',x,y);
```
![figure2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/434947/09f54452-583f-d143-9405-c661ff82f4f7.jpeg)

矢印がずれます。

![figure3.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/434947/b41ba105-4660-b221-a666-422c64ea7cff.jpeg)

これは、なぜかというと、figure全体で座標が0～1に割り振られており、グラフを描く領域(Axes)は、その一部であることによります。

![figure4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/434947/dcec73eb-e2c5-3b22-c14f-5abefeb57e0b.png)

では、Axesの座標はどこからどこまでなのでしょうか。
これは、下記のようにするとわかります。

```matlab:annotationwrite3.m
t=0:100;
A=sin(2*pi*t/100);%正弦波１周期分

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

このように出力されていると思います。この意味は、
![figure5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/434947/436373d1-2180-f7d9-0e1a-11b03630f5ff.png)
こうなります。

###３．アノテーションの座標を計算するfunctionを作ってみました。
以上のようになっていることがわかれば、正しい位置にアノテーションを表示することができるはずです。が、いちいち計算するのは面倒なので、functionを作成してみました。

```matlab:PositionCalc.m
%% Numfig:figureの中の図面領域の数（１か２）
%% 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の座標はデフォルトの座標で固定にしています。
例として、下図の点にアノテーションをつける場合をやってみます。
![figure6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/434947/7dc95780-3ef8-fd0a-f778-eb6da50b1d87.png)
functionに渡すパラメータですが、
Numfig=1 （Axesは１つ）
Orderfig=1 （１番目のAxesを操作したい）
Left=0 （Axesの左端の座標）
Bottom= -1 （Axesの下端の座標）
Width=100 （Axesの横幅）
Height=2 （Axesの高さ）
x=42 （アノテーションのｘ座標）
y=0.4818 （アノテーションのY座標）


```matlab:annotationwrite4.m
t=0:100;
A=sin(2*pi*t/100);%正弦波１周期分

figure(1);
plot(t,A,'r');

Numfig=1;% （Axesは１つ）
Orderfig=1;% （１番目のAxesを操作したい）
Left=0;% （Axesの左端の座標）
Bottom= -1;% （Axesの下端の座標）
Width=100;% （Axesの横幅）
Height=2;% （Axesの高さ）
x=42;% （アノテーションのｘ座標）
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','できた！')
```

![figure7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/434947/ae5bc944-941f-8777-a50a-0762d6dcca93.png)
このように描画されているかと思います。
矢印の形や大きさなどは変えられます。詳細は [MathWorksのドキュメント](https://jp.mathworks.com/help/matlab/ref/matlab.graphics.shape.arrow-properties.html)を見てください。

###追記：矢印か、テキストか、それが問題
コメントをいただいたので、少し追記します。
テキストでアノテーションを入れるのも出来て、前に載せた[I2C解析の記事](https://qiita.com/Monzo_N/items/e7f81d0e9137ed8ec8a0)では、テキストでアノテーションを入れています（下図の下の文字部分）。
![I2Csample.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/434947/313b4a98-c00f-4074-a75a-908bf429362f.png)
これだと、わりとアバウトな範囲しか示せないですが、ご指摘にあったとおり、[矢印がtexで追加できて](https://jp.mathworks.com/help/matlab/creating_plots/greek-letters-and-special-characters-in-graph-text.html)、グラフ上にドットも打てます。

```matlab:textannotation.m
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');
```
![texannotation.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/434947/0c9595e5-4721-fa15-7ca4-2e957d996121.png)
しかし、もっと混み入った表示をする場合、例えば、下記のような場合、
![annotation2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/434947/260f4f28-2b30-e782-6838-3688fd1a024b.png)
グラフに曲線がプロットされていて（緑色）、なにかイベントが発生したところに矢印でアノテーションを入れる。かつ、イベントの種類で矢印の色を変え、さらにイベントの大きさで矢印の長さを変える、というような内容を直感的に図示するとなると、やはり、このような表記になってしまうのでは、と思います。
（追記ここまで）。

###おまけ：Qiitaに動画を埋め込むには
MATLAB EXPOのデモを動画して、Qiitaに埋め込もうとしたところ、多くの先人が指摘しているように、動画はアップロードもできないことがわかりました。
Youtubeだと埋め込みはできないようです。
GIFアニメは画質が汚いし。
なんのかんので、Twitterに動画をアップロードし、Qiitaにリンクを張ると動画埋め込みができることがわかり、それを採用しました。

Twitterで動画をQiita上で公開し、評判はよかったのですが、１つ問題が起こりました。
Twitterのアカウントがフォローされてしまったのです。しかもビミョーな範囲に。
ということで、下手なことはつぶやけないし、来年のMATLAB EXPOの動画を先にTwitterに上げてしまえばネタバレするし。
（ただ、Qiitaの記事をストックするならQiitaのアカウントが必要だけど持ってないし、Twitterのアカウントは大半の人が持っているので、Twitterにフォローかけてしまうのは理解はできます。公開したときに自分がそこまで計算してなかったわけですね）

ということで、お返事は書けませんが、見てはおりますので。
 
以上でMATLABのプロットでアノテーションを終わります。

おつかれさまでした。