Recently, I am working on Tencent Cloud big data visualization project, dealing with various bar charts, pie charts, area charts and so on every day.
Pie charts are one of the most common charts that visually show the proportion of items in a pile of data. This article attempts to show how to draw a pie chart in a browser.
The preparatory work
The data to be presented
This is the data of a poverty alleviation project somewhere
-
Rain plan :21
-
Financial poverty alleviation :25
-
Poverty alleviation by industry :70
-
Infrastructure :40
D3.js
This is an excellent JavaScript library, support < SVG > and
Let’s get started
Start by organizing the data into a code-friendly format
Const oriData = [{" x ":" the rain plan ", "y" : 20}, {" x ":" financial poverty alleviation ", "y" : 20}, {" x ":" industry poverty ", "y" : 70}, {" x ":" infrastructure ", "y" : 40}].Copy the code
Define canvas size
// Canvas size const [width, height] = [450, 350];Copy the code
Then use D3 to generate a < SVG > element and mount it below #main. This < SVG > will be used as the canvas for subsequent drawing.
Let SVG = d3.select("#main").append(" SVG ").attr("width", width).attr("height", height);Copy the code
Attr (“width”, width) and attr(“height”, height) apply to the < SVG > element. Instead of “#main” as originally selected.
A data item is represented by a sector, and the sum of the data items is a complete circle. So pie charts are actually pie charts that correspond to each data item. Each fan has a starting Angle and an ending Angle.
We need to figure out the starting and ending angles of each sector, and d3.js packages this work, called the layout.
Let pie = d3.pie().value(d => d.y); //.sort(null); DrawData = pie(oriData); drawData = pie(oriData);Copy the code
D3.pie () creates the layout,
.value(d => d.y) Sets the value filter for the layout
A typical chain call.
Let’s look at what the layout transformed data looks like
console.log(drawData);
Copy the code
Data: stores raw data
Index: 2 sort index, D3 pie layout defaults to invert by data size
StartAngle: 4.607669225265029 Indicates the starting Angle of the arc
EndAngle: 5.445427266222308 indicates the endAngle of an arc
The minimum Angle is 0, and the maximum Angle is 2π(approximately equal to 6.283185307179586 mo-mo, Mo-mo).
By default, the beginning of the index 0 arc is in the direction from 12, and the end of the index arc is in the direction of 12, and the two arcs are closed end to end
Value: 20 The value from the source data, because code d => d.y sets the data source to be the Y attribute
PadAngle :0 Indicates the Angle between adjacent arcs. This is not set, so it is 0
With the Angle data for each sector, you are ready to draw. There is no “sector” element available in < SVG >, so you need to define any path to draw the sector using the
Using the
So we directly use the “arc generator” provided by D3.js to generate paths.
// let radius = math. min(width, height) * 0.8/2; Let arc = d3.arc().innerradius (0).outerradius (radius);Copy the code
Same chain call, you pass in the inner diameter and the outer diameter, pass the inner diameter 0 and you get the pie graph, pass the non-0 and you get the ring graph, which is easy to understand.
Arc is a Curryback function that takes objects with startAngle, endAngle, and padAngle attributes and returns the d attribute
Now that we are ready, we need to draw
But before we do that, we need to prepare another
element to act as a container for the
let pathParent = svg.append("g");
Copy the code
It then performs a long sequence of operations
pathParent.selectAll("path") .data(drawData) .enter() .append("path") .attr("d", oneData => arc(oneData)); // Call arc generator to get the pathCopy the code
Here comes the mystery
SelectAll (“path”) returns all
.data(drawData) binds the pre-prepared data that has been converted by the layout. Since the data is bound, the object returned by data knows how many
The first two lines of.enter() indicate that these
.append(“path”) selects these not yet existing
Attr (“d”, oneData => arc(oneData)) passes through these
At this point, the pie charts are made up of sectors. Take a look at:
And you get a result like this, yeah.
As you can see, we did not set the coordinate offset and fill color of each path.
Let’s start with coordinate offsets.
“Position is relative” observe the position of < SVG > and each
The reason is that in general 2d plane drawing, we take (0,0) coordinate as the origin, and in order to simplify the calculation complexity, we directly calculate the relative coordinate of the path, deliberately do not bring the absolute coordinate into the calculation, and then achieve the displacement through the displacement canvas or container.
A parent
element of all
pathParent.attr("transform", `translate(${width / 2}, ${height / 2})`);
Copy the code
The pie chart is already working.
Let’s go ahead and color it
Set the color scale. For the pie chart, the function of this scale is to obtain a corresponding color value according to the serial number of a section on the pie.
let colorScale = d3.scaleOrdinal().domain(d3.range(0, oriData.length)).range(d3.schemeCategory20c);
Copy the code
Set the fill property at the drawing
pathParent .selectAll("path") .data(drawData) .enter() .append("path") .attr("fill", Function (d) {// Set the fill color return colorScale(d.index); }) .attr("d", d => arc(d));Copy the code
Now that the pie chart is drawn, add some text labels.
Let sum = d3.sum(oriData, d => d.y); Let textParent = svg.append("g"); let textParent = svG.append ("g"); textParent.attr("transform", `translate(${width / 2}, ${height / 2})`); Textparent.selectall ("text").data(drawData).enter().append("text").attr("transform") Function (d) {return "translate(" + arc.centroid(d) + ")"; }) .attr("text-anchor", "middle") .attr("font-size", "10px").text(function(d) {return (d.data.y/sum * 100).tofixed (2) + "%"; });Copy the code
Complete the chart
So far, the basic cake is well drawn.
I still have a few things to do,
Mouse and sector interaction, click, over, etc.
Text labels are not friendly, many pie charts have realized labels connected by lines outside the pie, and connecting lines alone will involve a lot of problems to deal with. For example, when the pie charts implemented under some algorithms correspond to different data, the lines may intersect with the fan, which is very ugly, or the connecting lines are required to be only on both sides of the pie, etc.
These questions will be sent later.