MATLAB でインタラクティブな DashBoard をつくってみよう。

# はじめに
データの可視化については、世の中に数多くのツールがあります。そんな中でも、ユーザとやりとりができるような、簡単なダッシュボードをつくってみましょう。MATLAB でね。

イメージはこんな感じ↓
[DashBoard](http://bl.ocks.org/NPashaP/96447623ef4d342ee09b)
![2019-08-16_10-18-38.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482843/dd269aef-a8a9-072e-faa1-3b8fdfdd8ea2.gif)
# 実行環境
MATLAB (R2019a) のみ！
# 結論から
先にポイントとなるところだけ書いておきますね。

- データの取り込みに迷ったら **インポートツール** を使ってみる
- 対話型の **コールバック** を使ってみる
- 使用する **グラフの特性にあわせて**、データを変更する

# まずはデータの取り込みから
今回は、このデータを使いましょうか。総務省統計局からもってきます。人口を、各都道府県別に 年少人口（0～14歳）、生産年齢人口（15～64歳）、老年人口（65歳以上）で分けています。

[都道府県，年齢3区分別人口（エクセル：30KB）](https://www.stat.go.jp/data/nihon/zuhyou/n190200600.xls)

上記サイトから Excel をダウンロードしたら、適当なフォルダに置きます。まずはどんなファイルなのか、そのまま読めそうなのか、確認してみましょう。

MATLAB 上でそのファイルを右クリック → [データのインポート] で **インポートツール** が開きます。データの確認と、欲しいデータの選択をしましょう。今回はテーブルでよさそうですね。あとは、列名と変数名あたり、適当に変えましょうか。こんな感じで。
![import.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482843/1b6d62e3-f800-9c65-2386-f92b02816c5f.jpeg)
データをワークスペースへインポートする際、**スクリプトの生成** をすると、インポートツール上で行った手順が MATLAB プログラムとして生成されます。今後同じようなファイルに対して解析をするときは、生成されたプログラムが使えそうですね。

```MATLAB:createDashBoard.m
function createDashBoard
%% インポート オプションの設定
opts = spreadsheetImportOptions("NumVariables", 5);
% シートと範囲の指定
opts.Sheet = "02-06";
opts.DataRange = "B7:F53";
% 列名と型の指定
opts.VariableNames = ["Pref", "All", "Young", "Working", "Elderly"];% 列名
opts.SelectedVariableNames = ["Pref", "All", "Young", "Working", "Elderly"]; % 選択した列名
opts.VariableTypes = ["string", "double", "double", "double", "double"];% 各列のデータ型
%% データのインポート
pop = readtable("n190200600.xls", opts, "UseExcel", false);
```
# 対話型のコールバック
MATLAB では Figure 上にグラフを描きます。この Figure にはいくつかコールバックが用意されており、ユーザからのアクションを反映させることができます。今回であれば、マウスをクリックした時点で反応がほしいので、**WindowButtonDownFcn** を使用します。

```
f = figure;
f.WindowButtonDownFcn = @downfun;
```
# 使用するグラフについて
今回は、**棒グラフ（bar）** と **円グラフ（pie）** を使用します。上で紹介した **WindowButtonDownFcn** では、これらグラフの更新をすることになります。そこで、それぞれどんな特徴があるか見てみましょう。

■ 棒グラフ

```
% 棒グラフの描画
b = bar(ax1,pop10.All,'FaceColor','flat'); % Top10の総人口
```
```
>> b
b = 
  Bar のプロパティ:

    BarLayout: 'grouped'
     BarWidth: 0.8000
    FaceColor: 'flat'
    EdgeColor: [0 0 0]
    BaseValue: 0
        XData: [1×10 double]
        YData: [1×10 double]
```
■ 円グラフ

```
% 円グラフの描画
p = pie(ax2,sum(pop10{:,3:5})); % Top10における、年少人口、生産年齢人口、老年人口の割合
```
```
>> p
p = 
  1×6 graphics 配列:

  1 から 4 の列
    Patch    Text     Patch    Text 
  5 から 6 の列
    Patch    Text 
```
棒グラフは、それぞれの都道府県（**XData**）における人口（**YData**）を持ちます。クリック時には、これら **YData** を更新してあげればよさそうですね。ただ、円グラフはそのような構成になっていないので、今回は再度描きなおします。

```MATLAB:createDashBoard.m
function createDashBoard
%% インポート オプションの設定
opts = spreadsheetImportOptions("NumVariables", 5);
% シートと範囲の指定
opts.Sheet = "02-06";
opts.DataRange = "B7:F53";
% 列名と型の指定
opts.VariableNames = ["Pref", "All", "Young", "Working", "Elderly"];               % 列名
opts.SelectedVariableNames = ["Pref", "All", "Young", "Working", "Elderly"]; % 選択した列名
opts.VariableTypes = ["string", "double", "double", "double", "double"];         % 各列のデータ型

%% データのインポート
pop = readtable("n190200600.xls", opts, "UseExcel", false);

%% データのソートとTop10の抽出
pop_sorted = sortrows(pop,'All','descend');
pop10 = pop_sorted(1:10,:)

%% データの描画
f = figure;
f.WindowButtonDownFcn = @downfun;
% 軸の設定
ax1 = subplot(1,2,1);
ax2 = subplot(1,2,2);
% 棒グラフの描画
b = bar(ax1,pop10.All,'FaceColor','flat'); % Top10の総人口
cdata = b.CData;
% x軸のラベル設定
ax1.XTickLabel = pop10{:,1}; 
ax1.XTickLabelRotation = 45;
ax1.Position = [0.13 0.11 0.420811785929044 0.786142433234422]; 
% 円グラフの描画
p = pie(ax2,sum(pop10{:,3:5})); % Top10における、年少人口、生産年齢人口、老年人口の割合
 [p(1:2:5).Tag] = deal('3','4','5');
% テキストの描画
 x = 0.5; y = 0.9; 
txt(1)= text(ax1, x, y,            '全体',                                 'Units', 'normalized');
txt(2)= text(ax1, x, y-0.05,  ['年少人口：', p(2).String], 'Units','normalized');
txt(3)= text(ax1, x, y-0.1 ,   ['生産人口：', p(4).String], 'Units','normalized');
txt(4)= text(ax1, x, y-0.15,  ['老年人口：', p(6).String], 'Units','normalized');
 
function downfun(obj,event)
    delete(txt) % テキストの消去
    city = '全体';
    co = gco; % 選択したオブジェクト
    ca = gca; % 選択した軸
    cp = round(ca.CurrentPoint); % 選択した軸の位置
    pref = cp(1,1); 
    b.CData = cdata;
    % 棒グラフに触れたとき
    if (isempty(co.Tag)) && (1 <= pref && pref <= 10)
        % 一旦デフォルト表示に戻す
        p = pie(ax2,sum(pop10{:,3:5})); 
        b.YData = pop10.All;
        p = pie(ax2,pop10{pref,3:5}); % 円グラフの更新
        b.CData(pref,:) = [.5 0 .5]; % 選択した都道府県の色を変更
         city = pop10{pref,1};
    % 円グラフに触れたとき     
    elseif ~isempty(co.Tag)
        % 選択した人口の分布を表示
        b.YData = pop10{:,str2double(co.Tag)};
    % 上記以外に触れたとき
    else
        % デフォルト表示に戻す
        p = pie(ax2,sum(pop10{:,3:5})); 
        b.YData = pop10.All;
    end
    [p(1:2:5).Tag] = deal('3','4','5');
    if isempty(co.Tag)
        txt(1)= text(ax1, x, y,            '全体',                              'Units', 'normalized');
        txt(2)= text(ax1, x, y-0.05,  ['年少人口：', p(2).String], 'Units','normalized');
        txt(3)= text(ax1, x, y-0.1 ,   ['生産人口：', p(4).String], 'Units','normalized');
        txt(4)= text(ax1, x, y-0.15,  ['老年人口：', p(6).String], 'Units','normalized');
    end
end
end

```
#結果
こんな感じになりました:blush:
![2019-08-16_11-34-49.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482843/a22c4fb2-64c8-cca5-174a-a41c87bd2a02.gif)