【问题标题】:HeatMap dc.js - Displaying the Top 10 columnsHeatMap dc.js - 显示前 10 列
【发布时间】:2018-01-10 20:14:57
【问题描述】:

我正在使用 dc.js 制作热图。我无法显示前 10 列。下面是我的热图示例。

请注意,列太多了。我正在尝试显示前 10 列。例如, 第 5 列的项目总数最高 (a+b+c+d+e+f+h+i+j)。然后第 10 列的项目总数第二高,依此类推。

有没有办法在热图 dc.js 中显示它?这可能吗?这花了我几天的时间来弄清楚,我完全没有想法。下面是我的代码。

        chart
        .width(900)
        .height(400)
        .margins({top: 10, right: 0, bottom: 50, left: 70})
        .dimension(dimension)
        .group(group)
        .keyAccessor(function(d) { return d.key[0]; })
        .valueAccessor(function(d) { return d.key[1]; })
        .colorAccessor(function(d) { return d.value; })
        .title(function(d){
            })
        .colors(["#ccc","#edf8b1","#c7e9b4","#7fcdbb","#41b6c4","#1d91c0","#225ea8","#253494","#081d58"])
         .data(function (d) {
            return d.order(function (d) {
                return d;
            }
            ).top(10);
        })    
        ;

我的热图代码的其余部分只是显示列标签和点击功能等。

如果我的代码在 .colors() 函数之后出现乱码,请见谅。我试图了解.data() 以及如何使其成为前 10 名。显然,它仅获得特定行和列的最高总数,而不是一列的完整总数。

