Nested Grouping with Crossfilter?

随声附和 提交于 2021-01-05 07:08:51

问题


New to cross filter and working on a project that needs to maintain summed totals and peak values of those summed totals over a date range.

Tried to utilize the complex reduction from the dc.js examples.

I was able to get the max of a specific make and model over the date range but not the summed total peak (summed by day) for say the Region dimension or color dimension.

The project requires the following charts.

  • A bar chart that shows the total daily peak inventory count by region(s)
  • A selectable menu that has the make & model and their respective daily peak for the data set
  • A selectable menu that has the color and its respective daily peak for the data set

Below is a sample of the data (With the exclusion of the date being converted to a date object.)

var carData = [
    {Date: "11/26/2020", 'Inventory Region': 'SW', 'Make and Model': 'buick enclave' , 'Inventory Count': 12710, Color: 'charcoal' ,'Color Inventory': 3665},
    {Date: "11/26/2020", 'Inventory Region': 'SW', 'Make and Model': 'chevrolet 1500' , 'Inventory Count': 8510, Color: 'brown', 'Color Inventory': 2520},
    {Date: "11/26/2020", 'Inventory Region': 'NE', 'Make and Model': 'chevrolet camaro', 'Inventory Count': 5250, Color: 'silver', 'Color Inventory': 750},
    {Date: "11/26/2020", 'Inventory Region': 'NW', 'Make and Model': 'chevrolet malibu', 'Inventory Count': 4300, Color: 'brown','Color Inventory': 2100},
    {Date: "11/26/2020", 'Inventory Region': 'NW', 'Make and Model': 'dodge coupe', 'Inventory Count': 15100, Color: 'silver', 'Color Inventory': 5200},
    {Date: "11/26/2020", 'Inventory Region': 'NE', 'Make and Model': 'jeep compass', 'Inventory Count': 7300, Color: 'blue', 'Color Inventory': 2300},
    {Date: "11/26/2020", 'Inventory Region': 'NE', 'Make and Model': 'kia forte', 'Inventory Count': 4250,Color: 'white', 'Color Inventory': 2200},
    {Date: "11/26/2020", 'Inventory Region': 'SW', 'Make and Model': 'kia sorento', 'Inventory Count': 9450,Color: 'red', 'Color Inventory': 6525},
    {Date: "11/27/2020", 'Inventory Region': 'SW', 'Make and Model': 'buick enclave' , 'Inventory Count': 11251, Color: 'charcoal' ,'Color Inventory': 2206},
    {Date: "11/27/2020", 'Inventory Region': 'SW', 'Make and Model': 'chevrolet 1500' , 'Inventory Count': 8246, Color: 'brown', 'Color Inventory': 2256},
    {Date: "11/27/2020", 'Inventory Region': 'NE', 'Make and Model': 'chevrolet camaro', 'Inventory Count': 5200, Color: 'silver', 'Color Inventory': 700},
    {Date: "11/27/2020", 'Inventory Region': 'NW', 'Make and Model': 'chevrolet malibu', 'Inventory Count': 4250, Color: 'brown','Color Inventory': 2050},
    {Date: "11/27/2020", 'Inventory Region': 'NW', 'Make and Model': 'dodge coupe', 'Inventory Count': 15000, Color: 'silver', 'Color Inventory': 5100},
    {Date: "11/27/2020", 'Inventory Region': 'NE', 'Make and Model': 'jeep compass', 'Inventory Count': 7200, Color: 'blue', 'Color Inventory': 2200},
    {Date: "11/27/2020", 'Inventory Region': 'NE', 'Make and Model': 'kia forte', 'Inventory Count': 4150,Color: 'white', 'Color Inventory': 2100},
    {Date: "11/27/2020", 'Inventory Region': 'SW', 'Make and Model': 'kia sorento', 'Inventory Count': 8953,Color: 'red', 'Color Inventory': 6058}
];

回答1:


To put your question another way, you want to group by both color and day, and then find the max day for each color.

I'm going to assume you are also using dc.js since you mention it in your question. What we'll do is keep a running count of days for each color. Then, in the value accessor, we will find the max.

This is more efficient than calculating the maximum during group reduction.

const cf = crossfilter(carData),
  colorDimension = cf.dimension(({Color}) => Color),
  colorDayGroup = colorDimension.group().reduce(
    (p, v) => { // add
      const day = d3.timeDay(v.Date).getTime(); // 2. round to day, convert to int
      p[day] = (p[day] || 0) + v['Color Inventory']; // 3
      return p;
    },
    (p, v) => { // remove
      const day = d3.timeDay(v.Date).getTime(); // round to day, convert to int
      p[day] = (p[day] || 0) - v['Color Inventory']; // 4
      return p;
    },
    () => ({}) // 1. init
  );
  1. Each bin is a map from integer days to color sums
  2. We use d3.timeDay to round date objects to days - not needed in this example, but this would matter if the dates have times.
  3. When adding a row to a bin, lookup the day. If it does not exist, default it to zero. Then add the color inventory field.
  4. Same thing for removing a row, but we subtract.

Use it with a valueAccessor like this:

chart.valueAccessor(({key, value}) => d3.max(Object.values(value)))

This retrieves all the counts from the day->count object and finds the max count.

I used this fiddle to test. I changed the value of

{Date: "11/27/2020", 'Inventory Region': 'NE', 'Make and Model': 'kia forte', 'Inventory Count': 4150,Color: 'white', 'Color Inventory': 2700},

because 11/26 was the max day for every color, and I wanted to exercise the code better.

To test, I mapped each value using the value accessor:

console.log(JSON.stringify(colorDayGroup.all().map(({key, value}) => ({key, value: d3.max(Object.values(value))})), null, 2))

Result:

[
  {
    "key": "blue",
    "value": 2300
  },
  {
    "key": "brown",
    "value": 4620
  },
  {
    "key": "charcoal",
    "value": 3665
  },
  {
    "key": "red",
    "value": 6525
  },
  {
    "key": "silver",
    "value": 5950
  },
  {
    "key": "white",
    "value": 2700
  }
]
 


来源:https://stackoverflow.com/questions/65160017/nested-grouping-with-crossfilter

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!