I'm new to D3 and have been trying to generate arc in a function when attr-ing it.
But if I call the function from attr command, it gives me the following error in path generation:
Error: attribute d: Expected moveto path command ('M' or 'm'),
"function arc() {…".
Following the code and data:
<!DOCTYPE html>
<meta charset="utf-8">
<style>
.arc text {
font: 20px sans-serif;
text-anchor: middle;
}
.arc path {
stroke: #fff;
}
</style>
<svg id="vis" width="600" height="600"></svg>
<script src="d3.v4.js"></script>
<script>
var svg = d3.select("#vis"),
width = +svg.attr("width"),
height = +svg.attr("height"),
radius = Math.min(width, height) / 2,
g = svg.append("g").attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
var color = d3.scaleOrdinal(["#98abc5", "#8a89a6", "#7b6888", "#6b486b", "#a05d56", "#d0743c", "#ff8c00"]);
var classes = ["c1","c2","c3","c4","c5"];
var pie = d3.pie()
.sort(null)
.value(classes.length)
;
function getPaths(p, v) {
var rt = p + v;
var rm = (radius*v)/rt;
var ipath = d3.arc().innerRadius(0).outerRadius(parseInt(rm));
var epath = d3.arc().innerRadius(parseInt(rm)).outerRadius(parseInt(radius));
return [ipath,epath];
}
var label = d3.arc()
.outerRadius(radius - 40)
.innerRadius(radius - 40)
;
d3.csv("fakedatateste.csv", function(data) {
var arc = g.selectAll(".arc")
.data(pie(data))
.enter().append("g")
.attr("class", "arc")
;
var paths = getPaths(60, 40);
arc.append("path")
.attr("d", function(d){return getPaths(d.data.people, d.data.vehicles)[0];})
.attr("fill", function(d) { return color(d.data.region); })
;
arc.append("path")
.attr("d", paths[1])
.attr("fill", function(d) { return color(d.data.region); })
;
arc.append("text")
.attr("transform", function(d) { return "translate(" + label.centroid(d) + ")"; })
.attr("dy", "0.35em")
.text(function(d) { return d.data.region; })
;
}
);
</script>
And the data:
region,people,vehicles
c1,58,2
c2,59,1
c3,48,12
c4,30,30
c5,50,10
Can someone point me in the right direction? Where is the proper place to generate arcs based on my data?
Ex:
arc.append("path").attr("d", function(d){return getPaths(d.data.people, d.data.vehicles)[0];})
gives me the error.
Related
I'm building a 3D-Js chart, where i want the pie text being around the pie it self.
Here is exactly what i want:
I have two problems: i'm printing two charts right now (labels are printed in another chart) and adjusting them with CSS.
-First i didn't figure out how to set labels, in the same chart, so i'm adjusting it with CSS.
-i didn't figure out how to set the right angle to make the labels chart fit the first chart.
if there is a way, please make them printed in the same chart.
here is my code:
<script src="http://d3js.org/d3.v3.min.js"></script>
<div id = "svgContent"></div>
<script>
var data = [{label:"BC", value:50},{label:"Alb", value:20},{label:"Mani",value:100},{label:"Sascn", value:80},{label:"ORIO", value:20}];
var margin = {top:40,left:40,right:40,bottom:40};
width = 300;
height = 300;
radius = Math.min(width-100,height-100)/2;
var color = d3.scale.category10().range(["#e8af92", "#a9e892"]);
var arc = d3.svg.arc()
.outerRadius(radius -230)
.innerRadius(radius - 50)
.cornerRadius(20);
var arcOver = d3.svg.arc()
.outerRadius(radius +5000)
.innerRadius(200);
var a=width/2 - 20;
var b=height/2 - 90;
var svg = d3.select("#svgContent").append("svg")
.attr("viewBox", "0 0 " + width + " " + height/2)
.attr("preserveAspectRatio", "xMidYMid meet")
.append("g")
.attr("transform","translate("+a+","+b+")");
var pie = d3.layout.pie()
.sort(null)
.value(function(d){return d.value;})
.padAngle(.4);
var g = svg.selectAll(".arc")
.data(pie(data))
.enter();
g.append("path")
.attr("d",arc)
.style("fill",function(d){return color(d.data.value);})
.attr("d", arc);
</script>
<div id="datas" style="margin-top:-580px;margin-left:-10px;">
<script>
var delta = (2*Math.PI)/5;
var arc = d3.svg.arc()
.innerRadius(185)
.outerRadius(185)
.startAngle(function(d,i){return (i)*delta;})
.endAngle(function(d,i){return (i+1)*delta;});
var svg = d3.select("#datas").append("svg")
.attr("width", 960)
.attr("height", 500)
.selectAll("g")
.data(data)
.enter()
.append("g")
.attr("transform", "translate(480,250)rotate(00)");
var thing = svg.append("g")
.attr("id","thing")
.style("fill","navy")
.attr("class", "label");
var arcs = svg.append("path")
.attr("id", function(d,i){return "s"+i;})
.attr("d",arc);
thing.append("text")
.style("font-size",10)
.style("text-anchor","middle")
.append("textPath")
.attr("textLength",function(d,i){return d.label.length *8 ;})
.attr("xlink:href",function(d,i){return "#s"+i;})
.attr("startOffset",function(d,i){return "130";})
// .attr("dy","em")
.text(function(d){return d.label.toUpperCase();});
</script>
</div>
Here's your code refactored a bit:
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="style.css">
<script src="script.js"></script>
</head>
<body>
<script src="http://d3js.org/d3.v3.min.js"></script>
<div id="svgContent"></div>
<script>
var data = [{
label: "BC",
value: 50
}, {
label: "Alb",
value: 20
}, {
label: "Mani",
value: 100
}, {
label: "Sascn",
value: 80
}, {
label: "ORIO",
value: 20
}];
var margin = {
top: 40,
left: 40,
right: 40,
bottom: 40
};
width = 300;
height = 300;
radius = Math.min(width - 100, height - 100) / 2;
var color = d3.scale.category10().range(["#e8af92", "#a9e892"]);
var arc = d3.svg.arc()
.outerRadius(radius - 230)
.innerRadius(radius - 50)
.cornerRadius(20);
var arcOver = d3.svg.arc()
.outerRadius(radius + 5000)
.innerRadius(200);
var a = width / 2 - 20;
var b = height / 2 - 90;
var svg = d3.select("#svgContent").append("svg")
.attr("viewBox", "0 0 " + width + " " + height / 2)
.attr("preserveAspectRatio", "xMidYMid meet")
var defs = svg.append("defs");
svg = svg.append("g")
.attr("transform", "translate(" + a + "," + b + ")");
var pie = d3.layout.pie()
.sort(null)
.value(function(d) {
return d.value;
})
.padAngle(.4);
data = pie(data);
// build out the defs
defs.selectAll("path")
.data(data)
.enter()
.append("path")
.attr("id", function(d,i){
return "arc" + i;
})
.attr("d", arc);
// and the arcs
var g = svg.selectAll(".arc")
.data(data)
.enter()
.append("g");
g.append("path")
.style("fill", function(d) {
return color(d.data.value);
})
.attr("d", arc);
// add the texts
g.append("text")
.append("textPath")
.attr("xlink:href", function(d,i){
return "#arc" + i;
})
.text(function(d){
return d.data.label;
})
.style("font", "8px sans-serif");
</script>
</body>
</html>
I have to design a Pie chart, which dynamically updates when changes are made in an external JSON file. I have written a fairly simple code, but somehow I am not getting the chart rendered on the chrome page. There seems to be some Uncaught errors and definition of "data" missing. I am fairly new to d3 and Javascript, and I need your assistance in debugging/fixing this code for me.
My Json file is called by the d3.json method call.
x in the json file is Name and y is Value. x,y becomes my name:Value pair.
<!DOCTYPE html>
<meta charset="utf-8">
<body>
<script src="../lib/d3.v3.min.js"></script>
<script type="text/javascript">
var width = 960;
var height = 500;
var radius = 400;
var outerRadius = radius;
var innerRadius = 0;
var pie = d3.layout.pie().sort(null).y(function(d) {
return d.y;
});
var color = d3.scale.category10();
var svg = d3.select("body").append("svg").attr("width", width).attr(
"height", height).append("g").attr("transform",
"translate(" + width / 2 + "," + height / 2 + ")");
var g = svg.selectAll(".arc").data(pie(data)).enter().append("g").attr(
"class", "arc");
var arc = d3.svg.arc().outerRadius(outerRadius)
.innerRadius(innerRadius);
var labelArc = d3.svg.arc().outerRadius(radius - 40).innerRadius(
radius - 40);
d3.json("data.json", function(error, data ) {
data.forEach(function(d) {
d.x = d.x;
d.y = d.y+d.y;
x.domain(data.map(function(d) {
return d.x;
}));
y.domain([ 0, d3.max(data, function(d) {
return d.y;
}) ]);
g.append("path")
.attr("fill", function(d, i) {
return color(i);
}).attr("d", arc);
g.append("text").attr("transform", function(d) {
return "translate(" + labelArc.centroid(d) + ")";
}).attr("text-anchor", "middle").text(function(d) {
return d.data.x;
});
})
});
</script>
There is some logical issues with code structure... like the data variable is used outside d3.json where it isnt accessible. See the approach below... it should work, I havent tested it. Let me know if u face any issues running this code
var width = 960;
var height = 500;
var radius = 400;
var outerRadius = radius;
var innerRadius = 0;
var pie = d3.layout.pie().sort(null).y(function(d) {
return d.y;
});
var g, arc, labelArc;
var color = d3.scale.category10();
var svg = d3.select("body").append("svg").attr("width", width).attr(
"height", height).append("g").attr("transform",
"translate(" + width / 2 + "," + height / 2 + ")");
d3.json("data.json", function(error, data ) {
x.domain(data.map(function(d) { return d.x; }));
y.domain([ 0, d3.max(data, function(d) { return d.y; }) ]);
g = svg.selectAll(".arc")
.data(pie(data))
.enter()
.append("g")
.attr("class", "arc");
arc = d3.svg.arc()
.outerRadius(outerRadius)
.innerRadius(innerRadius);
labelArc = d3.svg.arc()
.outerRadius(radius - 40)
.innerRadius(radius - 40);
g.append("path")
.attr("fill", function(d, i) { return color(i); })
.attr("d", arc);
g.append("text")
.attr("transform", function(d) { return "translate(" + labelArc.centroid(d) + ")";})
.attr("text-anchor", "middle").text(function(d) { return d.data.x; });
});
I’m having a difficult time getting some D3 plots to use a color scheme that I specify. I’m using flask, Twitter Bootstrap, and D3.
To be specific, I’m trying to make a piechart using data from a CSV file (see code below). Even though I specify my own colors for the chart (see the part of the code: “.range(["#FF4A29", "#8a89a6", "#7b6888", "#6b486b", "#a05d56", "#d0743c", "#ff8c00”]);”) the resulting chart has weird purple and green colors (see below). These same purple and green colors appear in other D3 plots I make on the page.
When I use this javascript code on a non-Bootstrap page, it looks right! I’m guessing something in the Bootstrap CSS is overriding the javascript code? Is there anyway to force my specified colors?
<style>
.arc text {
font: 12px sans-serif;
text-anchor: middle;
}
.arc path {
stroke: #fff;
}
</style>
<script src="//d3js.org/d3.v3.min.js"></script>
<script>
var width = 500,
height = 500,
radius = Math.min(width, height) / 3;
var color = d3.scale.ordinal()
.range(["#FF4A29", "#8a89a6", "#7b6888", "#6b486b", "#a05d56", "#d0743c", "#ff8c00"]);
var arc = d3.svg.arc()
.outerRadius(radius - 10)
.innerRadius(0);
var labelArc = d3.svg.arc()
.outerRadius(radius + 60)
.innerRadius(radius - 40);
var pie = d3.layout.pie()
.sort(null)
.value(function(d) { return d.mentions; });
var svg2 = d3.select("#competitors").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2.3 + "," + height / 2.3 + ")");
d3.csv("static/competitor_mentions.csv", type, function(error, data) {
if (error) throw error;
var g = svg2.selectAll(".arc")
.data(pie(data))
.enter().append("g")
.attr("class", "arc");
g.append("path")
.attr("d", arc)
.style("fill", function(d) { return color(d.data.company); });
g.append("text")
.attr("transform", function(d) { return "translate(" + labelArc.centroid(d) + ")"; })
.attr("dy", ".35em")
.text(function(d) { return d.data.company; });
});
function type(d) {
d.mentions = +d.mentions;
return d;
}
</script>
I am quitte a newbie to D3.js and for a project i need to make a donutchart with data that changes every 2 seconds. But every time I try to change the data i get an error:
Uncaught TypeError: path.data is not a function
I used this code as an example for the change function
Code:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>D3 donuttest</title>
<script src="//d3js.org/d3.v3.min.jss"></script>
<style>
body {
font: 10px sans-serif;
}
</style>
</head>
<body>
</body>
<div id="chartwrapper">
</div>
</body>
<script>
var wrapper="#chartwrapper";
var dummydata=70;
var data=[dummydata,100-dummydata];
var width = 460,
height = 300,
radius = Math.min(width, height) / 2;
var color = d3.scale.category20();
var pie = d3.layout.pie()
.sort(null);
var arc = d3.svg.arc()
.innerRadius(radius - 100)
.outerRadius(radius - 50);
var svg = d3.select(wrapper).append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
var path = svg.selectAll("path")
.data(pie(data))
.enter().append("path")
.attr("fill", function(d, i) { return color(i); })
.attr("d", arc)
.transition()
.ease("bounce")
.duration(1000)
.attrTween("d", initTween);
var label=svg.append("g")
.attr("class", "display")
.attr("transform", "translate(-30,10)");
var labeltext=label.append("text")
.attr("font-size","2rem")
.text(dummydata + "%");
function change(data){
labeltext.text(data[0] + "%");
path.data(pie(data));
path.transition().duration(750).attrTween("d",arcTween);
};
//animation tween for when graph is drawn
function initTween(b) {
b.innerRadius = 0;
var i = d3.interpolate({startAngle: 0, endAngle: 0}, b);
return function(t) { return arc(i(t)); };
}
//animation for when data is changed
function arcTween(a) {
var i = d3.interpolate(this._current, a);
this._current = i(0);
return function(t) {
return arc(i(t));
};
};
//simulating data changes
setInterval(function() {
dummydata = parseInt(Math.random() * 100);
data=[dummydata,100-dummydata];
console.log(data)
change(data);
},2000);
</script>
Here's a slight modification of your code that might help you. I used this answer as a guide.
The modifications include:
only store the result of append() in the path variable;
when first drawing the chart, store the initial angles in _current instead of using the initTween function.
var wrapper = "#chartwrapper";
var dummydata = 70;
var data = [dummydata, 100 - dummydata];
var width = 460,
height = 300,
radius = Math.min(width, height) / 2;
var color = d3.scale.category20();
var arc = d3.svg.arc()
.outerRadius(radius - 100)
.innerRadius(radius - 50);
var pie = d3.layout.pie()
.sort(null);
var svg = d3.select(wrapper).append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
var path = svg.selectAll("path")
.data(pie(data))
.enter()
.append("path");
path.attr("fill", function(d, i) {
return color(i);
})
.attr("d", arc)
.transition()
.ease("bounce")
.duration(1000)
.each(function(d) {
this._current = d;
}); // store the initial angles
var label = svg.append("g")
.attr("class", "display")
.attr("transform", "translate(-30,10)");
var labeltext = label.append("text")
.attr("font-size", "2rem")
.text(dummydata + "%");
function change(data) {
labeltext.text(data[0] + "%");
path.data(pie(data));
path.transition().duration(750).attrTween("d", arcTween); // redraw the arcs
}
function arcTween(a) {
var i = d3.interpolate(this._current, a);
this._current = i(0);
return function(t) {
return arc(i(t));
};
}
setInterval(function() {
dummydata = parseInt(Math.random() * 100);
data = [dummydata, 100 - dummydata];
console.log(data)
change(data);
}, 2000);
body {
font: 10px sans-serif;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<div id="chartwrapper"></div>
I am using aster plot of d3 in my project.
I want legend labels along with the arc radius outside the circle.
I could get an example of piechart showing labels along and outside the arc.
http://bl.ocks.org/Guerino1/2295263
But i am unable to implement the same in aster plot of d3.
http://bl.ocks.org/bbest/2de0e25d4840c68f2db1
Any help would be appreciated.
Thanks
Couple things to fix.
1.) You have to introduce margins into the aster plot for the labels.
2.) You then have to take the outer arcs, add a an svg g do you can group a path with a text:
var outerGroup = svg.selectAll(".solidArc")
.data(pie(data))
.enter()
.append("g")
outerGroup
.append("path")
.attr("fill", function(d) { return d.data.color; })
.attr("class", "solidArc")
.attr("stroke", "gray")
.attr("d", arc)
.on('mouseover', tip.show)
.on('mouseout', tip.hide);
outerGroup
.append("text")
.attr("transform", function(d) {
return "translate(" + centroid(60, width, d.startAngle, d.endAngle) + ")";
})
.attr("text-anchor", "middle")
.text(function(d) { return d.data.label });
Note I had to create my own centroid function to move the labels outside the arc. The code in the pie chart example you linked did not work for me (it's using a old d3 version).
Here's my centroid function stolen from the d3 source:
function centroid(innerR, outerR, startAngle, endAngle){
var r = (innerR + outerR) / 2, a = (startAngle + endAngle) / 2 - (Math.PI / 2);
return [ Math.cos(a) * r, Math.sin(a) * r ];
}
Here's a working example.
Full code:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
<title>Testing Pie Chart</title>
<script type="text/javascript" src="http://mbostock.github.com/d3/d3.js?2.4.5"></script>
<style type="text/css">
.slice text {
font-size: 16pt;
font-family: Arial;
}
</style>
</head>
<body>
<script type="text/javascript">
var canvasWidth = 500, //width
canvasHeight = 500, //height
outerRadius = 150, //radius
//outerRadius = Math.min(canvasWidth, canvasHeight) / 2,
color = d3.scale.category20(); //builtin range of colors
innerRadius =0
var colorsArray = ['#0099ff','#cc00ff','#ff3366','#cc3300','#ff6600','#ffff33','#cccc00','#0066ff'];
var dataSet = [
{"legendLabel":"Testing Text Is", "magnitude":30,'score':4.8,width:20,color:colorsArray[0] },
{"legendLabel":"Two", "magnitude":8,'score':3.2,width:20,color:colorsArray[1] },
{"legendLabel":"Three", "magnitude":40,'score':3.9,width:20,color:colorsArray[2] },
{"legendLabel":"Four", "magnitude":50,'score':3.1,width:20,color:colorsArray[3] },
{"legendLabel":"Five", "magnitude":16,'score':4.2,width:20,color:colorsArray[4] },
{"legendLabel":"Six", "magnitude":50,'score':3.1,width:20,color:colorsArray[5] },
{"legendLabel":"Seven", "magnitude":30,'score':4.3,width:20,color:colorsArray[6] },
{"legendLabel":"Eight", "magnitude":20,'score':2.3,width:20,color:colorsArray[7] }
];
var vis = d3.select("body")
.append("svg:svg")
.data([dataSet])
.attr("width", canvasWidth)
.attr("height", canvasHeight)
.append("svg:g")
.attr("transform", "translate(" + 1.5*outerRadius + "," + 1.5*outerRadius + ")") // relocate center of pie to 'outerRadius,outerRadius'
var arc = d3.svg.arc()
.outerRadius(outerRadius);
var arc1 = d3.svg.arc()
.innerRadius(innerRadius)
.outerRadius(function (d) {
return (outerRadius - innerRadius) * (d.data.score / 5.0) + innerRadius;
});
var pie = d3.layout.pie()
.sort(null)
.value(function(d) { return d.width; });
// Select all <g> elements with class slice (there aren't any yet)
var arcs = vis.selectAll("g.slice")
.data(pie)
.enter()
.append("svg:g")
.attr("class", "slice");
arcs.append("svg:path")
//set the color for each slice to be chosen from the color function defined above
.attr("fill", function(d, i) { return d.data.color; } )
//this creates the actual SVG path using the associated data (pie) with the arc drawing function
.attr("d", arc1);
var text = arcs.append("svg:text")
.attr("transform", function(d) {
d.outerRadius = outerRadius + 75;
d.innerRadius = outerRadius + 70;
return "translate(" + arc.centroid(d) + ")";
})
.attr("text-anchor", "middle") //center the text on it's origin
.style("fill", "black")
.style("font", "bold 12px Arial")
.each(function (d) {
var arr = d.data.legendLabel.split(" ");
if (arr != undefined) {
for (i = 0; i < arr.length; i++) {
d3.select(this).append("tspan")
.text(arr[i])
.attr("dy", i ? "1.2em" : 0)
.attr("x", 0)
.attr("text-anchor", "middle")
.attr("class", "tspan" + i);
}
}
});
//.text(function(d, i) { return dataSet[i].legendLabel; })
// .html(function(d, i) { return '<tspan>'+dataSet[i].legendLabel+'</tspan></n><tspan>'+dataSet[i].score+'</tspan>'})
/* arcs.append("foreignObject")
.attr("transform", function(d) {
d.outerRadius = outerRadius + 75;
d.innerRadius = outerRadius + 70;
return "translate(" + arc.centroid(d) + ")";
})
.attr("width", 50)
.attr("height", 50)
.append("xhtml:body")
.style("font", "14px 'Helvetica Neue'")
.html(function(d, i) { return dataSet[i].legendLabel+'<br>'+dataSet[i].score; });*/
</script>
</body>
</html>