システムとモデリング

modelica, Julia, Design Structure Matrix, SysML, 他モデリング全般について。

Luxor.jlでDesignStructureMatrixの描画を改良

今回はJuliaの描画パッケージの1つ、Luxor.jlでDesign Structure Matrixの描画を改良した件についてまとめています。

Luxor.jlについて

github.com

Juliaのベクトル形式描画パッケージです。四角や丸やテキスト、テーブルなどあらゆるものの描画が可能です。png形式やsvg形式での吐き出しも可能です。 Cairo.jlの高級インターフェースだそうです。

ドキュメントが整備されているので簡単に使用できます。

juliagraphics.github.io

Design Structure Matrixについて

複雑なシステムを理解するための手法の一つです。簡単な解説は↓にあります。

otepipi.hatenablog.com

また、我田引水で恐縮ですが自作パッケージDesignStructureMatrix.jlをJuliaに登録しています。今回はこのパッケージの描画をLuxor.jlで改良しました。

github.com

結果

これまでのDesignStructureMatrix.jlはパッケージGadfly.jlを用いて以下のように描画していました。

https://user-images.githubusercontent.com/35882132/59391598-bf501300-8daf-11e9-923b-72509125d567.png

これを、Luxor.jlを用いて以下のように変更しました。

https://user-images.githubusercontent.com/35882132/150873248-843737c8-6619-4816-b54d-bec151d5ee69.svg

Design Structure Matrix中の対応箇所の表現をからに変えたことで全体的にわかりやすくなったのではと思います。さらに対角行列部分にも列ラベルを描画するようにしたため見やすさがあがったのではないかと………

方法

Luxor.jlのTable機能をフル活用しています。

juliagraphics.github.io

ドキュメント中のexampleでも例えば↓のようなマトリックスが出てきていますが、こういったものを参考に弄りました

f:id:Otepipi:20220130182222p:plain

テキストのサイズ

ラベルの文字数が多くなると見辛くなるのでは?という懸念は当初からありました。Luxor.jlのText fitting機能で見辛くなるのを軽減しています。

juliagraphics.github.io

exampleでは以下のような例が描画されています。

rh = 750 .* [4//11, 2//11, 4//11, 1//11]
cw = 750 .* [6//11, 1//11, 3//11, 1//11]
cells = Table(rh, cw)
for (pos, n) in cells
    setgrey(rand()/2)
    box(cells, n, :fill)
    setgrey(1)
    textfit("The sound of one hand clapping", BoundingBox(box(cells, n)))
end

f:id:Otepipi:20220130182700p:plain

この機能を使用してセルサイズに収まるように自動で文字の大きさを調整しています。

実践例

Luxor.jlを使った描画コード例を示します。

using Luxor

function plotDSM(DSM,label)
    (DSMr,DSMc) = size(DSM);

    @svg begin

        CellSizeRow = min(50,450/(DSMr+5));
        CellSizeColumn = min(50,450/(DSMc+5));
        t = Table(DSMr+1,DSMc+1, CellSizeRow, CellSizeColumn);

        sethue("black")

        for r in 2 : DSMr+1
            for c in 2 : DSMc+1
                box(t[r,c], t.colwidths[t.currentcol], t.rowheights[t.currentrow], :stroke);
                if r == c
                    sethue("grey")
                    box(t[r,c], t.colwidths[t.currentcol], t.rowheights[t.currentrow], :fill);
                    sethue("white")
                    textfit(label[r-1], BoundingBox(box(t[r,c],CellSizeRow, CellSizeColumn)))
                    sethue("black")
                end

                if DSM[r-1,c-1] != 0
                    circle(t[r,c], CellSizeColumn/3, :fill)
                end
            end
        end

        for r in 1 : DSMr
            textfit(label[r], BoundingBox(box(t[r+1,1],CellSizeRow, CellSizeColumn)))
        end

        for c in 1 : DSMc
            textfit(label[c], BoundingBox(box(t[1,c+1],CellSizeRow, CellSizeColumn)))
        end

    end
end

あとは以下のようにマトリックスを定義してやれば描画できます。

 DSM = [0 1 0 0 0 1 0;
            0 0 0 1 0 0 0;
            1 0 0 0 0 0 1;
            0 0 0 0 1 0 0;
            0 1 0 0 0 1 0;
            0 0 1 0 0 0 0;
            1 0 0 0 1 0 0];
 label = ["A", "B", "C", "D", "E", "F", "G"];
 plotDSM(DSM,label)

今回はここまでにします。