d3js - 力导向图:删除仅 link 自身的节点

d3js - Force-Directed Graph: Delete node that only link to itself

我正在尝试从 this example 做力导向图,但我的数据真的很大(5000 个节点)所以我想删除一些不 link 到任何其他节点的节点.

然而,在我的 JSON 中,每个节点至少有 1 个 link(即 link 到它自己)。这是我的数据示例:

{"directed": false, "graph": {}, 
"nodes": [{"id": 0}, {"id": 1}, {"id": 2}, {"id": 3}, {"id": 4}, {"id": 5}, 
         {"id": 6}, {"id": 7}, {"id": 8}, {"id": 9}, {"id": 10}, {"id": 11}, {"id": 12}], 

"links": [{"source": 0, "target": 0}, {"source": 1, "target": 1}, 
    {"source": 2, "target": 2}, {"source": 3, "target": 3}, 
    {"source": 4, "target": 4}, {"source": 5, "target": 5}, 
    {"source": 6, "target": 6}, {"source": 7, "target": 8}, 
    {"source": 7, "target": 9}, {"source": 7, "target": 10}, 
    {"source": 7, "target": 11}, {"source": 7, "target": 7}, 
    {"source": 8, "target": 8}, {"source": 9, "target": 9}, 
    {"source": 10, "target": 10}, {"source": 11, "target": 11}, 
    {"source": 12, "target": 12}], "multigraph": false}

即,节点 id:0 只有 link {"source": 0, "target": 0},所以它应该被删除,但节点 id:7 有 links {"source": 7, "target": 8}, {"source": 7, "target": 7}。它已 linked 到另一个节点,因此不应将其删除。

我的问题是如何删除仅 link 自身的节点?[​​=17=]

一种方法是首先将链接归结为不指向同一节点的链接,即 source !== target。我选择使用 Array.prototype.reduce() although other ways of iteration will work just the same. To speed up the elimintation of nodes later on I am also employing a Set 来存储 唯一的 id 值,不过从技术上讲,这并不是工作所必需的。

let uniqueNonSelfReferringLinks = data.links.reduce((set, {source:s, target:t}) =>
  s !== t ? set.add(s).add(t) : set,
  new Set()
);

过滤节点然后归结为迭代 nodes 数组查找节点 ID 值的集合:

let filteredNodes = data.nodes.filter(n => uniqueNonSelfReferringLinks.has(n.id));

将这两个步骤合并为一个可以更简洁地写成:

let filteredNodes = data.nodes.filter(
  function(n) { return this.has(n.id); },  
  data.links.reduce((set, {source:s, target:t}) =>
    s !== t ? set.add(s).add(t) : set,
    new Set()
  )
);

看看下面的工作演示:

var data = {
  "directed": false,
  "graph": {}, 
  "nodes": [{"id": 0}, {"id": 1}, {"id": 2}, {"id": 3}, {"id": 4}, {"id": 5}, 
         {"id": 6}, {"id": 7}, {"id": 8}, {"id": 9}, {"id": 10}, {"id": 11}, {"id": 12}], 

  "links": [{"source": 0, "target": 0}, {"source": 1, "target": 1}, 
    {"source": 2, "target": 2}, {"source": 3, "target": 3}, 
    {"source": 4, "target": 4}, {"source": 5, "target": 5}, 
    {"source": 6, "target": 6}, {"source": 7, "target": 8}, 
    {"source": 7, "target": 9}, {"source": 7, "target": 10}, 
    {"source": 7, "target": 11}, {"source": 7, "target": 7}, 
    {"source": 8, "target": 8}, {"source": 9, "target": 9}, 
    {"source": 10, "target": 10}, {"source": 11, "target": 11}, 
    {"source": 12, "target": 12}],
  "multigraph": false
};

let filteredNodes = data.nodes.filter(
  function(n) { return this.has(n.id); },  
  data.links.reduce((set, {source:s, target:t}) =>
    s !== t ? set.add(s).add(t) : set,
    new Set()
  )
);

console.log(filteredNodes);