【问题标题】:js d3 chart with timescale带有时间刻度的 js d3 图表
【发布时间】:2021-08-31 11:15:06
【问题描述】:

我是 js 和 d3 编码的新手,我有下面的代码,我想在 x 轴上显示数组中的日期而不是数字。 我尝试了很多方法来显示日期;大多数方式在 HTML 控制台中显示没有行的日期和有错误的数据,它无法读取它只允许数字的日期的数据类型。

<!DOCTYPE html>
<meta charset="utf-8">



<body>
</body>

<!-- Load in the d3 library -->
<script src="https://d3js.org/d3.v5.min.js"></script>
<script>

// 2. Use the margin convention practice 
var margin = {top: 200, right: 300, bottom: 400, left: 300}
  , width = window.innerWidth - margin.left - margin.right // Use the window's width 
  , height = window.innerHeight - margin.top - margin.bottom; // Use the window's height


var parseDate = d3.timeParse("%Y-%m-%d");

// 8. An array of objects of length N. Each object has key -> value pair, the key being "y" and the value is a random number
var xdata = [
    ["2021-08-01",(d3.randomUniform(100)()).toFixed(1)],
    ["2021-08-02",(d3.randomUniform(100)()).toFixed(1)],
    ["2021-08-03",(d3.randomUniform(100)()).toFixed(1)],
    ["2021-08-04",(d3.randomUniform(100)()).toFixed(1)],
    ["2021-08-05",(d3.randomUniform(100)()).toFixed(1)],
    ["2021-08-06",(d3.randomUniform(100)()).toFixed(1)],
    ["2021-08-07",(d3.randomUniform(100)()).toFixed(1)],
    ["2021-08-08",(d3.randomUniform(100)()).toFixed(1)],
    ["2021-08-09",(d3.randomUniform(100)()).toFixed(1)],
    ["2021-08-10",(d3.randomUniform(100)()).toFixed(1)],
    ["2021-08-11",(d3.randomUniform(100)()).toFixed(1)]
];



var n = xdata.length;
var max_value = 0;
var col1 = 0;
for (let i = 0; i < n; i++) {
xdata[i][0] = parseDate(xdata[i][0]);
//console.log(xdata[i][0]);
col1 = parseFloat(xdata[i][1])
if (col1 > max_value)
    max_value = col1


}
console.log(max_value);


// 5. X scale will use the index of our data
var xScale = d3.scaleLinear()
  .domain([0,n-1 ]) // input
    .range([0, width]); // output


// 6. Y scale will use the randomly generate number 
var yScale = d3.scaleLinear()
    .domain([0, max_value]) // input 
    .range([height, max_value]); // output 

// 7. d3's line generator
var line = d3.line()
    .x(function(d, i) { return xScale(i); }) // set the x values for the line generator
    .y(function(d) { return yScale(d.y); }) // set the y values for the line generator 
    .curve(d3.curveMonotoneX) // apply smoothing to the line



//var dataset = d3.range(n).map(function(d) { return {"y": (d3.randomUniform(100)()).toFixed(1) } })

var dataset = xdata.map(function(d) {
      return {
         x: parseDate(d[0]),
         y: d[1]
      };
      
  });

// 1. Add the SVG to the page and employ #2
var svg = d3.select("body").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 + ")");

// 3. Call the x axis in a group tag
svg.append("g")
    .attr("class", "x axis")
    .attr("transform", "translate(0," + height + ")")
    .call(d3.axisBottom(xScale)); // Create an axis component with d3.axisBottom

// 4. Call the y axis in a group tag
svg.append("g")
    .attr("class", "y axis")
    .call(d3.axisLeft(yScale)); // Create an axis component with d3.axisLeft

// 9. Append the path, bind the data, and call the line generator 
svg.append("path")
    .datum(dataset) // 10. Binds data to the line 
    .attr("fill", "none")
    .attr("stroke", "steelblue")
    .attr("stroke-width", 3)
    .attr("d", line); // 11. Calls the line generator 

// 12. Appends a circle for each datapoint 
svg.selectAll(".dot")
    .data(dataset)
  .enter().append("circle") // Uses the enter().append() method
    .style("fill","steelblue")
    .attr("cx", function(d, i) { return xScale(i) })
    .attr("cy", function(d) { return yScale(d.y) })
    .attr("r", 5);

