Matlabを使ってPublication-quality figureを作る

　データサイエンティストにとって、データの可視化 (data visualization) はデータ解析に匹敵するほど大切な仕事だと言っていいでしょう。サイエンスの世界でも、いい論文というのは、ほとんど必ず美しい図が伴っているものです。

　そのような**Publication-quality figure** の作成は、R、Pythonなど好みの言語のツールを用いて行いますが、今回は自分の備忘録も兼ね、**Matlab** でフツーの図をPublication-quality figure に作り直す方法を簡単にまとめたいと思います。

＃＃＃
　単純に色々な美しい図をMatlabで作りたい！という場合には、以下のブログが素晴らしく参考になります。

[Prettier plots in Matlab](https://anneurai.net/2016/06/13/prettier-plots-in-matlab/)

＃＃＃
　R使えないけどggplotっぽい図を作りたい！という場合には、以下のライブラリを使うとR使える雰囲気を漂わせることができます。

[gramm](https://github.com/piermorel/gramm)

#データ準備#
　適当な散布図 (scatter plot) と、そのデータに対する線形回帰直線 (linear regression line) と、$y=x$ のユニティーライン (unity line) を用意します。

```matlab:dataextract.m

%% generate artificial data and plot 
close all;
figure;
xdata = rand(1,30);
ydata = rand(1,30);
scatter(xdata,ydata,30,'filled')

%% plot a linear regression line
b = glmfit(xdata,ydata,'normal','link','identity');
hold on;
plot([0 1],b(1) + b(2)*[0 1])

%% plot a unity line
hold on;
plot([0 1],[0 1])

```

　これで、Matlab は散布図＋2本の線をプロットしてくれます。

![fig_before.png](https://qiita-image-store.s3.amazonaws.com/0/122354/592d2ea2-f984-dcf1-926e-144e52761564.png)

　このままのraw figure だとクオリティが低いので、図からデータを抽出し、新しく図を作り直しましょう。

#図からデータを抽出する#
　研究などはチームで行うことが多いので、**「誰かが作った図を美しく加工しなおす」** という仕事がしばしば発生します。Matlab で作られたraw figure であれば、データの抽出が以下のコマンドで簡単にできます。

```matlab:dataextract.m

%% extract data from the figure
% current figure handle;
h = gcf;

% axis object
axesObjs = get(h, 'Children'); 

% data object inside the axis
dataObjs = get(axesObjs, 'Children'); 

% extract 'scatter' objects
scatters = findobj(dataObjs, 'type', 'scatter');

% extract 'line' objects
lines = findobj(dataObjs, 'type', 'line');

```

　流れとしては、

- 現在のFigure (gcf) を、h という変数に入れる
- 図の子供 (Children)、つまり軸であるaxes object を取り出す
- 軸の子供、つまりデータポイントであるdata object を取り出す

　となります。例の図には'scatter', 'line' という2種類のタイプが含まれているので、最後の2行のコマンドで、deta object から、それぞれの要素をfindobj という関数を使って取り出しています。

#図を美しく加工しなおす#
　データさえ抽出してしまえば、古い図は用済みです。美しく作り直しましょう。
scatter object について今回は、

- x-axis に沿って、データポイントの透明度を下げる
- 色を赤にする
- 大きさを100にする
- ユニティーラインより下のデータポイントのマーカーを四角にする

　という加工をしてみましょう。

```matlab:dataextract.m

%% play with the extracted objects (scatter)
[xdata,idx] = sort(scatters.XData);
ydata = scatters.YData(idx);
figure;

% - change transparency in a gradient manner with x-axis
% - change color to red
% - change markersize to 100
% - change marker if datapoints are under the unity line
for i = 1:30
    if xdata(i) < ydata(i)
        scatter(xdata(i),ydata(i),100,'filled',...
            'markerfacecolor','r','markeredgecolor','r',...
            'markerfacealpha',i/30,'markeredgealpha',i/30);
    else
        scatter(xdata(i),ydata(i),100,'filled','s',...
            'markerfacecolor','r','markeredgecolor','r',...
            'markerfacealpha',i/30,'markeredgealpha',i/30);
    end
    hold on;
end

```

　line object に関しては、

- 線を太くする
- 回帰直線は、緑色のダッシュ
- ユニティーラインは、黒の点線

　にしてみましょう。

```matlab:dataextact.m

%% play with the extracted objects (line)
% - change width of the both lines
% - green dash regression line
% - black dotted unity line

% regression line
plot(lines(2).XData, lines(2).YData, '--g','linewidth', 2)
hold on;

% unity line
plot(lines(1).XData, lines(1).YData, ':k','linewidth', 2)

```

　最後に、軸を少しいじります。

- box を取り除く
- 軸の Tick を外向きにする
- 軸の Tick を0, 0.5, 1 のみにする
- フォントを大きくする
- X軸とY軸の長さを等しくする

```matlab:dataextract.m

%% other cosmetics
% box off
set(gca, 'box', 'off')

% tick out
set(gca, 'TickDir', 'out')

% remove some ticks
set(gca, 'XTick',[0 0.5 1])
set(gca, 'YTick',[0 0.5 1])

% larger font size
set(gca,'FontSize',18)

% square axis
axis square

```

　以上により、図が美しく描き換わりました。

![fig_after.png](https://qiita-image-store.s3.amazonaws.com/0/122354/7305c084-13e8-e873-3bcb-b18c320897da.png)

##まとめのまとめ##
　Matlabのraw figure からデータを抽出するスクリプトは、

```matlab

%% extract data from the figure
% current figure handle;
h = gcf;

% axis object
axesObjs = get(h, 'Children'); 

% data object inside the axis
dataObjs = get(axesObjs, 'Children'); 

```

##終わりに##
　Matlab は有料であるがゆえに、大学のような教育機関でしか使われていませんが、学習が容易で、このようにPublication-quality figure の図の作成も比較的簡単です。

　ちなみに、Matlab の図は*.fig* という特別な拡張子でデフォルトでは保存されますが、以下の簡単なコマンドにより高解像度のPDFとして保存できます。

```matlab

print(handle,'-dpdf',pdfFileName,sprintf('-r%d',dpi))

```

　handle は現在の図でしたら*gcf* でいいです。*pdfFileName* はパス指定された図の名前で、*dpi* は解像度です。Publication-quality figure であれば、300ほどあれば良いはずです。