LoginSignup
byh01337
@byh01337 (Geng Tanaka)

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

ネットワークグラフを描画する際に、しきい値を指定して一部のノード/エッジを不可視化したいのです

  javascript/vis.js をつかってネットワークグラフを書き始めました。現在、以下に上げました
・index.html
・style.css
・script.js
を用いて、グラフの描画そのものはできています。自分の環境では、これら3つのファイルを一つのディレクトリに配置し、index.html をダブルクリックすると描画は正常になされます(macOS バージョン: 10.15.7 Catalina/Google Chrome バージョン: 98.0.4758.102(Official Build) (x86_64))。肝心なコードは script.js にありますが、これはNomuraS様がCodePenのページ( https://codepen.io/NomuraS )上で公開してくださっているサンプルコード vis.js example1, vis.js example2 を組み合わせることでほぼ仕上がっています。

解決したいこと

  script.js に示しました通り、各ノードに weight という値を振り分けています。その上で、しきい値を指定し、その値未満のweightをもつノードとそれにつながっているエッジを不可視化(たとえば表示を透明にする等)したいのですが、その方法を調べきれず手を束ねています。まず、この描画されたwebページの上でしきい値を入力するためのインターフェースを用意できないでいます(このために各種のバーがインターフェースに備えられているサンプルを探したのですが)。そして、ノードとエッジを不可視化することに成功していません。

  しきい値に対してはボックスに数字を入力する、あるいはバーでコントロールするなど、動的な方法を取りたいのです。

* なお、ノードカラーとエッジカラーを別々に指定できないのでしょうか。
edges: {
arrows: 'to', // エッジに矢印を付けて有向グラフにする
smooth: true // falseにするとエッジが直線になる
},
→描画ok
edges: {
arrows: 'to', // エッジに矢印を付けて有向グラフにする
smooth: true // falseにするとエッジが直線になる
color: "skyblue" // エッジカラー
},
→どうも許されていない書き方。グラフが表示されず。

* これはまだ十分時間をかけて調べていないままの質問で恐縮しますが、各ノードの描画画面上での座標に関して、次の2件につきましてもよければご教示ください。
1 力学モデル(物理シミュレーションモデル)で配置された各ノードの座標を得る仕組み
2 各ノードの座標の初期値を指定する仕組み

sample.jpg

index.html

<!DOCTYPE html>
<html lang="en" >
<head>
  <meta charset="UTF-8">
  <title>CodePen - vis.js example2 by NomuraS</title>
  <link rel="stylesheet" href="./style.css">

</head>
<body>
<!-- partial:index.partial.html -->
<html>

<head>
    <meta charset="utf-8" />
    <title>Network | Manipulation</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/vis/4.21.0/vis.js"></script>
    <link href="https://cdnjs.cloudflare.com/ajax/libs/vis/4.21.0/vis-network.min.css" rel="stylesheet" type="text/css" />
</head>

<body onload="draw();">
    <div id="network-popUp">
        <span id="operation">node</span>
        <br>
        <table style="margin:auto;">
            <tr>
                <td>id</td>
                <td>
                    <input id="node-id" value="new value" />
                </td>
            </tr>
            <tr>
                <td>label</td>
                <td>
                    <input id="node-label" value="new value" />
                </td>
            </tr>
        </table>
        <input type="button" value="save" id="saveButton" />
        <input type="button" value="cancel" id="cancelButton" />
    </div>
    <br />
    <div id="mynetwork"></div>
    <div id="config"></div>

</body>

</html>
<!-- partial -->
  <script  src="./script.js"></script>

</body>
</html>

style.css

        #mynetwork {
            position: relative;
            width: 800px;
            height: 600px;
            border: 1px solid lightgray;
        }

        #network-popUp {
            display: none;
            position: absolute;
            top: 350px;
            left: 170px;
            z-index: 299;
            width: 250px;
            height: 120px;
            background-color: #f9f9f9;
            border-style: solid;
            border-width: 3px;
            border-color: #5394ed;
            padding: 10px;
            text-align: center;
        }

        #config {
            float: left;
            width: 400px;
            height: 600px;
        }

