简体   繁体   English

dc.js Scatter Plot 按键求和 X 和 Y 值

[英]dc.js Scatter Plot sum up X and Y values by key

My data set in general looks like this我的数据集一般看起来像这样

var records = [
    {name : "A", duration : 1, quantity : 2},
    {name : "A", duration : 2, quantity : 1},
    {name : "B", duration : 1, quantity : 4},
    {name : "A", duration : 3, quantity : 1},
    {name : "B", duration : 1, quantity : 1},
];

Using dc.js I am trying to create a scatter plot which creates a sum by the name of both values (duration and quantiy).使用 dc.js 我正在尝试创建一个散点图 plot ,它通过两个值的名称(持续时间和数量)创建一个总和。 Thus in the above example I would like to see a scatter plot with only two dots, like this:因此,在上面的示例中,我希望看到一个只有两个点的散点 plot,如下所示:

分散

There is something I am doing wrong either with the dimension or the group because none of my dots appear in the plot.我在维度或组方面做错了,因为我的点都没有出现在 plot 中。

var cfilter = crossfilter(records),
    dim     = cfilter.dimension(d => d.name),
    grp     = dim.group().reduce(
        (p, v) => [ p[0] + v.duration, p[1] + v.quantity ],
        (p, v) => [ p[0] - v.duration, p[1] - v.quantity ],
        () => [0, 0]
    );
var chart = dc.scatterPlot("#scatter_plot");
chart
    .dimension(dim)
    .group(grp)
    .x(d3.scaleLinear());

I'm assuming that my reduce function is correct.我假设我的减少 function 是正确的。 Atleast when I look at the output of grp.all() the datasets seem to be summed up correctly.至少当我查看grp.all()的 output 时,数据集似乎被正确总结了。

结果

But as already mentioned my plot remains empty.但正如已经提到的,我的 plot 仍然是空的。

It takes half a dozen little tricks to make this work.完成这项工作需要六个小技巧。

First, we need the coordinates in the key, not the value.首先,我们需要键中的坐标,而不是值。 We can use a "fake group" to flip key and value on the fly:我们可以使用“假组”来动态翻转键和值:

function flip_key_value(group) {
  return {
    all: () => group.all().map(({key, value}) => ({key: value, value: key}))
  };
}

chart
  .group(flip_key_value(grp))

Next, we need to map colors based on the value (now the name):接下来,我们需要根据值(现在的名称)map colors:

chart
  .colorAccessor(({value}) => value)

We need to set up both scales, use elastic and padding (for convenience), and set the axis labels:我们需要设置两个比例,使用弹性和填充(为了方便),并设置轴标签:

chart
  .x(d3.scaleLinear())
  .y(d3.scaleLinear())
  .elasticX(true).elasticY(true)
  .xAxisPadding(0.25).yAxisPadding(0.25)
  .xAxisLabel('duration').yAxisLabel('quantity')

Finally, we need to set a custom .legendables() method, because by default the legend displays different series for a series chart, but we want each dot to have its own color:最后,我们需要设置一个自定义的.legendables()方法,因为默认情况下,图例为系列图表显示不同的系列,但我们希望每个点都有自己的颜色:

chart.legendables = () => chart.group().all()
    .map(({key, value}) => ({chart, name: value, color: chart.colors()(value)}));

Note we are setting the colors consistent with the colorAccessor specified above.请注意,我们将 colors 设置为与上面指定的colorAccessor一致。

And finally, set margins to fit the legend on the right, and declare the legend:最后,设置边距以适合右侧的图例,并声明图例:

chart
  .margins({left: 35, top: 0, right: 75, bottom: 30})
  .legend(dc.legend().x(425).y(50));

Screenshot (I think you have Xs and Ys flipped in your desired output):屏幕截图(我认为您在所需的输出中翻转了 Xs 和 Ys):

散点图截图

Fiddle demo .小提琴演示

Implementing filtering实现过滤

In dc.js and crossfilter, filtering works by setting a filter on the dimension when the user makes a selection.在 dc.js 和 crossfilter 中,过滤通过在用户进行选择时在维度上设置过滤器来工作。

Since we have changed keys, the dimension is now inconsistent with the group data being displayed, and selection will cause an invalid filtering operation, causing all data to be erased from other charts.由于我们更改了key,现在维度与正在显示的组数据不一致,选择会导致无效的过滤操作,导致所有数据从其他图表中删除。

In order to rectify this, we can search for any points falling within the rectangular selection, and filter by the original keys, which are now the values:为了纠正这个问题,我们可以搜索落在矩形选择范围内的任何点,并通过原始键进行过滤,这些键现在是值:

chart.filterHandler((dimension, filters) => {
  if(filters.length === 0) {
    dimension.filter(null);
    return filters;
  }
  console.assert(filters.length && filters[0].filterType === 'RangedTwoDimensionalFilter');
  const filterFun = filters[0].isFiltered;
  const itemsInside = chart.group().all().filter(({key}) => filterFun(key));
  const origKeys = itemsInside.map(({value}) => value);
  if(origKeys.length === 1)
    dimension.filterExact(origKeys[0]);
  else
    dimension.filterFunction(k => origKeys.includes(k));
  return filters;
});

New fiddle version, with working selection .新的小提琴版本,带有工作选择

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM