MATLAB グラフのインパクトのある可視化（可触化）

# MATLAB っていろんな可視化があるよね。
　例えば、何かしらの実験結果とか計算結果とかを[こんなロゴ風に](https://jp.mathworks.com/help//matlab/visualize/creating-the-matlab-logo.html)出力できたときは「MATLAB のグラフィック綺麗！」「なんだかとってもいい感じ！」って感動できますよね。

![matlab_kuro.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/475339/2c5f8fc5-224e-1c09-622c-4d9d3d89d17c.jpeg)

　他にも[インタラクティブな可視化](https://qiita.com/kkado/items/88921058638123f35bfe)とか、[お絵かきMATLAB](https://qiita.com/mana_544/items/25fdb0ed427b38ea6525)とか、MATLABの可視化に関するステキな記事がありますね。


## ただし、何事も見慣れてしまうと効果的じゃない。
　いつも同じフォーマットの結果を見ていると、感動以前に何も感じなくなってしまいます。ああ、あの人は MATLAB で図を作ったんだろうな、ジャイアンツっぽい色だし。テカってるし。くらいの感覚。

　マンネリってやつですね。


# 昔の（かえって新しい）表現方法を使ってみよう。
　今の時代に古典的な可視化ができるようにしてみるとインパクトがあるはず。ということでこんなプログラムを作りました。


```matlab:legoplot.m
function legoplot(M,varargin)
% 3-D のメッシュ表示をレゴで作る設計図です。
%
% こんな感じに使ってください。
% legoplot(membrane * 24)
%
% ※ 24 は、ブロックの高さです。

f = figure(10698);
f.Name = 'LEGO設計図';
f.NumberTitle = 'off';


m = round(M);

cmap = parula(max(m(:))-min(m(:))+1);

sli = uicontrol('Style','Slider');
sli.Units = 'normalized';
sli.Position = [0.04 0.04 0.9 0.04];
sli.Max = max(m(:));
sli.Min = min(m(:));
sli.Value = sli.Max;
sli.SliderStep = 1/(sli.Max - sli.Min)*[1 1];
sli.Callback = @slider_callback;

pop = uicontrol('Style','popup');
pop.String = {'できるだけ薄め','2マスくらい','極厚'};
pop.Units = 'normalized';
pop.Position = [0.7 0.9 0.2 0.1];
pop.Value = 2;
pop.Callback = @slider_callback;

chk = uicontrol('Style','checkbox');
chk.String = '回転';
chk.Units = 'normalized';
chk.Position = [0.2 0.9 0.2 0.1];
chk.Callback = @chk_fun;

a1 = subplot(1,2,1);
bar3_plot(m)
a1.OuterPosition = [0 0 0.5 1];
a2 = subplot(1,2,2);
image_plot(m);
a2.OuterPosition = [0.5 0 0.5 1];

t = timer;
t.ExecutionMode = 'fixedRate';
t.Period = 0.01;
t.TimerFcn = @ax_rot;

    function slider_callback(~,~)
        [as,el] = view(a1);
        mm = m;
        if sli.Value < 0
            mm(mm >= 0) = NaN;
            mm(mm < sli.Value) = sli.Value;
            image_plot(mm,2);
        else
            mm(mm <= 0) = NaN;
            mm(mm > sli.Value) = sli.Value;
            image_plot(mm);
        end
        bar3_plot(mm,[as,el])
    end

    function bar3_plot(m,varargin)
        b = bar3(a1,m,1);
        hold(a1,'on')
        
        for k = 1:length(b)
            zdata = b(k).ZData;
            b(k).CData = zdata;
        end
        hold(a1,'off')
        
        colormap(a1,[cmap; 1 0 0])
        axis(a1,'equal')
        axis(a1,'off')
        if nargin == 2
            view(a1,[varargin{1}])
        end
    end

    function image_plot(m,varargin)
        if pop.Value == 1
            D = 1.5;
        elseif pop.Value == 2
            D = 2.3;
        else
            D = 5;
        end
        if nargin == 1
            p = m == max(m(:));
            z = bwdist(~p) > 0 & bwdist(~p) < D;
            imshow(z,'Parent',a2)
        else
            p = m == min(m(:));
            z = bwdist(~p) > 0 & bwdist(~p) < D;
            imshow(z,'Parent',a2)
        end
        axis(a2,'on')
        [x,y] = size(z);
        xticks(a2,0.5:x)
        yticks(a2,0.5:y)
        axis(a2,'equal')
        xticklabels(a2,{})
        yticklabels(a2,{})
        xlim(a2,[0.5 x+0.5])
        ylim(a2,[0.5 y+0.5])
        view(a2,[0 90])
        grid(a2,'on')
        colormap(a2,[1 1 1;cmap(round(sli.Value) - sli.Min + 1,:)])
    end

    function ax_rot(varargin)
        [as,el] = view(a1);
        view(a1,as+0.2,el)
    end

    function chk_fun(varargin)
        if chk.Value
            start(t)
        else
            stop(t)
        end
    end

f.CloseRequestFcn = @legoClose;
    function legoClose(varargin)
        stop(t)
        closereq
    end

% test
if nargin >= 2
    vec = sli.Min:sli.Max;
    [yoko,tate] = size(M);
    BW = false(yoko,tate,length(vec));
    for ix = 1:length(vec)
        sli.Value = vec(ix);
        slider_callback();
        drawnow
        BW(:,:,ix) = a2.Children.CData;
    end
    iptsetpref('VolumeViewerUseHardware',false);
    volumeViewer(BW)
    iptsetpref('VolumeViewerUseHardware',true);
end

end
```

## プログラムを実行すると設計図が出ます。

　とりあえず試しに MATLAB のロゴ (membrane) でいいかね。コマンドウィンドウで実行。

```
>> legoplot(membrane * 24)
```

こんなウィンドウが出るので、スライダーバーを動かそう。
![LEGOLOGO1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/475339/86dc2b62-a7b2-32d0-369e-afb4030afafb.png)

いろんな階層の断面図が見えますね。イカっぽく中身は空洞です。
![LEGOLOGO2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/475339/28dff327-6a87-9431-b808-7267f1c592e8.png)


# これで終わりじゃなくて、ここからレゴを積む。
　ここで出てきたのはレゴの設計図なので、断面図（右の図）の色が付いたところに合わせてブロックを積んでいきます（手動）。
x, y の１目盛りがブロックの１スタッド（１つの出っ張り）で、z の１目盛りが１ブロック分なので、高さを適当に24倍にしました。(membrane * 24)

　あとは z = 0 のところに板を置くとして結果を表示しています。

## 適当に24倍にして作り始めたおかげで部品が足りない。
　もっと低くすればよかった。。。LEGO Digital Designer で積んでみると、586個くらいブロックがいるようです。
![LEGOLOGO3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/475339/e8cbe3e5-cf7e-6a6d-1efb-87f6f6fac069.png)

## もう色とか気にしないことにする。
　上のみたいにできたら綺麗だけど、同じ色が手に入らん。あとなぜか手元に灰色ばっかりある。

## できた！（４日後）
　重たい！
![membrane.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/475339/74c400c1-a783-94b7-e90c-c783115f5c3a.jpeg)

# インパクトがある上に、努力が見える可視化です。
　グラフの重さも感じられますし、チクチクもします。（可触化！）
数式や実験結果をレゴで表現したい方は参考にしてくださいね。

# 後日
　落としたら壊れたので、バラバラにして片付けました。。(= close all)