[英]Circle points are not aligned with area shape
I'm trying to fit dot points on the line with area chart shape, however it doesn't fit. 我试图在面积图形状的线上拟合点,但它不适合。 I assume this is due to
.curve
using d3.curveBasis. 我假设这是由于
.curve
使用d3.curveBasis。
data = [ { "login_date": "2017-09-24", "unique_user_count": 2, "total_login_count": 2 }, { "login_date": "2017-09-25", "unique_user_count": 25, "total_login_count": 46 }, { "login_date": "2017-09-26", "unique_user_count": 31, "total_login_count": 74 }, { "login_date": "2017-09-27", "unique_user_count": 29, "total_login_count": 58 }, { "login_date": "2017-09-28", "unique_user_count": 29, "total_login_count": 60 }, { "login_date": "2017-09-29", "unique_user_count": 31, "total_login_count": 71 }, { "login_date": "2017-09-30", "unique_user_count": 1, "total_login_count": 1 }, { "login_date": "2017-10-01", "unique_user_count": 1, "total_login_count": 1 }, { "login_date": "2017-10-02", "unique_user_count": 41, "total_login_count": 71 }, { "login_date": "2017-10-03", "unique_user_count": 30, "total_login_count": 67 }, { "login_date": "2017-10-04", "unique_user_count": 28, "total_login_count": 45 }, { "login_date": "2017-10-05", "unique_user_count": 32, "total_login_count": 48 }, { "login_date": "2017-10-06", "unique_user_count": 30, "total_login_count": 50 }, { "login_date": "2017-10-07", "unique_user_count": 1, "total_login_count": 1 }, { "login_date": "2017-10-08", "unique_user_count": 1, "total_login_count": 1 }, { "login_date": "2017-10-09", "unique_user_count": 35, "total_login_count": 76 }, { "login_date": "2017-10-10", "unique_user_count": 37, "total_login_count": 63 }, { "login_date": "2017-10-11", "unique_user_count": 41, "total_login_count": 76 }, { "login_date": "2017-10-12", "unique_user_count": 42, "total_login_count": 83 }, { "login_date": "2017-10-13", "unique_user_count": 41, "total_login_count": 68 }, { "login_date": "2017-10-15", "unique_user_count": 1, "total_login_count": 1 }, { "login_date": "2017-10-16", "unique_user_count": 48, "total_login_count": 84 }, { "login_date": "2017-10-17", "unique_user_count": 50, "total_login_count": 98 }, { "login_date": "2017-10-18", "unique_user_count": 38, "total_login_count": 56 }, { "login_date": "2017-10-19", "unique_user_count": 38, "total_login_count": 98 }, { "login_date": "2017-10-20", "unique_user_count": 40, "total_login_count": 71 }, { "login_date": "2017-10-22", "unique_user_count": 2, "total_login_count": 2 }]; //Define SVG container full width and height const fullWidth = 600; const fullHeight = 200; //Define bar chart area widht and height const margin = { top: 10, bottom: 10, left: 20, right: 20 } const chartWidth = fullWidth - margin.left - margin.right; const chartHeight = fullHeight - margin.top - margin.bottom; //Draw SVG container let svg = d3.select('body') .append('svg') .attr('width', fullWidth) .attr('height', fullHeight); //Define xand y scale range of the bar chart const xScale = d3.scaleBand() .range([0, chartWidth]); const yScale = d3.scaleLinear() .range([chartHeight, 0]); const yScale2 = d3.scaleLinear() .range([chartHeight, 0]); console.log('Data received from an API:', data) //defiene x and y scale domain yScale .domain([0, d3.max(data, d => +d.total_login_count)]); yScale2 .domain([0, d3.max(data, d => +d.unique_user_count)]); xScale .domain(data.map(d => d.login_date)); //Generate total login area chart let area = d3.area() .curve(d3.curveBasis) .x(function (d) { return xScale(d.login_date); }) .y0(fullHeight) .y1(function (d) { return yScale(+d.total_login_count) }); //Generate unique user count area chart let area2 = d3.area() .curve(d3.curveBasis) .x(function (d) { return xScale(d.login_date); }) .y0(fullHeight) .y1(function (d) { return yScale2(+d.unique_user_count) }); //Draw bar chart let group = svg.selectAll('g') .data([data]) .enter() .append('g'); //Draw area for total login count group .append('path') .attr('class', 'area') .attr('d', area); //Draw area for unique user count group .append('path') .attr('class', 'area2') .attr('d', area2); //Dot points let points = group.selectAll('circle') .data(data) .enter() .append('circle'); //Dot points let points2 = group.select('circle') .data(data) .enter() .append('circle'); points.attrs({ "cx": d => xScale(d.login_date), "cy": d => yScale(+d.total_login_count) + 10, "r": 5 }) .style("opacity", 1) .style('fill', '#F9A2CB'); points2.attrs({ "cx": d => xScale(d.login_date), "cy": d => yScale2(+d.unique_user_count) + 5, "r": 5 }) .style("opacity", 1) .style('fill', '#8BDBCE');
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Bar chart</title> <script src="https://d3js.org/d3.v5.min.js"></script> <script src="https://d3js.org/d3-fetch.v1.min.js"></script> <script src='https://d3js.org/d3-selection-multi.v0.4.min.js'></script> </head> <style> .line { fill: none; stroke: orange; stroke-width: 1px; } .area { fill: #F9A2CB; stroke: none; opacity: 0.6; } .area2 { fill: #8BDBCE; stroke: none; opacity: 0.6; } </style> <body> <script type="text/javascript" src="main.js"></script> </body> </html>
Here is my approach: 这是我的方法:
//define x and y scale domain
yScale
.domain([0, d3.max(data, d => +d.total_login_count)]);
yScale2
.domain([0, d3.max(data, d => +d.unique_user_count)]);
xScale
.domain(data.map(d => d.login_date));
//Generate total login area chart
let area = d3.area()
.curve(d3.curveBasis)
.x(function (d) {
return xScale(d.login_date);
})
.y0(fullHeight)
.y1(function (d) {
return yScale(+d.total_login_count)
});
//Generate unique user count area chart
let area2 = d3.area()
.curve(d3.curveBasis)
.x(function (d) {
return xScale(d.login_date);
})
.y0(fullHeight)
.y1(function (d) {
return yScale2(+d.unique_user_count)
});
//Draw bar chart
let group = svg.selectAll('g')
.data([data])
.enter()
.append('g');
//Draw area for total login count
group
.append('path')
.attr('class', 'area')
.attr('d', area);
//Draw area for unique user count
group
.append('path')
.attr('class', 'area2')
.attr('d', area2);
//Dot points
let points = group.selectAll('circle')
.data(data)
.enter()
.append('circle');
//Dot points
let points2 = group.select('circle')
.data(data)
.enter()
.append('circle');
points.attrs({
"cx": d => xScale(d.login_date),
"cy": d => yScale(+d.total_login_count) + 10,
"r": 5
})
.style("opacity", 1)
.style('fill', '#F9A2CB');
points2.attrs({
"cx": d => xScale(d.login_date),
"cy": d => yScale2(+d.unique_user_count) + 5,
"r": 5
})
.style("opacity", 1)
.style('fill', '#8BDBCE');
You are correct, the problem is d3.curveBasis
indeed. 你是对的,问题确实是
d3.curveBasis
。
As you can see, d3.curveBasis
is an interpolator that generates a path which will not pass exactly over the control points: 如您所见,
d3.curveBasis
是一个插值器,它生成的路径不会完全通过控制点:
My suggestion is using an interpolator which generates a path that passes over the control points, such as d3.curveCatmullRom
: 我的建议是使用插值器生成一个通过控制点的路径,例如
d3.curveCatmullRom
:
Here is your code with that change: 以下是您更改的代码:
data = [ { "login_date": "2017-09-24", "unique_user_count": 2, "total_login_count": 2 }, { "login_date": "2017-09-25", "unique_user_count": 25, "total_login_count": 46 }, { "login_date": "2017-09-26", "unique_user_count": 31, "total_login_count": 74 }, { "login_date": "2017-09-27", "unique_user_count": 29, "total_login_count": 58 }, { "login_date": "2017-09-28", "unique_user_count": 29, "total_login_count": 60 }, { "login_date": "2017-09-29", "unique_user_count": 31, "total_login_count": 71 }, { "login_date": "2017-09-30", "unique_user_count": 1, "total_login_count": 1 }, { "login_date": "2017-10-01", "unique_user_count": 1, "total_login_count": 1 }, { "login_date": "2017-10-02", "unique_user_count": 41, "total_login_count": 71 }, { "login_date": "2017-10-03", "unique_user_count": 30, "total_login_count": 67 }, { "login_date": "2017-10-04", "unique_user_count": 28, "total_login_count": 45 }, { "login_date": "2017-10-05", "unique_user_count": 32, "total_login_count": 48 }, { "login_date": "2017-10-06", "unique_user_count": 30, "total_login_count": 50 }, { "login_date": "2017-10-07", "unique_user_count": 1, "total_login_count": 1 }, { "login_date": "2017-10-08", "unique_user_count": 1, "total_login_count": 1 }, { "login_date": "2017-10-09", "unique_user_count": 35, "total_login_count": 76 }, { "login_date": "2017-10-10", "unique_user_count": 37, "total_login_count": 63 }, { "login_date": "2017-10-11", "unique_user_count": 41, "total_login_count": 76 }, { "login_date": "2017-10-12", "unique_user_count": 42, "total_login_count": 83 }, { "login_date": "2017-10-13", "unique_user_count": 41, "total_login_count": 68 }, { "login_date": "2017-10-15", "unique_user_count": 1, "total_login_count": 1 }, { "login_date": "2017-10-16", "unique_user_count": 48, "total_login_count": 84 }, { "login_date": "2017-10-17", "unique_user_count": 50, "total_login_count": 98 }, { "login_date": "2017-10-18", "unique_user_count": 38, "total_login_count": 56 }, { "login_date": "2017-10-19", "unique_user_count": 38, "total_login_count": 98 }, { "login_date": "2017-10-20", "unique_user_count": 40, "total_login_count": 71 }, { "login_date": "2017-10-22", "unique_user_count": 2, "total_login_count": 2 }]; //Define SVG container full width and height const fullWidth = 600; const fullHeight = 200; //Define bar chart area widht and height const margin = { top: 10, bottom: 10, left: 20, right: 20 } const chartWidth = fullWidth - margin.left - margin.right; const chartHeight = fullHeight - margin.top - margin.bottom; //Draw SVG container let svg = d3.select('body') .append('svg') .attr('width', fullWidth) .attr('height', fullHeight); //Define xand y scale range of the bar chart const xScale = d3.scaleBand() .range([0, chartWidth]); const yScale = d3.scaleLinear() .range([chartHeight, 0]); const yScale2 = d3.scaleLinear() .range([chartHeight, 0]); console.log('Data received from an API:', data) //defiene x and y scale domain yScale .domain([0, d3.max(data, d => +d.total_login_count)]); yScale2 .domain([0, d3.max(data, d => +d.unique_user_count)]); xScale .domain(data.map(d => d.login_date)); //Generate total login area chart let area = d3.area() .curve(d3.curveCatmullRom) .x(function (d) { return xScale(d.login_date); }) .y0(fullHeight) .y1(function (d) { return yScale(+d.total_login_count) }); //Generate unique user count area chart let area2 = d3.area() .curve(d3.curveCatmullRom) .x(function (d) { return xScale(d.login_date); }) .y0(fullHeight) .y1(function (d) { return yScale2(+d.unique_user_count) }); //Draw bar chart let group = svg.selectAll('g') .data([data]) .enter() .append('g'); //Draw area for total login count group .append('path') .attr('class', 'area') .attr('d', area); //Draw area for unique user count group .append('path') .attr('class', 'area2') .attr('d', area2); //Dot points let points = group.selectAll('circle') .data(data) .enter() .append('circle'); //Dot points let points2 = group.select('circle') .data(data) .enter() .append('circle'); points.attrs({ "cx": d => xScale(d.login_date), "cy": d => yScale(+d.total_login_count), "r": 5 }) .style("opacity", 1) .style('fill', '#F9A2CB'); points2.attrs({ "cx": d => xScale(d.login_date), "cy": d => yScale2(+d.unique_user_count), "r": 5 }) .style("opacity", 1) .style('fill', '#8BDBCE');
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Bar chart</title> <script src="https://d3js.org/d3.v5.min.js"></script> <script src="https://d3js.org/d3-fetch.v1.min.js"></script> <script src='https://d3js.org/d3-selection-multi.v0.4.min.js'></script> </head> <style> .line { fill: none; stroke: orange; stroke-width: 1px; } .area { fill: #F9A2CB; stroke: none; opacity: 0.6; } .area2 { fill: #8BDBCE; stroke: none; opacity: 0.6; } </style> <body> <script type="text/javascript" src="main.js"></script> </body> </html>
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.