Random Data
var data = [53245];
var data2 = [28479, 234234];
var data3 = [19697];
var data4 = [41123,12313];
Width & Height of canvas
var w = 960,
h = 500,
r = Math.min(w, h) / 2,
donut = d3.layout.pie().sort(null),
Here is where i decide how big I wish a arc to be
arc = d3.svg.arc().innerRadius(r - 100).outerRadius(r - 20).startAngle(-2).endAngle(-1.34),
arc2 = d3.svg.arc().innerRadius(r - 100).outerRadius(r - 20).startAngle(-1.34).endAngle(-0.68),
arc3 = d3.svg.arc().innerRadius(r - 100).outerRadius(r - 20).startAngle(-0.68).endAngle(-0.02),
arc4 = d3.svg.arc().innerRadius(r - 100).outerRadius(r - 20).startAngle(-0.02).endAngle(0.64),
arc5 = d3.svg.arc().innerRadius(r - 100).outerRadius(r - 20).startAngle(0.64).endAngle(1.3),
arc6 = d3.svg.arc().innerRadius(r - 100).outerRadius(r - 20).startAngle(1.3).endAngle(1.96),
I have tried using transform, but my shape sits upside down. I would like it to be an arc not a U shape.
var svg = d3.select("body").append("svg:svg")
.append("svg:g")
.attr("transform", "translate(700,400) scale(1, -1)");
The paths for color etc
var arcs = svg.selectAll("path")
.data(donut(data))
.enter().append("svg:path")
.attr("fill", function(d, i) { return 'blue'; })
.attr("d", arc)
.data(donut(data2))
.enter().append("svg:path")
.attr("fill", function(d, i) { return 'green'; })
.attr("d", arc2)
.data(donut(data3))
.enter().append("svg:path")
.attr("fill", function(d, i) { return 'pink'; })
.attr("d", arc3)
.data(donut(data4))
.enter().append("svg:path")
.attr("fill", function(d, i) { return 'black'; })
.attr("d", arc4)
.data(donut(data4))
.enter().append("svg:path")
.attr("fill", function(d,i) {return 'yellow';})
.attr("d",arc5)
.data(donut(data4))
.enter().append("svg:path")
.attr("fill", function(d,i) {return 'orange';})
.attr("d",arc6)
I've solved it myself:
.attr("transform", "translate(700,450) rotate(180) scale(-1, -1)")
Simply added rotate & changed the scale :)
Related
I am trying to add a SVG circle within my d3 donut. My SVG circle displays the percentage as a fill of circle, for example, if the D3 donut is at 50%, the SVG will show 50% filled. I want to put the SVG circle within the inside of my D3 donut.
Here is my codepen for this. http://codepen.io/iamsok/pen/MwdPpx
class ProgressWheel {
constructor(patient, steps, container){
this._patient = patient;
this._steps = steps;
this.$container = $(container);
var τ = 2 * Math.PI,
width = this.$container.width(),
height = this.$container.height(),
innerRadius = Math.min(width,height)/4,
//innerRadius = (outerRadius/4)*3,
fontSize = (Math.min(width,height)/4);
var tooltip = d3.select(".tooltip");
var status = {
haveNot: 0,
taken: 1,
ignored: 2
}
var daysProgress = patient.progress
var percentComplete = Math.round(_.countBy(daysProgress)[status.taken] / daysProgress.length * 100);
var participation = 100;
var color = ["#CCC", "#FDAD42", "#EFD8B5"];
var pie = d3.layout.pie()
.value(function(d) { return 1; })
.sort(null);
var arc = d3.svg.arc();
var svg = d3.select(container).append("svg")
.attr("width", '100%')
.attr("height", '100%')
.attr('viewBox','0 0 '+Math.min(width,height) +' '+Math.min(width,height) )
.attr('preserveAspectRatio','xMinYMin')
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
var innerCircle = d3.select("svg")
.append("svg")
.attr("width", 250)
.attr("height", 250);
var grad = innerCircle.append("defs")
.append("linearGradient").attr("id", "grad")
.attr("x1", "0%").attr("x2", "0%").attr("y1", "100%").attr("y2", "0%");
grad.append("stop").attr("offset", percentComplete + "%").style("stop-color", "lightblue");
grad.append("stop").attr("offset", percentComplete + "%").style("stop-color", "white");
innerCircle.append("circle")
.attr("r", 40)
.attr("cx", 70)
.attr("cy", 70)
.style("stroke", "black")
.style("fill", "url(#grad)");
var gs = svg.selectAll(".arc")
.data(pie(daysProgress))
.enter().append("g")
.attr("class", "arc");
var path = gs.append("path")
.attr("fill", function(d, i) { return color[d.data]; })
.attr("d", function(d, i, j) { return arc.innerRadius(innerRadius+(20*j)).outerRadius(innerRadius+20+(20*j))(d); })
.attr("class", function(d, i, j) { if (i>=participation && j<1) return "passed" ; })
svg.append("text")
.attr("dy", "0.5em")
.style("text-anchor", "middle")
.attr("class", "inner-circle")
.attr("fill", "#36454f")
.text(Math.round(_.countBy(daysProgress)[status.taken] / daysProgress.length * 100) + "%");
}
}
var patient = {progress: [0, 2, 2, 1, 0, 0, 0, 1, 1, 0, 1, 1, 2, 2]}
var progressWheel = new ProgressWheel(patient, 14, '.chart-container' )
Simply put the d3 donut and inner circle under the same svg so that they have the same coordinate system.
Check out here http://codepen.io/anon/pen/ojbQNE
Modified code is on codepen
I have a pie chart and I want to increase the inner radius of the arc the user mouses over.
For example, if I mouse over the arc with 161, I want only the inner radius of that arc segment to increase.
How would I do this?
// arc radius
var radius = 200;
var p = Math.PI *2; //full circle
var data = [11,12,51,21,31,58,41,13,14,31,71,31,51,71,16,41,31,161];
var data1 = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18];
var width = 1000;
var height = 1000;
//========== color scale ==========//
var colorScale = d3.scale.ordinal()
.range(['#FFEBEB', '#FFC2C2', '#FFADAD', '#FF9999', '#FF7070', '#FF5C5C', '#FF4747',
'#FF1F1F', '#FF0A0A', '#F50000', '#CC0000', '#A30000', '#8F0000', '#660000', '#520000', '#3D0000', '#290000', '#140000']);
//========== Create canvas and arc ==========//
var canvas = d3.select("body")
.append("svg")
.attr("height", height)
.attr("width", width);
var group = canvas.append("g")
.attr("transform", "translate(" + width/2 + ",500)");
var arc = d3.svg.arc()
.innerRadius(radius-50)
.outerRadius(radius);
var pie = d3.layout.pie()
.value(function (d){return d;});
var sorted = data.sort(function(a,b){return a-b});
var arcs = group.selectAll(".arc")
.data(pie(sorted))
.enter()
.append("g")
.attr("class", "arc");
arcs.append("path")
.attr("d", arc)
.style('stroke', 'white')
.style('stroke-width', 2)
.attr("fill", function(d, i){return colorScale(d.data);});
arcs.append("text")
.attr("transform", function(d){
return "translate(" + arc.centroid(d) +")";
})
.attr("text-anchor", "middle")
.text(function(d){return d.data});
//======== mouse over/out =========//
var prevColor;
arcs.on("mouseover", function(d){
prevColor = d3.select(this).select("path").attr("fill");
d3.select(this).select("path")
.attr("fill", "black");
})
.on("mouseout", function(d){
d3.select(this).select("path")
.attr("fill", prevColor);
});
http://jsfiddle.net/64vFq/
If I understand you correctly, it looks like you can just change this line:
var arc = d3.svg.arc()
.innerRadius(radius-50)
.outerRadius(radius);
I changed it to this and it produced a decent result:
var arc = d3.svg.arc()
.innerRadius(radius-150)
.outerRadius(radius);
(increase the 50 to make the part the user can mouse over larger; decrease it for the opposite effect)
I found a solution that seems to work pretty well.
All you need to do is create another arc (a bigger one)
var biggerArc = d3.svg.arc().outerRadius(radius+10).innerRadius(radius - 40);
then add it to your mouseover
arcs.on("mouseover", function (d) {
prevColor = d3.select(this).select("path").attr("fill");
d3.select(this).select("path").attr("fill", "black");
d3.select(this).select("path").transition()
.duration(100)
.attr("d", biggerArc);
}).on("mouseout", function (d) {
d3.select(this).select("path").attr("fill", prevColor);
d3.select(this).select("path").transition()
.duration(100)
.attr("d", arc);
});
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/
I have created a donut using multi-arcs and I want to update my donut with new data(arcs).
var width = 300;
var height = 300;
var p = Math.PI * 2;
var vis = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
var group = vis.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
var arcs = [];
arcs[0] = d3.svg.arc()
.innerRadius(50)
.outerRadius(70)
.startAngle(0)
.endAngle(p - 2);
arcs[1] = d3.svg.arc()
.innerRadius(50)
.outerRadius(70)
.startAngle(p - 2)
.endAngle(p);
group.append("path")
.attr("d", arcs[0])
.attr("class", "first")
.attr("fill", "green");
group.append("path")
.attr("d", arcs[1])
.attr("class", "second")
.attr("fill", "grey");
The new data(arcs - functions) must be in arrays and I have to pass them using the .data(dataset) method.
// New data
var data1 = [];
data1[0] = d3.svg.arc()
.innerRadius(60)
.outerRadius(100)
.startAngle(0)
.endAngle(p - 1);
var data2 = [];
data2[0] = d3.svg.arc()
.innerRadius(60)
.outerRadius(100)
.startAngle(p - 1)
.endAngle(p);
-I can update my donut with the new arcs but the issue that I have is that the transition doesn't work.
-I want just to make the transition work following the steps that I described before.
I know already that if i don't use the .data(dataset) method and I use the .attr("d", arc) instead of .attrTween method then the transition will work.
-However that is not what I want because I want to apply the solution to multi-donuts.
//On click, update with new data
d3.select("p")
.on("click", function () {
//Update all rects
vis.selectAll("path.first")
.data(data1)
.transition()
.duration(1000)
.attrTween("d", function (d) { return d; });
vis.selectAll("path.second")
.data(data2)
.transition()
.duration(1000)
.attrTween("d", function (d) { return d; });
Here is an example, click update to see the changes: example
i have donut chart with legend specification. I have 2 values in dataset. But here with this code i'm getting only the first value, "Unresolved".
var dataset = {
Unresolved: [3],
Resolved:[7]
};
var keyValue=[];
for(key in dataset){
keyValue.push(key);
}
var width = 260,
height = 300,
radius = Math.min(width, height) / 2;
var color = ["#9F134C", "#ccc"];
var pie = d3.layout.pie()
.sort(null);
var arc = d3.svg.arc()
.innerRadius(radius - 90)
.outerRadius(radius - 80);
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
var gs = svg.selectAll("g").data(d3.values(dataset)).enter().append("g");
var path = gs.selectAll("path")
.data(function(d,i) { return pie(d); })
.enter().append("path")
.attr("fill", function(d, i) { console.log("log", keyValue[i]);return color[i]; }) //Here i'm getting only the 1st value "unresolved".
.attr("d", arc);
var legendCircle = d3.select("body").append("svg").selectAll("g").data(keyValue).enter().append("g")
.attr("class","legend")
.attr("width", radius)
.attr("height", radius * 2)
.attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; });
legendCircle.append("rect")
.attr("width", 18)
.attr("height", 10)
.style("fill", function(d, i) { return color[i];});
legendCircle.append("text")
.attr("x", 24)
.attr("y", 5)
.attr("dy", ".35em")
.text(function(d) { return d; });
The output i'm getting is,
Can anyone help on this? Thanks.
It looks like you're doing a nested selection in your code, which you would usually only need for nested data. Your data is not nested however -- there's a single level with 2 values. What's happening is that, by using a nested selection, you're descending into the value arrays, each of which contains only a single value.
It works fine if you do away with the nested selection and pass your original data to the pie layout.
var gs = svg.selectAll("g").data(pie(d3.values(dataset))).enter().append("g");
var path = gs.append("path")
.attr("fill", function(d, i) { return color[i]; })
.attr("d", arc);
Complete example here.