Cytoscape.js强制控制的布局和节点放置 [英] Cytoscape.js force-directed layouts and node placement

查看:161
本文介绍了Cytoscape.js强制控制的布局和节点放置的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我最近发现有关Cytoscape.js的信息,并想尝试使用力导向的布局:乔木和弹性.

现在,我有几个问题:

  1. 是否可以通过使用其中一种布局(其中节点放置基于某种算法并且不需要节点坐标)来获得图形?例如,在VivaGraphJS中,图形会收敛,以便连接的节点形成组,而孤立的节点会移动到外围.如果可以在力导向的布局上完成此操作,可以关闭力以选择节点并在画布上自由拖动这些节点吗?

  2. Cytoscape可以实际处理多少个图形(节点/边的数量)?

  3. 说每个节点和边缘都有五个属性,我想要一个在鼠标悬停时显示这些属性的文本框.最简单的方法是什么?

  4. Wiki表示可以按如下所示添加单个节点,但是cy没有节点功能.这是错误吗? var n0 = cy.node("n1"); cy.add(n0);//添加单个元素n0

  5. 我试图创建一个使用Arbor/Springy的琐碎随机数据图.下面的代码给出了一个错误 返回数据.cy"中的数据未定义".当布局是随机的"时,代码将起作用.我在做什么错了?

 <!DOCTYPE html>
<html>
<head>
    <title>Test</title>
    <style type="text/css">
    .full-height { height: 600px; margin: 0 0; padding: 0 0; }
    </style>

    <script src="jquery-1.7.2.js"></script>
    <script src="demo/cytoscape.all.js"></script>
    <script src="demo/extensions/cytoscape.layout.arbor.js"></script>
    <script src="demo/extensions/cytoscape.layout.springy.js"></script>


    <script src="demo/arbor.js"></script>
    <script src="demo/arbor-tween.js"></script>
    <script src="demo/springy.js"></script>


    <script type='text/javascript'>
        function onLoad() {

             // create a mapper for node size
            var nodeSizeMapper = {
                continuousMapper: {
                    attr: {
                        name: "weight",
                        min: 0,
                        max: 40
                    },
                    mapped: {
                        min: 5,
                        max: 25
                    }
                }
            };

            $("#cy").cytoscape( {
                layout: { name: "arbor" }, // works when "random"
                style: {
                    selectors: {
                        "node":{
                            shape: "ellipse",
                            fillColor: "#3366FF",
                            height: nodeSizeMapper,
                            width: nodeSizeMapper,
                            labelText: {
                                passthroughMapper: "id"
                            }
                        },
                        "edge": {
                            lineColor: "#CCFF33",//"#ccc",
                            targetArrowColor: "#CCFF33", //"#ccc",
                            width: {
                                continuousMapper: {
                                    attr: {
                                        name: "weight",
                                        min: 20,
                                        max: 35
                                    },
                                    mapped: {
                                        min: 1,
                                        max: 3
                                    }
                                }
                            },
                            targetArrowShape: "triangle",
                            // labelText: {
                            //     passthroughMapper: "weight"
                            // }
                        },
                        "node:selected": {
                            fillColor: "#333"
                        },
                        "edge:selected":{
                            lineColor: "#666",
                            targetArrowColor: "#666"
                        }
                    }
                },                    
                ready: function(cy) { },
            });
            window.cy = $("#cy").cytoscape("get");

            $.getJSON('edges_nodes.json', function(elements) {
                //console.log(elements);
                window.elements = elements;
                cy.load( elements );
            });
        }
    </script>
</head>

<body onload="onLoad()">
        <div class="full-height" id="cy">
        </div>
</body>
</html>
 

JSON文件显示为:

