【MATLAB】annotationコマンドの矢印を気軽に使う

## はじめに
　**annotation コマンドによる矢印**は、美しく気品に満ちていて好きです。しかし、座標の指示方法が、axes内で設定したaxisの単位によるものではなく、**figure画面の全体を[幅1.0×高さ1.0]として、normalized単位で指定**しなければなりません。

 　これが面倒で、使うのをためらいがちになってしまいます。しかし、比較的簡単に解決できる方法があります。**座標変換用のローカル関数**を作って利用するものです。ただ、過去に使っていた関数では**引数の数が多かったのがネック**で、今一歩の感がありました。

## 本題
 　ところが、**ここで紹介する関数は引数が少なく、たった３つだけ**です。この応用例を図１に示します。往復電線路周りの磁界のquiver図です。詳しくは、プログラムリストの中のコメントを参照ください。

**図１**
![annotation矢印による往復電線路周りの磁界表示.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/932484/92b047bb-93ca-97c3-6cdc-a6c65fc5c156.png)

## おわりに
　実は、この記事の内容は、過去の記事の一部を抜き出して、再編集しただけのものです。「いいね」があまり付かなかった記事でも、一部を抜き出して紹介したところ、予想外の「いいね」を頂けたという経験がありました。そこで２匹目のドジョウを狙ってみました。あざとくて、すみません。
  
## プログラム
### 座標変換用ローカル関数
　実際には、磁界のquiver図のプログラムのうしろに付けるべきものです。しかし、この記事の主役なので、分離して先に示しました。**axesのハンドルを引数の一つとして渡しているところがミソ**です。

```MATLAB
% ===============================================================
% axes の座標値を figure の normalized 単位に変換するローカル関数
% ===============================================================

function [A,B]=axe2fig(haxe,X,Y)
  % 【入力】
  % 　haxe:　現在アクティブになっている axes のハンドル。
  % 　　　　　　呼び出し側での引数は「gca」とすること。
  % 　X: 　　axes 上の点の x座標群
  % 　　　　　　　　　　　　（点の数に相当する要素数の配列やベクトル）
  % 　Y: 　　　　〃　　　　y　　　　　　　　　　〃
  % 【出力】
  % 　A: 　　X を normalized 単位に変換後の配列やベクトル
  % 　B: 　　Y　　　　　　　　　　〃

  ap = haxe.Position;
  al = ap(1); ab = ap(2); aw = ap(3); ah = ap(4);
  area = axis(haxe);
  xmin = area(1); xmax = area(2); ymin = area(3); ymax = area(4);
  A = aw*(X-xmin)/(xmax-xmin) + al;
  B = ah*(Y-ymin)/(ymax-ymin) + ab;
end
```
### 磁界のquiver図

```MATLAB
% arrow_test03.m

% annotationコマンドの矢印の利用例（往復電線路周りの磁界quiver図）

clear
close all

% ==========================================================
% 往復電線路周りの磁界の計算（比例スケールだが、単位は適当）
% ==========================================================

x=[-10:2:10];
y=[-8:2:8];
[X,Y]=meshgrid(x,y);
d=8;                              % 電線間の距離
U1=Y.*(1./((X-d/2).^2+Y.^2));     % 右側の電流による磁界のx方向成分
V1=-(X-d/2)./((X-d/2).^2+Y.^2);   % 右側の電流による磁界のy方向成分
U2=-Y.*(1./((X+d/2).^2+Y.^2));    % 左側の電流による磁界のx方向成分
V2=(X+d/2)./((X+d/2).^2+Y.^2);    % 左側の電流による磁界のy方向成分
U=U1+U2; V=V1+V2;                 % 合成磁界のベクトル（x,y方向成分)
L=sqrt(U.^2+V.^2);                % 磁界の強さ
U0=U./L; V0=V./L;                 % 磁界の単位ベクトル（x,y方向成分)

% 矢印の基準点を、矢印軸の根元から矢印軸の中央に変更
r=0.8;                            % 矢印の長さの半分
A=atan2(V,U);                     % 磁界ベクトルの傾き角度
X1=X+r*cos(A+pi);                 % 磁界ベクトル矢印の
Y1=Y+r*sin(A+pi);                 % 　　　　始点のx,y座標
X2=X+r*cos(A);                    % 磁界ベクトル矢印の
Y2=Y+r*sin(A);                    % 　　　　終点のx,y座標

% ============================================================
% 磁界ベクトルのquiver図を描画（比例スケールだが、単位は適当）
% ============================================================

figure(1)

ha=axes;
hapos=ha.Position;
ha.Position=hapos+[-0.04 -0.02 0 0];
                              % カラーバーやタイトルのスペースを
                              % 　空けるために、サイズを変えずに、
                              % 　axesをやや左下に移動。
hapos=ha.Position;            % その結果の位置を再取得

axis equal
axis([[-9 9]*1.2679 [-9 9]]); % 1.2679: 既定のアスペクト比
hold on

cmap=jet;                     % カラーマップjetのデータを借用
% 磁界の強さの階調分け（cmapアクセス用のインデックス nc）
Lmax=max(L(:));
Lmin=min(L(:));
nc=floor(63.99*(L-Lmin)/(Lmax-Lmin))+1;

% axis系 → normalized系 座標変換（ローカル関数の呼び出し）
[A1,B1]=axe2fig(gca,X1,Y1);   % 矢印の始点群行列のx/y座標（A1/B1）
[A2,B2]=axe2fig(gca,X2,Y2);   % 　〃　終点群　　　〃　　 （A2/B2）

% 矢印の描画
for l=1:size(X,1)
  for c=1:size(X,2)
    a1=A1(l,c); a2=A2(l,c); b1=B1(l,c); b2=B2(l,c);  
    % 電線の位置では、磁界の大きさがNaNになるので矢印は描かない。
    if ~(isnan(a1) | isnan(a2) | isnan(b1) | isnan(b2))
      annotation('arrow',[a1 a2],[b1 b2],'LineWidth',1, ...
                                         'Color',cmap(nc(l,c),:));
    end
  end
end

grid on
% 電流の方向を図示
text(4,0,'$$\otimes$$','FontSize',20,'Interpreter','latex', ...
     'HorizontalAlign','center','VerticalAlign','middle');
text(-4,0,'$$\odot$$','FontSize',20,'Interpreter','latex', ...
     'HorizontalAlign','center','VerticalAlign','middle');
title('annotation矢印による 往復電線路周りの磁界表示','FontSize',13);
colormap(jet);      % カラーマップとして jet を使用
% 位置を指定してカラーバーを表示
colorbar('Position',[hapos(1)+hapos(3)+0.01 hapos(2) 0.03 hapos(4)])
```