如何将原始数据行检索到dc.js Boxplot数据点?

问题描述 投票:1回答:1

我使用dc.js创建了一个Boxplot,工作正常。为了给图表添加更多的交互性,我想让用户点击离群值来获取额外的信息。

因此,我创建了一个事件处理程序,就像本文中解释的那样。D3文件. 结果和预期的一样,当用户点击数据点时,我得到了一个事件。我的期望是以某种方式访问原始数据,以检索点击数据点的fc属性,但我失败了,目前不知道如何解决这个问题。任何帮助都将是非常感激的。

const data = [{
    "duration": 248,
    "type": "M248",
    "sfc": "M248BJ0L2809783",
    "pass": 1
  },
  {
    "duration": 249,
    "type": "M248",
    "sfc": "M248BK0L2809676",
    "pass": 1
  },
  {
    "duration": 156,
    "type": "M248",
    "sfc": "M248BK0L2809676",
    "pass": 1
  },
  {
    "duration": 254,
    "type": "M248",
    "sfc": "M248BP0L2809798",
    "pass": 1
  },
  {
    "duration": 134,
    "type": "M248",
    "sfc": "M248BJ0L2809783",
    "pass": 1
  },
  {
    "duration": 128,
    "type": "M248",
    "sfc": "M248BP0L2809798",
    "pass": 0
  },
  {
    "duration": 228,
    "type": "M248",
    "sfc": "M248B90L2809800",
    "pass": 0
  },
  {
    "duration": 125,
    "type": "M248",
    "sfc": "M248B90L2809800",
    "pass": 0
  },
  {
    "duration": 242,
    "type": "M248",
    "sfc": "M248BJ0L2809792",
    "pass": 1
  },
  {
    "duration": 149,
    "type": "M248",
    "sfc": "M248BJ0L2809792",
    "pass": 1
  },
  {
    "duration": 237,
    "type": "M248",
    "sfc": "M248BJ0L2809819",
    "pass": 1
  },
  {
    "duration": 153,
    "type": "M248",
    "sfc": "M248BJ0L2809819",
    "pass": 1
  },
  {
    "duration": 232,
    "type": "M248",
    "sfc": "M248BK0L2809847",
    "pass": 1
  },
  {
    "duration": 482,
    "type": "M248",
    "sfc": "M248BK0L2809847",
    "pass": 1
  },
  {
    "duration": 238,
    "type": "M248",
    "sfc": "M248BK0L2809883",
    "pass": 1
  },
  {
    "duration": 143,
    "type": "M248",
    "sfc": "M248BK0L2809883",
    "pass": 1
  },
  {
    "duration": 213,
    "type": "M247",
    "sfc": "M247B50L2693004",
    "pass": 1
  },
  {
    "duration": 217,
    "type": "M247",
    "sfc": "M247B50L2693004",
    "pass": 0
  },
  {
    "duration": 229,
    "type": "M248",
    "sfc": "M248BC0L2809902",
    "pass": 1
  },
  {
    "duration": 151,
    "type": "M248",
    "sfc": "M248BC0L2809902",
    "pass": 0
  }
];

const cycletimeChart = dc.boxPlot('#cycletime-chart');

const ndx = crossfilter(data),
  typeDimension = ndx.dimension(function(d) {
    return d.type;
  }),
  cycletimeGroupByType = typeDimension.group().reduce(function(p, v) {
    // keep array sorted for efficiency
    p.splice(d3.bisectLeft(p, v.duration), 0, v.duration);
    return p;
  }, function(p, v) {
    p.splice(d3.bisectLeft(p, v.duration), 1);
    return p;
  }, function() {
    return [];
  });

cycletimeChart
  .dimension(typeDimension)
  .group(cycletimeGroupByType)
  .on('pretransition', function(chart) {
    chart.selectAll('circle.outlier').on('click.sfcClick', function(datum, index, nodes) {
      console.log(`Clicked on outlier with array index ${datum}, ${index}, ${nodes}.`);
      //Here I would like to retrieve the the sfc attribute from the original data object.
    });
  });
cycletimeChart.render();
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>Boxplot test</title>
  <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.16.0/d3.min.js"></script>
  <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/crossfilter/1.3.12/crossfilter.min.js"></script>
  <script type="text/javascript" src="https://unpkg.com/dc@4/dist/dc.js"></script>
  <link rel="stylesheet" type="text/css" href="https://unpkg.com/dc@4/dist/style/dc.css">
</head>

<body>
  <div id="cycletime-chart"></div>

</body>

</html>
d3.js dc.js crossfilter
1个回答
0
投票

这里有三个问题。

  1. 由于crossfilter对数据进行了聚合,所以只有你在reduce函数中提供的数据才是可用的。
  2. boxplot将数组索引与离群值绑定,而不是数据。
  3. 如果这些持续时间不是唯一的,你在过滤时会遇到麻烦。

1. 将整行数据通过crossfilter

由于crossfilter都是聚合的,所以默认情况下,原始数据是不可用的。一个变通的方法是将还原改为存储 v 而不是 v.duration:

  bisectLeft = d3.bisector(d => d.duration).left,
  cycletimeGroupByType = typeDimension.group().reduce(function(p, v) {
    // keep array sorted for efficiency
    p.splice(bisectLeft(p, v.duration), 0, v);
    return p;
  }, function(p, v) {
    p.splice(bisectLeft(p, v.duration), 1);
    return p;
  }, function() {
    return [];
  });