{"nodes": [{"classes": "b", "data": {"id": "n0", "weight": 40}}, {"classes": "b", "data": {"id": "n1", "weight": 19}}, {"classes": "c", "data": {"id": "n2", "weight": 0}}, {"classes": "d", "data": {"id": "n3", "weight": 19}}, {"classes": "e", "data": {"id": "n4", "weight": 4}}, {"classes": "a", "data": {"id": "n5", "weight": 21}}, {"classes": "e", "data": {"id": "n6", "weight": 13}}, {"classes": "a", "data": {"id": "n7", "weight": 6}}, {"classes": "a", "data": {"id": "n8", "weight": 10}}, {"classes": "b", "data": {"id": "n9", "weight": 6}}, {"classes": "c", "data": {"id": "n10", "weight": 24}}, {"classes": "c", "data": {"id": "n11", "weight": 14}}, {"classes": "e", "data": {"id": "n12", "weight": 11}}, {"classes": "b", "data": {"id": "n13", "weight": 6}}, {"classes": "e", "data": {"id": "n14", "weight": 24}}, {"classes": "b", "data": {"id": "n15", "weight": 26}}, {"classes": "b", "data": {"id": "n16", "weight": 6}}, {"classes": "c", "data": {"id": "n17", "weight": 36}}, {"classes": "a", "data": {"id": "n18", "weight": 7}}, {"classes": "b", "data": {"id": "n19", "weight": 37}}, {"classes": "c", "data": {"id": "n20", "weight": 28}}, {"classes": "d", "data": {"id": "n21", "weight": 11}}, {"classes": "d", "data": {"id": "n22", "weight": 20}}, {"classes": "e", "data": {"id": "n23", "weight": 7}}, {"classes": "b", "data": {"id": "n24", "weight": 31}}, {"classes": "b", "data": {"id": "n25", "weight": 1}}, {"classes": "e", "data": {"id": "n26", "weight": 29}}, {"classes": "d", "data": {"id": "n27", "weight": 31}}, {"classes": "d", "data": {"id": "n28", "weight": 34}}, {"classes": "b", "data": {"id": "n29", "weight": 40}}, {"classes": "d", "data": {"id": "n30", "weight": 38}}, {"classes": "b", "data": {"id": "n31", "weight": 17}}, {"classes": "a", "data": {"id": "n32", "weight": 39}}, {"classes": "d", "data": {"id": "n33", "weight": 4}}, {"classes": "c", "data": {"id": "n34", "weight": 38}}, {"classes": "d", "data": {"id": "n35", "weight": 13}}, {"classes": "b", "data": {"id": "n36", "weight": 15}}, {"classes": "a", "data": {"id": "n37", "weight": 29}}, {"classes": "a", "data": {"id": "n38", "weight": 2}}, {"classes": "d", "data": {"id": "n39", "weight": 35}}, {"classes": "c", "data": {"id": "n40", "weight": 24}}, {"classes": "c", "data": {"id": "n41", "weight": 7}}, {"classes": "e", "data": {"id": "n42", "weight": 24}}, {"classes": "c", "data": {"id": "n43", "weight": 4}}, {"classes": "d", "data": {"id": "n44", "weight": 40}}, {"classes": "a", "data": {"id": "n45", "weight": 19}}, {"classes": "b", "data": {"id": "n46", "weight": 17}}, {"classes": "b", "data": {"id": "n47", "weight": 36}}, {"classes": "b", "data": {"id": "n48", "weight": 26}}, {"classes": "a", "data": {"id": "n49", "weight": 18}}], "edges": [{"data": {"source": "n5", "id": "e0", "weight": 31, "target": "n19"}}, {"data": {"source": "n37", "id": "e1", "weight": 31, "target": "n25"}}, {"data": {"source": "n19", "id": "e2", "weight": 31, "target": "n2"}}, {"data": {"source": "n16", "id": "e3", "weight": 23, "target": "n27"}}, {"data": {"source": "n29", "id": "e4", "weight": 17, "target": "n4"}}, {"data": {"source": "n1", "id": "e5", "weight": 33, "target": "n12"}}, {"data": {"source": "n13", "id": "e6", "weight": 38, "target": "n33"}}, {"data": {"source": "n12", "id": "e7", "weight": 34, "target": "n4"}}, {"data": {"source": "n32", "id": "e8", "weight": 34, "target": "n13"}}, {"data": {"source": "n44", "id": "e9", "weight": 32, "target": "n19"}}, {"data": {"source": "n31", "id": "e10", "weight": 24, "target": "n19"}}, {"data": {"source": "n35", "id": "e11", "weight": 18, "target": "n48"}}, {"data": {"source": "n25", "id": "e12", "weight": 19, "target": "n15"}}, {"data": {"source": "n31", "id": "e13", "weight": 18, "target": "n16"}}, {"data": {"source": "n24", "id": "e14", "weight": 39, "target": "n27"}}, {"data": {"source": "n47", "id": "e15", "weight": 22, "target": "n3"}}, {"data": {"source": "n1", "id": "e16", "weight": 34, "target": "n35"}}, {"data": {"source": "n22", "id": "e17", "weight": 15, "target": "n5"}}, {"data": {"source": "n37", "id": "e18", "weight": 40, "target": "n10"}}, {"data": {"source": "n37", "id": "e19", "weight": 21, "target": "n29"}}]}

