如何将现有的d3区域转换为堆叠区域
How can I transform an existing d3 area into a stacked area?
目前,我有一个面积图,它显示了多个数据路径的面积。然而,我正在寻找一种将其转换为堆叠面积图的方法。基本上,我希望数据集堆叠在一起,这样它们就可见,不会被其他更大的区域隐藏。
我发现了两个例子:http://bl.ocks.org/mbostock/3885211和http://bl.ocks.org/mbostock/3020685.我遇到的问题是,我的数据格式非常不同,我也不确定d3是如何做到这一点的。从概念上讲,我很难理解d3在幕后做什么。我的理解是,它正在计算添加的最后一层之间的差异,但这似乎可以在不使用堆栈的情况下完成。
我的数据结构如下:
// datasets { data1: Array[10], data2: Array[10], data3: Array[10] }
// data1 [{value: 2340234, year: 1945}...]
绘图功能是这样的:
function draw(series) {
var data1 = [];
var data2 = [];
var data3 = [];
var prop = 0;
for (prop in series) {
var current = series[prop];
data1.push({value: current.data1, year: current.year});
data2.push({value: current.data2, year: current.year});
data3.push({value: current.data3, year: current.year});
}
var datasets = {
data1: data1,
data2: data2,
data3: data3
};
// updated
var layers = [datasets.data1, datasets.data2, datasets.data3];
var height = 800;
var width = window.innerWidth - 100;
var x = d3.time.scale()
.range([0, width]);
var y = d3.scale.linear()
.range([height, 0]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left");
// updated
var stack = d3.layout.stack()
.values( function(d) { return d.values; });
/
var stacked = stack(layers.map( function(layer) {
return {
values: layer.map( function(d) {
return { year: new Date(d.year, 0), y: +d.value};
})
};
}));
var area = d3.svg.area()
.x( function(d) {
console.log( x(d.year) + ' is the result of x(d.year)' )
return x(d.year);
})
// d.year is defined correctly
.y0(height)
.y1( function(d) {
console.log( y(d.value) + ' is the result of y(d.value)' )
return y(d.value);
});
// d is Object {year: Sat Jan 01 2005 00:00:00 GMT-0800 (PST), y: 47390331, y0: 0}
// here y(d.value) returns NaN for some reason
var svg = d3.select('body').append("svg")
.append("g")
.attr("transform", "translate(" + 120 + "," + 30 + ")");
// Calculate max value
var maxY = 0;
var minY = 0;
series.forEach( function(object) {
for (var key in object) {
if (object[key] > maxY) {
maxY = object[key];
}
}
});
// Calculate min value
series.forEach( function(object) {
for (var key in object) {
if (object[key] < minY) {
minY = object[key];
} else if (minY === 0) {
continue;
}
}
});
var minYear = new Date("1945");
var maxYear = new Date("2015");
x.domain([minYear, maxYear]);
y.domain([minY, maxY]);
svg.append("path").data(stacked)
.attr('d', function(d) { return area(d.values); });
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.call(yAxis);
}
将其转换为堆积面积图的最佳方法是什么?
编辑
已修复。解决方案包括计算面积,如示例所示:
var area = d3.svg.area()
.x(function(d) { return x(d.year); })
.y0(function(d) { return y(d.y0); })
.y1(function(d) { return y(d.y0 + d.y); });
您需要做的事情的快速飞越:
创建一个合适的堆栈生成器:
var stack = d3.layout.stack()
.values(function(d) { return d.values; });
通过堆栈生成器运行数据。您应该给生成器一个"层"数组。对于下面的例子,我假设发生了类似layers = [datasets.data1, datasets.data2, datasets.data3]
的事情。
var stacked = stack(layers.map(function(layer) {
return {
values: layer.map(function(d) {
return {year: new Date(d.year, 0), y: +d.value};
})
};
}));
values
键与之前设置生成器时使用的键相同。如果以后绘图时需要,可以向该对象添加更多内容。
创建堆叠数据后,通过区域生成器运行它:
svg.append("path")
.data(stacked)
.attr("d", function(d) { return area(d.values); });
在原始代码中,您使用了.datum(datasets[data])
—如果你愿意,你可以继续这样做,但for循环需要在堆叠的数据上运行:
for (var data in stacked) { ...
但是,我建议尽可能使用.data
而不是.datum
。在将原始数据集发送到d3生成器之前,您对其进行了大量操作,但我怀疑其中大部分是不必要的或重复的。你应该能够得到这样的东西:
var datasets = ...
var stacked = stack(datasets.map(function(dataset) { ... }));
svg.selectAll("path")
.data(stacked)
.enter()
.attr("d", function(d) { return area(d.values); });
设置数据集和生成器应该只不过是映射您关心的特定字段/值的位置。
如果有帮助的话,我可以试着做一个完整的工作示例。不过,我需要一个真实的数据文件。
- JavaScript:将字符串数组转换为文本区域
- 将文本区域行/列转换为屏幕 x/y 坐标
- 将 HTML 文本区域值转换为 jqmath 公式
- 将元素转换为可丢弃区域的要求是什么
- 如何将现有的d3区域转换为堆叠区域
- 文本区域 HTML 标记将转换为纯文本
- 是否有一种本机方法可以将字符串从任何区域设置转换为数字
- “转换”文本框到带有滑动动画的文本区域
- 将 html 单元格转换为文本区域
- 使用 JS/CSS 将<区域>转换为具有完全相同位置和形状的
- 如何防止 HTML 文本区域转换特殊符号,如 >
- 将 CKEDITOR 转换为文本区域
- 将 DOM 元素转换为 HTML 代码并显示在页面上的文本区域中
- 从服务器文件系统将XML转换为HTML文本区域
- 将语言代码转换为(dojo)区域设置代码
- 转换文本区域中的输入字段
- 用java将datetime转换为另一个区域设置datetime
- 将文本区域中的html标记转换为富格文本
- D3.js不同的图表区域转换
- 将无序列表中的多个文本区域转换为LI