如何使用 D3 和 CoffeeScript 将节点替换为图像以进行网络可视化?
我已经尝试解决这个问题好几天了,完全被难住了.
我正在使用此网络实施演练:,但是我对 CoffeeScript 的熟悉程度不足以将代码添加到正确的位置......而且我觉得我已经尝试了每个地方,但没有运气.
我真正想做的是根据节点包含的数据将特定图片放在节点的位置.我希望在 CoffeeScript 本身中有一个 if 语句来插入基于所选节点的图片,(可以是名称或组或其他.)我还希望每个节点都有文本标签,显示,说数量",但是我仍然需要更多地研究如何做到这一点.
示例节点:
节点":[{匹配":1.0",名称":飞机",虚拟金额":1000",艺术家":飞机",金额":999.99",id":a1234",播放次数":500",组":airplanePic.jpg"}, {
谢谢!任何帮助将不胜感激!
(使用我的代码)
谢谢 Lars,我不知道无法将图像与 SVG 一起使用.这是我正在使用的代码:
这是我认为我需要编辑的 CoffeeScript 部分,以获取所需的 SVG 文件来替换当前节点的圆圈.
# 节点的进入/退出显示updateNodes = () ->节点 = 节点G.selectAll("circle.node").data(curNodesData, (d) -> d.id)node.enter().append("圆").attr(类",节点").attr("cx", (d) -> d.x).attr("cy", (d) -> d.y).attr("r", (d) -> d.radius).style("填充", (d) -> nodeColors(d.artist)).style("中风", (d) -> strokeFor(d)).style("笔画宽度", 1.0)
我一直在尝试使用这样的 if 语句,但是我是 CoffeeScript 新手,所以要温柔.
如果 d.group 是 "airplane" #comment: 或者我正在寻找的任何组名.attr("src", "tinyWhale.jpg")
但是,我现在知道这不起作用,因为我无法将图像导入 SVG.即使在阅读了 Lar 的评论和链接问题之后,我仍然对如何用 SVG 替换节点感到非常困惑.
我可以只创建一个 if 语句并用 google 搜索的 svg 文件替换圆圈吗?
再次感谢您的帮助.
更新 2:非常感谢 Lars,我正在尝试将其添加到 vis.coffee 文件中,但是当我添加任何代码时它会中断.这是我添加代码的方式:
第 4 个 .attr 是添加的代码.
node.enter().append("circle").attr(类",节点").attr("cx", (d) -> d.x).attr("cy", (d) -> d.y).attr("r", (d) -> d.radius) #这是添加的代码.attr("填充", (d) -> "url(#" + d.group + ")").style("填充", (d) -> nodeColors(d.artist)).style("中风", (d) -> strokeFor(d)).style("笔画宽度", 1.0)
我在这里添加了这个,这也破坏了代码.我把它放在完全错误的地方了吗?
#网络可视化的起点# 初始化可视化并开始强制布局网络=(选择,数据)-># 格式化我们的数据allData = setupData(数据)# 创建我们的 svg 和组vis = d3.select(selection).append("svg").attr("宽度", 宽度).attr(高度",高度)linksG = vis.append("g").attr("id", "links")节点G = vis.append("g").attr("id", "nodes")defs = svg.append("defs")defs.selectAll("模式").data(curNodesData).append("模式").attr("id", (d) -> d.group).append("图片").attr("xlink:href", (d) -> d.group)
感谢您的帮助和耐心等待!
这是我的 vis.coffee 文件:https://dl.dropboxusercontent.com/u/18496047/vis.coffee添加空格,因为它不会让我在问题中有多个链接.
编辑 3:使用它来关闭,我希望这将帮助我弄清楚 CoffeeScript 节点的实现.
# 从原始数据创建节点对象# 这将作为每个背后的数据# 在 vis 中冒泡,然后添加每个节点# 到@nodes 以供稍后使用create_nodes: () =>@data.forEach (d) =>节点 = {身份证:d.id半径:@radius_scale(d.total_amount)值:d.total_amount名称:d.tweet_rate组织:d.organization组:d.tweet_amounttop_conv:d.top_convx: Math.random() * 900y: Math.random() * 800}@nodes.push 节点@nodes.sort (a,b) ->b.value - a.value# 在 #vis 创建 svg 然后# 为每个节点创建圆形表示create_vis: () =>@vis = d3.select("#vis").append("svg").attr("宽度", @width).attr("身高", @height).attr("id", "svg_vis")@circles = @vis.selectAll("circle").data(@nodes, (d) -> d.id)# 使用是因为我们需要'this'# 鼠标回调那=这# 半径最初将设置为 0.# 看下面的过渡@circles.enter().append("圆").attr("r", 0).attr("填充", (d) => @fill_color(d.group)).attr("笔画宽度", 2).attr("中风", (d) => d3.rgb(@fill_color(d.group)).brighter(5)).attr("id", (d) -> "bubble_#{d.id}").on("鼠标悬停", (d,i) -> that.show_details(d,i,this)).on("mouseout", (d,i) -> that.hide_details(d,i,this))# 使气泡出现的花式过渡,以# 正确的半径@circles.transition().duration(2000).attr("r", (d) -> d.radius)
编辑 4:
为了可读性和我自己的舒适性,我将 CoffeeSctipt 转换为 JavaScript.
任何答案都可以通过 JS 或 CoffeeScript 提供.
谢谢...这个问题让我很生气.
任何想要帮助的人:plnkr.co/edit/DeI4a0gjg0p8ypRS2HUn?p=preview
解决方案为什么不用你的图片替换圆圈:
node.enter().append("image").attr(类",节点").attr("href", "tinyWhale.jpg").attr("x", function(d) { return d.x;}).attr("y", function(d) { return d.y;}).attr("宽度", function(d) { return d.radius;}).attr("高度", function(d) { return d.radius;})
代替:
node.enter().append('circle')...
I've been attempting to solve this problem for days, and am completely stumped.
I'm using this network implementation walk-through: http://flowingdata.com/2012/08/02/how-to-make-an-interactive-network-visualization/
I have successfully created my visualization through this walk-through, and now would like to replace a node with a small picture, based on the node's value.
This is a great example of code to work from, where every node was replaced with an image. http: //bl.ocks .org/mbostock/950642
Specifically:
node.append("image")
.attr("xlink:href", "https://github.com/favicon.ico")
.attr("x", -8)
.attr("y", -8)
.attr("width", 16)
.attr("height", 16);
The only issue is that this code is in JavaScript, and my implementation of the network graph is written in CoffeeScript.
I tried creating my own JavaScript file with the code above and linking to it, however this did not work for me, and quite frankly I don't know if that is the best approach to take anyway.
I tried converting the code from JavaScript into CoffeeScript through this JS to CoffeeScript tool, http://js2coffee.org/, however I am not familiar with CoffeeScript enough to add the code in the correct location... and I feel like I've tried every spot with no luck.
What I'm exactly trying to do is to put a specific picture in place of a node based on the data contained by the node. I would prefer to have an if statement in the CoffeeScript itself to insert a picture based on the node selected, (could be the name or group or whatever.) I would also like to have the text label for each node as well, displaying, say, "amount," however I still need to research more on how to do that one.
Sample node:
"nodes" : [{
"match" : "1.0",
"name" : "Airplane",
"virtualAmount" : "1000",
"artist" : "Airplane",
"amount" : "999.99",
"id" : "a1234",
"playcount" : "500",
"group" : "airplanePic.jpg"
}, {
Thanks! Any help would be very much appreciated!
Edit: (with my code)
Thank you Lars, I was unaware of the inability to use an image with an SVG. Here is the code I am working with:
This is the CoffeeScript section that I believe I need to edit to get my desired SVG file to replace what is currently a circle for a node.
# enter/exit display for nodes
updateNodes = () ->
node = nodesG.selectAll("circle.node")
.data(curNodesData, (d) -> d.id)
node.enter().append("circle")
.attr("class", "node")
.attr("cx", (d) -> d.x)
.attr("cy", (d) -> d.y)
.attr("r", (d) -> d.radius)
.style("fill", (d) -> nodeColors(d.artist))
.style("stroke", (d) -> strokeFor(d))
.style("stroke-width", 1.0)
I have been trying to use an if statement, like this, however I'm new to CoffeeScript so be gentle.
if d.group is "airplane" #comment: or whatever group name I'm looking for
.attr("src", "tinyWhale.jpg")
However, I'm now aware that this won't work since I can't import an image to an SVG. I'm still very confused as to how to replace the node with an SVG, even after reading Lar's comment and linked question.
Would I be able to just create an if statement and replace the circle with a googled svg file?
Thanks again for the help.
Update 2: Thanks so much Lars, I am trying to add this to the vis.coffee file, however it breaks when I add any of the code. Here is how I am adding the code:
The 4th .attr is the code added.
node.enter().append("circle")
.attr("class", "node")
.attr("cx", (d) -> d.x)
.attr("cy", (d) -> d.y)
.attr("r", (d) -> d.radius) #this is the code added
.attr("fill", (d) -> "url(#" + d.group + ")")
.style("fill", (d) -> nodeColors(d.artist))
.style("stroke", (d) -> strokeFor(d))
.style("stroke-width", 1.0)
And I added this here, which also breaks the code. Am I putting this in the entirely wrong spot?
# Starting point for network visualization
# Initializes visualization and starts force layout
network = (selection, data) ->
# format our data
allData = setupData(data)
# create our svg and groups
vis = d3.select(selection).append("svg")
.attr("width", width)
.attr("height", height)
linksG = vis.append("g").attr("id", "links")
nodesG = vis.append("g").attr("id", "nodes")
defs = svg.append("defs")
defs.selectAll("pattern")
.data(curNodesData)
.append("pattern")
.attr("id", (d) -> d.group)
.append("image")
.attr("xlink:href", (d) -> d.group)
Thanks for your help and patience!
Here is my vis.coffee file: https:// dl.dropboxusercontent .com/u/18496047/vis.coffee Added spaces because it won't let me have more than one link in the question.
Edit 3: Using this to go off of, which I hope will help me figure out the CoffeeScript node implementation.
# create node objects from original data
# that will serve as the data behind each
# bubble in the vis, then add each node
# to @nodes to be used later
create_nodes: () =>
@data.forEach (d) =>
node = {
id: d.id
radius: @radius_scale(d.total_amount)
value: d.total_amount
name: d.tweet_rate
org: d.organization
group: d.tweet_amount
top_conv: d.top_conv
x: Math.random() * 900
y: Math.random() * 800
}
@nodes.push node
@nodes.sort (a,b) -> b.value - a.value
# create svg at #vis and then
# create circle representation for each node
create_vis: () =>
@vis = d3.select("#vis").append("svg")
.attr("width", @width)
.attr("height", @height)
.attr("id", "svg_vis")
@circles = @vis.selectAll("circle")
.data(@nodes, (d) -> d.id)
# used because we need 'this' in the
# mouse callbacks
that = this
# radius will be set to 0 initially.
# see transition below
@circles.enter().append("circle")
.attr("r", 0)
.attr("fill", (d) => @fill_color(d.group))
.attr("stroke-width", 2)
.attr("stroke", (d) => d3.rgb(@fill_color(d.group)).brighter(5))
.attr("id", (d) -> "bubble_#{d.id}")
.on("mouseover", (d,i) -> that.show_details(d,i,this))
.on("mouseout", (d,i) -> that.hide_details(d,i,this))
# Fancy transition to make bubbles appear, ending with the
# correct radius
@circles.transition().duration(2000).attr("r", (d) -> d.radius)
Edit 4:
I converted the CoffeeSctipt to JavaScript for readability and my own comfortability.
Any answers can be contributed via JS or CoffeeScript.
Thanks... this problem is killing me.
Anyone who wants to help: plnkr.co/edit/DeI4a0gjg0p8ypRS2HUn?p=preview
解决方案Why not replacing circles with your image:
node.enter().append("image")
.attr("class", "node")
.attr("href", "tinyWhale.jpg")
.attr("x", function(d) { return d.x;})
.attr("y", function(d) { return d.y;})
.attr("width", function(d) { return d.radius;})
.attr("height", function(d) { return d.radius;})
instead of:
node.enter().append('circle')...
相关文章