解决方案

(1)是,如果您在init选项中指定了布局,则它将最初用于放置节点,而您不必指定节点位置.我认为ungrabifyWhileSimulating乔木布局选项将满足您在乔木期间交互性的要求.

(2)使用SVG渲染器,与旧版本大致相同-数量不多.我现在正在做很多重构工作,以使内核更快并处理更多元素,而我们正在研究的新的canvas渲染器有望使我们能够处理100,000个元素(甚至可能是1,000,000个元素).

(3)使用 qtip 之类的东西,然后通过cytoscape正常读取属性值. js API(即eles.data()).

(4)不幸的是,鉴于预发行版本的不断发展的特性,该API很难在Wiki上维护,并且您阅读的内容已过时.我正在建立一个更好的解决方案,并且很快就会解决.

(5)当图形为空时,这可能是乔木布局中的错误.毕竟,您是从一个空图开始的.也许,通过在$.getJSON()回调中初始化cytoscape.js暂时解决该问题?

I recently found out about Cytoscape.js and would like to try out the force-directed layouts: arbor and springy.

Now, I have a couple of questions:

  1. Is it possible to achieve a graph, by using one of the layouts, in which the node placement is based on some algorithm and node coordinates are not necessary? For example, in VivaGraphJS the graph converges so that the connected nodes form groups and lone nodes move to the periphery. If this can be done on force-directed layout, can the forces be turned off so the nodes can be selected and dragged freely on the canvas?

  2. How large graphs (number of nodes/edges) can Cytoscape realistically handle?

  3. Say that every node and edge has five attributes and I want a textbox that displays these on mouseover. What's the easiest way to do this?

  4. Wiki says that single nodes can be added like shown below, but cy doesn't have node function; is this an error? var n0 = cy.node("n1"); cy.add(n0); // add a single element, n0

  5. I tried to create a trivial random data graph that uses Arbor/Springy. The code below gives an error "data is undefined" at "return data.cy". When layout is "random" the code works. What am I doing wrong?