【问题讨论】:

    标签: heatmap dc.js


    【解决方案1】:

    使用过滤器

    如果您愿意过滤所有数据(包括基于此交叉过滤器的任何其他图表),我认为做前十名最简单的方法是在列上创建另一个维度,然后使用组来确定前十名,并据此筛选。

    我已经构建了一个小提琴来演示这种技术,based on the standard heatmap example

    首先我们需要一个基于列的维度(在本例中为“运行”):

    var runDim = ndx.dimension(function(d) { return +d.Run; }),
    

    然后,我们将创建一个汇总每列中所有值(在本例中为“速度”)的组:

        runTotalGroup = runDim.group().reduceSum(function(d) {
           return +d.Speed;
        });
    

    获取该组中的前十个键:

    var topTen = runTotalGroup.top(10).map(kv => kv.key);
    

    并根据这些键过滤维度:

    runDim.filter(function(k) {
        return topTen.indexOf(k) !== -1;
    });
    

    我们还需要从热图中删除所有空箱,为此我们可以使用fake group from the FAQ

    function remove_empty_bins(source_group) {
        return {
            all:function () {
                return source_group.all().filter(function(d) {
                    //return Math.abs(d.value) > 0.00001; // if using floating-point numbers
                    return d.value !== 0; // if integers only
                });
            }
        };
    }
    
    chart
        .group(remove_empty_bins(runExptGroup))
    

    Here is the fiddle.

    正如我上面提到的,这种方法的最大警告是,这将过滤此交叉过滤器上所有图表的数据。它也很不灵活 - 前十名可能会根据其他过滤器的变化而变化,但我们只是拍了一张快照,不会看到这些变化。

    以“正确的方式”执行此操作需要以不同的方式聚合数据和/或更复杂的假组。如果此解决方案不适合您,请联系我,我会考虑更多。

    使用精心制作的假组

    如果您想以正确的方式执行此操作,而不应用额外的过滤器,则需要以几种不同的方式扭曲数据。

    首先,我们将按列减少数据。然后我们将按总数排序,最后将列展平回到热图期望的 x/y 箱中。之后,我们仍然需要告诉热图如何对列进行排序!

    但是,首先,让我们确保我们所有的数据都是数字,而不是字符串。对字符串进行聚合可能会导致糟糕的结果。

    experiments.forEach(function(d) {
        d.Run = +d.Run;
        d.Expt = +d.Expt;
        d.Speed = +d.Speed;
    });
    

    这里是三向数据扭曲器(我警告过你!):

    function flatten_group(group, field) { // step 3
        return {
            all: function() {
                var ret = [];
                group.all().forEach(function(kv) {
                    Object.keys(kv.value[field]).forEach(function(i) {
                        ret.push({
                            key: [kv.key, +i],
                            value: kv.value[field][i]
                        });
                    });
                });
                return ret;
            }
        };
    }
    function reduce_second_dimension(dim, dimfield, valfield) {
        var group1 = dim.group().reduce( // step 1
            function(p, v) { // add
                p.second[v[dimfield]] = (p.second[v[dimfield]] || 0) + v[valfield];
                return p;
            },
            function(p, v) { // remove
                p.second[v[dimfield]] = p.second[v[dimfield]] - v[valfield];
                return p;
            },
            function() {
                return {second: {}};
            }
        );
        return flatten_group({
            all: function() { // step 2
                var _all = group1.all().slice();
                _all.forEach(function(kv) {
                    kv.value.total = d3.sum(Object.keys(kv.value.second), 
                                            function(k) { return kv.value.second[k]; });
                });
                _all.sort(function(a, b) {
                    return b.value.total - a.value.total;
                });
                return _all;
            }
        }, 'second');
    }
    

    它可能可以更好地模块化,但三个步骤是

    1. 按列分组和减少,为每列中的每一行创建键/值映射
    2. 按总计对列进行排序
    3. 将每个缩减列中的键/值映射拆分为多个列/行箱。 (来自this question。)

    热图仍然会尝试对数据进行排序,因此我们需要告诉它每次开始处理数据时的列顺序:

    function apply_keyorder() {
        var xkeyorder = {}, j = 0;
        runExptGroup.all().forEach(function(kv) {
            if(xkeyorder[kv.key[0]] === undefined) {
                xkeyorder[kv.key[0]] = j++;
            }
        });
        chart.colOrdering((a,b) => xkeyorder[a] - xkeyorder[b]);
    }
    chart.on('preRender', apply_keyorder);
    chart.on('preRedraw', apply_keyorder);
    

    使用.cols() 可能比使用.colOrdering() 更简单——这是我首先看到的。

    我已经没时间进一步解释了:here's the fiddle!

    【讨论】:

    • 感谢您的回复!我有多个使用相同数据电子表格的图表。如果我这样做,它会在加载页面时自动过滤所有其他图表吗?不用担心空垃圾箱。我们想查看具有空箱的列的哪些行。另外,我添加了一个功能,如果有空箱(或项目等于 0),它将不会过滤。
    • 是的,这就是这种方法的问题——它将按前十列过滤所有图表——这就是runDim.filter( .... 所做的。我认为可以只修改图表的数据,但这更复杂。
    • 有没有办法根据列的总数按降序对列进行排序并显示前 10 列?这种方法我试图这样做,但它没有奏效,或者我做错了。这可能吗?
    • 这几乎是同样的问题,因为排序与数据的形状无关,热图期望在{key: [x,y], value} 对中。这绝对是可行的,只需稍微考虑一下最好的方法是什么。
    • 是否可以选择要显示的特定列?我通过执行 var topTen = runTotalGroup.top(10).map(kv => kv.key); 获得了前 10 名列表。我可以看到哪些是前十名,我可以使用该列表来显示它。不确定要使用哪个热图 api,但我可以尝试循环列表并返回等于列表中任何列的列。我尝试使用 .cols(..) 但它的显示很有趣。有什么建议可以使用哪个 api 手动显示热图中的特定列?
    【解决方案2】:

    我想通了。我所做的是..

    使用 crossfilter() 库获取前 10 名。

    var runDim = ndx.dimension(function(d) { return +d.Run; }),
        runTotalGroup = runDim.group().reduceSum(function(d) {
           return +d.Speed;
        });
    var topTen = runTotalGroup.top(10).map(kv => kv.key);
    

    一旦我抓住了列表中唯一的前十名,然后在热图中,使用 .data(...) 函数。这是您使用 for 循环和 if 语句手动显示数据的地方。这很棘手,但是一旦我了解了数据在热图中的格式,我就可以手动显示数据而无需过滤所有其他 dc 图表。并且交叉过滤有效!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-03-13
      • 1970-01-01
      • 2016-05-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多