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>
Related
I have made two separate graph on separate page of Bar and pie chart respectively and now i wanted to combine this two graph in the single page so that I can have a dashboard. but when i start to combine to two graph in the main page its not happening and they overlap of each other.
Code:
https://github.com/Mustafa2911/d3-design/blob/main/combine.html
Combine file contain: Code of both pie and bar chart.
Bar file contain: Code of bar chart.
Pie chart contain: Code of pie chart.
Tried this with your code.
Scroll to see the bar graph axis.
NOTE: The bar graph data will not be available ∵ it is from the demo1.csv file in your repository.
Hope this helps.
<!DOCTYPE html>
<meta charset="utf-8">
<head>
<!-- Load d3.js -->
<script src="https://d3js.org/d3.v4.js"></script>
<script src="https://d3js.org/d3-scale-chromatic.v1.min.js"></script>
<style>
#my_dataviz {
display: inline-block;
width: 50%;
}
</style>
</head>
<body>
<div id="my_dataviz"></div>
<script>
// set the dimensions and margins of the graph
var width = 800
height = 450
margin = 40
// The radius of the pieplot is half the width or half the height (smallest one). I subtract a bit of margin.
var radius = Math.min(width, height) / 2 - margin
// append the svg object to the div called 'my_dataviz'
var svg = d3.select("#my_dataviz")
.append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
// Create dummy data
var data = {
Corporation_Tax: 15,
Income_Tax: 15,
Customs: 5,
Union_Excise_Duties: 7,
Good_and_Service_tax: 16,
Non_tax_Revenue: 5,
Non_Dept_Capital_Receipt: 2,
Borrowings_Liabilities: 35
}
// set the color scale
var color = d3.scaleOrdinal()
.domain(["a", "b", "c", "d", "e", "f", "g", "h"])
.range(d3.schemeSet1);
// Compute the position of each group on the pie:
var pie = d3.pie()
.sort(null) // Do not sort group by size
.value(function(d) {
return d.value;
})
var data_ready = pie(d3.entries(data))
// The arc generator
var arc = d3.arc()
.innerRadius(radius * 0.5) // This is the size of the donut hole
.outerRadius(radius * 0.8)
// Another arc that won't be drawn. Just for labels positioning
var outerArc = d3.arc()
.innerRadius(radius * 0.9)
.outerRadius(radius * 0.9)
// Build the pie chart: Basically, each part of the pie is a path that we build using the arc function.
svg
.selectAll('allSlices')
.data(data_ready)
.enter()
.append('path')
.attr('d', arc)
.attr('fill', function(d) {
return (color(d.data.key))
})
.attr("stroke", "white")
.style("stroke-width", "2px")
.style("opacity", 1)
// Add the polylines between chart and labels:
svg
.selectAll('allPolylines')
.data(data_ready)
.enter()
.append('polyline')
.attr("stroke", "black")
.style("fill", "none")
.attr("stroke-width", 1)
.attr('points', function(d) {
var posA = arc.centroid(d) // line insertion in the slice
var posB = outerArc.centroid(d) // line break: we use the other arc generator that has been built only for that
var posC = outerArc.centroid(d); // Label position = almost the same as posB
var midangle = d.startAngle + (d.endAngle - d.startAngle) / 2 // we need the angle to see if the X position will be at the extreme right or extreme left
posC[0] = radius * 0.95 * (midangle < Math.PI ? 1 : -1); // multiply by 1 or -1 to put it on the right or on the left
return [posA, posB, posC]
})
// Add the polylines between chart and labels:
svg
.selectAll('allLabels')
.data(data_ready)
.enter()
.append('text')
.text(function(d) {
console.log(d.data.key);
return d.data.key
})
.attr('transform', function(d) {
var pos = outerArc.centroid(d);
var midangle = d.startAngle + (d.endAngle - d.startAngle) / 2
pos[0] = radius * 0.99 * (midangle < Math.PI ? 1 : -1);
return 'translate(' + pos + ')';
})
.style('text-anchor', function(d) {
var midangle = d.startAngle + (d.endAngle - d.startAngle) / 2
return (midangle < Math.PI ? 'start' : 'end')
})
</script>
<style>
#my_dataviz {
display: inline-block;
width: 50%;
}
</style>
<div id="my_dataviz_es"></div>
<script>
// set the dimensions and margins of the graph
var margin = {
top: 20,
right: 30,
bottom: 40,
left: 160
},
width = 460,
height = 400;
// append the svg object to the body of the page
var svg = d3.select("#my_dataviz_es")
.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 + ")");
// Parse the Data
d3.csv("demo1.csv", function(data) {
// Add X axis
var x = d3.scaleLinear()
.domain([0, 550000])
.range([0, width]);
svg.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x))
.selectAll("text")
.attr("transform", "translate(-10,0)rotate(-45)")
.style("text-anchor", "end");
// Y axis
var y = d3.scaleBand()
.range([0, height])
.domain(data.map(function(d) {
return d.Country;
}))
.padding(.1);
svg.append("g")
.call(d3.axisLeft(y))
//Bars
svg.selectAll("myRect")
.data(data)
.enter()
.append("rect")
.attr("x", x(0))
.attr("y", function(d) {
return y(d.Country);
})
.attr("width", function(d) {
return x(d.Value);
})
.attr("height", y.bandwidth())
.attr("fill", "#69b3a2")
// .attr("x", function(d) { return x(d.Country); })
// .attr("y", function(d) { return y(d.Value); })
// .attr("width", x.bandwidth())
// .attr("height", function(d) { return height - y(d.Value); })
// .attr
})
</script>
</body>
</html>
EDIT: See here - https://codepen.io/KZJ/pen/rNpqvdq?editors=1011 - for changes made reg. the below comment
what if I want to have my bar chart at the top and on right side i want to have my pie chart
Changed -
a) Both charts were using the same name 'svg' to d3.select() the divs. This caused the charts to overlap.
b) Modified width, height, transform, and added some border CSS - only for demonstration purposes - It can be removed/edited as required.
FYR this is how it looks now -
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.
Im new to d3.js im able to create donut chart and im able to rotate chart but i dont want labels on chart to rotate. Can anyone help how to proceed. how shall i make sure that labels on chart should not rotate
var dataset = [
{
count: 10
},
{
count: 20
},
{
label: 'Cantaloupe',
count: 30
}
];
var width = 360;
var height = 360;
var radius = 100;
var color = d3.scale.ordinal()
.range(["red", "blue", "green"]);
var svg = d3.select('body')
.append('svg')
.attr('width', width)
.attr('height', height)
.append('g')
.attr('transform', 'translate(' + (width / 2) +
',' + (height / 2) + ')');
var arc = d3.svg.arc()
.innerRadius(radius - 60)
.outerRadius(radius);
var pie = d3.layout.pie()
.value(function (d) {
return d.count;
});
var arcs = svg.selectAll('.arc')
.data(pie(dataset))
.enter()
.append('g')
.attr("class", "arc");
arcs.append("path")
.attr("d", arc)
.attr("fill", function (d) {
return color(d.data.count);
})
.on("click", function (d) {
var curAngle = 180;
svg.attr("transform", "translate(" + width / 2 + "," + height / 2 + ") rotate(" + curAngle + ")");
});
arcs.append("text")
.attr("transform", function (d) {
return "translate(" + arc.centroid(d) + ")";
}).attr("text-anchor", "middle")
.attr("font-size", "1.5em")
.text(function (d) {
return d.data.count
});
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>
I'm drawing charts with d3.js.
Is it possible to add radial gradients to donut chart, how on this picture?
Assuming the arc parts are path elements that are filled you can use a radial gradient to get that result.
See this similar question, we can reuse the example to arrive at:
var dataset = {
apples: [53245, 28479, 19697, 24037, 40245],
};
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("body").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
var grads = svg.append("defs").selectAll("radialGradient").data(pie(dataset.apples))
.enter().append("radialGradient")
.attr("gradientUnits", "userSpaceOnUse")
.attr("cx", 0)
.attr("cy", 0)
.attr("r", "100%")
.attr("id", function(d, i) { return "grad" + i; });
grads.append("stop").attr("offset", "15%").style("stop-color", function(d, i) { return color(i); });
grads.append("stop").attr("offset", "20%").style("stop-color", "white");
grads.append("stop").attr("offset", "27%").style("stop-color", function(d, i) { return color(i); });
var path = svg.selectAll("path")
.data(pie(dataset.apples))
.enter().append("path")
.attr("fill", function(d, i) { return "url(#grad" + i + ")"; })
.attr("d", arc);
Jsfiddle: http://jsfiddle.net/X8hfm/