d3.js V3强制有向图和未链接的节点

时间:2017-09-09 19:35:46

标签: javascript d3.js

我正在做我的第一个数据可视化项目。它更多的是练习,并学习d3.js,因为数据可视化让我感兴趣。

我的第一个项目是制作一个力导向图。该数据集是与其毗邻国家相关的50个州。

源是状态,目标是边界状态。

夏威夷和阿拉斯加没有接壤国家。

如果我将目标状态留在csv文件中,它们会以一个空字符串的中间节点相互连接。

如果我的目标是空的不同长度的字符串,它们显然会附加到节点上。这几乎没问题,但现在我的工具提示中有节点有空白值。

它不是100%清洁。

我不确定这是否可行,让节点没有任何链接。

csv snippet

Georgia,North Carolina
Georgia,South Carolina
Georgia,Tennessee
Hawaii,
Idaho,Montana
Idaho,Nevada
Idaho,Oregon

创建nodeList

var nodesList = {}

data.forEach((link) => {
  link.source = nodesList[link.source] ||
    (nodesList[link.source] = { name: link.source });
  link.target = nodesList[link.target] ||
    (nodesList[link.target] = { name: link.target });
});

我尝试在那里写一个条件,如果源是阿拉斯加或夏威夷将名称设置为null,但这也不起作用。

感谢您的帮助!

1 个答案:

答案 0 :(得分:2)

由于我们无法看到您的所有代码,因此很难说出您正在做什么,但似乎基本问题是您希望夏威夷和阿拉斯加在您的节点列表中,但不在您的链接列表中。

最简单的事情,因为你知道所有状态都只有一个states.csv文件。那么只需要从你的csv制作链接列表就应该这么简单:

var links = []

data.forEach(link => {
    if (link[0] && link[1]) links.push({source: link[0], target: link[1]})
});

或者如果您更喜欢地图&过滤器:

var links = data
  .filter(link => link[0] && link[1])
  .map(link => ({source: link[0], target: link[1]}))

这是一个版本,其状态列表仅截断为链接中的状态



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

var color = d3.scaleOrdinal(d3.schemeCategory20);

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));

var states = [
     {id:"Georgia",abbreviation:"GA"},
     {id:"Hawaii",abbreviation:"HI"},
     {id:"Idaho",abbreviation:"ID"},
     {id:"Montana",abbreviation:"MT"},
     {id:"Nevada",abbreviation:"NV"},
     {id:"North Carolina",abbreviation:"NC"},
     {id:"Oregon",abbreviation:"OR"},
     {id:"South Carolina",abbreviation:"SC"},
     {id:"Tennessee",abbreviation:"TN"},
]

var data = [
     ['Georgia','North Carolina'],
     ['Georgia','South Carolina'],
     ['Georgia','Tennessee'],
     ['Hawaii'],
     ['Idaho',  'Montana'],
     ['Idaho',  'Nevada'],
     ['Idaho',  'Oregon']
]


var links = data.filter(link => link[0] && link[1])
            .map(link => ({source: link[0], target: link[1]}))
  

  var link = svg.append("g")
      .attr("class", "links")
    .selectAll("line")
    .data(links)
    .enter().append("line")
      .attr("stroke-width", 1);

  var node = svg.append("g")
      .attr("class", "nodes")
    .selectAll("circle")
    .data(states)
    .enter().append("circle")
      .attr("r", 5)
    .call(d3.drag()
          .on("start", dragstarted)
          .on("drag", dragged)
          .on("end", dragended));

  node.append("title")
      .text(function(d) { return d.abbreviation; });

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

  simulation.force("link")
      .links(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;
}

.links line {
  stroke: #999;
  stroke-opacity: 0.6;
}

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

<script src="https://d3js.org/d3.v4.min.js"></script>
<svg width="500" height="200"></svg>
&#13;
&#13;
&#13;