D3 Draw Circle With Arc
Chapter 05Arcs and Pie Charts
In this department we'll discuss how to compute information for circular and annular paths and how to utilise that data to depict pie charts. D3 provides the post-obit methods for calculating the generators that nosotros need.
-
d3.arc() - returns an arc path generator
-
d3.pie() - returns an bending generator
In each of the following examples, we'll apply a 200px by 200px svg
element as divers below.
<svg id="demo1" width="200" superlative="200"></svg>
In each, nosotros'll dynamically centre a g
element inside the svg
element using lawmaking similar to the code shown below.
d3.select("#demo1") .append("1000") .attr("transform", "translate(100,100)");
It is in these g
elements that nosotros'll render our shapes.
Arcs
Recall from the tutorial on Paths that the path
element can exist used to create lines, polylines, polygons, arcs, circles, ellipses, and other more circuitous shapes. Recollect likewise that the d
aspect defines the shape of the path.
d3.arc()
returns a generator that when called automatically generates and returns a string of characters that tin be assigned to the d
attribute of a path
element to define an arc, circle, or annulus. To create an arc generator simply call d3.arc()
.
var arcGen = d3.arc();
The d3.arc()
method returns a function object that we'll refer to as the arc generator. There are a number of methods that we can call on the arc generator object:
-
arc.startAngle([bending])
-
arc.endAngle([bending])
-
arc.innerRadius([radius])
-
arc.outerRadius([radius])
-
arc.padAngle([angle])
-
arc.padRadius([ardius])
-
arc.cornerRadius([radius])
-
arc.centroid(arguments...)
-
arc.context([context])
In the example beneath we set the starting time and ending angle. Angles are specified in radians where 0 radians is at 12 o'clock and positive radians trace a path clockwise. Nosotros also specify an inner and outer radius.
var arcGen = d3.arc() .innerRadius(0) .outerRadius(90) .startAngle(Math.PI/four) .endAngle(three*Math.PI/4);
The arc generator returns the string that is assigned to the d
aspect of the path element. To render the arc (in this example a quarter of a circle) we append a path
element to the yard
element and gear up its d
attribute equal to the cord returned past arcGen
.
d3.select("#demo1 g") .append("path") .attr("d", arcGen) .attr("make full", "pinkish") .attr("stroke", "gray") .attr("stroke-width", one);
< script > d3.select("#demo1") .append("chiliad") .attr("transform", "translate(100,100)"); var arcGen = d3.arc() .innerRadius(0) .outerRadius(90) .startAngle(Math.PI / four) .endAngle(3 * Math.PI / 4); d3.select("#demo1 g") .append("path") .attr("d", arcGen) .attr("fill", "pinkish") .attr("stroke", "gray") .attr("stroke-width", 1); </ script > < svg id="demo1" width="200" height="200" > </ svg >
To create a circle, set the beginning bending to 0 and the cease angle to ii * Math.PI.
var arcGen = d3.arc() .innerRadius(0) .outerRadius(xc) .startAngle(0) .endAngle(2*Math.PI);
< script > d3.select("#demo2") .append("g") .attr("transform", "translate(100,100)"); var arcGen = d3.arc() .innerRadius(0) .outerRadius(ninety) .startAngle(0) .endAngle(two * Math.PI); d3.select("#demo2 yard") .append("path") .attr("d", arcGen) .attr("fill", "pink") .attr("stroke", "grayness") .attr("stroke-width", 1); </ script > < svg id="demo2" width="200" height="200" > </ svg >
To create an annulus nosotros simple set the inner Radius to a value other than 0.
var arcGen = d3.arc() .innerRadius(seventy) .outerRadius(90) .startAngle(0) .endAngle(ii*Math.PI);
< script > d3.select("#demo3") .suspend("g") .attr("transform", "translate(100,100)"); var arcGen = d3.arc() .innerRadius(seventy) .outerRadius(90) .startAngle(0) .endAngle(2 * Math.PI); d3.select("#demo3 g") .append("path") .attr("d", arcGen) .attr("fill", "pink") .attr("stroke", "grey") .attr("stroke-width", 1); </ script > < svg id="demo3" width="200" height="200" > </ svg >
Pie Charts
Ane way to create a pie nautical chart is to compute alee of time angle data for each wedge of the pie chart and tape it in an an assortment like the one beneath.
var data = [ {startAngle: 0, endAngle: Math.PI/iv}, {startAngle: Math.PI/iv, endAngle: Math.PI/2}, {startAngle: Math.PI/2, endAngle: Math.PI}, {startAngle: Math.PI, endAngle: ii*Math.PI} ];
We'll as well need an arc generator and gear up the radii properties.
var arcGen = d3.arc() .innerRadius(0) .outerRadius(ninety);
Next, we create a set of path
elements and join the angle holding data to them. As described to a higher place, we ready the d
attribute to the value returned by arcGen
. In this example, when the arcGen
function is called for a path
element, it looks in the data joined to it for the bending information information technology needs to compute the path.
d3.select("#demo4 1000") .selectAll("path") .data(data) .enter() .append("path") .attr("d", arcGen) .attr("fill up", "pink") .attr("stroke", "gray") .attr("stroke-width", 1);
< script > d3.select("#demo4") .append("g") .attr("transform", "translate(100,100)"); var information = [ {startAngle: 0, endAngle: Math.PI / 4}, {startAngle: Math.PI / four, endAngle: Math.PI / 2}, {startAngle: Math.PI / 2, endAngle: Math.PI}, {startAngle: Math.PI, endAngle: 2 * Math.PI} ]; var arcGen = d3.arc() .innerRadius(0) .outerRadius(90); d3.select("#demo4 k") .selectAll("path") .data(data) .enter() .append("path") .attr("d", arcGen) .attr("fill", "pinkish") .attr("stroke", "gray") .attr("stroke-width", one); </ script > < svg id="demo4" width="200" summit="200" > </ svg >
d3.pie()
More than often than non, we'll want to compute the angle data dynamically based on some array of data. The d3.pie()
method returns an bending generator function which when called returns an array of objects that contain the angle information we need to return a pie nautical chart.
var angleGen = d3.pie();
When the angle generator is chosen, an array of data is passed to it.
var information = angleGen([1,1,ane,ane,4,2,2,4]);
The angle generator uses the input data to compute the angles necessary to represent the array of data as a pie chart. The array returned from the angle generator contains an object for each element in the array passed into the generator, and each object contains the following backdrop:
-
data - input datum
-
endAngle - finish angle of the arc
-
index - zero-based index of the arc
-
padAngle - pad bending of the arc
-
startAngle - beginning angle of the arc
-
value - value used to compute angles
Notation that thevalue
holding contains the value that was used to compute the start and end angles. The data
field may contain an object - non just a numeric value (meet pie.value
beneath).
We then create an arc generator and bring together the new data to the path
elements exactly as before.
< script > d3.select("#demo5") .append("m") .attr("transform", "interpret(100,100)"); var angleGen = d3.pie(); var data = angleGen([1,1,1,1,iv,ii,2,4]); var arcGen = d3.arc() .innerRadius(0) .outerRadius(90); d3.select("#demo5 yard") .selectAll("path") .information(data) .enter() .suspend("path") .attr("d", arcGen) .attr("fill", "pink") .attr("stroke", "greyness") .attr("stroke-width", 1); </ script > < svg id="demo5" width="200" height="200" > </ svg >
The angle generator object has a number of methods that tin can be called on it.
-
pie.value([value])
-
pie.sort([compare])
-
pie.sortValues([compare])
-
pie.startAngle([bending])
-
pie.endAngle([angle])
-
pie.padAngle([angle])
pie.value()
The value
method is useful when the array that is passed to the angle generator contains objects. To gear up the value
property of the arcs based on the backdrop of the objects, we can laissez passer an accessor role object to the value
method. The accessor function is chosen for each chemical element in the array passed to the angle generator and is passed the data (d), index (i), and data array (information).
In the example beneath we have an array of objects that hold the same data as before.
var input = [ {proper noun: "a", size: "ane"}, {proper name: "b", size: "1"}, {proper name: "c", size: "1"}, {proper noun: "d", size: "1"}, {name: "e", size: "4"}, {proper name: "f", size: "ii"}, {proper noun: "yard", size: "2"}, {name: "h", size: "four"} ];
Then, we create an angle generator using d3.pie
and chain a call to the value
method to return the value of the property that we desire to use when computing the start and terminate angles of the wedge. In the case below, we return the value of the size
belongings for each object.
var angleGen = d3.pie() .value((d) => d.size);
We and so call the bending generator, passing to information technology the data,
var data = angleGen(input);
The angle generator returns a new array of objects, one for each element in the original information array, just as in the previous instance. Notation how the information field contains the original data object and the value field holds the value that was used to compute the angles.
Then, like before, nosotros create an arc generator and append path elements with joined data to the svg.
< script > d3.select("#demo6") .append("grand") .attr("transform", "translate(100,100)"); var input = [ {proper name: "a", size: "1"}, {name: "b", size: "i"}, {name: "c", size: "1"}, {name: "d", size: "1"}, {proper noun: "east", size: "4"}, {name: "f", size: "two"}, {proper name: "one thousand", size: "2"}, {proper name: "h", size: "4"} ]; var angleGen = d3.pie() .value((d) => d.size); var information = angleGen(input); var arcGen = d3.arc() .innerRadius(0) .outerRadius(90); d3.select("#demo6 g") .selectAll("path") .data(information) .enter() .append("path") .attr("d", arcGen) .attr("fill", "pink") .attr("stroke", "grayness") .attr("stroke-width", 1); </ script > < svg id="demo6" width="200" height="200" > </ svg >
pie.sort()
In order to render the arcs in a dissimilar social club than the default lodge, we tin can sort the input information assortment or sort the values computed by the value accessor method prior to computing the angle information. The pie.sort
method sorts the input data array and thepie.sortValues
method sorts the values computed by the value accessor method.
If the input data array contains numeric values, we can use the pie.sort
function to reorder the input data prior to computing the bending data. In the example beneath nosotros create an bending generator and set up a comparator function.
var angleGen = d3.pie() .sort((a,b) => a > b ? one : -i);
We and then call the angle generator, passing in an array of data, to get the angle data.
var data = angleGen([1,1,1,ane,4,2,ii,4]);
< script > d3.select("#demo7") .append("one thousand") .attr("transform", "translate(100,100)"); var angleGen = d3.pie() .sort((a,b) => a > b ? one : - i); var data = angleGen([1,i,i,1,4,2,2,4]); var arcGen = d3.arc() .innerRadius(0) .outerRadius(90); d3.select("#demo7 g") .selectAll("path") .data(information) .enter() .append("path") .attr("d", arcGen) .attr("make full", "pink") .attr("stroke", "grayness") .attr("stroke-width", i); </ script > < svg id="demo7" width="200" top="200" > </ svg >
pie.sortValues()
If the input information assortment contains object and requires a value accessor function, the pie.sortValues
method can be used to sort the values subsequently the accessor function is called.
Assume once more that we're using an array of objects as our input information.
var input = [ {name: "a", size: "ane"}, {proper noun: "b", size: "1"}, {name: "c", size: "1"}, {proper name: "d", size: "1"}, {name: "e", size: "4"}, {name: "f", size: "2"}, {proper noun: "g", size: "2"}, {proper name: "h", size: "4"} ];
Nosotros so create an angle generator with an accessor method and a comparator.
var angleGen = d3.pie() .value((d) => d.size) .sortValues((a,b) => a < b ? 1 : -1);
And create the angle data by calling the bending generator on the input data.
var data = angleGen(input);
< script > d3.select("#demo8") .append("k") .attr("transform", "translate(100,100)"); var input = [ {name: "a", size: "ane"}, {name: "b", size: "1"}, {name: "c", size: "i"}, {proper noun: "d", size: "i"}, {name: "east", size: "4"}, {name: "f", size: "2"}, {name: "yard", size: "2"}, {name: "h", size: "4"} ]; var angleGen = d3.pie() .value((d) => d.size) .sortValues((a,b) => a < b ? 1 : - i); var data = angleGen(input); var arcGen = d3.arc() .innerRadius(0) .outerRadius(90); d3.select("#demo8 g") .selectAll("path") .data(data) .enter() .append("path") .attr("d", arcGen) .attr("make full", "pink") .attr("stroke", "gray") .attr("stroke-width", one); </ script > < svg id="demo8" width="200" height="200" > </ svg >
pie.startAngle() and pie.endAngle()
If we need to modify where the pie graph starts from nosotros tin use pie.startAngle()
and laissez passer in a new bending. This will alter where the entire graph starts from and scale it properly.
var angleGen .startAngle(Math.PI / 2);
Like to pie.startAngle()
, if nosotros need to change where the pie graph ends, we can use pie.endAngle()
var angleGen = d3.pie() .startAngle(Math.PI / 4) .endAngle(7 * Math.PI / 4);
It is important to note that the pie graph is measured in radians, not degrees, and then whatever angle passed in should be in radian form. If yous are unsure of what the radian form is, you lot can employ radians = degrees * (Math.
to catechumen degrees into radians.
By default startAngle = 0 and endAngle = 2π.
< script > d3.select("#demo9") .append("g") .attr("transform", "translate(100,100)"); var input = [ {name: "a", size: "one"}, {proper name: "b", size: "i"}, {name: "c", size: "1"}, {name: "d", size: "i"}, {proper noun: "east", size: "4"}, {proper noun: "f", size: "2"}, {proper noun: "g", size: "2"}, {name: "h", size: "iv"} ]; var angleGen = d3.pie() .startAngle(Math.PI / 4) .endAngle(seven * Math.PI / four) .value((d) => d.size) .sortValues((a,b) => a < b ? 1 : - i); var information = angleGen(input); var arcGen = d3.arc() .innerRadius(0) .outerRadius(90); d3.select("#demo9 1000") .selectAll("path") .data(data) .enter() .suspend("path") .attr("d", arcGen) .attr("fill", "pink") .attr("stroke", "gray") .attr("stroke-width", ane); </ script > < svg id="demo9" width="200" meridian="200" > </ svg >
pie.padAngle()
Sometimes nosotros need to display our graph in a less crowded way, using pie.padAngle()
nosotros can make space betwixt our private sections of the graph, making information technology seem less crowded.
This looks best when we also ready our arcGen.
to have a college value.
var angleGen = d3.pie() .padAngle(.05); var arcGen = d3.arc() .innerRadius(50) .outerRadius(90);
< script > d3.select("#demo10") .suspend("g") .attr("transform", "translate(100,100)"); var input = [ {name: "a", size: "1"}, {name: "b", size: "i"}, {name: "c", size: "1"}, {proper noun: "d", size: "1"}, {name: "eastward", size: "4"}, {name: "f", size: "2"}, {name: "g", size: "2"}, {name: "h", size: "4"} ]; var angleGen = d3.pie() .startAngle(Math.PI / 4) .endAngle(7 * Math.PI / iv) .padAngle(.05) .value((d) => d.size) .sortValues((a,b) => a < b ? ane : - 1); var data = angleGen(input); var arcGen = d3.arc() .innerRadius(fifty) .outerRadius(90); d3.select("#demo10 g") .selectAll("path") .data(data) .enter() .append("path") .attr("d", arcGen) .attr("fill", "pink") .attr("stroke", "gray") .attr("stroke-width", 1); </ script > < svg id="demo10" width="200" pinnacle="200" > </ svg >
Colored Wedges
I way to colorize the wedges is to create a color calibration with the domain existence the domain of values used to compute the angles.
var colorScale = d3.scaleSequential(d3.interpolate("regal", "orange")) .domain([1,4]);
We and then simply fill up the path chemical element, we utilise the value
property of the elements data object to get the value that was used to compute the angle.
.attr("make full", (d) => colorScale(d.value))
< script > d3.select("#demo11") .suspend("g") .attr("transform", "translate(100,100)"); var input = [ {proper noun: "a", size: "1"}, {name: "b", size: "1"}, {name: "c", size: "i"}, {proper noun: "d", size: "1"}, {name: "e", size: "4"}, {name: "f", size: "two"}, {proper name: "m", size: "ii"}, {name: "h", size: "iv"} ]; var angleGen = d3.pie() .startAngle(Math.PI / iv) .endAngle(7 * Math.PI / 4) .padAngle(.05) .value((d) => d.size) .sortValues((a,b) => a < b ? 1 : - 1);; var data = angleGen(input); var arcGen = d3.arc() .innerRadius(l) .outerRadius(90); var colorScale = d3.scaleSequential(d3.interpolate("purple", "orangish")) .domain([one,4]); d3.select("#demo11 g") .selectAll("path") .information(data) .enter() .append("path") .attr("d", arcGen) .attr("fill", (d) => colorScale(d.value)) .attr("stroke", "gray") .attr("stroke-width", one); </ script > < svg id="demo11" width="200" height="200" > </ svg >
d3.pointRadial()
The d3.pointRadial(bending, radius) part returns an array that contains x
and y
coordinates. The coordinates represent the signal on the circle at angle
with a radius set by radius
. For the angle
, 0 is located at the meridian (12 o'clock) and the angle progresses clockwise.
d3.pointRadial(a, r) returns an array with two elements. The ten
position is the outset element or d3.
and the y
position is d3.
.
Examples of dissimilar angles and radii:
< script > var pointRadialArr = [eight]; var textArr = [ {text: "0", x: "", y: ""}, {text: "π/iv", x: "", y: ""}, {text: "π/2", x: "", y: ""}, {text: "3π/4", x: "", y: ""}, {text: "π", x: "", y: ""}, {text: "5π/4", ten: "", y: ""}, {text: "3π/2", ten: "", y: ""}, {text: "7π/four", ten: "", y: ""}]; for(let i = 0; i < eight; i += 1){ pointRadialArr[i] = d3.pointRadial( (i / 4) * Math.PI, 60); textArr[i].x = d3.pointRadial( (i / 4) * Math.PI, lxxx)[0]; textArr[i].y = d3.pointRadial( (i / 4) * Math.PI, eighty)[1]; } d3.select("#demoPointRadialA") .append("circle") .attr("cx", 100) .attr("cy", 100) .attr("r", 60) .attr("fill up", "none") .attr("stroke", "grey") .attr("stroke-width", "one.5"); d3.select("#demoPointRadialA") .selectAll("newCircle") .information(pointRadialArr) .enter() .suspend("circle") .attr("cx", d => d[0]) .attr("cy", d => d[1]) .attr("r", 2.5) .attr("transform", "translate(100,100)"); d3.select("#demoPointRadialA") .selectAll("text") .information(textArr) .enter() .append("text") .text(d => d.text) .attr("10", d => d.ten) .attr("y", d => d.y) .attr("font-size", "15px") .attr("text-ballast", "centre") .attr("transform", "interpret(100,100)"); var pointRadialArr = [four]; var textArr = [4]; for(let i = 0; i < 4; i += ane){ pointRadialArr[i] = d3.pointRadial( (i / 2) * Math.PI, i * 20 + twenty); textArr[i] = {text: "", x: "", y: ""} textArr[i].text = i * 20 + 20; textArr[i].10 = d3.pointRadial( (i / two) * Math.PI, i * 20 + thirty)[0]; textArr[i].y = d3.pointRadial( (i / 2) * Math.PI, i * 20 + 30)[1]; } d3.select("#demoPointRadialR") .selectAll("circle") .data(textArr) .enter() .suspend("circle") .attr("cx", 100) .attr("cy", 100) .attr("r", d => d.text) .attr("fill", "none") .attr("stroke", "grey") .attr("stroke-width", "1.five"); d3.select("#demoPointRadialR") .selectAll("newCircle") .data(pointRadialArr) .enter() .append("circle") .attr("cx", d => d[0]) .attr("cy", d => d[1]) .attr("r", 2.5) .attr("transform", "translate(100,100)"); d3.select("#demoPointRadialR") .selectAll("text") .data(textArr) .enter() .append("text") .text(d => d.text) .attr("x", d => d.x) .attr("y", d => d.y) .attr("font-size", "10px") .attr("text-anchor", "center") .attr("transform", "translate(100,100)"); </ script > < svg id="demoPointRadialA" width="250" height="200" > </ svg > < svg id="demoPointRadialR" width="200" height="200" > </ svg >
Nosotros can suspend some text
elements to our SVG to characterization our pie graph with the names of the slices. We volition fix ten
and y
attributes to point radials with an angle
of the information's startAngle and endAngle and a radius
of our inner and outer radii:
< script > d3.select("#demoPointRadialLabel") .suspend("g") .attr("transform", "translate(100,100)"); var input = [ {name: "a", size: "one"}, {proper noun: "b", size: "i"}, {proper name: "c", size: "1"}, {name: "d", size: "1"}, {name: "e", size: "iv"}, {proper name: "f", size: "two"}, {name: "yard", size: "2"}, {name: "h", size: "4"} ]; var angleGen = d3.pie() .startAngle(Math.PI / 4) .endAngle(seven * Math.PI / 4) .padAngle(.05) .value((d) => d.size) .sortValues((a,b) => a < b ? ane : - 1);; var data = angleGen(input); var arcGen = d3.arc() .innerRadius(50) .outerRadius(90); var colorScale = d3.scaleSequential(d3.interpolate("royal", "orange")) .domain([1,4]); d3.select("#demoPointRadialLabel grand") .selectAll("path") .data(data) .enter() .append("path") .attr("d", arcGen) .attr("fill", (d) => colorScale(d.value)) .attr("stroke", "gray") .attr("stroke-width", one); d3.select("#demoPointRadialLabel") .selectAll("newText") .information(data) .enter() .append("text") .attr("x", d => d3.pointRadial((d.startAngle + d.endAngle - 0.1)/ 2 , (l + 90)/ two)[0]) .attr("y", d => d3.pointRadial((d.startAngle + d.endAngle - 0.1)/ 2 , (l + 90)/ ii)[1]) .attr("text-anchor", "middle") .text(d => d.data.name) .attr("font-size", "15px") .attr("fill", "white") .attr("transform","interpret(100,100)"); </ script > < svg id="demoPointRadialLabel" width="200" meridian="200" > </ svg >
williamswrinke1952.blogspot.com
Source: http://using-d3js.com/05_07_arcs_pie_charts.html
0 Response to "D3 Draw Circle With Arc"
Post a Comment