<!DOCTYPE html>
<html>
<head>
    <title>Test</title>
    <style type="text/css">
    .full-height { height: 600px; margin: 0 0; padding: 0 0; }
    </style>

    <script src="jquery-1.7.2.js"></script>
    <script src="demo/cytoscape.all.js"></script>
    <script src="demo/extensions/cytoscape.layout.arbor.js"></script>
    <script src="demo/extensions/cytoscape.layout.springy.js"></script>


    <script src="demo/arbor.js"></script>
    <script src="demo/arbor-tween.js"></script>
    <script src="demo/springy.js"></script>


    <script type='text/javascript'>
        function onLoad() {

             // create a mapper for node size
            var nodeSizeMapper = {
                continuousMapper: {
                    attr: {
                        name: "weight",
                        min: 0,
                        max: 40
                    },
                    mapped: {
                        min: 5,
                        max: 25
                    }
                }
            };

            $("#cy").cytoscape( {
                layout: { name: "arbor" }, // works when "random"
                style: {
                    selectors: {
                        "node":{
                            shape: "ellipse",
                            fillColor: "#3366FF",
                            height: nodeSizeMapper,
                            width: nodeSizeMapper,
                            labelText: {
                                passthroughMapper: "id"
                            }
                        },
                        "edge": {
                            lineColor: "#CCFF33",//"#ccc",
                            targetArrowColor: "#CCFF33", //"#ccc",
                            width: {
                                continuousMapper: {
                                    attr: {
                                        name: "weight",
                                        min: 20,
                                        max: 35
                                    },
                                    mapped: {
                                        min: 1,
                                        max: 3
                                    }
                                }
                            },
                            targetArrowShape: "triangle",
                            // labelText: {
                            //     passthroughMapper: "weight"
                            // }
                        },
                        "node:selected": {
                            fillColor: "#333"
                        },
                        "edge:selected":{
                            lineColor: "#666",
                            targetArrowColor: "#666"
                        }
                    }
                },                    
                ready: function(cy) { },
            });
            window.cy = $("#cy").cytoscape("get");

            $.getJSON('edges_nodes.json', function(elements) {
                //console.log(elements);
                window.elements = elements;
                cy.load( elements );
            });
        }
    </script>
</head>

<body onload="onLoad()">
        <div class="full-height" id="cy">
        </div>
</body>
</html>

The JSON file reads:

