用着色条件构建地图

时间:2017-01-22 08:12:26

标签: d3.js dc.js crossfilter

我正在努力建立一个在dc.js中并不完全是一个等值的合唱。我要做的是根据着色条件为地图着色,最终这也将与其他图表和过滤器进行交互。我的csv看起来像这样:

country,id,condition,value
AU,1,yes,19
US,2,no,23
US,2,no,30
US,2,no,4    
IN,3,yes,14
SG,4,yes,2
NZ,5,no,6
NZ,5,no,20

这是我到目前为止的方法,产生了发生次数。

var ndx = crossfilter(data)
var countryDimension = ndx.dimension(function (d){
  return d.country
});

var colors = d3.scale.ordinal().domain(['yes','no']).range(["green","blue"])
worldMap.width(mapWidth)
.height(mapHeight)
  .dimension(countryDimension)
  .group(countryDimension.group())
  .projection(project)
  .colors(colors)
  .colorCalculator(function(d){
    return d ? worldMap.colors()(d) : '#d8d8d8';
  })
  .overlayGeoJson(geoJson.features, "id", function(d){
    return d.id;
  })
  .title(function(d){
    return 'Country: ' + d.key + '\nCondition: ' + d.value;
  });

我对这个令人惊叹的d3和dc.js世界都很陌生。虽然我一直在阅读文档和论坛,但我无法弄清楚我是如何制作它以便绘制地图的,以及具有条件的国家'是'是绿色和有条件的国家没有'是蓝色的。所以,如果我做console.log(d.value)它应该返回“是”'或者没有'。我不知道我和我的小组有什么关系。

1 个答案:

答案 0 :(得分:1)

如果每个国家/地区在数据中列出condition时都具有相同的值,那么在某种意义上,数据为denormalized。这很好,因为crossfilter最适合单个数据阵列。

当然,这意味着等值线不会响应其他图表上的刷牙,因为该值不受当前过滤的行数的影响。但它可以过滤其他图表。

计算是

有几种方法可以做到这一点。一种方法是计算yes的数量,并根据计数设置值:

var yesnoGroup = countryDimension.group().reduceSum(function(d) {
    return d.condition === 'yes' ? 1 : 0;
});
worldMap.valueAccessor(function(kv) {
    return kv.value ? 'yes' : 'no';
})

抓住第一个值

然而,这可能会导致各国在被其他图表过滤掉时变成蓝色。所以你也可以使用“抓住第一个值并坚持下去”这样的策略:

var yesnoGroup = countryDimension.group().reduce(
    function(p, v) { // add
        return v.condition;
    },
    function(p, v) { // remove
        return p; // ignore remove event
    },
    function() { // initialize
        return null; // no value
    });

使用crossfilter有点丑陋和奇怪的方式,但这只是因为crossfilter期望数据对减少的值产生一些影响,而不是在这里。

编辑:三个州

根据下面的对话,我了解到你实际上在寻找三种状态:不,零和是。 (这比上面的解决方案更有意义,但我会留给后人的。)这里有两种完全不同的方法来解决no / zero / yes问题。

这两种解决方案都使用以下三向色标:

var colors = d3.scale.ordinal().domain(['no', 'zero', 'yes']).range(["blue", "grey", "green"])

否/零/是负数/正数

这很聪明,很简单:我们只将每个号码计为-1,将每个号码计为+1。如果总和为零,我们将画灰色。这里唯一需要注意的是,如果数据中存在矛盾,则可能会出现假零。但这可能比假的没有或是(?)

更好
var nozeroyesGroup = countryDimension.group().reduceSum(function(d) {
  return d.condition === 'no' ? -1 : d.condition === 'yes' : +1 : 0;
});
worldMap.valueAccessor(function(kv) {
    return kv.value < 0 ? 'no' : kv.value > 0 ? 'yes' : 'zero';
})

否/是极性

我们还可以分别记住计数和极性。这可能更安全但也可能更慢。 (除非你的数据很大,否则你不会注意到。)这有点复杂。这是一种偏好。

var nozeroyesGroup = countryDimension.group().reduce(
    function(p, v) { // add
        if(p.polarity && p.polarity != v.condition)
            console.warn('inconsistent');
        p.polarity = v.condition;
        ++p.count;
        return p;
    },
    function(p, v) { // remove
        if(p.polarity != v.condition || p.count <= 0)
            console.warn('inconsistent');
        --p.count;
        return p;
    },
    function() { // initialize
        return {count: 0, polarity: null}; // no value
    });
worldMap.valueAccessor(function(kv) {
    return kv.value.count ? kv.value.polarity : 'zero';
})