Posted at

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


はじめに

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

イメージはこんな感じ↓

DashBoard


実行環境

MATLAB (R2019a) のみ!


結論から

先にポイントとなるところだけ書いておきますね。


  • データの取り込みに迷ったら インポートツール を使ってみる

  • 対話型の コールバック を使ってみる

  • 使用する グラフの特性にあわせて、データを変更する


まずはデータの取り込みから

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

都道府県,年齢3区分別人口(エクセル:30KB)

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

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 を更新してあげればよさそうですね。ただ、円グラフはそのような構成になっていないので、今回は再度描きなおします。


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: