1

I have a table as follows:

table

The number of experiments are arbitrary but the column name's prefix is "client_" following by the client number.

I want to draw a box plot of values against the "client_#" using dc.js. The table is a csv file which is loaded using d3.csv().

There are examples using ordinary groups, however I need each column to be displayed as its own boxplot and none of the examples do this. How can I create a boxplot from each column?

Community
  • 1
  • 1
  • You can check the following example as a start https://observablehq.com/@d3/d3-box-plot – Coola Apr 08 '19 at 12:14
  • Welcome to SO! Please use only the most specific tags when asking a question - it is true you will use javascript and d3.js to solve this but this question is about dc.js and people who know about javascript won't necessarily be able to help you. – Gordon Apr 08 '19 at 18:11
  • It's also a good idea to spell out the exact problem you're having. I know your title "says it all" but it's important to describe what examples you have found and how your problem is different. I have attempted to fill out your question as I understand it. – Gordon Apr 08 '19 at 18:28
  • Yes. Your understanding about the question is correct. – Sudeep Gupta Apr 09 '19 at 05:39

1 Answers1

1

This is very similar to this question:

dc.js - how to create a row chart from multiple columns

Many of the same caveats apply - it will not be possible to filter (brush) using this chart, since every row contributes to every box plot.

The difference is that we will need all the individual values, not just the sum total.

I didn't have an example to test with, but hopefully this code will work:

function column_values(dim, cols) {
  var _groupAll = dim.groupAll().reduce(
    function(p, v) { // add
      cols.forEach(function(c) {
        p[c].splice(d3.bisectLeft(p[c], v[c]), 0, v[c]);
      });
      return p;
    },
    function(p, v) { // remove
      cols.forEach(function(c) {
        p[c].splice(d3.bisectLeft(p[c], v[c]), 1);
      });
      return p;
    },
    function() { // init
      var p = {};
      cols.forEach(function(c) {
        p[c] = [];
      });
      return p;
    });
  return {
    all: function() {
      // or _.pairs, anything to turn the object into an array
      return d3.map(_groupAll.value()).entries();
    }
  };
}

As with the row chart question, we'll need to group all the data in one bin using groupAll - ordinary crossfilter bins won't work since every row contributes to every bin.

The init function creates an object which will be keyed by column name. Each entry is an array of the values in that column.

The add function goes through all the columns and inserts each column's value into each array in sorted order.

The remove function finds the value using binary search and removes it.

When .all() is called, the {key,value} pairs will be built from the object.

The column_values function takes either a dimension or a crossfilter object for the first parameter, and an array of column names for the second parameter. It returns a fake group with a bin for each client, where the key is the client name and the value is all of the values for that client in sorted order.

You can use column_values like this:

var boxplotColumnsGroup = column_values(cf, ['client_1', 'client_2', 'client_3', 'client_4']);
boxPlot
  .dimension({}) // no valid dimension as explained in earlier question
  .group(boxplotColumnsGroup);

If this does not work, please attach an example so we can debug this together.

Gordon
  • 19,811
  • 4
  • 36
  • 74