如何使用D3?
基于一系列嵌套值展平表格对于以下cars.json
,我希望使用D3展平层次结构,为每个year
的每个模型model
提供一个新行。因此,总共应该有九个订单项,每个品牌和型号都有三个。
我确定我接近这个错误,但我在D3有点新,而且我不知道怎么想。我已经看到了使用d3.nest
的其他问题,但由于我不打算对任何内容进行分组,因此它似乎不适用。谢谢!
cars.json
[
{
"make": "Ford",
"model": "Escape",
"years": [
{
"year": 2013,
"price": 16525
},
{
"year": 2014
},
{
"year": 2015
}
]
},
{
"make": "Kia",
"model": "Sportage",
"years": [
{
"year": 2012
},
{
"year": 2013,
"price": 16225
},
{
"year": 2014
}
]
},
{
"make": "Honda",
"model": "CR-V",
"years": [
{
"year": 2008
},
{
"year": 2009
},
{
"year": 2010,
"price": 12875
}
]
}
]
所需的输出
<table>
<thead>
<tr><th>Make</th><th>Model</th><th>Year</th><th>Price</th></tr>
</thead>
<tbody>
<tr><td>Ford</td><td>Escape</td><td>2013</td><td>16525</td></tr>
<tr><td>Ford</td><td>Escape</td><td>2014</td><td></td></tr>
<tr><td>Ford</td><td>Escape</td><td>2015</td><td></td></tr>
<tr><td>Kia</td><td>Sportage</td><td>2012</td><td></td></tr>
<tr><td>Kia</td><td>Sportage</td><td>2013</td><td>16225</td></tr>
<tr><td>Kia</td><td>Sportage</td><td>2014</td><td></td></tr>
<tr><td>Honda</td><td>CR-V</td><td>2008</td><td></td></tr>
<tr><td>Honda</td><td>CR-V</td><td>2009</td><td></td></tr>
<tr><td>Honda</td><td>CR-V</td><td>2010</td><td>12875</td></tr>
</tbody>
</table>
当前尝试
<table id="cars_table">
<thead>
<th>Make</th><th>Model</th><th>Year</th><th>Price</th>
</thead>
<tbody></tbody>
<tfoot></tfoot>
</table>
<script>
(function(){
d3.json('/static/cars.json', function(error, cars) {
var tbody = d3.select('tbody')
rows = tbody.selectAll('tr').data(cars).enter().append('tr')
rows.append('td').html(function(d) {
return d.make
})
rows.append('td').html(function(d) {
return d.model
})
var years = rows.append('td').html(function(d) {
return d.years
// don't want this nested; probably should be peeled out into another `selectAll`, but I don't know where?
})
})
})()
</script>
答案 0 :(得分:2)
在渲染数据之前,必须将数据展平,以便每行有一个数据(因为行不嵌套,所以不应嵌套数据)。这样你展示的表格渲染代码应该可以正常工作。
理想情况下,您已经将数据平移。 CSV非常适合传输平面数据,这通常来自关系数据库。在您的情况下,列将是“制造”,“模型”,“年份”和“价格”,其中每个品牌/模型出现3次 - 每年一次。
如果您无法修改数据,请在加载后立即将其展平。我几乎可以肯定,没有一个d3实用工具(d3.nest()
与你要求做的相反),但是用循环来做这个很简单:
var flatCars = []
cars.forEach(function(car) {
car.years.forEach(function(carYear) {
flatCars.push({
make: car.make,
model: car.model,
year: carYear.year,
price: carYear.price
});
});
});
或
var flatCars = cars.reduce(memo, car) {
return memo.concat(
car.years.map(function(carYear) {
return {
make: car.make,
model: car.model,
year: carYear.year,
price: carYear.price
}
});
);
}, [])
答案 1 :(得分:2)
您必须先将数据展平,然后再将其传递给D3 data()
方法。 D3应该只负责将数据结构转换为DOM树。换句话说:如果您希望使用嵌套的DOM结构,请使用嵌套数据结构。
所以,像这样压平数据(在这里使用lodash):
data = _.flatten(data.map(function (model) {
return model.years.map(function (year) {
return _.assign(year, _.pick(model, 'make', 'model'));
});
}));
然后将其传递给data()
方法。在这里工作代码:http://codepen.io/anon/pen/grPzPJ?editors=1111