增加网络/图表中节点之间的距离

Posted

技术标签:

【中文标题】增加网络/图表中节点之间的距离【英文标题】:Increase Distance Between Nodes in Network/Chart 【发布时间】:2017-12-02 10:47:36 【问题描述】:

我正在尝试找出一种方法来为我的 d3.js 代码在我的网络图中分隔节点。我不必关心加载页面时网络的形状,因为我只需单击并拖动节点即可制作任何我想要的形状。但我不确定我从哪里开始尝试分隔我的节点。我四处搜寻,但没有发现任何东西似乎对我有用。非常感谢您的帮助。

这是我加载页面时网络的样子: https://i.gyazo.com/919ad4bde39d9fe6a6b6c91548dbcc2f.png

这是我希望它大致看起来的样子(同样,形状并不重要,我只是希望在初始负载上保持一点距离): https://i.gyazo.com/fefa29cf861e204bc83f34cbc2d1a17d.png

(我只有8个rep所以我不能上传图片抱歉)

到目前为止,这是我的代码:

<!DOCTYPE html>
<style>

    .links line 
        stroke-opacity: 0.6;
    

    .nodes circle 
        stroke: #fff;
        stroke-width: 1.5px;
    

</style>

<html lang="en" xmlns="http://www.w3.org/1999/xhtml">

<head>

    <meta charset="utf-8" />
    <title>Group Comments</title>
    <script src="http://d3js.org/d3.v4.min.js"></script>

</head>

<body>
    <p> Not Ready: Group 6 Comments </p>
    <svg  ></svg>
    <script>

        //fetches the svg
        var svg = d3.select("svg"),
            width = +svg.attr("width"),
            height = +svg.attr("height");

        //Sets a color scale
        var color = d3.scaleOrdinal(d3.schemeCategory20);

        var strokeColor = d3.scaleLinear()
            .domain([0, 1, 2])
            .range(["white", "red", "green"]);

        //Creates a force simulation
        var simulation = d3.forceSimulation()
            .force("link", d3.forceLink().id(function (d)  return d.id; ))
            .force("charge", d3.forceManyBody())
            .force("center", d3.forceCenter(width / 2, height / 2))

        //reads the JSON file
        d3.json("NR6comments.json", function (error, graph) 
            if (error) throw error;

            //sets up the "links" between the nodes
            var link = svg.append("g")
                .attr("class", "links")
                .selectAll("line")
                .data(graph.links)
                .enter().append("line")
                    .attr("stroke-width", function (d)  return Math.sqrt(d.value) )
                    .attr("stroke", function (d)  return strokeColor(d.value) );

            //sets up the nodes
            var node = svg.append("g")
                .attr("class", "nodes")
                .selectAll("circle")
                .data(graph.nodes)
                .enter().append("circle")
                    .attr("r", 10)
                    .attr("fill", function (d)  return color(d.group); )
                    .call(d3.drag()
                        .on("start", dragstarted)
                        .on("drag", dragged)
                        .on("end", dragended));

            //displays the ID number on a node when hovering over
            node.append("title")
                .text(function (d)  return d.id; );

            simulation
                .nodes(graph.nodes)
                .on("tick", ticked);

            simulation.force("link")
                .links(graph.links);

            function ticked() 
                link
                    .attr("x1", function (d)  return d.source.x; )
                    .attr("y1", function (d)  return d.source.y; )
                    .attr("x2", function (d)  return d.target.x; )
                    .attr("y2", function (d)  return d.target.y; );

                node
                    .attr("cx", function (d)  return d.x; )
                    .attr("cy", function (d)  return d.y; );
            
        );

        function dragstarted(d) 
            if (!d3.event.active) simulation.alphaTarget(0.3).restart();
            d.fx = d.x;
            d.fy = d.y;
        

        function dragged(d) 
            d.fx = d3.event.x;
            d.fy = d3.event.y;
        

        function dragended(d) 
            if (!d3.event.active) simulation.alphaTarget(0);
            //d.fx = null;
            //d.fy = null;
        
    </script>
    <p><a href="likes.html">Likes Chart</a></p>
</body>
</html>

如果我能在这个问题上得到一些帮助,我将不胜感激。谢谢!

【问题讨论】:

【参考方案1】:

有不同的方法来实现你想要的。最简单的方法是设置strengthmanyBody 方法。根据API:

如果指定了强度,则将强度访问器设置为指定的数字或函数,重新评估每个节点的强度访问器,并返回此力。正值使节点相互吸引,类似于重力,而负值使节点相互排斥,类似于静电荷。

由于我无权访问您的数据,因此这是一个简化的演示。第一个版本没有strength,就像你的代码:

var width = 400;
var height = 300;

var svg = d3.select("body")
  .append("svg")
  .attr("width", width)
  .attr("height", height);

var nodes = [
  name: "foo",
  color: "blue"
, 
  name: "bar",
  color: "green"
, 
  name: "baz",
  color: "red"
, 
  name: "foofoo",
  color: "yellow"
, 
  name: "foobar",
  color: "blue"
, 
  name: "foobaz",
  color: "green"
, 
  name: "barfoo",
  color: "red"
, 
  name: "barbar",
  color: "yellow"
, 
  name: "barbaz",
  color: "blue"
];

