背景
我正在使用 D3 4.x 构建一个多系列折线图 (see an example) 来比较多年的年度数据,其中 Y 轴是多年来可能值的范围,X-轴表示01/01-12/31日期之间的时间间隔。
问题
在构建此图表时,时间间隔似乎是特定于年份的,从而防止不同年份的数据呈现在同一张图表上。重申一下,目前的方法是将每年叠加在同一张图表上;每年一行。要以特定年份的时间间隔执行此操作,需要大量(且错误的)数据操作。
在下面的示例图表中,可以看到 2014 年从左侧(颜色:蓝色)接近,2015 年从右侧继续(颜色:橙色)。我希望看到的是这两者相互叠加。
确认/警告
通过将数据相互叠加(即多行,每行代表一年)来比较多年数据的一些复杂性已得到承认。比如如何处理有闰日的年份和没有闰日的年份。这在编程上使事情变得复杂,但在视觉上应该不是问题。
问题
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/