首页 > 解决方案 > 将字符串时间戳转换为小时轴

问题描述

我正在尝试基于 d3 中的两个时间戳创建散点图,但我不确定使用 d3-time-format 方法正确解析时间戳格式中的值并基于 24 构建范围的正确方法-小时期间。到目前为止,我构建了一个函数来遍历我的数组并使用 d3 方法将字符串转换为 d3 可读格式,但我似乎可以弄清楚如何格式化输出,以便将其从日期格式转换为时间格式。我的问题是 d3 接受时间格式吗?以及如何将日期对象转换为时间对象?目前我有一个 y 轴,它显示了多年的刻度。

提供的是我的完整代码:

<meta charset="utf-8">

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

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

<style>
div.tooltip {   
    position: absolute;         
    text-align: center;         
    width: 100px;                   
    height: 30px;                   
    padding: 2px;               
    font: 12px sans-serif;      
    background: lightsteelblue; 
    border: 0px;        
    border-radius: 8px;         
    pointer-events: none;           
}
</style>

<script>

    var data = [
      {
        "x": "23:19:30",
        "y": "08:07:00"
      },
      {
        "x": "22:55:30",
        "y": "06:08:00"
      },
      {
        "x": "21:14:30",
        "y": "06:13:30"
      },
      {
        "x": "21:24:30",
        "y": "06:04:30"
      },
      {
        "x": "21:24:00",
        "y": "06:04:00"
      },
      {
        "x": "21:28:00",
        "y": "06:09:00"
      },
      {
        "x": "23:23:30",
        "y": "08:20:30"
      },
      {
        "x": "23:47:00",
        "y": "08:01:30"
      },
      {
        "x": "00:03:00",
        "y": "06:49:30"
      },
      {
        "x": "21:46:00",
        "y": "06:21:00"
      },
      {
        "x": "21:58:00",
        "y": "06:02:30"
      },
      {
        "x": "21:33:00",
        "y": "05:56:00"
      },
      {
        "x": "22:33:00",
        "y": "06:15:30"
      },
      {
        "x": "23:49:00",
        "y": "07:10:30"
      },
      {
        "x": "23:46:30",
        "y": "08:35:30"
      },
      {
        "x": "23:15:30",
        "y": "05:59:30"
      },
      {
        "x": "21:26:00",
        "y": "06:05:00"
      },
      {
        "x": "21:26:30",
        "y": "05:54:00"
      },
      {
        "x": "21:06:00",
        "y": "05:53:00"
      },
      {
        "x": "21:25:00",
        "y": "05:47:30"
      },
      {
        "x": "00:29:30",
        "y": "08:59:30"
      },
      {
        "x": "01:14:00",
        "y": "08:09:30"
      },
      {
        "x": "23:12:30",
        "y": "06:06:30"
      },
      {
        "x": "21:26:00",
        "y": "05:52:30"
      },
      {
        "x": "21:18:30",
        "y": "05:47:00"
      },
      {
        "x": "20:54:30",
        "y": "07:07:30"
      },
      {
        "x": "21:36:00",
        "y": "05:53:30"
      },
      {
        "x": "00:28:00",
        "y": "08:00:00"
      },
      {
        "x": "23:21:30",
        "y": "07:58:30"
      },
      {
        "x": "21:34:00",
        "y": "05:51:00"
      },
      {
        "x": "21:23:30",
        "y": "05:58:00"
      },
      {
        "x": "21:05:30",
        "y": "05:53:00"
      },
      {
        "x": "21:33:30",
        "y": "05:39:30"
      },
      {
        "x": "23:49:30",
        "y": "06:50:00"
      },
      {
        "x": "01:11:00",
        "y": "08:37:30"
      },
      {
        "x": "22:34:30",
        "y": "05:15:00"
      },
      {
        "x": "22:49:30",
        "y": "05:55:00"
      },
      {
        "x": "22:06:30",
        "y": "06:03:00"
      },
      {
        "x": "21:32:30",
        "y": "06:01:00"
      },
      {
        "x": "21:49:00",
        "y": "05:39:30"
      },
      {
        "x": "22:47:30",
        "y": "08:27:30"
      },
      {
        "x": "21:26:30",
        "y": "05:51:00"
      },
      {
        "x": "21:47:30",
        "y": "05:51:00"
      },
      {
        "x": "21:28:00",
        "y": "05:47:30"
      },
      {
        "x": "21:32:00",
        "y": "05:47:30"
      },
      {
        "x": "21:13:30",
        "y": "05:46:00"
      },
      {
        "x": "23:42:30",
        "y": "06:45:00"
      },
      {
        "x": "21:33:00",
        "y": "05:48:00"
      },
      {
        "x": "21:45:00",
        "y": "05:51:00"
      },
      {
        "x": "21:29:30",
        "y": "06:06:00"
      },
      {
        "x": "21:16:00",
        "y": "05:43:00"
      },
      {
        "x": "21:14:00",
        "y": "05:46:30"
      },
      {
        "x": "00:01:30",
        "y": "07:25:30"
      },
      {
        "x": "02:24:00",
        "y": "10:35:30"
      },
      {
        "x": "22:29:30",
        "y": "07:04:00"
      },
      {
        "x": "21:43:30",
        "y": "05:51:00"
      },
      {
        "x": "21:31:30",
        "y": "05:45:00"
      },
      {
        "x": "22:16:30",
        "y": "05:50:30"
      },
      {
        "x": "21:59:00",
        "y": "05:47:00"
      },
      {
        "x": "02:55:30",
        "y": "11:15:30"
      },
      {
        "x": "02:57:00",
        "y": "07:23:00"
      },
      {
        "x": "21:49:30",
        "y": "06:48:30"
      },
      {
        "x": "21:31:30",
        "y": "05:26:30"
      }
    ]
    
    // D3 date parser
    for (var i=0; i < data.length; i++){
        
        var parser = d3.timeParse("%I:%M:%S")
        data[i].x = parser(data[i].x);
        data[i].y = parser(data[i].y);
    }

    console.log(data)
    var margin = { top: 10, right: 30, bottom: 30, left: 60  }
    var width = 800 - margin.left - margin.right;
    var height = 800 - margin.top - margin.bottom;


    // Define the div for the tooltip
    var div = d3.select("body").append("div")   
        .attr("class", "tooltip")               
        .style("opacity", 0);

    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 + ")"); // translate(margin left, margin top)

    var x = d3.scaleTime()
        .domain([d3.min(data, function(d) { return d.date }), d3.max(data, function(d) { return d.date })])
        .range([0, width]);
    
    svg.append("g")
        .attr("transform", "translate(" + 0 + "," + height + ")")
        .call(d3.axisBottom(x))
            // .tickFormat(d3.time.format);

    // text label for the x axis
    svg.append("text")             
        .attr("transform",
                "translate(" + (width/2) + " ," + (height + margin.top + 20) + ")")
        .style("text-anchor", "middle")
        .text("Date");

    var y = d3.scaleTime()
        .domain([0, d3.max(data, function(d){ return +d.y })])
        .range([height, 0]);
    
    svg.append("g")
        .call(d3.axisLeft(y));

    // text label for the y axis
    svg.append("text")
        .attr("transform", "rotate(-90)")
        .attr("y", 0 - margin.left)
        .attr("x",0 - (height / 2))
        .attr("dy", "1em")
        .style("text-anchor", "middle")
        .text("Time Asleep (Minutes)");

    // Add line path
    svg.append("path")
        .datum(data)
        .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.y) })
        );

    // Add the scatterplot (data points)
    svg.selectAll("dot")
        .data(data)
    .enter().append("circle")
        .attr("r", 3)
        .attr("cx", function(d){ return x(d.date) })
        .attr("cy", function(d){ return y(d.y) })
        // Add tooltip on hover
        .on("mouseover", function(d) {
            div.transition()
                .duration(200)
                .style("opacity", .9);
            div.html(d.x + "<br/>" + d.label)
                .style("left", (d3.event.pageX) + "px")
                .style("top", (d3.event.pageY - 30) + "px")
        })
        // Remove tooltip after hover
        .on("mouseout", function(d) {
            div.transition()
                .duration(500)
                .style("opacity", 0);
        });
    

