【问题标题】:d3: flatten nested data?d3:扁平化嵌套数据?
【发布时间】:2016-03-07 18:40:10
【问题描述】:

如何使用 D3 根据一系列嵌套值展平表格?

对于下面的cars.json,我希望使用D3来扁平化层次,为每个model的每个模型year提供一个新行。因此,总共应该有九个订单项,每个品牌和型号三个。

我确定我在处理这个错误,但我对 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>

【问题讨论】:

    标签: javascript html d3.js


    【解决方案1】:

    您必须在渲染数据之前将其展平,以便每行有一个数据(并且由于行没有嵌套,因此不应嵌套数据)。这样,您显示的表格渲染代码应该可以正常工作。

    理想情况下,您应该已经平面传输数据。 CSV 非常适合传输平面数据,这通常是它从关系数据库中出来的方式。在您的情况下,这些列将是“品牌”、“型号”、“年份”和“价格”,其中每个品牌/型号出现 3 次 - 每年一次。

    如果您无法修改数据,请在加载后立即在 JS 中将其展平。我几乎可以肯定没有 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
          }
        });
      );
    }, [])
    

    【讨论】:

    • 非常有意义;非常感谢。如果你有第二个,你能解释一下reduce,为什么你可以在这里使用它而不是forEach
    • 我包含.reduce() 示例主要是为了花哨:) 仅通过查看使用它的代码很难了解它是如何工作的,但是如果您阅读description of how it works 应该会变得足够清楚。
    • 在这种情况下优势是微不足道的,但仍然:使用 reduce,内部函数不需要引用在这些函数之外定义的变量(第一个示例中的flatCars.push)。这意味着您可以编写flatCars = cars.reduce(flattenCar),其中flattenCar 在其他地方定义。可能会有一些性能提升(这里可以忽略不计)。它还在 1 行而不是 2 行中实现了结果,这可以说使代码更具可读性。 IE。开发人员可能会对var flatCars = [] 的用途感到困惑——直到他们阅读下一段代码。
    【解决方案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() 方法。在这里工作的codepen:http://codepen.io/anon/pen/grPzPJ?editors=1111

    【讨论】:

      猜你喜欢
      • 2017-04-17
      • 1970-01-01
      • 2017-03-19
      • 1970-01-01
      • 1970-01-01
      • 2023-04-03
      • 2014-08-12
      • 2019-04-24
      • 2023-04-08
      相关资源
      最近更新 更多