d3.js V3强制有向图和未链接的节点 [英] d3.js V3 force directed graph and unlinked nodes

查看:25
本文介绍了d3.js V3强制有向图和未链接的节点的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在做我的第一个数据可视化项目.这不仅是练习,而且随着数据可视化使我学习d3.js.

我的第一个项目是制作力导向图.数据集是链接到其边界状态的50个状态.

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

夏威夷和阿拉斯加没有边界国.

如果我在csv文件中将目标状态留空,则它们之间的中间节点为空字符串,它们彼此相连.

如果我将它们的目标设置为不同长度的空字符串,则它们显然会附加到节点上.几乎可以,但是现在我的节点上的工具提示中带有空白值.

这不是100%干净的.

我不确定是否有可能没有任何链接的节点.

csv片段

 北卡罗来纳州乔治亚州南卡罗来纳州佐治亚州田纳西州佐治亚州夏威夷蒙大拿州爱达荷州内华达州爱达荷州俄勒冈爱达荷州 

创建nodeList

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

我尝试在其中写一个条件,如果源是阿拉斯加或夏威夷,则将name设置为null,但这也不起作用.

感谢您的帮助!

解决方案

很难分辨您在做什么,因为我们看不到您的所有代码,但似乎最基本的问题是您想要夏威夷和Alaska在您的节点列表中,但不在您的链接列表中.

最容易做的事情是,因为您知道所有状态都只有一个states.csv文件.然后,只需从您的csv中创建一个链接列表就可以了,就像这样简单:

  var链接= []data.forEach(link => {if(link [0]&& link [1])links.push({源:链接[0],目标:链接[1]})}); 

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

  var链接=数据.filter(link => link [0]&& link [1]).map(link =>({source:link [0],target:link [1]})) 

这是一个带有状态列表的版本,该列表仅被截断为链接中的状态

  var svg = d3.select("svg"),宽度= + svg.attr(宽度"),高度= + svg.attr(高度");var color = d3.scaleOrdinal(d3.schemeCategory20);var模拟= 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状态= [{id:乔治亚州",缩写:"GA"},{id:夏威夷",缩写:"HI"},{id:爱达荷州",缩写:"ID"},{id:蒙大拿州",缩写:"MT"},{id:内华达州",缩写:"NV"},{id:北卡罗来纳州",缩写:"NC"},{id:俄勒冈州",缩写:"OR"},{id:南卡罗来纳州",缩写:"SC"},{id:田纳西州",缩写:"TN"},]var数据= [['Georgia','North Carolina'],['Georgia','South Carolina'],['Georgia','Tennessee'],['夏威夷'],['Idaho','Montana'],['Idaho','Nevada'],[爱达荷州,俄勒冈州]]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(链接).enter().append("line").attr("stroke-width",1);var node = svg.append("g").attr("class","nodes").selectAll("circle").data(状态).enter().append("circle").attr("r",5).call(d3.drag().on("start",dragstarted).on(拖动",拖动).on("end",dragged));node.append("title").text(function(d){return d.abbreviation;});模拟.nodes(状态).on("tick",勾号);Simulation.force("link").links(链接);函数tickd(){关联.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;});节点.attr("cx",function(d){return d.x;}).attr("cy",function(d){return d.y;});}函数dragstarted(d){如果(!d3.event.active)Simulation.alphaTarget(0.3).restart();d.fx = d.x;d.fy = d.y;}函数dragd(d){d.fx = d3.event.x;d.fy = d3.event.y;}函数dragended(d){如果(!d3.event.active)Simulation.alphaTarget(0);d.fx = null;d.fy = null;}  

  .links行{中风:#999;中风不透明度:0.6;}.nodes圈子{中风:#fff;笔划宽度:1.5px;}  

 <脚本src ="https://d3js.org/d3.v4.min.js"></script>< svg width ="500" height ="200"></svg>  

I'm doing my first data visualization project. It's more for practice, and to learn d3.js as data visualization interests me.

My first project is making a force directed graph. The data set is the 50 states linked to their bordering states.

The source is the state, the target is the bordering state(s).

Hawaii and Alaska have no bordering States.

If I leave the target State blank in the csv file, they attach to each other with a middle node that is an empty string.

If I make their targets empty string of different lengths, they obviously attach to nodes. That's almost okay, but now I have nodes with blank values on their tooltips.

It's just not 100% clean.

I'm not sure if this is possible, to have nodes with no link whatsoever.

csv snippet

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

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

I tried writing a conditional in there that if the source was Alaska or Hawaii to set name to null, but that didn't work either.

Thanks for any help!

解决方案

It's a little hard to tell what you're doing because we can't see all your code, but it seems like the basic problem is that you want Hawaii and Alaska in your nodelist, but not in your link list.

The easiest thing to do, since you know all the states is to just have a states.csv file. Then it's just a matter of making a links list from your csv which should be as simple as:

var links = []

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

or if you prefer map & filter:

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

Here's a version with a state list truncated to just the states in your links

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>

这篇关于d3.js V3强制有向图和未链接的节点的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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