{"nodes": [{"classes": "b", "data": {"id": "n0", "weight": 40}}, {"classes": "b", "data": {"id": "n1", "weight": 19}}, {"classes": "c", "data": {"id": "n2", "weight": 0}}, {"classes": "d", "data": {"id": "n3", "weight": 19}}, {"classes": "e", "data": {"id": "n4", "weight": 4}}, {"classes": "a", "data": {"id": "n5", "weight": 21}}, {"classes": "e", "data": {"id": "n6", "weight": 13}}, {"classes": "a", "data": {"id": "n7", "weight": 6}}, {"classes": "a", "data": {"id": "n8", "weight": 10}}, {"classes": "b", "data": {"id": "n9", "weight": 6}}, {"classes": "c", "data": {"id": "n10", "weight": 24}}, {"classes": "c", "data": {"id": "n11", "weight": 14}}, {"classes": "e", "data": {"id": "n12", "weight": 11}}, {"classes": "b", "data": {"id": "n13", "weight": 6}}, {"classes": "e", "data": {"id": "n14", "weight": 24}}, {"classes": "b", "data": {"id": "n15", "weight": 26}}, {"classes": "b", "data": {"id": "n16", "weight": 6}}, {"classes": "c", "data": {"id": "n17", "weight": 36}}, {"classes": "a", "data": {"id": "n18", "weight": 7}}, {"classes": "b", "data": {"id": "n19", "weight": 37}}, {"classes": "c", "data": {"id": "n20", "weight": 28}}, {"classes": "d", "data": {"id": "n21", "weight": 11}}, {"classes": "d", "data": {"id": "n22", "weight": 20}}, {"classes": "e", "data": {"id": "n23", "weight": 7}}, {"classes": "b", "data": {"id": "n24", "weight": 31}}, {"classes": "b", "data": {"id": "n25", "weight": 1}}, {"classes": "e", "data": {"id": "n26", "weight": 29}}, {"classes": "d", "data": {"id": "n27", "weight": 31}}, {"classes": "d", "data": {"id": "n28", "weight": 34}}, {"classes": "b", "data": {"id": "n29", "weight": 40}}, {"classes": "d", "data": {"id": "n30", "weight": 38}}, {"classes": "b", "data": {"id": "n31", "weight": 17}}, {"classes": "a", "data": {"id": "n32", "weight": 39}}, {"classes": "d", "data": {"id": "n33", "weight": 4}}, {"classes": "c", "data": {"id": "n34", "weight": 38}}, {"classes": "d", "data": {"id": "n35", "weight": 13}}, {"classes": "b", "data": {"id": "n36", "weight": 15}}, {"classes": "a", "data": {"id": "n37", "weight": 29}}, {"classes": "a", "data": {"id": "n38", "weight": 2}}, {"classes": "d", "data": {"id": "n39", "weight": 35}}, {"classes": "c", "data": {"id": "n40", "weight": 24}}, {"classes": "c", "data": {"id": "n41", "weight": 7}}, {"classes": "e", "data": {"id": "n42", "weight": 24}}, {"classes": "c", "data": {"id": "n43", "weight": 4}}, {"classes": "d", "data": {"id": "n44", "weight": 40}}, {"classes": "a", "data": {"id": "n45", "weight": 19}}, {"classes": "b", "data": {"id": "n46", "weight": 17}}, {"classes": "b", "data": {"id": "n47", "weight": 36}}, {"classes": "b", "data": {"id": "n48", "weight": 26}}, {"classes": "a", "data": {"id": "n49", "weight": 18}}], "edges": [{"data": {"source": "n5", "id": "e0", "weight": 31, "target": "n19"}}, {"data": {"source": "n37", "id": "e1", "weight": 31, "target": "n25"}}, {"data": {"source": "n19", "id": "e2", "weight": 31, "target": "n2"}}, {"data": {"source": "n16", "id": "e3", "weight": 23, "target": "n27"}}, {"data": {"source": "n29", "id": "e4", "weight": 17, "target": "n4"}}, {"data": {"source": "n1", "id": "e5", "weight": 33, "target": "n12"}}, {"data": {"source": "n13", "id": "e6", "weight": 38, "target": "n33"}}, {"data": {"source": "n12", "id": "e7", "weight": 34, "target": "n4"}}, {"data": {"source": "n32", "id": "e8", "weight": 34, "target": "n13"}}, {"data": {"source": "n44", "id": "e9", "weight": 32, "target": "n19"}}, {"data": {"source": "n31", "id": "e10", "weight": 24, "target": "n19"}}, {"data": {"source": "n35", "id": "e11", "weight": 18, "target": "n48"}}, {"data": {"source": "n25", "id": "e12", "weight": 19, "target": "n15"}}, {"data": {"source": "n31", "id": "e13", "weight": 18, "target": "n16"}}, {"data": {"source": "n24", "id": "e14", "weight": 39, "target": "n27"}}, {"data": {"source": "n47", "id": "e15", "weight": 22, "target": "n3"}}, {"data": {"source": "n1", "id": "e16", "weight": 34, "target": "n35"}}, {"data": {"source": "n22", "id": "e17", "weight": 15, "target": "n5"}}, {"data": {"source": "n37", "id": "e18", "weight": 40, "target": "n10"}}, {"data": {"source": "n37", "id": "e19", "weight": 21, "target": "n29"}}]}

解决方案

(1) Yes, if you specify a layout in the init options, it will be used to place nodes initially and you won't have to specify node locations. The ungrabifyWhileSimulating arbor layout option will do what you're asking regarding interactivity during arbor, I think.

(2) With the SVG renderer, about the same as the old version -- which isn't all that many. I'm doing a lot of refactoring now to make the core faster and handle more elements, and the new canvas renderer we're working on will hopefully let us handle 100,000s of elements (or maybe even 1,000,000s of elements).

(3) Use something like qtip, and read the property values as normal via the cytoscape.js API (i.e. eles.data()).

(4) Unfortunately, the API is hard to maintain on the wiki, and what you read was out-of-date, given the evolving nature of the prerelease builds. I'm building a better solution, and it will be up soon.

(5) It's probably a bug in the arbor layout when the graph is empty. You're starting with an empty graph, after all. Perhaps, work around it for now by initialising cytoscape.js in your $.getJSON() callback?

这篇关于Cytoscape.js强制控制的布局和节点放置的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