【问题标题】:Data points not placed correctly on x-axis数据点未正确放置在 x 轴上
【发布时间】:2017-04-03 15:10:10
【问题描述】:

大家好,我正在 d3 中构建一个区域线图,一切都很顺利,直到我创建了一个网格并发现数据点和线与 x 轴不正确对齐。正如您在 JSfiddle 中看到的那样,数据点在网格的右侧以及 x 轴刻度上稍微多一点。我请了几个人检查一下,但没有人找到解决方案,我怀疑它与以下内容有关:

xLine.domain(d3.extent(data, function(d) { return d.date; }));

还有可能是网格和 x 轴没有正确放置。

我创建了一个有同样问题的 JSfiddle: https://jsfiddle.net/kmafcLh2/

提前非常感谢!

【问题讨论】:

    标签: javascript d3.js


    【解决方案1】:

    不要使用Date.parse,而是使用D3方法d3.timeParse

    var parseTime = d3.timeParse("%Y-%m-%d")
    
    data.forEach(function(d) {
        d.date = parseTime(splitDate(d));
    })
    

    这是工作代码,圆圈和面积图与时间刻度相匹配:

    var line1_data = [{
      "date": "2017-03-22",
      "value": 5742008
    }, {
      "date": "2017-03-23",
      "value": 4394721
    }, {
      "date": "2017-03-24",
      "value": 3275048
    }, {
      "date": "2017-03-25",
      "value": 2693866
    }, {
      "date": "2017-03-26",
      "value": 2773392
    }];
    
    // set the dimensions and margins of the graph
    var marginLine = {
        top: 30,
        right: 40,
        bottom: 30,
        left: 85
      },
      widthLine = parseInt(d3.select('.line-chart').style('width'), 10) - marginLine.right - marginLine.left,
      heightLine = parseInt(d3.select('.line-chart').style('width'), 10) * 0.5 - marginLine.top - marginLine.bottom;
    
    // set the ranges
    var xLine = d3.scaleTime()
      .range([0, widthLine]);
    
    var yLine = d3.scaleLinear().range([heightLine, 0]);
    
    // define the line
    var valueline = d3.line()
      .x(function(d) {
        return xLine(d.date);
      })
      .y(function(d) {
        return yLine(d.value);
      });
    
    var area = d3.area()
      .x(function(d) {
        return xLine(d.date);
      })
      .y0(heightLine)
      .y1(function(d) {
        return yLine(d.value);
      });
    
    var divLine = d3.select('body').append("div")
      .attr('class', 'chart-tooltip')
      .style("opacity", 0);
    
    // gridlines in x axis function
    function make_x_gridlines() {
      return d3.axisBottom(xLine)
        .ticks(10)
    }
    
    // gridlines in y axis function
    function make_y_gridlines() {
      return d3.axisLeft(yLine)
        .ticks(5)
    }
    
    
    // append the svg obgect to the body of the page
    // appends a 'group' element to 'svg'
    // moves the 'group' element to the top left margin
    var svgLine = d3.select(".line-chart").append("svg")
      .attr("width", widthLine + marginLine.left + marginLine.right)
      .attr("height", heightLine + marginLine.top + marginLine.bottom)
      .append("g")
      .attr("transform",
        "translate(" + marginLine.left + "," + marginLine.top + ")");
    
    function splitDate(data) {
      var dateLine = data.date.split('T');
      return dateLine[0];
    
    
    }
    // Get the data
    data = line1_data
    
    var parseTime = d3.timeParse("%Y-%m-%d")
    
    data.forEach(function(d) {
      d.date = parseTime(splitDate(d));
    })
    
    //if (error) throw error;
    var maxYLine = d3.max(data, function(d) {
      return d.value + d.value * 0.1;
    });
    
    var ticklength = data.length;
    
    
    // Scale the range of the data
    xLine.domain(d3.extent(data, function(d) {
      return d.date;
    }));
    yLine.domain([0, maxYLine]);
    // Add the valueline path.
    svgLine.append("path")
      .data([data])
      .attr("class", "line")
      .attr("d", valueline);
    
    svgLine.append("linearGradient")
      .attr("id", "temperature-gradient")
      .attr("gradientUnits", "userSpaceOnUse")
      .attr("x1", 0).attr("y1", yLine(data.value))
      .attr("x2", 0).attr("y2", yLine(heightLine))
      .selectAll("stop")
      .data([{
        offset: "0%",
        color: "#a7e1b8"
      }, {
        offset: "100%",
        color: "white"
      }])
      .enter().append("stop")
      .attr("offset", function(d) {
        return d.offset;
      })
      .attr("stop-color", function(d) {
        return d.color;
      });
    
    svgLine.append("path")
      .data([data])
      .attr("class", "area")
      .attr("d", area);
    
    svgLine.selectAll("circle")
      .data(data)
      .enter()
      .append("circle")
      // .on('mouseover', function() {
      //     divLine
      //         .attr('class', 'chart-tooltip')
      //         .html("<div class='line-tooltip'>" +
      //             "fjnaidnasjdnasjdnasjdn" +
      //             "</div>")
      //     divLine
      //         .style('top', d3.event.pageY - 40 + 'px')
      //         .style('left', d3.event.pageX - parseInt(d3.select('.chart-tooltip').style('width')) + 'px');
      //
      //     divLine.transition()
      //         .duration(200)
      //         .style('opacity', .9);
      //
      // })
      // .on('mouseout', function(d) {
      //     divLine
      //         .transition()
      //         .duration(200)
      //         .style('opacity', 0);
      // })
    
    .attr("r", 4)
      .attr("cx", function(d) {
        return xLine(d.date)
      })
      .attr("cy", function(d) {
        return yLine(d.value)
      })
      .attr("fill", "#2ECC71")
      .attr("stroke", "#2ECC71");
    
    // add the X gridlines
    svgLine.append("g")
      .attr("class", "grid")
      .attr("transform", "translate(0," + heightLine + ")")
      .call(make_x_gridlines()
        .tickSize(-heightLine)
        .tickFormat("")
      )
    
    // add the Y gridlines
    svgLine.append("g")
      .attr("class", "grid")
      .call(make_y_gridlines()
        .tickSize(-widthLine)
        .tickFormat("")
      )
      // Add the X Axis
    svgLine.append("g")
      .attr("transform", "translate(0," + heightLine + ")")
      .call(d3.axisBottom(xLine)
        .tickFormat(d3.timeFormat("%B %d"))
        .ticks(ticklength)
      );
    
    // Add the Y Axis
    svgLine.append("g")
      .call(d3.axisLeft(yLine));
    /* Bar chart */
    
    .bar-chart {
      position: relative;
    }
    
    .bar-chart-tooltip {
      position: absolute;
      background-color: #f3f3f3;
      padding: 0.5em;
      pointer-events: none;
      z-index: 1000;
    }
    
    .chart-tooltip {
      position: absolute;
      background-color: #f3f3f3;
      padding: 0.5em;
      pointer-events: none;
    }
    
    .bar {
      transition: opacity 1s;
    }
    
    .bar:hover {
      opacity: 0.5;
    }
    
    .number {
      font-weight: 600;
    }
    
    .domain {
      stroke: none;
    }
    
    .arrow-up {
      position: absolute;
      width: 0px;
      height: 0px;
      border-left: 30px solid transparent;
      border-right: 30px solid transparent;
      border-bottom: 30px solid #f3f3f3;
    }
    
    .div-container {
      display: flex;
      justify-content: space-around;
    }
    
    .section-label {
      display: inline-block;
      width: 33%;
      text-align: center;
      border-right: 1px solid #707070;
      color: #707070;
    }
    
    .x-axis line {
      display: none;
    }
    
    .section-label:last-child {
      border-right: none;
    }
    
    text {
      font-size: 14px;
      fill: grey;
    }
    
    
    /*horizontal stacked chart*/
    
    
    /* Line chart */
    
    .line-chart .grid line {
      stroke: lightgrey;
      stroke-opacity: 0.7;
      shape-rendering: crispEdges;
    }
    
    .line-chart .grid path {
      stroke-width: 0;
    }
    
    .line {
      fill: none;
      stroke: #2ecc71;
      stroke-width: 4px;
    }
    
    .area {
      fill: url(#temperature-gradient);
      stroke-width: 05px;
    }
    
    
    /* multi-line */
    
    
    /* Pie chart */
    
    .pie-chart text {
      fill: white;
    }
    
    .arc path {
      transition: opacity 1s;
    }
    
    .arc path:hover {
      opacity: 0.5;
    }
    
    
    /*CircleChart*/
    
    .percentageText {
      display: block;
      font-size: 48;
    }
    
    .percentageTextSmall {
      font-size: 33;
    }
    
    
    /* Scatter plot */
    
    .dot {
      transition: opacity 1s;
    }
    
    .dot:hover {
      opacity: 0.5;
    }
    
    
    /* Map chart */
    
    
    /* Bar small chart */
    
    .x-axis .tick text {
      display: none;
    }
    
    .bar-small-chart {
      position: relative;
    }
    <script src="https://d3js.org/d3.v4.min.js"></script>
    <div class="line-chart">
    </div>

    【讨论】:

      【解决方案2】:

      看起来问题出在日期解析上。默认情况下,Javascript 会将任何新日期放入浏览器的时区,因此例如“2017-02-02”可能在美国中部时间 (UTC-6) 中变为 Date(2017, 2, 1, 18, 0, 0)。如果您只使用Date.UTC,您可能会得到您想要的结果。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-12-14
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多