</script>

标签: d3.js

解决方案


要格式化日期,请使用d3.timeParse. 这会将任何日期字符串解析为 Date 对象。D3 可以理解和使用timeScale.

我已将您的原始数据重命名为rawData. 我们还需要按 X 轴对数据进行排序:

var toDate = d3.timeParse("%H:%M:%S")
var data = rawData.map(d => ({
    x: toDate(d.x), 
    y: toDate(d.y),
})).sort((a, b) => d3.descending(a.x, b.x)

要计算域,请使用d3.extentwhich 将自动计算域。

var x = d3.scaleTime()
    .domain(d3.extent(data, d => d.x))
    .range([0, width]);

<head></head>
    <meta charset="utf-8">

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

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

    <style>
    div.tooltip {   
        position: absolute;         
        text-align: center;         
        width: 100px;                   
        height: 30px;                   
        padding: 2px;               
        font: 12px sans-serif;      
        background: lightsteelblue; 
        border: 0px;        
        border-radius: 8px;         
        pointer-events: none;           
    }
    </style>

    <script>

        var rawData = [
          {
            "x": "23:19:30",
            "y": "08:07:00"
          },
          {
            "x": "22:55:30",
            "y": "06:08:00"
          },
          {
            "x": "21:14:30",
            "y": "06:13:30"
          },
          {
            "x": "21:24:30",
            "y": "06:04:30"
          },
          {
            "x": "21:24:00",
            "y": "06:04:00"
          },
          {
            "x": "21:28:00",
            "y": "06:09:00"
          },
          {
            "x": "23:23:30",
            "y": "08:20:30"
          },
          {
            "x": "23:47:00",
            "y": "08:01:30"
          },
          {
            "x": "00:03:00",
            "y": "06:49:30"
          },
          {
            "x": "21:46:00",
            "y": "06:21:00"
          },
          {
            "x": "21:58:00",
            "y": "06:02:30"
          },
          {
            "x": "21:33:00",
            "y": "05:56:00"
          },
          {
            "x": "22:33:00",
            "y": "06:15:30"
          },
          {
            "x": "23:49:00",
            "y": "07:10:30"
          },
          {
            "x": "23:46:30",
            "y": "08:35:30"
          },
          {
            "x": "23:15:30",
            "y": "05:59:30"
          },
          {
            "x": "21:26:00",
            "y": "06:05:00"
          },
          {
            "x": "21:26:30",
            "y": "05:54:00"
          },
          {
            "x": "21:06:00",
            "y": "05:53:00"
          },
          {
            "x": "21:25:00",
            "y": "05:47:30"
          },
          {
            "x": "00:29:30",
            "y": "08:59:30"
          },
          {
            "x": "01:14:00",
            "y": "08:09:30"
          },
          {
            "x": "23:12:30",
            "y": "06:06:30"
          },
          {
            "x": "21:26:00",
            "y": "05:52:30"
          },
          {
            "x": "21:18:30",
            "y": "05:47:00"
          },
          {
            "x": "20:54:30",
            "y": "07:07:30"
          },
          {
            "x": "21:36:00",
            "y": "05:53:30"
          },
          {
            "x": "00:28:00",
            "y": "08:00:00"
          },
          {
            "x": "23:21:30",
            "y": "07:58:30"
          },
          {
            "x": "21:34:00",
            "y": "05:51:00"
          },
          {
            "x": "21:23:30",
            "y": "05:58:00"
          },
          {
            "x": "21:05:30",
            "y": "05:53:00"
          },
          {
            "x": "21:33:30",
            "y": "05:39:30"
          },
          {
            "x": "23:49:30",
            "y": "06:50:00"
          },
          {
            "x": "01:11:00",
            "y": "08:37:30"
          },
          {
            "x": "22:34:30",
            "y": "05:15:00"
          },
          {
            "x": "22:49:30",
            "y": "05:55:00"
          },
          {
            "x": "22:06:30",
            "y": "06:03:00"
          },
          {
            "x": "21:32:30",
            "y": "06:01:00"
          },
          {
            "x": "21:49:00",
            "y": "05:39:30"
          },
          {
            "x": "22:47:30",
            "y": "08:27:30"
          },
          {
            "x": "21:26:30",
            "y": "05:51:00"
          },
          {
            "x": "21:47:30",
            "y": "05:51:00"
          },
          {
            "x": "21:28:00",
            "y": "05:47:30"
          },
          {
            "x": "21:32:00",
            "y": "05:47:30"
          },
          {
            "x": "21:13:30",
            "y": "05:46:00"
          },
          {
            "x": "23:42:30",
            "y": "06:45:00"
          },
          {
            "x": "21:33:00",
            "y": "05:48:00"
          },
          {
            "x": "21:45:00",
            "y": "05:51:00"
          },
          {
            "x": "21:29:30",
            "y": "06:06:00"
          },
          {
            "x": "21:16:00",
            "y": "05:43:00"
          },
          {
            "x": "21:14:00",
            "y": "05:46:30"
          },
          {
            "x": "00:01:30",
            "y": "07:25:30"
          },
          {
            "x": "02:24:00",
            "y": "10:35:30"
          },
          {
            "x": "22:29:30",
            "y": "07:04:00"
          },
          {
            "x": "21:43:30",
            "y": "05:51:00"
          },
          {
            "x": "21:31:30",
            "y": "05:45:00"
          },
          {
            "x": "22:16:30",
            "y": "05:50:30"
          },
          {
            "x": "21:59:00",
            "y": "05:47:00"
          },
          {
            "x": "02:55:30",
            "y": "11:15:30"
          },
          {
            "x": "02:57:00",
            "y": "07:23:00"
          },
          {
            "x": "21:49:30",
            "y": "06:48:30"
          },
          {
            "x": "21:31:30",
            "y": "05:26:30"
          }
        ]
        
        // D3 date parser
        var toDate = d3.timeParse("%H:%M:%S")
        var data = rawData.map(d => ({
            x: toDate(d.x), 
            y: toDate(d.y),
        })).sort((a, b) => d3.descending(a.x, b.x))

        console.log(data[0])
        
        var margin = { top: 10, right: 30, bottom: 30, left: 60  }
        var width = 800 - margin.left - margin.right;
        var height = 800 - margin.top - margin.bottom;


        // Define the div for the tooltip
        var div = d3.select("body").append("div")   
            .attr("class", "tooltip")               
            .style("opacity", 0);

        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 + ")"); // translate(margin left, margin top)

        var x = d3.scaleTime()
            .domain(d3.extent(data, d => d.x))
            .range([0, width]);
        
        svg.append("g")
            .attr("transform", "translate(" + 0 + "," + height + ")")
            .call(d3.axisBottom(x))
                // .tickFormat(d3.time.format);

        // text label for the x axis
        svg.append("text")             
            .attr("transform",
                    "translate(" + (width/2) + " ," + (height + margin.top + 20) + ")")
            .style("text-anchor", "middle")
            .text("Date");

        var y = d3.scaleTime()
            .domain(d3.extent(data, d => d.y))
            .range([height, 0]);
        
        svg.append("g")
            .call(d3.axisLeft(y));

        // text label for the y axis
        svg.append("text")
            .attr("transform", "rotate(-90)")
            .attr("y", 0 - margin.left)
            .attr("x",0 - (height / 2))
            .attr("dy", "1em")
            .style("text-anchor", "middle")
            .text("Time Asleep (Minutes)");

        // Add line path
        svg.append("path")
            .datum(data)
            .attr("fill", "none")
            .attr("stroke", "steelblue")
            .attr("stroke-width", 1.5)
            .attr("d", d3.line()
                .x(function(d) { return x(d.x) })
                .y(function(d) { return y(d.y) })
            );

        // Add the scatterplot (data points)
        svg.selectAll("dot")
            .data(data)
        .enter().append("circle")
            .attr("r", 3)
            .attr("cx", function(d){ return x(d.x) })
            .attr("cy", function(d){ return y(d.y) })
            // Add tooltip on hover
            .on("mouseover", function(d) {
                div.transition()
                    .duration(200)
                    .style("opacity", .9);
                div.html(d.x + "<br/>" + d.label)
                    .style("left", (d3.event.pageX) + "px")
                    .style("top", (d3.event.pageY - 30) + "px")
            })
            // Remove tooltip after hover
            .on("mouseout", function(d) {
                div.transition()
                    .duration(500)
                    .style("opacity", 0);
            });
        

    </script>


推荐阅读