首页 > 解决方案 > 在 D3 轴上形成分和秒

问题描述

我正在做一个 D3 项目,我有时间(分钟和秒)采用 JSON 格式,如下所示:

"Time": "36:50"

如何在 D3 图表的 y 轴上以该格式绘制时间?我应该使用d3.scaleTime还是d3.scaleLinear用于轴?如何制作minute:second以 JSON 格式显示时间的刻度?

编辑:
这是我迄今为止的尺度/轴:

  //Format data for X Axis
      var yearFormat = "%Y";
      var parsedYear = years.map(function(d) {
        return d3.timeParse(yearFormat)(d)
      });


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


      // Format data for Y Axis
      var specifier = "%M:%S";
      var parsedTime = times.map(function(d) {
        return d3.timeParse(specifier)(d)
      })

      var y = d3.scaleTime()
                .range([height, 0])
                .domain(d3.extent(parsedTime));

      // X Axis
      g.append("g")
        .attr("transform", "translate(0," + height + ")")
        .call(d3.axisBottom(x))
        .attr("stroke-width", 2)
        .style("font-size", ".6em")


      // Y Axis
      g.append("g")
        .call(d3.axisLeft(y))
        .attr("stroke-width", 2)
        .style("font-size", ".6em")
        .tickValues(parsedTime)
        .tickFormat(function(d){
           return d3.timeFormat(specifier)(d)
         });

标签: javascriptd3.jstimeaxis

解决方案


您的问题的任何可能答案都是危险的基于意见的,因为它完全取决于您想要什么:您想将时间视为时间吗?还是您想将时间视为单独的、单独的事件?

这里实际上有三个选项供您选择:

  1. 使用序数尺度(波段、点...):在这种情况下,每个数据条目将只是一个分类变量。轴中刻度之间的空间将是相同的。
  2. 使用线性刻度:这允许轴中刻度的不同距离。但是,这些值不会是时间,您必须创建一个数学来设置值(最简单的可能是计算秒数)。
  3. 使用时间尺度:这有一个优势,那就是您将时间视为时间。然而,主要的缺点正是前面的陈述:时间是一个复杂的野兽,你会有闰年、夏令时、时区差异等......

由于线性比例很容易创建(而序数比例更简单),这里有一个答案,展示了如何使用时间比例来做到这一点。

假设你有这个数据数组:

var data = ["12:32", "21:05", "24:56", "36:30", "45:14", "71:11"];

第一步是解析日期:

var specifier = "%M:%S";
var parsedData = data.map(function(d) {
  return d3.timeParse(specifier)(d)
});

然后创建规模:

var scale = d3.scaleTime()
  .domain(d3.extent(parsedData));

为此,我们必须设置tickValues使用我们解析的数据数组,并将刻度格式化为分钟和秒:

var axis = d3.axisBottom(scale)
    .tickValues(parsedData)
    .tickFormat(function(d){
        return d3.timeFormat(specifier)(d)
    });

结果如下:

var data = ["12:32", "21:05", "24:56", "36:30", "45:14", "71:11"];
var specifier = "%M:%S";
var svg = d3.select("svg");
var parsedData = data.map(function(d) {
  return d3.timeParse(specifier)(d)
});
var scale = d3.scaleTime()
  .domain(d3.extent(parsedData))
  .range([30, 470]);
var axis = d3.axisBottom(scale)
  .tickValues(parsedData)
  .tickFormat(function(d) {
    return d3.timeFormat(specifier)(d)
  });
var gX = svg.append("g")
  .attr("transform", "translate(0,50)")
  .call(axis)
<script src="https://d3js.org/d3.v5.min.js"></script>
<svg width="500" height="100"></svg>

如您所见,刻度线在此处的间距正确。但是我们有一个问题:这些刻度是实际日期(如果您检查代码,您会看到年份是 1900 年)。因此,最后一个刻度,应该是 71 分 11 秒,显示为11:11,因为它是下一小时的第 11 分钟。

一个简单的解决方案是引用原始字符串数组:

.tickFormat(function(d,i) {
    return data[i]
});

结果如下:

var data = ["12:32", "21:05", "24:56", "36:30", "45:14", "71:11"];
var specifier = "%M:%S";
var svg = d3.select("svg");
var parsedData = data.map(function(d) {
  return d3.timeParse(specifier)(d)
});
var scale = d3.scaleTime()
  .domain(d3.extent(parsedData))
  .range([30, 470]);
var axis = d3.axisBottom(scale)
  .tickValues(parsedData)
  .tickFormat(function(d, i) {
    return data[i]
  });
var gX = svg.append("g")
  .attr("transform", "translate(0,50)")
  .call(axis)
<script src="https://d3js.org/d3.v5.min.js"></script>
<svg width="500" height="100"></svg>


推荐阅读