I'm trying to make a bubble chart for class, but somehow it doesn't work at all, I checked the code again and again, couldn't find what's wrong with it.
<!DOCTYPE html>
<html>
<head>
<title>bubble</title>
<script src="https://d3js.org/d3.v3.min.js"></script>
</head>
<body>
</body>
<script type="text/javascript">
var diameter = 500, //max size of the bubbles
color = d3.scale.category20b(); //color category
var bubble = d3.layout.pack()
.sort(null)
.size([diameter, diameter])
.padding(1.5);
var svg = d3.select("body")
.append("svg")
.attr("width", diameter)
.attr("height", diameter)
.attr("class", "bubble");
d3.csv("fruit.csv", function(error, data){
//convert numerical values from strings to numbers
data = data.map(function(d){ d.value = +d["Amount"]; return d; });
//bubbles needs very specific format, convert data to this.
var nodes = bubble.nodes({children:data}).filter(function(d) { return !d.children; });
//setup the chart
var bubbles = svg.append("g")
.attr("transform", "translate(0,0)")
.selectAll(".bubble")
.data(nodes)
.enter();
//create the bubbles
bubbles.append("circle")
.attr("r", function(d){ return d.r; })
.attr("cx", function(d){ return d.x; })
.attr("cy", function(d){ return d.y; })
.style("fill", function(d) { return color(d.value); });
//format the text for each bubble
bubbles.append("text")
.attr("x", function(d){ return d.x; })
.attr("y", function(d){ return d.y + 5; })
.attr("text-anchor", "middle")
.text(function(d){ return d["Fruit"]; })
.style({
"fill":"white",
"font-family":"Helvetica Neue, Helvetica, Arial, san-serif",
"font-size": "12px"
});
})
</script>
</html>
And this is the data file I'm using, the file name is fruit.csv. I did check everything line by line, couldn't find anything wrong
Fruit,Amount
Apple,32
Orange,89
Banana,15
Related
I am new to Javascript and D3.js and I am currently trying to build a bubble chart in d3.js using an example provided here https://jrue.github.io/coding/2014/exercises/basicbubblepackchart/ and modifying it according to my assignment. I know that the example above was written in a previous version of d3, and I am using version v4 where syntax has slightly changed,however I am getting a following error when running a program:
Uncaught TypeError: d3.pack(...).sort is not a function
var diameter = 500, //max size of the bubbles
color = d3.scaleOrdinal(d3.schemeCategory10); //color category
var bubble = d3.pack()
.sort()
.size([diameter, diameter])
.padding(1.5);
var svg = d3.select("body")
.append("svg")
.attr("width", diameter)
.attr("height", diameter)
.attr("class", "bubble");
d3.csv("teams.csv", function(error, data){
data = data.map(function(d){ d.value = +d["Amount"]; return d; });
var nodes = bubble.nodes({children:data}).filter(function(d) { return !d.children; });
//setup the chart
var bubbles = svg.append("g")
.attr("transform", "translate(0,0)")
.selectAll(".bubble")
.data(nodes)
.enter();
bubbles.append("circle")
.attr("r", function(d){ return d.r; })
.attr("cx", function(d){ return d.x; })
.attr("cy", function(d){ return d.y; })
.style("fill", function(d) { return color(d.value); });
bubbles.append("text")
.attr("x", function(d){ return d.x; })
.attr("y", function(d){ return d.y + 5; })
.attr("text-anchor", "middle")
.text(function(d){ return d["Team"]; })
.style({
"fill":"black",
"font-family":"Helvetica Neue, Helvetica, Arial, san-serif",
"font-size": "12px"
});
What is the problem here?
Be sure to use the same version of d3 as the author in the example (it looks like you're good by the syntax). Also, it's 'd3.layout.pack().sort(null)'
:)
Hello I currently have a stacked bar chart in d3,js that currently won't transition.
The chart is able to update but unfortunately no transition :(
I am under the feeling that there is a 1 line fix to this.
Please help!!!
Took this from
http://bl.ocks.org/anotherjavadude/2940908
<!DOCTYPE html>
<html>
<head>
<title>Simple Stack</title>
<script src="http://d3js.org/d3.v3.js"></script>
<style>
svg {
border: solid 1px #ccc;
font: 10px sans-serif;
shape-rendering: crispEdges;
}
</style>
</head>
<body>
<div id="viz"></div>
<script type="text/javascript">
var w = 960,
h = 500
// create canvas
var svg = d3.select("#viz").append("svg:svg")
.attr("class", "chart")
.attr("width", w)
.attr("height", h )
.append("svg:g")
.attr("transform", "translate(10,470)");
x = d3.scale.ordinal().rangeRoundBands([0, w-800])
y = d3.scale.linear().range([0, h-100])
z = d3.scale.ordinal().range(["blue", "lightblue"])
// console.log("RAW MATRIX---------------------------");
// 3 columns: ID,c1,c2
var matrix = [
[ 1, 5871, 8916]
];
// console.log(matrix)
var matrix2 = [
[ 1, 21, 800]
];
function rand_it(x){
return Math.floor((Math.random() * x) + 1);
}
function render(matrix){
var t = d3.transition()
.duration(300);
// remove
svg.selectAll("g.valgroup")
.remove();
svg.selectAll("rect")
.transition(t)
.remove();
var remapped =["c1","c2"].map(function(dat,i){
return matrix.map(function(d,ii){
return {x: ii, y: d[i+1] };
})
});
console.log("NEW ONE !!!\n",matrix[0]);
// console.log("LAYOUT---------------------------");
var stacked = d3.layout.stack()(remapped)
x.domain(stacked[0].map(function(d) { return d.x; }));
y.domain([0, d3.max(stacked[stacked.length - 1], function(d) { return d.y0 + d.y; })]);
// Add a group for each column.
var valgroup = svg.selectAll("g.valgroup")
.data(stacked)
.enter().append("svg:g")
.classed("valgroup", true)
.style("fill", function(d, i) { return z(i); })
.style("stroke", function(d, i) { return d3.rgb(z(i)).darker(); });
// Add a rect for each date.
var rect = valgroup.selectAll("rect")
.data(function(d){return d;})
.enter().append("svg:rect")
.transition(t)
.attr("x", function(d) { return x(d.x); })
.attr("y", function(d) { return -y(d.y0) - y(d.y); })
.attr("height", function(d) { return y(d.y); })
.attr("width", x.rangeBand());
// column
rect.selectAll("rect")
.transition() // this is to create animations
.duration(500) // 500 millisecond
.ease("bounce")
.delay(500)
.attr("x", function(d) { return x(d.x); })
.attr("y", function(d) { return -y(d.y0) - y(d.y); })
.attr("height", function(d) { return y(d.y); })
.attr("width", x.rangeBand());
};
render(matrix);
setInterval( function() { render([[1, rand_it(10), rand_it(50)]]); console.log("2"); }, 5000 );
</script>
</body>
</html>
You are not using the transition() correctly. A transition changes from a previous value to a final value. So, in this code:
var something = svg.append("something").attr("x", 10);
something.transition().duration(500).attr("x", 20);
The x attribute of something will change from 10 to 20 in 500ms.
But when you do, as you did:
var rect = valgroup.selectAll("rect")
.data(function(d){return d;})
.enter().append("svg:rect")
.transition(t)
.attr("x", function(d) { return x(d.x); })
.attr("y", function(d) { return -y(d.y0) - y(d.y); })
.attr("height", function(d) { return y(d.y); })
.attr("width", x.rangeBand());
Where are the previous values? This is an "enter" selection. To make things more complicated, you did:
svg.selectAll("rect")
.transition(t)
.remove();
In the beginning of the function, so, there is no rectangle to make any transition.
I made a few changes in your code, removing the remove() and creating some "update" selections: https://jsfiddle.net/gerardofurtado/3ahrabyj/
Please have in mind that this is not an optimised code, even less a beautiful code: I made just the bare minimum changes to make the transitions to work, you'll have to make a lot of improvements here.
I've created a D3 heatmap based on this example, and have written an update function for it. Here's the relevant code for the base heatmap:
<!DOCTYPE html>
<html lange = "en">
<head>
<meta charset="UTF-8">
<title>Heatmap</title>
<script type ="text/javascript" src="d3/d3.v3.js"></script>
<script type ="text/javascript" src="updateHeatmap.js"> </script>
<style type ="text/css">
.btn {
display: inline;
}
rect.bordered {
stroke: #E6E6E6;
stroke-width:2px;
}
text.mono {
font-size: 9pt;
font-family: Consolas, courier;
fill: #aaa;
}
text.axis-workweek {
fill: #000;
}
text.axis-worktime {
fill: #000;
}</style>
</head>
<body>
<div id="n1" class="btn">
<input name="updateButton"
type="button"
value="1"
/>
</div>
<div id="n2" class="btn">
<input name="updateButton"
type="button"
value="2"
/>
</div>
<div id="chart"></div>
<script type="text/javascript">
var margin = {top:50, right:0, bottom:100, left:30},
width=960-margin.left-margin.right,
height=430-margin.top-margin.bottom,
gridSize=Math.floor(width/24),
legendElementWidth=gridSize*2.665,
buckets = 10,
colors = ["#f7fcf0","#e0f3db","#ccebc5","#a8ddb5","#7bccc4","#4eb3d3","#2b8cbe","#0868ac","#084081"],
days = ["Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
times = ["12am", "1am", "2am", "3am", "4am", "5am", "6am", "7am", "8am", "9am", "10am", "11am", "12am", "1pm", "2pm", "3pm", "4pm", "5pm", "6pm", "7pm", "8pm", "9pm", "10pm", "11pm"];
var heatmap;
var legend;
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+")");
d3.csv("1.csv", function(d){
return {
day:+d.day2,
hour:+d.hour,
value:+d.per_day_per_hour
};
},
function(error, data){
console.log(data);
var colorScale = d3.scale.quantile()
.domain([0, (d3.max(data, function(d){return d.value;})/2), d3.max(data, function(d){return d.value;})])
.range(colors);
var dayLabels = svg.selectAll(".dayLabel")
.data(days)
.enter().append("text")
.text(function (d) {return d; })
.attr("y", function (d, i){ return i*gridSize;})
.style("text-anchor", "end")
.attr("transform", "translate(-6," + gridSize/1.5+")")
.attr("class", function(d, i) { return ((i>=0 && i<=4) ? "dayLabel mono axis axis-workweek": "dayLabel mono axis"); });
var timeLabels = svg.selectAll(".timeLabel")
.data(times)
.enter().append("text")
.text(function(d){return d;})
.attr("x", function(d,i) {return i * gridSize;})
.attr("y",0)
.style("text-anchor", "middle")
.attr("transform", "translate(" + gridSize/2+", -6)")
.attr("class", function(d, i) { return ((i>=9 && i<= 17) ? "timeLabel mono axis axis-worktime": "timeLabel mono axis"); });
var heatMap = svg.selectAll(".hour")
.data(data)
.enter().append("rect")
.attr("x", function(d) {return (d.hour) * gridSize;})
.attr("y", function(d) {return (d.day) * gridSize;})
.attr("rx", 4)
.attr("ry", 4)
.attr("class", "hour bordered")
.attr("width", gridSize)
.attr("height", gridSize)
.style("fill", colors[0]);
heatMap.transition().duration(1000)
.style("fill", function(d){ return colorScale(d.value);});
heatMap.append("title").text(function(d) {return d.value;});
var legend = svg.selectAll(".legend")
.data([0].concat(colorScale.quantiles()), function(d) {return d;})
.enter().append("g")
.attr("class", "legend");
legend.append("rect")
.attr("x", function(d, i){ return legendElementWidth * i;})
.attr("y", height)
.attr("width", legendElementWidth)
.attr("height", gridSize/2)
.style("fill", function(d, i) {return colors[i]; });
legend.append("text")
.attr("class", "mono")
.text(function(d) {return "≥ "+d.toString().substr(0,4);})
.attr("x", function(d, i){ return legendElementWidth *i;})
.attr("y", height+ gridSize);
d3.select("#n1")
.on("click", function() {
updateHeatmap("1_1.csv");
});
d3.select("#n2")
.on("click", function() {
updateHeatmap("1_2.csv");
});
;
}
);
</script>
<script>
</script>
</body>
</html>
The code above is essentially the same as that in the fiddle I've linked to up top, except that it includes 2 buttons, and has the legend, svg, and heatmap variables declared globally.
Here's the meat of my question, which has to do with the update function I created to load in two new CSVs:
function updateHeatmap(x){
svg.selectAll(".legend").attr("opacity", 0);
d3.csv(x, function(d){
return {
day:+d.day2,
hour:+d.hour,
value:+d.per_day_per_hour
};
},
function(error, data){
colorScale = d3.scale.quantile()
.domain([0, (d3.max(data, function(d){return d.value;})/2), d3.max(data, function(d){return d.value;})])
.range(colors);
var heatMap = svg.selectAll(".hour")
.data(data)
.transition().duration(1000)
.style("fill", function(d){ return colorScale(d.value);});
heatMap.selectAll("title").text(function(d) {return d.value;});
var legend = svg.selectAll(".legend")
.data([0].concat(colorScale.quantiles()), function(d) {return d;})
.enter().append("g")
.attr("class", "legend");
legend.append("rect")
.attr("x", function(d, i){ return legendElementWidth * i;})
.attr("y", height)
.attr("width", legendElementWidth)
.attr("height", gridSize/2)
.style("fill", function(d, i) {return colors[i]; });
legend.append("text")
.attr("class", "mono")
.text(function(d) {return "≥ "+d.toString().substr(0,4);})
.attr("x", function(d, i){ return legendElementWidth *i;})
.attr("y", height+ gridSize);
}
)
}
I've managed to update the color of the heatmap squares (huzzah), but can't get the legend that sits below the heatmap to cooperate, and can't get the values underlying each square to display on hover like I did on initial loading. I get a feeling that it's because my JS is pretty flaky (as is, let's face it, my D3), but can't be sure — I think it may have to do with my screwing up the appropriate syntax for selecting the text element (i.e., I'm unsure of how to do it the right way).
To sum up: legend in this heatmap (here's the gist block) isn't updating properly, and the on-hover values for each of the squares don't appear on update. Yikes. Any suggestions?
I've updated my example to allow switching between datasets - this should help.
http://bl.ocks.org/tjdecke/5558084
I am completely stuck adding labels to the force directed tree graph found here http://bl.ocks.org/mbostock/1138500
I have attempted to synthesize the force directed tree with other examples that include labels as well as following the answer to Add text label to d3 node in Force directed Graph and resize on hover but the graph always seems to break.
This code works for the force directed graph with labels and pictures
<!DOCTYPE html>
<meta charset="utf-8">
<style>
.link {
stroke: #ccc;
}
.node text {
pointer-events: none;
font: 10px sans-serif;
}
</style>
<body>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>
var width = 960,
height = 500
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
var force = d3.layout.force()
.gravity(.05)
.distance(100)
.charge(-100)
.size([width, height]);
d3.json("graph.json", function(error, json) {
force
.nodes(json.nodes)
.links(json.links)
.start();
var link = svg.selectAll(".link")
.data(json.links)
.enter().append("line")
.attr("class", "link");
var node = svg.selectAll(".node")
.data(json.nodes)
.enter().append("g")
.attr("class", "node")
.call(force.drag);
node.append("image")
.attr("xlink:href", "https://github.com/favicon.ico")
.attr("x", -8)
.attr("y", -8)
.attr("width", 16)
.attr("height", 16);
node.append("text")
.attr("dx", 12)
.attr("dy", ".35em")
.text(function(d) { return d.name });
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 + ")"; });
});
});
</script>
However when I attempt to modify this to form a tree structure from Mike's example my code looks like this but does not work.
<!DOCTYPE html>
<meta charset="utf-8">
<style>
.link {
stroke: #ccc;
}
.node text {
pointer-events: none;
font: 10px sans-serif;
}
</style>
<body>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>
var width = 960,
height = 500
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
var force = d3.layout.force()
.gravity(.05)
.distance(100)
.charge(-100)
.size([width, height]);
d3.json("test.json", function(error, json) {
force
.nodes(json.nodes)
.links(json.links)
.start();
var link = svg.selectAll(".link")
.data(json.links)
.enter().append("line")
.attr("class", "link");
var node = svg.selectAll(".node")
.data(json.nodes)
.enter().append("g")
.attr("class", "node")
.call(force.drag);
node.append("image")
.attr("xlink:href", "https://github.com/favicon.ico")
.attr("x", -8)
.attr("y", -8)
.attr("width", 16)
.attr("height", 16);
node.append("text")
.attr("dx", 12)
.attr("dy", ".35em")
.text(function(d) { return d.name });
force
.nodes(json.nodes)
.links(json.links)
.on("tick", tick)
.start();
function tick(e) {
// Push sources up and targets down to form a weak tree.
var k = 6 * e.alpha;
json.links.forEach(function(d, i) {
d.source.y -= k;
d.target.y += k;
});
node.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; });
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; });
}
});
</script>
I have tried and tried to resolve this but cannot combine the labels with the force directed graph, any assistance would be greatly appreciated, I've been beating my head against the wall on this for some time now...
Thanks!
The part missing from your sample code is the addition to the tick callback that decreases the y value of the source, and increases that of the target by a small amount each time.
Here's a jsfiddle example which I think does what you're after.
The key portion is the addition of a parameter, called e here, to the tick function, along with the lines
var k = 6 * e.alpha;
json.links.forEach(function(d, i) {
d.source.y -= k;
d.target.y += k;
});
The result looks like this, once you also increase the magnitude of the charge to push the nodes a little further away from each other:
I am trying to draw some circles using D3 Javascript library based on the JSON file format that I have. Here is the JSON file:
{"Resources":[{"resource":[{"name":"A"}]}],
"literals":[{"literal":[{"name":"B"},{"name":"C"}]}]}
This is my code for drawing three circles based on this JSON format:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Sample2</title>
<style>
.node {
stroke: #fff;
stroke-width: 1.5px;
}
.link {
stroke: #999;
stroke-opacity: .6;
}
</style>
</head>
<body>
<script type="text/javascript" src="d3/d3.v3.js"></script>
<script>
var width = 1000;//960,
height = 500;
var color = d3.scale.category20();
var force = d3.layout.force()
.charge(-120)
.linkDistance(30)
.size([width, height]);
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
d3.json("folder/newjsonsample6.json", function(error, graph) {
// Resource
force
.nodes(graph.Resources[0].resource)
.start();
var resourceNode = svg.selectAll(".node")
.data(graph.Resources[0].resource)
.append("circle")
.attr("class", "node")
.attr("r", 20)
.style("fill", function(d) { return color(2); })
.call(force.drag);
resourceNode.append("title")
text(function(d) { return d.name; });
force.on("tick", function() {
resourceNode.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; });
resourceNode.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; });
});
// Literals
force
.nodes(graph.literals[0,0].literal)
.start();
var node = svg.selectAll(".node")
.data(graph.literals[0,0].literal)
.enter().append("circle")
.attr("class", "node")
.attr("r", 10)
.style("fill", function(d) { return color(1); })
.call(force.drag);
node.append("title")
.text(function(d) { return d.name; });
force.on("tick", function() {
node.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; });
node.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; });
});
});
</script>
</body>
</html>
As you may notice, I drew the resources circle and then the literals circles (The literals circles are three). It shows me in the canvas that there are only the three literals circles. I cant find the resources circle. Could anyone please help me to find what the problem is. Why am I not able to display the resource circle however the code to draw the resource circle is similar to the code for drawing the literals circles. Your help would be very much appreciated
The circle is created, it just never appears at the correct position as you're overwriting the function that sets that (the on tick function). It should work if you define that as follows.
force.on("tick", function() {
resourceNode.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; });
node.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; });
});