LoginSignup
14
2

More than 3 years have passed since last update.

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

Last updated at Posted at 2019-08-19

MATLAB っていろんな可視化があるよね。

 例えば、何かしらの実験結果とか計算結果とかをこんなロゴ風に出力できたときは「MATLAB のグラフィック綺麗!」「なんだかとってもいい感じ!」って感動できますよね。

matlab_kuro.jpg

 他にもインタラクティブな可視化とか、お絵かき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

いろんな階層の断面図が見えますね。イカっぽく中身は空洞です。
LEGOLOGO2.png

これで終わりじゃなくて、ここからレゴを積む。

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

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

適当に24倍にして作り始めたおかげで部品が足りない。

 もっと低くすればよかった。。。LEGO Digital Designer で積んでみると、586個くらいブロックがいるようです。
LEGOLOGO3.png

もう色とか気にしないことにする。

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

できた!(4日後)

 重たい!
membrane.jpg

インパクトがある上に、努力が見える可視化です。

 グラフの重さも感じられますし、チクチクもします。(可触化!)
数式や実験結果をレゴで表現したい方は参考にしてくださいね。

後日

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

14
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
2