skip to Main Content

Suppose I have a list of customers with their orders:

const customers = [
  { id: 1, orders: [{ products: ["apple", "banana"] }, { products: ["apple"] }] },
  { id: 2, orders: [{ products: ["strawberry"] }] },
  { id: 3, orders: [{ products: ["apple"] }, { products: ["strawberry"] }] },
  { id: 4, orders: [] }
]

I would like to see a pie chart that shows a slice for every single product available. When filtering, I would like to click on "apple" and filter by the customers who ordered apples at any point in time.

I’m currently able to render the pie chart but it shows every possible combination of products as a slice.

Meaning, my pie chart has a slice for apple, banana, strawberry, apple, strawberry, and none.

This isn’t what I’m going for. I did this by creating the dimension:

const dimension = crossfilter.dimension((customer: Customer) => {

    const productList = customer.orders.flatMap(x => x.products)
    const products = new Set<string>(productList);
    const result = [...products ];
    if (result.length === 0) return "none";

    return result;
})

const group = dimension.group();

The filtering behavior works correctly but the pie charts slices are not sustainable in this way.

EDIT: I added a js fiddle that demonstrates the situation a little more clearly: https://jsfiddle.net/qcaod71z/1/

2

Answers


  1. It seems that’s because you are returning an array, the result variable.
    You can extract products in a single list:

    const customers = [
      { id: 1, orders: [{ products: ["apple", "banana"] }, { products: ["apple"] }] },
      { id: 2, orders: [{ products: ["strawberry"] }] },
      { id: 3, orders: [{ products: ["apple"] }, { products: ["strawberry"] }] },
      { id: 4, orders: [] }
    ];
    
    const allProducts = [...customers.reduce((s, a) => {
      const customerProducts = a.orders.flatMap(o => o.products);
      customerProducts.forEach(p => s.add(p));
      if (customerProducts.length === 0)
        s.add("none");
      return s;
    }, new Set())];
    
    console.log(allProducts);

    Or you can:

    const customers = [
      { id: 1, orders: [{ products: ["apple", "banana"] }, { products: ["apple"] }] },
      { id: 2, orders: [{ products: ["strawberry"] }] },
      { id: 3, orders: [{ products: ["apple"] }, { products: ["strawberry"] }] },
      { id: 4, orders: [] }
    ]
    const flattenedData = [];
    
    customers.forEach(customer => {
        customer.orders.forEach(order => {
            order.products.forEach(product => {
                flattenedData.push({
                    customerId: customer.id,
                    product: product
                });
            });
        });
    });
    
    console.log(flattenedData);

    And the setup crossfilter:

    const crossfiltered = crossfilter(flattenedData);
    const productDimension = crossfiltered.dimension(d => d.product);
    const productGroup = productDimension.group();
    
    Login or Signup to reply.
  2. https://github.com/crossfilter/crossfilter/wiki/API-Reference#dimension

    You can now set the second argument specify that the return value is an array.

    const dimension = crossfilter.dimension((customer: Customer) => {
        const productList = customer.orders.flatMap(x => x.products)
        const products = new Set<string>(productList);
        const result = [...products ];
        if (result.length === 0) return "none";
    
        return result;
    }, true)
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search