どのツールボックスがどれに依存してるの?digraphで有向グラフを描いてみよう
今回は Twitter でもおなじみ齊藤さん(@Kojiro__Saito)がお送りします。
こんにちは、アプリケーションエンジニアの齊藤です。MATLAB Answers に Kojiro Saito という名前で生息しています。普段はサーバー、クラウドなどでの MATLAB/Simulink 利用をサポートしていますが、MATLAB のセミナーや体験会もたくさんやらせてもらっています。今日は初めて公式ブログにゲスト出演させてもらっています。緊張しますね。
今回は MATLAB の Toolbox システム要求のページの情報をグラフ描画で見やすくする方法について紹介したいと思います!
Toolbox の依存関係を知るには
MATLAB の Toolbox を使うときに前提となる Toolbox が必要な場合があります。例えば Computer Vision Toolbox には MATLAB と Image Processing Toolbox が前提になっています。
どの Toolbox が前提となっているのか知りたい、というときに先日公開された MATLAB Answers の回答「どのように MathWorks ツールボックス製品の依存関係を確認しますか?」で紹介されている製品要件ページが便利です。Toolbox 毎に依存関係のある Toolbox が表形式でまとまっています。
ただ、MATLAB 芸を使って依存関係をもっと見やすく可視化できないか、考えてみました。
readtableでHTMLからテーブル形式で読み込み
readtable が HTML 形式に対応したのが R2021b、そして R2022a で WebOptions を入れられるようになり、文字エンコーディングを指定できるようになりました。
それでは製品要件ページを readtable で読み込んでみます。
% 製品要件ページのURL
url = “https://www.mathworks.com/support/requirements/product-requirements-platform-availability-list.html”;
% HTMLの読み込む形式を指定
opts = detectImportOptions(url);
opts.TableSelector = “//TABLE”; % 最初の<table>タグを読み取り
opts.SelectedVariableNames = [“Product”, “Required Products”]; % Detailsカラムは使用しないので読み込まない
tbl = readtable(url, opts);
% 先頭行を確認
head(tbl)
読み込んだテーブルの詳細確認
製品要件ページの表をうまく読み込めていますが、「Required Products」の列に「↵」のような文字が含まれてしまっています。
HTML のリスト形式である<li>タグを分割する際に入ってしまったようですね。
また、「↵」が4個になっているのと思いきや、SimBiology がある91行目では、MATLAB と Statistics and Machine Learning Toolbox の間に「↵」が1個だけになっています。
disp(tbl(91, :))
これはHTMLの元ページが
<li>MATLAB</li><li> Statistics and Machine Learning Toolbox</li>
ではなく、
<li>MATLAB<br> Statistics and Machine Learning Toolbox</li>
と、段落の改行を表す HTML の <br> タグが使われてしまっているためなんです。
読み込んだテーブルの「↵」コードを取り除く必要がありますね。
テーブルの前処理
それでは「Required Products」を前処理していきます。
% テーブルの行毎に改行コードで分割し、空白行を削除する
tbl.ReqProd = table2array(varfun(@(x) arrayfun(@(a) rmmissing(convertStringsToChars(split(a, newline))), x, ‘UniformOutput’, false), tbl(:, 2)));
ここで varfun や arrayfun を組み合わせて使いました。ベクトル演算に慣れないうちは for 文で書いてみるのも良いでしょう。下記のコメントを解除(「%」を削除)して実行してみてください。同じ結果が得られます。
% for n=1:height(tbl)
% tempText = split(tbl.(“Required Products”)(n), newline);
% idx = tempText ~= “”;
% tbl.ReqProd{n} = convertStringsToChars(tempText(idx));
% end
ここで「Required Products」カラムではなく「ReqProd」カラムを追加して分割したデータを格納しています。
head(tbl.ReqProd)
各行にセル配列として前提製品が格納されていることが分かりますね。
table.(‘カラム名’)なのかい、table.カラム名なのかい、どっちなんだい!?
ここで少し脱線します。
さっきは tbl.(“Required Products”) でカラムのデータにアクセスしていましたが、今度は tbl.ReqProd でアクセスしています。
table.(‘カラム名’)なのかtable.カラム名なのか、どっちを使えば良いのか迷いますね。
先に ReqProducts カラムで実験してみましょう。
head(tbl.(‘ReqProd’)) % table.(‘カラム名’)
head(tbl.(“ReqProd”)) % table.(“カラム名”)
head(tbl.ReqProd) % table.カラム名
「ReqProd」カラムだとtable.(‘カラム名’)、table.(“カラム名”)、table.カラム名全てでいけますね。
次に「Required Products」カラムの場合を見てみます。
head(tbl.(‘Required Products’)) % table.(‘カラム名’)
head(tbl.(“Required Products”)) % table.(“カラム名”)
%head(tbl.Required Products) % table.カラム名
「Required Products」カラムの場合、table.カラム名でアクセスするとエラーになってしまいました。
ドキュメント「table 内のデータへのアクセス」にありますが、R2019b から変数名と行名にスペースや非 ASCII 文字など任意の文字を入れられるようになりました。
カラム名にスペースや日本語などのマルチバイト文字が入っている場合、table.(‘カラム名’)やtable.(“カラム名”)を使うことができます。
digraph で有向グラフで可視化
さて、それでは製品依存を可視化していきます。
ここで digraph を使って有向グラフ(矢印付きのグラフ)で描いていきます。
% グラフ表示用のテーブルを作成
% tbl.ReqProdを各行でセル配列の中身を展開する
edgeTbl = varfun(@(x) vertcat(x{:}), tbl(:, 3));
% カラム名をFun_ReqProdからReqProdにリネーム
edgeTbl = renamevars(edgeTbl, “Fun_ReqProd”, “ReqProd”);
% Productを各行でReqProdの長さごとに複製
cellT = rowfun(@(x, y) repmat(x, height(y{:}), 1), tbl, InputVariables=[“Product”, “ReqProd”], OutputFormat=“cell”);
edgeTbl.Product = vertcat(cellT{:});
% Productカラムを1列目に変更
edgeTbl = movevars(edgeTbl, ‘Product’, ‘Before’, ‘ReqProd’);
% MATLABをProductのカテゴリーに追加
edgeTbl.Product = categorical(edgeTbl.Product);
edgeTbl.Product = addcats(edgeTbl.Product, “MATLAB”);
% アルファベット順にカテゴリーを並べ替え
edgeTbl.Product = reordercats(edgeTbl.Product);
% missingの行を削除
edgeTbl = rmmissing(edgeTbl, DataVariables=“ReqProd”);
edgeTbl.ReqProd = categorical(edgeTbl.ReqProd);
% ノードテーブルの作成
nodeTbl = tbl.Product;
nodeTbl(end+1, 🙂 = “MATLAB”;
% 有向グラフの作成
diG = digraph(edgeTbl.Product, edgeTbl.ReqProd, [], nodeTbl);
% 有向グラフの可視化
impDig = centrality(diG, “indegree”);
impDig(impDig >= 20) = 20;
impDig(impDig >= 10 & impDig < 20) = 10;
impDig(impDig >= 5 & impDig < 10) = 5;
impDig(impDig >= 1 & impDig < 5) = 1;
diG.Nodes.Rank = impDig;
p = plot(diG,‘NodeLabel’, diG.Nodes.Name, ‘Layout’,‘force’, ‘ArrowSize’, 6, ‘NodeCData’, diG.Nodes.Rank, ‘MarkerSize’, diG.Nodes.Rank+1);
ax = gca;
% 黒枠線の削除
ax.Box = ‘off’;
ax.XColor = ‘none’;
ax.YColor = ‘none’;
ax.Position = [0.0258823529411765 0.00122549019607843 0.956470588235294 0.97671568627451];
どの Toolbox がどの製品を前提としているのか、可視化できましたね。
どの Toolbox がベースを支えている?
digraph にはさらに便利な機能も。
ワードクラウドで文字を可視化してみましょう。
wordcloud(edgeTbl.ReqProd)
MATLAB が一番多く、Simulink が続くのは予想通り。さらに Signal Processing Toolbox がありますね。
数値で見てみる
内向きの矢印数
indegArr = indegree(diG);
外向きの矢印数
outdegArr = outdegree(diG);
多い順にソート
[sortedRank, sortIdx] = sortrows(indegArr, ‘descend’);
table(sortedRank, diG.Nodes.Name(sortIdx))
MATLAB、Simulink が1、2位なのは予想通りですが、3位に Signal Processing Toolbox、4位に DSP System Toolbox と信号処理系がランクイン。
MATLAB 以外で見てみる
MATLAB が前提となったのは分かったので、それ以外を見やすくするように、グラフから MATLAB と Simulink を除いてみます。
subgraph 関数で、グラフから部分グラフを抽出できます。
idx = nodeTbl ~= “MATLAB” & nodeTbl ~= “Simulink”;
subG = subgraph(diG, idx);
% 有向グラフの可視化
plot(subG, ‘NodeLabel’, subG.Nodes.Name, ‘Layout’,‘circle’, ‘ArrowSize’, 6)
ax = gca;
ax.Box = ‘off’;
ax.XColor = ‘none’;
ax.YColor = ‘none’;
留意点
このデモは R2023a 時点のものです。今後システム要件ページが更新されることにより、この実行結果と合わなくなる可能性もあります。また、今回はシステム要件ページの「Details」カラムは考慮していません。実際には例えばDeep Learning Toolboxのモデルの学習(trainNetwork)でGPUを使用する場合はParallel Computing Toolboxが必要になりますので、「Required Products」カラムだけで見た場合と前提製品が変わることもあります。
Comments
To leave a comment, please click here to sign in to your MathWorks Account or create a new one.