// 13. Appends data text to each datapoint  
svg.selectAll(".text")
    .data(dataset)
    .enter().append("text")
    .style("fill", "red") 
    .attr("x", function(d, i) { return xScale(i) - 5 })
    .attr("y", function(d) { return yScale(d.y) - 20 })
    .text(function(d) { return d.y });
    

</script>

提前感谢您的回答

【问题讨论】:

    标签: javascript html d3.js


    【解决方案1】:

    我建议立即将字符串解析为 Date 对象,然后使用 d3.scaleTime 作为 x 刻度。下面是一个例子。

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="UTF-8">
        <script src="https://d3js.org/d3.v7.js"></script>
    </head>
    
    <body>
        <div id="chart"></div>
    
        <script>
          // set up
    
          const margin = { top: 40, bottom: 40, left: 40, right: 40 };
    
          const width = 500 - margin.left - margin.right;
          const height = 250 - margin.top - margin.bottom;
    
          const svg = d3.select('#chart')
            .append('svg')
              .attr('width', width + margin.left + margin.right)
              .attr('height', height + margin.top + margin.bottom);
    
          const g = svg.append('g')
              .attr('transform', `translate(${margin.left},${margin.top})`);
    
          // data
    
          const parseDate = d3.timeParse("%Y-%m-%d");
    
          const dataset = [
            ["2021-08-01",(d3.randomUniform(100)()).toFixed(1)],
            ["2021-08-02",(d3.randomUniform(100)()).toFixed(1)],
            ["2021-08-03",(d3.randomUniform(100)()).toFixed(1)],
            ["2021-08-04",(d3.randomUniform(100)()).toFixed(1)],
            ["2021-08-05",(d3.randomUniform(100)()).toFixed(1)],
            ["2021-08-06",(d3.randomUniform(100)()).toFixed(1)],
            ["2021-08-07",(d3.randomUniform(100)()).toFixed(1)],
            ["2021-08-08",(d3.randomUniform(100)()).toFixed(1)],
            ["2021-08-09",(d3.randomUniform(100)()).toFixed(1)],
            ["2021-08-10",(d3.randomUniform(100)()).toFixed(1)],
            ["2021-08-11",(d3.randomUniform(100)()).toFixed(1)]
          ].map(d => ({ date: parseDate(d[0]), value: parseFloat(d[1]) }));
    
          const minMaxDate = d3.extent(dataset, d => d.date);
          const maxValue = d3.max(dataset, d => d.value);
    
          // scales
    
          const x = d3.scaleTime()
              .domain(minMaxDate)
              .range([0, width]);
    
          const y = d3.scaleLinear()
              .domain([0, maxValue])
              .range([height, 0]);
    
          // line generator
    
          const line = d3.line()
              .x(d => x(d.date))
              .y(d => y(d.value))
              .curve(d3.curveMonotoneX);
    
    
          // axes
    
          g.append("g")
              .attr("class", "x axis")
              .attr("transform", `translate(0,${height})`)
              .call(d3.axisBottom(x));
          
          g.append("g")
              .attr("class", "y axis")
              .call(d3.axisLeft(y));
    
    
          // line
    
          g.append('path')
              .datum(dataset)
              .attr('fill', 'none')
              .attr('stroke', 'steelblue')
              .attr('stroke-width', 3)
              .attr('d', line);
    
          // circles
    
          g.selectAll('.dot')
            .data(dataset)
            .join('circle')
              .attr('fill', 'steelblue')
              .attr('cx', d => x(d.date))
              .attr('cy', d => y(d.value))
              .attr('r', 5);
    
          // text labels
    
          g.selectAll('.text')
            .data(dataset)
            .join('text')
              .attr('fill', 'red')
              .attr('x', d => x(d.date) - 5)
              .attr('y', d => y(d.value) - 20)
              .text(d => d.value);
        </script>
    </body>
    </html>

    【讨论】:

    • 太棒了,谢谢。我只是更改了 maxValue,因为它将值作为字符串而不是浮点数进行比较;因此语法为:const maxValue = d3.max(dataset, d =&gt; parseFloat(d.value));
    • 你说得对,我错过了值是字符串。我已经更新了答案来解决这个问题。我现在在解析日期的同时将值解析为浮点数。
    猜你喜欢
    • 1970-01-01
    • 2019-03-03
    • 1970-01-01
    • 2013-08-29
    • 1970-01-01
    • 2013-04-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多