我正在做我的第一个数据可视化项目。它更多的是练习,并学习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,但这也不起作用。
感谢您的帮助!
答案 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;