I'm trying to dynamically update a d3 circle pack layout with data I receive in json. Every second I call d3.json() to get the new json. Instead of updating the existing visualization, my implementation just creates a new one under the old one. I want to to dynamically update the existing layout instead...
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="d3.v2.js">
</script>
<script type="text/javascript" src="jquery-1.4.min.js"></script>
<link rel="stylesheet" href="style.css" type="text/css">
<link rel="stylesheet" href="syntax.css" type="text/css">
<link rel="stylesheet" href="pack.css" type="text/css">
</head>
<body>
<div id="chart"> </div>
<script type="text/javascript">
var width = 960,
height = 960,
format = d3.format(",d");
var pack = d3.layout.pack()
.size([width - 4, height -4])
.value(function(d) { return d.size; });
var vis = null;
var node = null;
vis = d3.select("#chart").append("svg")
.attr("width", width)
.attr("height", height)
.attr("class", "pack");
/* vis.append("g")
.attr("transform", "translate(2, 2)"); */
function update(json){
// Creating the circle packed core
var gNodes = vis.data([json]).selectAll("g.node")
.data(pack.nodes);
//remove old data
gNodes.exit().remove();
}
setInterval(function(){
d3.json("http://10.0.1.4:8080/cluster", function(json) {
update(json);
//update the visualization
vis
.selectAll("circle")
.data([json]).selectAll("g.node")
.data(pack.nodes)
.attr("class", function(d) { return d.children ? "node" : "leaf node"; })
.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; })
.transition()
.duration(500)
.attr("r", function(d) { return d.children ? coreSize : d.r; });
var node = gNodes
.enter().append("g")
.attr("class", function(d) { return d.children ? "node" : "leaf node"; })
.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });
node.append("title")
.text(function(d) { return (d==null? "": d.name + (d.children ? "" : ": " + format(d.size))); });
node.append("circle")
.attr("r", function(d) { return (d==null? 0: d.r); });
node.filter(function(d) { return (d==null? "" : !d.children); }).append("text")
.attr("text-anchor", "middle")
.attr("dy", ".3em")
.text(function(d) { return (d==null?"":d.name.substring(0, d.r / 3)); });
});
}, 1000);
</script>
Take a look at my example here.
Basically, there is code for initial load, where all circles, tooltips, etc. are created and positioned in initial places. As well, the layout (pack) is created.
Than, on each button press, new data is loaded into pack, and the pack is recalculated. That crucial code is here:
if (dataSource == 0)
pack.value(function(d) { return d.size; });
if (dataSource == 1)
pack.value(function(d) { return 100; });
if (dataSource == 2)
pack.value(function(d) { return 1 +
Math.floor(Math.random()*501); });
var data1 = pack.nodes(data);
( I have three buttons, thats why 3 ifs)
After that, elements are tranistioned to new positions, and its attributes are changed as you determine.
Here are some pics with transition in action:
Start:
Transition:
End:
Related
I met a problem that I want to put the state name on my geo chart. I tried to use others' method, but they cannot well-matched with my chart. Could you please let me know what's wrong with my code and how to improve it.Thank you in advance!
Index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="stylesheet" href="stylemap.css">
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id = "chart"></div>
<script src="https://d3js.org/d3.v5.js"></script>
<script src="mainmap.js"></script>
</body>
</html>
Mainmap.js:
//weight and height
var chart_height = 600;
var chart_width = 800;
var color = d3.scaleQuantize().range([ 'rgb(255,245,240)','rgb(254,224,210)','rgb(252,187,161)',
'rgb(252,146,114)','rgb(251,106,74)','rgb(239,59,44)',
'rgb(203,24,29)','rgb(165,15,21)','rgb(103,0,13)']);
//Projection
var projection = d3.geoAlbersUsa()
.scale([chart_width])
.translate([chart_width / 2, chart_height / 2 ]);
// .translate([0, 100]);
var path = d3.geoPath(projection);
// .projection(projection);
//create svg
var svg = d3.select('#chart')
.append("svg")
.attr('width', chart_width)
.attr('height', chart_height);
// svg.append("rect")
// .attr("class", "background")
// .attr("width", width)
// .attr("height", height);
var g = svg.append("g")
.attr("transform", "translate(" + chart_width / 2 + "," + chart_height / 2 + ")")
.append("g")
.attr("id", "states");
//Data
d3.json('zombie-attacks.json').then(function(zombie_data){
color.domain([
d3.min(zombie_data, function(d){
return d.num;
}),
d3.max(zombie_data, function(d){
return d.num;
})
]);
d3.json('us.json').then(function(us_data){
us_data.features.forEach(function(us_e, us_i){
zombie_data.forEach(function(z_e,z_i){
if(us_e.properties.name !== z_e.state){
return null;
}
us_data.features[us_i].properties.num = parseFloat(z_e.num)
});
});
// console.log(us_data)
svg.selectAll('path')
.data(us_data.features)
.enter()
.append('path')
.attr('d',path)
.attr('fill', function(d){
var num = d.properties.num;
return num ? color(num) : '#ddd';
})
.text(function(d){
return d.properties.name;
})
.attr('stroke', '#fff')
.attr('stroke-width',1)
.attr("class", "country-label")
.append("text")
// .attr("transform", function(d) { console.log("d", d); return "translate(" + path.centroid(d) + ")"; })
// .text(function(d) { return d.properties.name; })
.attr("dy", function (d) {
return "0.35em";
})
.style('fill', 'black');
g.selectAll("text")
.data(us_data.features)
.enter()
.append("text")
.text(function(d){
return d.properties.name;
})
.attr("x", function(d){
return path.centroid(d)[0];
})
.attr("y", function(d){
return path.centroid(d)[1];
})
.attr("text-anchor","middle")
.attr('font-size','6pt')
.style('fill', 'green');
})
})
// Add names of the states to a map in d3.js
You're appending text and path to different parents: svg and g. This is an issue because:
var g = svg.append("g")
.attr("transform", "translate(" + chart_width / 2 + "," + chart_height / 2 + ")")
Your g, with the text has a transform that the svg doesn't. Which is why your text is pushed width/2, height/2 further than the projected paths. Just use svg.selectAll for the text.
The projection already has a translate applied to it, you can either apply the translation to the parent or to the projection, but shouldn't use both.
I have ran into a problem of pointers changing their size along with the link width. I wanted to be able to dynamically change link width based on number of connections between the nodes. This function seems to be working fine, but now my pointers also change size and shift away. I would like pointers to stay the same size and not shift. Here is the fiddle: https://jsfiddle.net/Alexey_D3/xhx3L8jn/1/
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<meta name="robots" content="noindex, nofollow">
<meta name="googlebot" content="noindex, nofollow">
<script type="text/javascript" src="d3.v3.js"></script>
<style type="text/css">
.link {
stroke: #999;
stroke-opacity: .6;
}
.node text {
pointer-events: none;
font: 10px sans-serif;
color: black;
}
</style>
<title>OnlineQ</title>
</head>
<body>
<div id="container" class="container">
<div id="sidebar" style="display: none;">
<div class="item-group">
<label class="item-label">Filter</label>
<div id="filterContainer" class="filterContainer checkbox-interaction-group"></div>
</div>
</div>
<div id="graphContainer" class="graphContainer">
<script>
var links =
[
{"source":"a0","target":"a0","s_portfolio":"a","t_portfolio":"a","SOURCE_TYPE":"APP","DES_TYPE":"APP"},
{"source":"a1","target":"a2","s_portfolio":"a","t_portfolio":"c","SOURCE_TYPE":"APP","DES_TYPE":"APP"},
{"source":"a1","target":"a2","s_portfolio":"a","t_portfolio":"c","SOURCE_TYPE":"APP","DES_TYPE":"APP"},
{"source":"a1","target":"a0","s_portfolio":"b","t_portfolio":"a","SOURCE_TYPE":"APP","DES_TYPE":"APP"},
{"source":"a2","target":"a3","s_portfolio":"c","t_portfolio":"d","SOURCE_TYPE":"APP","DES_TYPE":"DB"},
{"source":"a4","target":"a3","s_portfolio":"e","t_portfolio":"d","SOURCE_TYPE":"APP","DES_TYPE":"DB"},
{"source":"a4","target":"a3","s_portfolio":"e","t_portfolio":"d","SOURCE_TYPE":"APP","DES_TYPE":"DB"},
{"source":"a4","target":"a3","s_portfolio":"e","t_portfolio":"d","SOURCE_TYPE":"APP","DES_TYPE":"DB"},
{"source":"a4","target":"a3","s_portfolio":"e","t_portfolio":"d","SOURCE_TYPE":"APP","DES_TYPE":"DB"},
{"source":"a1","target":"a2","s_portfolio":"a","t_portfolio":"c","SOURCE_TYPE":"APP","DES_TYPE":"APP"}
];
//Constants for the SVG
var width = 600,
height = 600;
var counter = {};
links.forEach(function(obj) {
var key = JSON.stringify(obj);
counter[key] = (counter[key] || 0) + 1
});
var finalArray = [];
for (var key in counter) {
var tempkey = key.substring(0, key.length - 1) + ",\"value\":" + counter[key] + "}";
finalArray.push(tempkey)
};
finalArray.forEach(function(d, i, array) {
array[i] = (JSON.parse(d))
})
console.log(finalArray);
var nodes = {};
// Compute the distinct nodes from the links.
finalArray.forEach(function(link) {
link.source = nodes[link.source] || (nodes[link.source] = {name: link.source, portfolio: link.s_portfolio, s_node_TYPE: link.SOURCE_TYPE});
link.target = nodes[link.target] || (nodes[link.target] = {name: link.target, portfolio: link.t_portfolio, t_node_TYPE: link.DES_TYPE});
});
//Set up the colour scale
var color = d3.scale.category20();
//Set up the force layout
var force = d3.layout.force()
.size([width, height])
.linkDistance(200)
.gravity(0.01);
//Append a SVG to the body of the html page. Assign this SVG as an object to svg
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
var linkedByIndex = {};
//Creates the graph data structure out of the json data
force.nodes(d3.values(nodes))
.links(finalArray)
.start();
//Create all the line svgs but without locations yet
var link = svg.selectAll(".link")
.data(finalArray)
.enter().append("line")
.attr("class", "link")
.style("stroke-width", function(d) {
if (d.value <2.5) { return 1}
if (d.value >2.5 && d.value <3.5) { return 2}
if (d.value >3.5) { return 3}
})
.style("marker-end", function(d) {
if (d.SOURCE_TYPE == "DB" || d.DES_TYPE =="DB" || d.source==d.target) {return ""}
else {return "url(#source)";}}) //Added ;
//Do the same with the circles for the nodes - no
console.log(links);
var node = svg.selectAll(".node")
.data(force.nodes())
.enter().append("g")
.attr("class", function (d) {
if (d.type == "a") {
return "BA node";
} else {
return "other node";
}
})
.on("mouseover", mouseover)
.on("mouseout", mouseout)
.call(force.drag);
d3.selectAll(".BA").append("rect")
.attr("width", 10)
.attr("height", 10)
.attr("stroke", "black")
.attr("stroke-width", function(d) {
if (d.class == "L") {return 0}
if (d.class == "M") {return 1}
else {return 2}
;})
.style("fill", function (d) { return color(d.portfolio);
});
d3.selectAll(".other").append("circle")
.attr("r", 8)
.attr("stroke", "black")
.attr("stroke-width", function(d) {
if (d.class == "L") {return 0}
if (d.class == "M") {return 1}
else {return 2}
;})
.style("fill", function (d) { return color(d.portfolio);
});
node.append("text")
.attr("dx", 10)
.attr("dy", ".35em")
.style("stroke", "white")
.style("stroke-width", 2)
.text(function(d) { return d.name; });
node.append("text")
.attr("dx", 10)
.attr("dy", ".35em")
.text(function(d) { return d.name });
//End changed
svg.append("arrow").selectAll("marker")
.data(["source", "target"])
.enter().append("marker")
.attr("id", function(d) { return d; })
.attr("viewBox", "0 -5 10 10")
.attr("refX", 25)
.attr("refY", 0)
.attr("markerWidth", 8)
.attr("markerHeight", 8)
.attr("orient", "auto")
.append("path")
.attr("d", "M0,-5L10,0L0,5 L10,0 L0, -5")
.style("stroke", "#4679BD")
.style("opacity", "0.6");
//Now we are giving the SVGs co-ordinates - the force layout is generating the co-ordinates which this code is using to update the attributes of the SVG elements
force.on("tick", function () {
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("transform", function (d) {
return "translate(" + d.x + "," + d.y + ")"; });
finalArray.forEach(function(d) {
linkedByIndex[d.source.index + "," + d.target.index] = 1;
linkedByIndex[d.target.index + "," + d.source.index] = 1;
});
});
function neighboring(a, b) {
return a.index == b.index || linkedByIndex[a.index + "," + b.index];
}
function mouseover(d) {
d3.selectAll("path").style("stroke","red").style("stroke-width",1);
d3.selectAll(".link").style("stroke","black");
d3.selectAll(".link").transition().duration(500)
.style("opacity", function(o) {
return o.source === d || o.target === d ? 1 : .1;
});
d3.selectAll(".link2").style("stroke","black");
d3.selectAll(".link2").transition().duration(500)
.style("opacity", function(o) {
return o.source === d || o.target === d ? 1 : .1;
});
d3.selectAll(".node").transition().duration(500)
.style("opacity", function(o) {
return neighboring(d, o) ? 1 : .1;
});
}
function mouseout() {
d3.selectAll("path").style("stroke","#4679BD").style("stroke-width",1);
d3.selectAll(".link").style("stroke","grey");
d3.selectAll(".link").transition().duration(500)
.style("opacity", 1);
d3.selectAll(".link2").style("stroke","green");
d3.selectAll(".link2").transition().duration(500)
.style("opacity", 1);
d3.selectAll(".node").transition().duration(500)
.style("opacity", 1);
}
/*
src="https://d3js.org/d3.v3.js">
type="text/javascript" src="https://raw.githubusercontent.com/john-guerra/forceInABox/master/forceInABox.js">
type="text/javascript" src="http://code.jquery.com/jquery-2.1.0.js">
*/
</script>
</div>
</div>
</body>
</html>
why pointers change size along with the link width?
That's the normal behaviour of an SVG marker: the wider the stroke of the path, the larger the marker. According to the documentation, the default behaviour is:
‘markerWidth’, ‘markerHeight’ and the contents of the ‘marker’ represent values in a coordinate system which has a single unit equal the size in user units of the current stroke width (emphasis mine)
To prevent that, you have to use markerUnits = userSpaceOnUse:
.attr("markerUnits", "userSpaceOnUse")
Here is your updated fiddle: https://jsfiddle.net/gnv1x84k/
(PS: I made some changes in your fiddle, which was not producing any arrow heads)
Would like to add an infobox to a d3.js file.
Have studied this SO question, and this SO question, and this SO question, and this fiddle.
Most of the following HTML + JavaScrip + d3.js + JSON file works as planned.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
<script src="http://labratrevenge.com/d3-tip/javascripts/d3.tip.v0.6.3.js" charset="utf-8"></script>
<style type="text/css">
.node { cursor: pointer; }
.node circle { fill: #fff; stroke: steelblue; stroke-width: 1.5px; }
.node text { font: 10px sans-serif; }
.link { fill: none; stroke: #ccc; stroke-width: 1.5px; }
.link:hover { stroke:blue; }
div#tooltip{ color:#ffffff; background:#000000; opacity:1; padding:5px; }
</style>
<title>Soils with Local JSON</title>
</head>
<body>
<h1>Soils with Local JSON</h1>
<div id="tooltip" style="display:none"></div>
<script type="text/javascript">
var margin = {
top: 20,
right: 120,
bottom: 20,
left: 120
},
width = 1000 - margin.right - margin.left,
height = 400 - margin.top - margin.bottom;
var i = 0,
duration = 750,
root;
var tree = d3.layout.tree()
.size([height, width]);
var diagonal = d3.svg.diagonal()
.projection(function (d) {
return [d.y, d.x];
});
//Add tool tip: d3-tip.
var tip = d3.tip()
.attr('class', 'd3-tip')
.html(function(d) { return '' + d.name + '' });
var svg = d3.select("body").append("svg")
.attr("width", width + margin.right + margin.left)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
//Call tool-tip in var svg =
.call(tip);
var root = {
"name":"Soil","children":[
{"name":"Albaqualfs","url":"http://en.wikipedia.org/wiki/Albaqualfs","children":[
{"name":"Aeric Albaqualfs","children":[
{"name":"Auxvasse"},
{"name":"Cayagua"},
{"name":"Mamou"},
{"name":"Marine"},
{"name":"Medoc"},
{"name":"Springfield"},
{"name":"Tenot"}]}]}]};
root.x0 = height / 2;
root.y0 = 0;
function collapse(d) {
if (d.children) {
d._children = d.children;
d._children.forEach(collapse);
d.children = null;
}
}
root.children.forEach(collapse);
update(root);
d3.select(self.frameElement).style("height", "800px");
function update(source) {
// Compute the new tree layout.
var nodes = tree.nodes(root).reverse(),
links = tree.links(nodes);
// Normalize for fixed-depth.
nodes.forEach(function (d) {
d.y = d.depth * 180;
});
// Update the nodes
var node = svg.selectAll("g.node")
.data(nodes, function (d) {
return d.id || (d.id = ++i);
});
// Enter any new nodes at the parent's previous position.
var nodeEnter = node.enter().append("g")
.attr("class", "node")
.attr("transform", function (d) {
return "translate(" + source.y0 + "," + source.x0 + ")";
})
.on("click", click);
nodeEnter.append("circle")
.attr("r", 1e-6)
.style("fill", function (d) {
return d._children ? "lightsteelblue" : "#fff";
});
nodeEnter.append("text")
.attr("x", function (d) {
return d.children || d._children ? -10 : 10;
})
.attr("dy", ".35em")
.attr("text-anchor", function (d) {
return d.children || d._children ? "end" : "start";
})
.text(function (d) {
return d.name;
})
.style("fill-opacity", 1e-6)
.on("mouseover", function (d) {
var r = d3.select(this).node().getBoundingClientRect();
d3.select("div#tooltip")
.style("display", "inline")
.style("top", (r.top-25) + "px")
.style("left", r.left + "px")
.style("position", "absolute")
.text(d.test);
})
.on("mouseout", function(){
d3.select("div#tooltip").style("display", "none")
});
// Transition nodes to their new position.
var nodeUpdate = node.transition()
.duration(duration)
.attr("transform", function (d) {
return "translate(" + d.y + "," + d.x + ")";
});
nodeUpdate.select("circle")
.attr("r", 4.5)
.style("fill", function (d) {
return d._children ? "lightsteelblue" : "#fff";
});
nodeUpdate.select("text")
.style("fill-opacity", 1);
// Transition exiting nodes to the parent's new position.
var nodeExit = node.exit().transition()
.duration(duration)
.attr("transform", function (d) {
return "translate(" + source.y + "," + source.x + ")";
})
.remove();
nodeExit.select("circle")
.attr("r", 1e-6);
nodeExit.select("text")
.style("fill-opacity", 1e-6);
// Update the links
var link = svg.selectAll("path.link")
.data(links, function (d) {
return d.target.id;
});
// Enter any new links at the parent's previous position.
link.enter().insert("path", "g")
.attr("class", "link")
.attr("d", function (d) {
var o = {
x: source.x0,
y: source.y0
};
return diagonal({
source: o,
target: o
});
});
// Transition links to their new position.
link.transition()
.duration(duration)
.attr("d", diagonal);
// Transition exiting nodes to the parent's new position.
link.exit().transition()
.duration(duration)
.attr("d", function (d) {
var o = {
x: source.x,
y: source.y
};
return diagonal({
source: o,
target: o
});
})
.remove();
// Stash the old positions for transition.
nodes.forEach(function (d) {
d.x0 = d.x;
d.y0 = d.y;
});
}
// Toggle children on click.
function click(d) {
if (d.children) {
d._children = d.children;
d.children = null;
} else {
d.children = d._children;
d._children = null;
}
update(d);
}
</script>
</body>
</html>
Now would like to add an infobox for an item that displays information like this:
Am currently working with d3-tip.
The included file has a JSON field for "name" and "url". It also includes an attempt to map the "url" to d.url and "name" to d.name.
One issue is the need to keep the infobox temporarily persistent so that users can click the item's URL if they choose. Once the cursor is moved away from the infobox, it should clear.
The target infobox image above shows an X to close the infobox if clicked. However, I don't see how to introduce a second selector - the current selector opens the next level of the tree. Therefore, I'm hoping that a temporarily persistent infobox, revealed on mouseover, can be implemented.
The infobox can overlay the tree data - no need to re-draw the tree to adjust to the placement of the infobox.
How to correct the d3-tip code to work as desired?
If an SO reader uses an alternative to d3-tip that basically accomplishes the same task, that would be good too.
I am attempting to create a Sankey diagram from a csv file. I am utilizing code provided by timelyportfolio, and also the code from the d3 site (and even the sample csv files). However, when I try to run the code in Chrome, I am getting a blank Html page, indicating that the code is crashing. I attempted to redirect the source codes to files on my desktop, but I am still running into the same issues. (I am working on a computer with Windows XP)
I have pasted the code below:
<!DOCTYPE html>
<meta charset="utf-8">
<title>SANKEY Experiment</title>
<style>
.node rect {
cursor: move;
fill-opacity: .9;
shape-rendering: crispEdges;
}
.node text {
pointer-events: none;
text-shadow: 0 1px 0 #fff;
}
.link {
fill: none;
stroke: #000;
stroke-opacity: .2;
}
.link:hover {
stroke-opacity: .5;
}
</style>
<body>
<p id="chart">
<script src="http://d3js.org/d3.v3.js"></script>
<script src="C:\Documents and Settings\jennifer.ducz\Desktop\sankey.js"></script>
<script>
var units = "Units";
var margin = {top: 10, right: 10, bottom: 10, left: 10},
width = 1400 - margin.left - margin.right,
height = 740 - margin.top - margin.bottom;
var formatNumber = d3.format(",.0f"), // zero decimal places
format = function(d) { return formatNumber(d) + " " + units; },
color = d3.scale.category20();
// append the svg canvas to the page
var svg = d3.select("#chart").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform",
"translate(" + margin.left + "," + margin.top + ")");
// Set the sankey diagram properties
var sankey = d3.sankey()
.nodeWidth(36)
.nodePadding(10)
.size([width, height]);
var path = sankey.link();
// load the data with d3.csv instead of d3.json
//for another much simpler example uncomment the below
d3.csv("C:\Documents and Settings\jennifer.ducz\Desktop\sankey.csv", function(error, data) {
//d3.csv("d3noob_energy.csv", function(error, data) {
//set up graph in same style as original example but empty
graph = {"nodes" : [], "links" : []};
data.forEach(function (d) {
graph.nodes.push({ "name": d.source });
graph.nodes.push({ "name": d.target });
graph.links.push({ "source": d.source, "target": d.target, "value": +d.value });
});
//thanks Mike Bostock https://groups.google.com/d/msg/d3-js/pl297cFtIQk/Eso4q_eBu1IJ
//this handy little function returns only the distinct / unique nodes
graph.nodes = d3.keys(d3.nest()
.key(function (d) { return d.name; })
.map(graph.nodes));
//it appears d3 with force layout wants a numeric source and target
//so loop through each link replacing the text with its index from node
graph.links.forEach(function (d, i) {
graph.links[i].source = graph.nodes.indexOf(graph.links[i].source);
graph.links[i].target = graph.nodes.indexOf(graph.links[i].target);
});
//now loop through each nodes to make nodes an array of objects rather than an array of strings
graph.nodes.forEach(function (d, i) {
graph.nodes[i] = { "name": d };
});
sankey
.nodes(graph.nodes)
.links(graph.links)
.layout(32);
// add in the links
var link = svg.append("g").selectAll(".link")
.data(graph.links)
.enter().append("path")
.attr("class", "link")
.attr("d", path)
.style("stroke-width", function(d) { return Math.max(1, d.dy); })
.sort(function(a, b) { return b.dy - a.dy; });
// add the link titles
link.append("title")
.text(function(d) {
return d.source.name + " → " +
d.target.name + "\n" + format(d.value); });
// add in the nodes
var node = svg.append("g").selectAll(".node")
.data(graph.nodes)
.enter().append("g")
.attr("class", "node")
.attr("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")"; })
.call(d3.behavior.drag()
.origin(function(d) { return d; })
.on("dragstart", function() {
this.parentNode.appendChild(this); })
.on("drag", dragmove));
// add the rectangles for the nodes
node.append("rect")
.attr("height", function(d) { return d.dy; })
.attr("width", sankey.nodeWidth())
.style("fill", function(d) {
return d.color = color(d.name.replace(/ .*/, "")); })
.style("stroke", function(d) {
return d3.rgb(d.color).darker(2); })
.append("title")
.text(function(d) {
return d.name + "\n" + format(d.value); });
// add in the title for the nodes
node.append("text")
.attr("x", -6)
.attr("y", function(d) { return d.dy / 2; })
.attr("dy", ".35em")
.attr("text-anchor", "end")
.attr("transform", null)
.text(function(d) { return d.name; })
.filter(function(d) { return d.x < width / 2; })
.attr("x", 6 + sankey.nodeWidth())
.attr("text-anchor", "start");
// the function for moving the nodes
function dragmove(d) {
d3.select(this).attr("transform",
"translate(" + (
d.x = Math.max(0, Math.min(width - d.dx, d3.event.x))
) + "," + (
d.y = Math.max(0, Math.min(height - d.dy, d3.event.y))
) + ")");
sankey.relayout();
link.attr("d", path);
}
});
</script>
</body>
</html>
If someone can tell me what I'm doing wrong, please let me know.
Edit: This is the sample data I'm using courtesy of timelyportfolio
source target value
Barry Elvis 2
Frodo Elvis 2
Frodo Sarah 2
Barry Alice 2
Elvis Sarah 2
Elvis Alice 2
Sarah Alice 4
I've never played with it; however,
1) run your developer tools/console to see exactly which line is crashing the app
2) the following link discusses problems/solutions in formatting the data
http://www.d3noob.org/2013/02/sankey-diagrams-description-of-d3js-code.html
if you are not using MAMP or any other kind of virtual server, Chrome won't load the csv or any other local files other than the html. Try using a local webserver and everything should be fine
I want to change the word cloud when the onchange functions is triggered.
in my current scriupt bellow, when I change the selection from the drop down list the other image shows up on my chrome windows, I think this might have something to do with this like d3.select("body").append("svg")
How can I show one wordcloud at a time and not append to the current windows?
I tried d3.select("body") = "svg" instead but didn't work, I tried to remove empty clear the screen body element and then shows up the word cloud didn't work too.
Any hint will be highly appreciated!
Thanks!
<!DOCTYPE html>
<meta charset="utf-8">
<body>
<script src="js/d3.js"></script>
<script src="js/d3.layout.cloud.js"></script>
<script>
function displayResult()
{
//location.reload();
//var e = document.getElementsByTagName('svg');
//e.removeChild(document.body.svg);
var client_name=document.getElementById("client_name");
var client_nameSelected = client_name.options[client_name.selectedIndex].value;
//alert(client_nameSelected);
var fill = d3.scale.category20();
//var ClientName = {"Hello":0.10 , "world":0.20, "normally cool!":0.25, "you":0.15, "want":0.60, "more":0.45, "words":0.90 };
var data = { 'name1':{"Hello":0.10 , "world":0.20, "normally cool!":0.65, "you":0.15, "want":0.60, "more":0.85, "words":0.90 }, 'name2':{"Hello":0.10 , "world":0.20, "normally cool!":0.25, "you you":0.15, "Hug":0.99, "more feedback":0.45, "words":0.90 }};
var ClientName = data[client_nameSelected];
var keysdic = Object.keys(ClientName);
//document.write(keysdic);
d3.layout.cloud().size([600, 600])
.words( [].concat(keysdic)
.map(function(d) {
var wordsize = 10 + ClientName[d] * 40 ;
result = {text: d, size: wordsize };
return result;
}))
.padding(5)
.rotate(function() { return ~~(Math.random() * 2) * 90; })
.font("Impact")
.fontSize(function(d) { return d.size; })
.on("end", draw)
.start();
function draw(words) {
d3.select("body").append("svg")
.attr("padding", 60)
.attr("width", 600)
.attr("height", 600)
.append("g")
.attr("transform", "translate(150,150)")
.selectAll("text")
.data(words)
.enter().append("text")
.style("font-size", function(d) { return d.size + "px"; })
.style("font-family", "Impact")
.style("fill", function(d, i) { return fill(i); })
.attr("text-anchor", "middle")
.attr("transform", function(d) {
return "translate(" + [d.x, d.y] + ")rotate(" + d.rotate + ")";
})
.text(function(d) { return d.text; });
}
}
</script>
<body>
Client Name List :
<select name = 'client_name' id = "client_name" onchange="displayResult();" >
<option value='name1'>name1</option>
<option value='name2'>name2</option>
</select><br />
<body>