javascript - 多系列图表——时间(年)区间x轴叠加多年数据

标签 javascript d3.js charts

背景

我正在使用 D3 4.x 构建一个多系列折线图 (see an example) 来比较多年的年度数据,其中 Y 轴是多年来可能值的范围,X-轴表示01/01-12/31日期之间的时间间隔。

问题

在构建此图表时,时间间隔似乎是特定于年份的,从而防止不同年份的数据呈现在同一张图表上。重申一下,目前的方法是将每年叠加在同一张图表上;每年一行。要以特定年份的时间间隔执行此操作,需要大量(且错误的)数据操作。

在下面的示例图表中,可以看到 2014 年从左侧(颜色:蓝色)接近,2015 年从右侧继续(颜色:橙色)。我希望看到的是这两者相互叠加。

enter image description here

确认/警告

通过将数据相互叠加(即多行,每行代表一年)来比较多年数据的一些复杂性已得到承认。比如如何处理有闰日的年份和没有闰日的年份。这在编程上使事情变得复杂,但在视觉上应该不是问题。

问题

1) 当年份刚刚过去时,使用时间间隔的最佳方法是什么?

2) 是否有更好、更优雅的方法来创建多系列折线图,这些折线图表示多个年份相互叠加,而不是拼凑在一起?

3) 有没有办法(不是静态的)从轴上删除年份(即 2015 年)并改用月份(一月)?

4) 是否可以将 X 轴上的文本向右移动(以编程方式),以便月份出现在刻度线之间(IMO,它在视觉上更准确)?

最佳答案

有几种方法可以解决这个问题。实际上,这个问题太多了,过于宽泛。当然,每种方法都有其优点和缺点。例如,一个简单的方法是完全放弃时间尺度,并为 x 轴使用点尺度。

我会建议一种不同的方法,稍微复杂一些,但仍然使用时间尺度:创建几个不同的时间尺度,每年一个。他们每个人都有相同的范围:这样,每年的线可以相互重叠。

例如,从 2013 年到 2017 年:

var years = [2013, 2014, 2015, 2016, 2017];

var scales = {};

years.forEach(d => {
    scales["scale" + d] = d3.scaleTime()
        .domain([new Date(+d, 0, 1), new Date(+d, 11, 31)])
        .range([30, 470]);
});

这样,您就可以继续使用 x 轴的时间刻度。问题是:时间尺度处理每年的情况:不同。有的年份天数多,有的年份天数少。即使是日子也可以有更多或更少的时间。

因此,我选择了一年 (2017),并在 x 轴上仅显示了那一年的月份。结果可能不是非常精确,但如果您在 x 轴上有整整一年就足够了。

这是演示。数据是随机生成的,每一行都是不同的年份(从 2013 年到 2017 年),从 1 月 1 日到 12 月 31 日:

var svg = d3.select("body").append("svg")
  .attr("width", 500)
  .attr("height", 200);

var color = d3.scaleOrdinal(d3.schemeCategory10);

var thisYear;

var line = d3.line()
  .x(d => scales[thisYear](d.x))
  .y(d => yScale(d.y))
  .curve(d3.curveMonotoneX);

var years = [2013, 2014, 2015, 2016, 2017];

var data = [];

years.forEach((d, i) => {
  data.push({
    year: d,
    points: []
  });
  for (var j = 0; j < 12; j++) {
    data[i].points.push({
      y: Math.random() * 80 + 20,
      x: new Date(d, j)
    })
  }
});

var scales = {};

var yScale = d3.scaleLinear()
  .domain([0, 100])
  .range([170, 30]);

years.forEach(d => {
  scales["scale" + d] = d3.scaleTime()
    .domain([new Date(+d, 0, 1), new Date(+d, 11, 31)])
    .range([30, 470]);
});

var paths = svg.selectAll("foo")
  .data(data)
  .enter()
  .append("path");

paths.attr("stroke", (d, i) => color(i))
  .attr("d", d =>{
  thisYear = "scale" + d.year;
  return line(d.points);
  })
  .attr("fill", "none");
  
var xAxis = d3.axisBottom(scales.scale2017).tickFormat(d=>d3.timeFormat("%b")(d));
var yAxis = d3.axisLeft(yScale);

var gX = svg.append("g").attr("transform", "translate(0,170)").call(xAxis);

var gY = svg.append("g").attr("transform", "translate(30,0)").call(yAxis);
<script src="https://d3js.org/d3.v4.js"></script>

关于javascript - 多系列图表——时间(年)区间x轴叠加多年数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42870187/

相关文章:

dom - 在不直接操作 DOM 的情况下绘制 d3 轴

c# - 如何在C#中绘制蜡烛图

javascript - Highcharts,仅在选定点上显示标记

javascript - JS : Why is ~10 (binary, ~1010) = -11 (二进制, -1011)?

javascript - 如何使用 d3.js 绘制带箭头的线

javascript - d3 - 按周缩放时间

javascript - Google TableChart 与页面上的其他图表不能很好地配合

javascript - Angular : centralised resource factory with promises

javascript - 从 MVC 项目中的操作返回的 HTML 文件中的脚本路径不正确

javascript - 函数 isisogram 无法正常工作