由于 dc.boxPlot 期待一个数字数组,你还需要修改 valueAccessor 来提取持续时间。

  .valueAccessor(d => d.value.map(r => r.duration))

2. 使用数组索引获取基准值

如上所述 盒状图数据点离群值的排列和颜色。绑定了dc.js的boxplot。阵列索引 到离群点。

由于交叉滤波的键值对被绑定到父级的 <g> 元素,可以用咒语来检索原始基准。

d3.select(this.parentNode).datum().value[datum]

3. 3. 非独特的期限

在第一步中,我们开始在还原中保存数据的行,而不是只保存durations。如果这些持续时间不是唯一的,就会有一个问题:当行被过滤掉时,错误的值可能会从数组中删除。

为了更加小心,我们应该扫描准确的值,而不是删除第一个具有相同持续时间的条目。

  function(p, v) {
    let i = d3.bisectLeft(p, v.duration);
    while(p[i] !== v) ++i;
    p.splice(i, 1);
    return p;
  }

注意:这是未经测试的,因为在你的例子中没有过滤。

const data = [{
    "duration": 248,
    "type": "M248",
    "sfc": "M248BJ0L2809783",
    "pass": 1
  },
  {
    "duration": 249,
    "type": "M248",
    "sfc": "M248BK0L2809676",
    "pass": 1
  },
  {
    "duration": 156,
    "type": "M248",
    "sfc": "M248BK0L2809676",
    "pass": 1
  },
  {
    "duration": 254,
    "type": "M248",
    "sfc": "M248BP0L2809798",
    "pass": 1
  },
  {
    "duration": 134,
    "type": "M248",
    "sfc": "M248BJ0L2809783",
    "pass": 1
  },
  {
    "duration": 128,
    "type": "M248",
    "sfc": "M248BP0L2809798",
    "pass": 0
  },
  {
    "duration": 228,
    "type": "M248",
    "sfc": "M248B90L2809800",
    "pass": 0
  },
  {
    "duration": 125,
    "type": "M248",
    "sfc": "M248B90L2809800",
    "pass": 0
  },
  {
    "duration": 242,
    "type": "M248",
    "sfc": "M248BJ0L2809792",
    "pass": 1
  },
  {
    "duration": 149,
    "type": "M248",
    "sfc": "M248BJ0L2809792",
    "pass": 1
  },
  {
    "duration": 237,
    "type": "M248",
    "sfc": "M248BJ0L2809819",
    "pass": 1
  },
  {
    "duration": 153,
    "type": "M248",
    "sfc": "M248BJ0L2809819",
    "pass": 1
  },
  {
    "duration": 232,
    "type": "M248",
    "sfc": "M248BK0L2809847",
    "pass": 1
  },
  {
    "duration": 482,
    "type": "M248",
    "sfc": "M248BK0L2809847",
    "pass": 1
  },
  {
    "duration": 238,
    "type": "M248",
    "sfc": "M248BK0L2809883",
    "pass": 1
  },
  {
    "duration": 143,
    "type": "M248",
    "sfc": "M248BK0L2809883",
    "pass": 1
  },
  {
    "duration": 213,
    "type": "M247",
    "sfc": "M247B50L2693004",
    "pass": 1
  },
  {
    "duration": 217,
    "type": "M247",
    "sfc": "M247B50L2693004",
    "pass": 0
  },
  {
    "duration": 229,
    "type": "M248",
    "sfc": "M248BC0L2809902",
    "pass": 1
  },
  {
    "duration": 151,
    "type": "M248",
    "sfc": "M248BC0L2809902",
    "pass": 0
  }
];

const cycletimeChart = dc.boxPlot('#cycletime-chart');

const ndx = crossfilter(data),
  typeDimension = ndx.dimension(function(d) {
    return d.type;
  }),
  bisectLeft = d3.bisector(d => d.duration).left,
  cycletimeGroupByType = typeDimension.group().reduce(function(p, v) {
    // keep array sorted for efficiency
    p.splice(bisectLeft(p, v.duration), 0, v);
    return p;
  }, function(p, v) {
    let i = bisectLeft(p, v.duration);
    while(p[i] !== v) ++i;
    p.splice(i, 1);
    return p;
  }, function() {
    return [];
  });

cycletimeChart
  .dimension(typeDimension)
  .group(cycletimeGroupByType)
  .valueAccessor(d => d.value.map(r => r.duration))
  .on('pretransition', function(chart) {
    chart.selectAll('circle.outlier').on('click.sfcClick', function(datum, index, nodes) {
      console.log(`Clicked on outlier with datum, index, nodes ${datum}, ${index}, ${nodes}.`);
      console.log('parent array', d3.select(this.parentNode).datum().value);
      console.log(`Original datum`, d3.select(this.parentNode).datum().value[datum]);
      //Here I would like to retrieve the the sfc attribute from the original data object.
    });
  });
cycletimeChart.render();
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>Boxplot test</title>
  <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.16.0/d3.min.js"></script>
  <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/crossfilter/1.3.12/crossfilter.min.js"></script>
  <script type="text/javascript" src="https://unpkg.com/dc@4/dist/dc.js"></script>
  <link rel="stylesheet" type="text/css" href="https://unpkg.com/dc@4/dist/style/dc.css">
</head>

<body>
  <div id="cycletime-chart"></div>

</body>

</html>
© www.soinside.com 2019 - 2024. All rights reserved.