如何将这些数据分组为可过滤的

How to group this data to be filterable

我正在使用 dc.js 创建具有如下架构的 "changesets" 数组的可交叉筛选图表:

  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) 以便每个变更集都显示在每个容器中。但是因为所有的变更集都会共享 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'、[=51= 的堆叠条形图]] 关键方法和 1 个常规条形图与 results/filtering 进行比较。

为了将变更集分成几组,我使用了一个自定义缩减器,它将数据转换成看起来像

的东西
{
    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]}
  })
}

因此,为了让每个部分都可以过滤堆积条,我必须结合使用在中找到的答案 并在

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

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

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

中所述
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)

最后,您必须重新定义第一个 link 中提到的过滤器处理程序。这个过滤器是我用来过滤的 “至少有 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 标签的变更集有道路修改”等问题的结果。

再次感谢@Gordon!