如何将这些数据分组以进行过滤

时间:2020-06-08 21:55:31

标签: javascript data-manipulation dc.js crossfilter

我正在使用dc.js创建具有“变更集”数组的可交叉过滤的图表,这些变更集具有如下所示的架构:

  id,
  first_name, last_name, user_id,
  created_at,
  num_changes,
  hashtags: [str],
  total_add, total_mod, total_del,
  buildings_add, buildings_mod, buildings_del,
  pois_add, pois_mod, pois_del,
  roads_add, roads_mod, roads_del,
  road_km_add, road_km_mod, road_km_del,
  waterways_add, waterways_mod, waterways_del,
  waterway_km_add, waterway_km_mod, waterway_km_del
}

问题

我试图创建可过滤的堆叠条形图,其中的条形图表示add/mod/del,堆栈表示变化的数据类型buildings/pois/roads/waterways/road_km/waterway_km

任何1个变更集可以具有这些字段的任意组合,因此不能将每个变更集与1个修改类型配对。有没有更好的方法可以完成此分组,可以在图表上应用过滤器了?

我尝试过的代码

我可以使用正确的数据显示图表,但是我设置它的方式已经做到了,因此无法过滤图表。最初,我将维写为crossfilter.dimension(d => ['add', 'mod', 'del'], true),以便每个变更集都显示在每个bin中。但是由于所有变更集都将共享add / mod / del,因此不会过滤任何内容。

然后我在这里看到了过滤器堆栈示例:https://github.com/dc-js/dc.js/blob/develop/web-src/examples/filter-stacks.html

然后我尝试为编辑运行多键维度

let editDim = ndx.dimension(d => {
  let rt = []
  stackKeys.forEach(key => {
    editStacks.forEach(stack => {
      if (d[sAcc(stack,key)]) {
        rt.push(key + '.' + stack)
      }
    })
  })
  return rt
}, true)

此方法看起来非常接近,但过滤堆栈不会在其他图表上产生正确的结果。 似乎无论我选择从该图表中过滤掉什么,其他图表都会产生0。

这是一个jsfiddle,其中我有1个使用多键方法的堆叠条形图,1个使用['add','mod','del']键方法的堆叠条形图和1个常规条形图图表以比较结果/进行过滤。

为了将变更集分为几组,我使用了一个自定义的reducer,它将数据转换为类似的内容

{
    key: 'add',
    value: {
        add: {
            buildings': 42,
            pois: 12,
            roads: 1,
            waterway: 2,
            waterway_km: 0.003,
            road_km: 0
        },
        mod: {...}
        del: {...}
    }
}

该维度分组为['add', 'mod', 'del'],并使用

创建堆栈
const editStacks = ['buildings', 'pois', 'roads', 'waterways']
editStacks.forEach((stack, i) => {
    // first is group, others are stacked
    let action = i ? 'stack' : 'group'
    chart[action](group, stack, d => d.value[d.key][stack])
})

在多键方法中,将值转换为正 {key: 'add', value: {building, roads, pois, waterways}} 使用此功能

all: function () {
  var all = group.all()
  var m = {}
  all.forEach(kv => {
    let [k,s] = kv.key.split('.')
    m[k] = m[k] || {}
    m[k][s] = kv.value[k][s]
  })
  return Object.keys(m).map(key => {
    return {key, value: m[key]}
  })
}

1 个答案:

答案 0 :(得分:0)

因此,要使堆积的条块可按每个部分进行过滤,我必须结合使用以下内容中的答案 dc.js - Creating a row chart from multiple columns and enabling filtering 和在 Plotting aggregated data with sub-columns in dc.js

要构建可过滤的维度,您必须使用第一个链接中描述的方法在维度上创建自定义的filterHandler,该维度仅按元素分组

let dimension = ndx.dimension(d => d)

然后我通过使用groupAll并创建一个对象来构造我的组 { key.stack: value }}使用reduce函数。 然后,我通过为该组创建“全部”方法将其转换回标准组 如第二个链接所述。

function reduceAdd (p, v) {
    keys.forEach(k => {
        stacks.forEach(s => {
            p[`${k}.${s}`] += v[accessor(k, s)] || 0
        })
    })
    return p
}
function reduceRemove (p, v) {
    keys.forEach(k => {
        stacks.forEach(s => {
            p[`${k}.${s}`] -= v[accessor(k, s)] || 0
        })
    })
    return p
}
function reduceInit () {
    let p = {}
    keys.forEach(k => {
        stacks.forEach(s => {
            p[`${k}.${s}`] = 0
        })
    })
    return p
}

function stackedGroup (group) {
    return {
        all: function () {
            var all = Object.entries(group.value()).map(([key, value]) => ({ key, value }))
            var m = {}
            all.forEach(kv => {
                let [k, s] = kv.key.split('.')
                m[k] = m[k] || {}
                m[k][s] = kv.value
            })
            return Object.keys(m).map(key => {
                return { key, value: m[key] }
            })
        }
    }
}

let group = dimension.groupAll().reduce(reduceAdd, reduceRemove, reduceInit)
group = stackedGroup(group)

最后,您必须按照第一个链接中所述重新定义过滤器处理程序。这个过滤器是我用来过滤的 “具有至少1个x的变更集”,其中“ x”是某种类型的编辑,例如“添加建筑物”或“修改后的道路”

chart.filterHandler((dim, filters) => {
    if (filters && filters.length) {
        dim.filterFunction((r) => {
            return filters.some((c) => {
                //the changeset must have a value in this field to be left in the chart
                let [stack, field] = c[0].split('.')
                return r[accessor(field, stack)] > 0
            })
        })
    } else {
        dim.filter(null)
    }
    return filters
})

此后,主题标签图表显示了意外的结果,因此我也必须对主题标签图表进行类似的标注和分组。 我相信这是因为主题标签图表是使用数组维度定义的,但是将其分组为d => d并定义自定义filterHandler产生了令我满意的结果。 可以对两个图表进行过滤,以找到问题的结果,例如“有#Kaart主题标签的变更集有多少条道路经过修改”。

再次感谢@戈登!