Search code examples
dc.jscrossfilter

dc.js scatter plot filtering dimension from selection of control


I am attempting to filter a dimension on a scatter and the plots rendered via a control (select box) and I am having trouble getting this to work. Perhaps I am thinking because the dimension returns an array [key, value, value] and I am trying to filter using a text value from the control.

<div id="chart-scatter"></div>
<select id="selection">
  <option value="BranchA">Branch A</option>
  <option value="BranchB">Branch B</option>
  <option value="BranchC">Branch C</option>
  <option value="BranchD">Branch D</option>
</select>

var transactions = [
  {
    accountType: 9,
    amount: 284,
    serviceName: "BranchE"
  },
  {
    accountType: 7,
    amount: 716,
    serviceName: "BranchE"
  },
  {
    accountType: 5,
    amount: 899,
    serviceName: "BranchD"
  },
  {
    accountType: 8,
    amount: 781,
    serviceName: "BranchD"
  },
  {
    accountType: 5,
    amount: 295,
    serviceName: "BranchA"
  },
  {
    accountType: 9,
    amount: 770,
    serviceName: "BranchB"
  },
  {
    accountType: 9,
    amount: 195,
    serviceName: "BranchE"
  },
  {
    accountType: 5,
    amount: 335,
    serviceName: "BranchF"
  },
  {
    accountType: 10,
    amount: 74,
    serviceName: "BranchF"
  },
  {
    accountType: 10,
    amount: 223,
    serviceName: "BranchC"
  },
  {
    accountType: 5,
    amount: 290,
    serviceName: "BranchD"
  },
  {
    accountType: 10,
    amount: 485,
    serviceName: "BranchA"
  },
  {
    accountType: 7,
    amount: 364,
    serviceName: "BranchE"
  },
  {
    accountType: 9,
    amount: 509,
    serviceName: "BranchB"
  },
  {
    accountType: 8,
    amount: 74,
    serviceName: "BranchC"
  },
  {
    accountType: 9,
    amount: 442,
    serviceName: "BranchE"
  }
];

filter = crossfilter(transactions);
dim = filter.dimension(function(d) {
  return [d.accountType, d.amount, d.serviceName];
});
grp = dim.group();
scatterChart = dc.scatterPlot("#chart-scatter");
scatterChart
  .width(380)
  .height(200)
  .margins({
    top: 10,
    right: 20,
    bottom: 30,
    left: 40
  })
  .dimension(dim)
  .group(grp)
  .x(d3.scale.linear().domain([4., 11.]))
  .y(d3.scale.linear().domain([0., 1000.]))
  .renderHorizontalGridLines(true)
  .renderVerticalGridLines(true)
  .symbolSize(30)
  .highlightedSize(8)
  .colorAccessor(function(d) {
    return d.key[2];
  })
  .colors(d3.scale.ordinal()
    .domain(['BranchA', 'BranchB', 'BranchC','BranchD','BranchE', 'BranchF'])
    .range(["#fa3701", "#339933", "#bbbbbb","#aaaaaa","#999999","#888888"])
  );

  d3.select("#selection").on('change', function(){

       dim.filter($("#selection").val()) 
       scatterChart.redraw();
       dc.redrawAll();
  })

dc.renderAll();

from examples I have found this seems like the approach in various places, however none are really for a scatter that I can find and I am wondering what the difference would be given the dim = array

JSFiddle


Solution

  • A group does not observe filters on its own dimension (https://github.com/crossfilter/crossfilter/wiki/Crossfilter-Gotchas#a-group-does-not-observe-its-dimensions-filters). Because you are filtering on the same dimension the group is defined on, the filter has no affect on the group.

    Define a 2nd dimension for the service name and put a default filter in place:

    serviceDim = filter.dimension(function(d) {
        return "" + d.serviceName;
    })
    serviceDim.filter('BranchA')
    

    Then update your change function as follows:

    d3.select("#selection").on('change', function(){
         serviceDim.filter($("#selection").val())
         //scatterChart.redraw();
         dc.redrawAll();
    })
    

    Here is an updated JSFiddle: https://jsfiddle.net/esjewett/uhvh23b0/