javascriptd3.jsparallel-coordinates

D3 parcoords axis scale not updating correctly


I'm using the d3 parcoords library. When I modify data plotted in a parallel coordinates chart, and reload the chart, the scale of the axis isn't refreshed.

I tried calling .autoscale(), but if I call it before .render(), it has no effect, and if I call it after .render(), then no polylines are drawn anymore.

    $("#example").html(""); //to make sure "ghost" axes are removed

            parcoords = d3.parcoords()("#example")
                .data(parsedData)
                .createAxes()
                .brushMode("1D-axes")
                .reorderable()//;
                .detectDimensions()
                .dimensions(dimensionObj)
                .autoscale() //no visible effect if placed here
                .render()
                .updateAxes();

Not sure if this is related (although the issue started at the same time), I started specifying an order for the dimensions. To do this, instead of using an array containing the axes (dimensionArray), I use a JS object dimensionObj containing numbered "index" keys, as follows:

//dimensionArray = ["axis1", "axis2", "axis3", "axis4"]; //orderless array

//Default axes to display with predefined ordering
dimensionObj = {
  "axis1": {index:0},
  "axis2": {index:1},
  "axis3": {index:2},
  "axis4": {index:3}
  }

For illustration purposes, the following screenshots show how on the top image, the scales are properly set, but on the second (updated) chart, some new polylines are going to 0 on the 1st and 3rd axis, but the scale isn't updated so lines go out of range.

Is there a simple way to refresh the axis scales when reloading a chart? Is it possible that using the JS object in .dimensions() is creating some conflicts with the underlying scale function?

1st chart with default data

2nd updated chart with updated data


Solution

  • Found what was causing this behaviour: an if statement in d3.parcoords.js pc.autoscale function which was only resetting scales if the yscale was not previously defined. Essentially I edited the if statement from original:

      d3.keys(__.dimensions).forEach(function(k) {
        if (!__.dimensions[k].yscale){
          __.dimensions[k].yscale = defaultScales[__.dimensions[k].type](k);
        }
      });
    

    to this (of course the if statement could be dropped altogether, I simply kept it in this form in case I need to revert to original version later for any reason):

      d3.keys(__.dimensions).forEach(function(k) {
        if (!__.dimensions[k].yscale || __.dimensions[k].yscale){
          __.dimensions[k].yscale = defaultScales[__.dimensions[k].type](k);
        }
      });