d3:展平嵌套数据?

时间:2016-03-07 18:40:10

标签: javascript html d3.js

如何使用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>

2 个答案:

答案 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