script.js

        var network = null;

        var nodes = new vis.DataSet([
            { id: 1, label: '環境', weight: 100 },
            { id: 2, label: 'エネルギー', weight: 86 },
            { id: 3, label: '省エネ', weight: 40 },
            { id: 4, label: 'ESD', weight: 34 },
            { id: 5, label: 'HEM', weight: 13 },
            { id: 6, label: '家庭', weight: 89 },
            { id: 7, label: '生き物', weight: 75 },
            { id: 8, label: '植物', weight: 70 },
            { id: 9, label: '地域', weight: 55 },
            { id: 10, label: '動物', weight: 68 },
            { id: 11, label: '学校', weight: 45 },
            { id: 12, label: '社会', weight: 66 }
        ]);

        var edges = new vis.DataSet([
            { from: 1, to: 2},
            { from: 1, to: 7},
            { from: 1, to: 8},
            { from: 2, to: 1},
            { from: 2, to: 3},
            { from: 3, to: 4},
            { from: 3, to: 5},
            { from: 3, to: 6},
            { from: 4, to: 1},
            { from: 4, to: 5},
            { from: 5, to: 6},
            { from: 6, to: 3},
            { from: 7, to: 1},
            { from: 7, to: 8},
            { from: 7, to: 10},
            { from: 9, to: 4},
            { from: 9, to: 6},
            { from: 9, to: 11},
            { from: 9, to: 12}
        ]);

        // create a network
        var data = {
            nodes: nodes,
            edges: edges
        };


        function destroy() {
            if (network !== null) {
                network.destroy();
                network = null;
            }
        }

        function draw() {
            destroy();
            nodes = [];
            edges = [];

            // create a network
            var container = document.getElementById('mynetwork');
            var options = {
                physics: false, // 物理シミュレーションをオフにする
                nodes: {
                    shape: 'box', // ノードの形をellipseからboxに
                    size: 20, // ノードの大きさ

                    font: {
                        boldital: { color: 'pink' }, // <i><b>aaa</b></i>タグのカラー
                        ital: { color: 'orange' },  // <i>aaa</i>タグのカラー
                        mono: { color: 'blue' }, // <code>aaa</code>タグのカラー
                        bold: { color: 'purple' }, // <b>aaa</b>タグのカラー
                        // color: 'yellow', // タグなしのノードの文字の色
                        color: 'black', // タグなしのノードの文字の色
                    },
                    color: "skyblue" // ノードカラー
                },
                edges: {
                    arrows: 'to', // エッジに矢印を付けて有向グラフにする
                    smooth: true // falseにするとエッジが直線になる
                },
                manipulation: {
                    addNode: function (data, callback) {
                        // filling in the popup DOM elements
                        document.getElementById('operation').innerHTML = "Add Node";
                        document.getElementById('node-id').value = data.id;
                        document.getElementById('node-label').value = data.label;
                        document.getElementById('saveButton').onclick = saveData.bind(this, data, callback);
                        document.getElementById('cancelButton').onclick = clearPopUp.bind();
                        document.getElementById('network-popUp').style.display = 'block';
                    },
                    editNode: function (data, callback) {
                        // filling in the popup DOM elements
                        document.getElementById('operation').innerHTML = "Edit Node";
                        document.getElementById('node-id').value = data.id;
                        document.getElementById('node-label').value = data.label;
                        document.getElementById('saveButton').onclick = saveData.bind(this, data, callback);
                        document.getElementById('cancelButton').onclick = cancelEdit.bind(this, callback);
                        document.getElementById('network-popUp').style.display = 'block';
                    },
                    addEdge: function (data, callback) {
                        if (data.from == data.to) {
                            var r = confirm("Do you want to connect the node to itself?");
                            if (r == true) {
                                callback(data);
                            }
                        } else {
                            callback(data);
                        }
                    }
                },
                configure: {
                    filter: function (option, path) {
                        if (path.indexOf('physics') !== -1) {
                            return true;
                        }
                        if (path.indexOf('smooth') !== -1 || option === 'smooth') {
                            return true;
                        }
                        return false;
                    },
                    container: document.getElementById('config')
                }

            };

            network = new vis.Network(container, data, options);
        }

        function clearPopUp() {
            document.getElementById('saveButton').onclick = null;
            document.getElementById('cancelButton').onclick = null;
            document.getElementById('network-popUp').style.display = 'none';
        }

        function cancelEdit(callback) {
            clearPopUp();
            callback(null);
        }

        function saveData(data, callback) {
            data.id = document.getElementById('node-id').value;
            data.label = document.getElementById('node-label').value;
            clearPopUp();
            callback(data);
        }

0

1Answer

しきい値のスライダーを追加したものを書いてみたのでご覧ください
https://jsfiddle.net/ukfoo/dmek6Loc/1

追加したコードは以下の部分です

html
    <div>しきい値(<span id="thval" style="display:inline-block; text-align:center; width:2em;">0</span>):
      <input type="range" id="threshold" min="0" max="100" value="0" oninput="thval.innerHTML=this.value">
    </div>

js
            // しきい値変更イベントを追加
            document.getElementById('threshold').addEventListener('input', function(ev) {
              var val = Number(ev.target.value);
              data.nodes.forEach(function(item){
                // ノードがしきい値以下か?
                var hflag = item.weight < val;
                if( !!item.hidden !== hflag ) {
                  data.nodes.update({id:item.id, hidden:hflag});
                }
              });
            });

色について

smooth: true // falseにするとエッジが直線になる
color: "skyblue" // エッジカラー

これでグラフが表示されなくなるのは、smooth行の後ろに,が足りずエラーになっているからだと思います。動かない時はエラーメッセージをコンソールで確認してください。

edgeの色の変え方ですが、color:'skyblue'だと無視されますが、color: {color: 'skyblue'}のようにすると反映されるようです。ドキュメントは前者でも良いとされてるように読める気がしますがよくわかりませんでした。

座標について

1 力学モデル(物理シミュレーションモデル)で配置された各ノードの座標を得る仕組み

NetworkオブジェクトのgetPositions(ノードIDの配列)またはgetPosition(ノードID)メソッドで取得できます。

network.getPositions();

これで全ノードの座標が返ってきます

2 各ノードの座標の初期値を指定する仕組み

DataSetでx,yプロパティを指定すると反映されるようです。上記のデモで環境とエネルギーにそれぞれ指定してみました。

参照

Network
https://visjs.github.io/vis-network/docs/network/
DataSet
https://visjs.github.io/vis-data/data/dataset.html

1

Comments

  1. @byh01337

    Questioner
     ご丁寧にご教示くださり、誠にありがとうございます。

    スライダー、DataSetでx,yプロパティの順で調べて参ります。結果の報告を今しばらくお待ち下さい。特にスライダーで動的に値を入力できることは助かります。これを試したくてjavascript/vis.jsを触り始めましたから。

    なお、Chromeのディベロッパーツール、コンソールで
    network.getPositions();
    JSON.stringify(data.nodes.get())
    (よく見ますと、ここで ; を入れたり入れなかったりしていましたが表示は変わらない様子)
    を打ち込み、全ノードの座標をエディタにコピペして作業していますが、これを自動的に取得する仕組みを示唆していただいているようです。重ね重ね、ありがとうございます。
  2. @byh01337

    Questioner
     カンマ忘れはお恥ずかしいことでした。

Your answer might help someone💌