var links = [
  "source": 0,
  "target": 1
, 
  "source": 0,
  "target": 2
, 
  "source": 0,
  "target": 3
, 
  "source": 1,
  "target": 3
, 
  "source": 1,
  "target": 4
, 
  "source": 2,
  "target": 5
, 
  "source": 3,
  "target": 6
, 
  "source": 1,
  "target": 7
, 
  "source": 6,
  "target": 8
, 
  "source": 0,
  "target": 7
, 
  "source": 2,
  "target": 6
, 
  "source": 3,
  "target": 8
];

var simulation = d3.forceSimulation()
  .force("link", d3.forceLink())
  .force("charge", d3.forceManyBody())
  .force("center", d3.forceCenter(width / 2, height / 2));

var link = svg.selectAll(null)
  .data(links)
  .enter()
  .append("line")
  .style("stroke", "#ccc")
  .style("stroke-width", 1);

var node = svg.selectAll(null)
  .data(nodes)
  .enter()
  .append("circle")
  .attr("r", function(d) 
    return d.r = 10;
  )
  .attr("stroke", "gray")
  .attr("stroke-width", "2px")
  .attr("fill", function(d) 
    return d.color
  );

simulation.nodes(nodes);
simulation.force("link")
  .links(links);

simulation.on("tick", function() 

  link.attr("x1", function(d) 
      return d.source.x;
    )
    .attr("y1", function(d) 
      return d.source.y;
    )
    .attr("x2", function(d) 
      return d.target.x;
    )
    .attr("y2", function(d) 
      return d.target.y;
    )

  node.attr("cx", function(d) 
    return d.x
  ).attr("cy", function(d) 
    return d.y
  );

);
&lt;script src="https://d3js.org/d3.v4.min.js"&gt;&lt;/script&gt;

然而,第二个版本将strength 设置为负值:

.force("charge", d3.forceManyBody().strength(-500))

这里是:

var width = 400;
var height = 300;

var svg = d3.select("body")
  .append("svg")
  .attr("width", width)
  .attr("height", height);

var nodes = [
  name: "foo",
  color: "blue"
, 
  name: "bar",
  color: "green"
, 
  name: "baz",
  color: "red"
, 
  name: "foofoo",
  color: "yellow"
, 
  name: "foobar",
  color: "blue"
, 
  name: "foobaz",
  color: "green"
, 
  name: "barfoo",
  color: "red"
, 
  name: "barbar",
  color: "yellow"
, 
  name: "barbaz",
  color: "blue"
];

var links = [
  "source": 0,
  "target": 1
, 
  "source": 0,
  "target": 2
, 
  "source": 0,
  "target": 3
, 
  "source": 1,
  "target": 3
, 
  "source": 1,
  "target": 4
, 
  "source": 2,
  "target": 5
, 
  "source": 3,
  "target": 6
, 
  "source": 1,
  "target": 7
, 
  "source": 6,
  "target": 8
, 
  "source": 0,
  "target": 7
, 
  "source": 2,
  "target": 6
, 
  "source": 3,
  "target": 8
];

var simulation = d3.forceSimulation()
  .force("link", d3.forceLink())
  .force("charge", d3.forceManyBody().strength(-500))
  .force("center", d3.forceCenter(width / 2, height / 2));

var link = svg.selectAll(null)
  .data(links)
  .enter()
  .append("line")
  .style("stroke", "#ccc")
  .style("stroke-width", 1);

var node = svg.selectAll(null)
  .data(nodes)
  .enter()
  .append("circle")
  .attr("r", function(d) 
    return d.r = 10;
  )
  .attr("stroke", "gray")
  .attr("stroke-width", "2px")
  .attr("fill", function(d) 
    return d.color
  );

simulation.nodes(nodes);
simulation.force("link")
  .links(links);

simulation.on("tick", function() 

  link.attr("x1", function(d) 
      return d.source.x;
    )
    .attr("y1", function(d) 
      return d.source.y;
    )
    .attr("x2", function(d) 
      return d.target.x;
    )
    .attr("y2", function(d) 
      return d.target.y;
    )

  node.attr("cx", function(d) 
    return d.x
  ).attr("cy", function(d) 
    return d.y
  );

);
&lt;script src="https://d3js.org/d3.v4.min.js"&gt;&lt;/script&gt;

【讨论】:

好心的先生,值得一吃!太感谢了!我假设如果我想要更多的距离,我只会让这个数字越来越负?有没有办法让我可以将值设置为可能的最小值,而无需任何节点离开画布? .strength(-500) 对我的大部分数据都非常好,但如果节点太多,那么我可能需要将其更改为 like .strength(-200) 之类的。那么有没有一种方法可以自动为我确定最佳强度值?非常感谢! 正如我所说,这只是一种方法......例如,您也可以使用链接距离。

以上是关于增加网络/图表中节点之间的距离的主要内容,如果未能解决你的问题,请参考以下文章

在prolog中查找图节点之间的距离

如何excel 柱状图的柱子之间的距离靠近一些

网络拓扑-节点距离的计算方法

如何excel 柱状图的柱子之间的距离靠近一些

在excel图表中怎么设置网格线之间的距离啊 ?

UBUNTU NS3里面的给2组节点设置距离具体要用哪个函数?