我正在使用D3 4.x构建一个多系列折线图(see an example)来比较多年的年度数据,其中Y轴是多年来可能值的范围和X轴表示日期01 / 01-12 / 31之间的时间间隔。
在构建此图表时,似乎时间间隔是特定年份,以防止来自不同年份的数据在同一图表上呈现。重申一下,目前的做法是将每年重叠在同一张图表上;每年一行。并且,如果时间间隔是特定年份,则需要进行大量(和错误的)数据操作。
在下面的示例图表中,可以看到2014年从左边开始(颜色:蓝色),2015年继续向右(颜色:橙色)。我希望看到的是这两者叠加在一起。
通过将数据叠加在彼此之上(即多条线,每条代表一年)来比较多年数据的一些复杂性得到承认。比如如何处理与闰日相比的年份。这会以编程方式使事情变得复杂,但在视觉上不应成为问题。
1)当年度受阻时,使用时间间隔的最佳方法是什么?
2)是否有一种更好,更优雅的方法来创建多个系列折线图,这些折线图表示多年相互叠加,而不是将各个部分拼凑在一起?
3)是否有办法(非静态)从轴上删除年份(即2015年)并使用月份(1月)?
4)是否可以将X轴上的文本向右移动(以编程方式),以便月份出现在刻度线之间(IMO,它在视觉上更准确)?
答案 0 :(得分:3)
有几种方法可以解决这个问题。实际上,他们中有很多人认为这个问题属于太宽泛。当然,每种方法都有其优点和缺点。例如,一个简单的方法是完全放弃时间刻度,并使用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年1月到2017年的不同年份(从2013年到2017年):
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);
&#13;
<script src="https://d3js.org/d3.v4.js"></script>
&#13;