简体   繁体   English

圆点与面积形状不对齐

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM