首页 > 解决方案 > 1890 年到 1910 年之间的 d3.scaleTime 日期显示为 :00 (d3.v4)

问题描述

我正在使用我在此处找到的示例在 d3 中创建线图-> https://www.d3-graph-gallery.com/graph/line_brushZoom.html

我的数据包含从 1890 年到 2018 年的观察结果,格式如下:

1880-01-01,1
1890-01-01,3
1890-02-02,1
1890-02-17,1
1890-03-29,1
1890-04-04,1
1890-05-04,1
1890-06-02,1
1890-06-05,1
1890-06-11,1
1890-07-01,1
1890-10-28,1
1890-12-24,1
1890-12-25,1
1891-01-29,1
1891-03-03,1
1891-06-07,1
1892-05-09,1
1893-08-20,1
1893-10-06,1
1894-03-28,1
1895-10-17,1
1896-05-25,1
1897-02-05,1
1897-07-29,1
1897-08-26,1
1898-07-05,1
1900-01-01,1
1900-08-12,1
1901-09-21,1
1903-08-16,1
1903-09-23,1
1904-02-13,1
1904-09-02,1
1904-09-04,1
1905-05-08,1
1905-07-06,1
1905-11-19,1
1906-09-24,1
1908-02-03,1
1909-01-01,1
1910-09-26,1 

我注意到 x 轴刻度呈现 1890 年到 1910 年之间的日期,并带有以下刻度:00

而不是 1890、1900、1910

原始图表代码给出了以下行来设置

    // Add X axis --> it is a date format
    var x = d3.scaleTime()
    //.domain(d3.extent(data, function(d) { return d.date; }))// original line
      .domain([new Date(1880, 0, 1), new Date(2018, 0, 1)]) // debugline
      .range([ 0, width ]);
    xAxis = svg.append("g")
      .attr("transform", "translate(0," + height + ")")
      .call(d3.axisBottom(x));

d3.v5 做到了。有点不同

const xScale = d3.scaleTime().range([0,width]);
const yScale = d3.scaleLinear().rangeRound([height, 0]);
xScale.domain(d3.extent(data, function(d){
    return timeConv(d.date)}));
yScale.domain([(0), d3.max(slices, function(c) {
    return d3.max(c.values, function(d) {
        return d.measurement + 4; });
        })
    ]);

我不知道问题出在哪里,我在 d3.v5 中尝试了相同的数据,但无法重现该问题。我想知道不同类型是否需要一些额外的解析?

谢谢乔纳森

PS 请求完整代码(从 d3-gallery 复制并粘贴)

<!-- Code from d3-graph-gallery.com -->
<!DOCTYPE html>
<meta charset="utf-8">

<!-- Load d3.js -->
<script src="https://d3js.org/d3.v4.min.js"></script>

<!-- Create a div where the graph will take place -->
<div id="my_dataviz"></div>


<script>

// set the dimensions and margins of the graph
var margin = {top: 50, right: 30, bottom: 30, left: 60},
    width = 900 - margin.left - margin.right,
    height = 600 - margin.top - margin.bottom;

// append the svg object to the body of the page
var svg = d3.select("#my_dataviz")
  .append("svg")
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom)
  .append("g")
    .attr("transform",
          "translate(" + margin.left + "," + margin.top + ")");

//Read the data
d3.csv("all_cases.csv",

  // When reading the csv, I must format variables:
  function(d){
    return { date : d3.timeParse("%Y-%m-%d")(d.date), value : d.value }
  },

  // Now I can use this dataset:
  function(data) {

    // Add X axis --> it is a date format
    var x = d3.scaleTime()
    //  .domain(d3.extent(data, function(d) { return d.date; }))
      .domain([new Date(1880, 0, 1), new Date(2018, 0, 1)]) 
      .range([ 0, width ]);
    xAxis = svg.append("g")
      .attr("transform", "translate(0," + height + ")")
      .call(d3.axisBottom(x));

    // Add Y axis
    var y = d3.scaleLinear()
      .domain([0, d3.max(data, function(d) { return +d.value; })+5])
      .range([ height, 0 ]);
    yAxis = svg.append("g")
      .call(d3.axisLeft(y));

    // Add a clipPath: everything out of this area won't be drawn.
    var clip = svg.append("defs").append("svg:clipPath")
        .attr("id", "clip")
        .append("svg:rect")
        .attr("width", width )
        .attr("height", height )
        .attr("x", 0)
        .attr("y", 0);

    // Add brushing
    var brush = d3.brushX()                   // Add the brush feature using the d3.brush function
        .extent( [ [0,0], [width,height] ] )  // initialise the brush area: start at 0,0 and finishes at width,height: it means I select the whole graph area
        .on("end", updateChart)               // Each time the brush selection changes, trigger the 'updateChart' function

    // Create the line variable: where both the line and the brush take place
    var line = svg.append('g')
      .attr("clip-path", "url(#clip)")

    // Add the line
    line.append("path")
      .datum(data)
      .attr("class", "line")  // I add the class line to be able to modify this line later on.
      .attr("fill", "none")
      .attr("stroke", "steelblue")
      .attr("stroke-width", 1.5)
      .attr("d", d3.line()
        .x(function(d) { return x(d.date) })
        .y(function(d) { return y(d.value) })
        )

    // Add the brushing
    line
      .append("g")
        .attr("class", "brush")
        .call(brush);

    // A function that set idleTimeOut to null
    var idleTimeout
    function idled() { idleTimeout = null; }

    // A function that update the chart for given boundaries
    function updateChart() {

      // What are the selected boundaries?
      extent = d3.event.selection

      // If no selection, back to initial coordinate. Otherwise, update X axis domain
      if(!extent){
        if (!idleTimeout) return idleTimeout = setTimeout(idled, 350); // This allows to wait a little bit
        x.domain([ 4,8])
      }else{
        x.domain([ x.invert(extent[0]), x.invert(extent[1]) ])
        line.select(".brush").call(brush.move, null) // This remove the grey brush area as soon as the selection has been done
      }

      // Update axis and line position
      xAxis.transition().duration(1000).call(d3.axisBottom(x))
      line
          .select('.line')
          .transition()
          .duration(1000)
          .attr("d", d3.line()
            .x(function(d) { return x(d.date) })
            .y(function(d) { return y(d.value) })
          )
    }

    // If user double click, reinitialize the chart
    svg.on("dblclick",function(){
      x.domain(d3.extent(data, function(d) { return d.date; }))
      xAxis.transition().call(d3.axisBottom(x))
      line
        .select('.line')
        .transition()
        .attr("d", d3.line()
          .x(function(d) { return x(d.date) })
          .y(function(d) { return y(d.value) })
      )
    });

})

svg.append("text")
        .attr("x", 400)             
        .attr("y", -5)
        .attr("text-anchor", "middle")  
        .style("font-size", "16px") 
        .style("text-decoration", "solid")  
        .text("Outbreaks 1890 - 2018");

</script>

标签: javascriptd3.js

解决方案


在此处输入图像描述您正在使用 D3 v4,并且该轴适用于 D3 v5:

<script src="https://d3js.org/d3.v4.min.js"></script>

要使您的代码与 v5 一起使用,您必须d3.csv稍微更改 的语法,因为它在 v5 中使用了 Promise。您无需更改任何其他内容。

d3.csv("all_cases.csv",
  function(d){
    return { date : d3.timeParse("%Y-%m-%d")(d.date), value : d.value }
  })
.then(function(data) {
  // code
})

推荐阅读