uwdata / graphscape

A directed graph model of the visualization design space, using Vega-Lite.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Generate vega-lite-feature by using Compass

yhoonkim opened this issue · comments

Compass can help to generate all kinds of vega-lite specifications.

  • use Compass to generate spec
  • It is also required to implement the function converting vega-lite objects to vega-lite feature objects.

Input for Compass

  • Variables List / Schema
  • Generation Parameters
    • Variable
      • Maximum variable that output visualization can have (4)
    • Transformation?
      • aggregate: mean or no aggregate // yhoonkim should read about the rules in aggregation in Compass
      • no binning, no time unit
    • Mark Type, Channels that I allowed: See below,
    • rescaling (log, no-rescale)
var marktypesAll = ['bar','point','line','area'];
var channelsAll = ['x','y','shape','color','size','row','column'];
var aggregateAll = ['mean'];

Code structure would be roughly like this. (Will provide you some code later)

  1. Generate sets of variables

  2. Generate transformations of each set of variable
    2.1) Generate different aggregation
    2.2) Generate different rescaling

  3. Map each transformed variable to encoding

The code should be something like this. Haven’t tested, but should be pretty close.

// data = JSON data (e.g., from cars.json)
// fieldDefs = List of fieldDef object {field:..., type: ...}
const stats = dl.summary(data).reduce(function(s, profile) {
  s[profile.field] = profile;
  return s;
}, {
  '*': {
    max: data.length,
    min: 0
  }
});

const specs = genProjections(fieldDefs, stats, {
  maxAdditionalVariables: 3
}).reduce(function(fieldSets, fieldSet) {
  return genScales(fieldSets, fieldSet, {rescaleQuantitative: [undefined, 'log']});
}, []).reduce(function(fieldSets, fieldSet) {
  return genAggregate(fieldSets, fieldSet, stats, {
    // TODO: add AggregationOption parameter here
  });
}, []).reduce(function(specs, fieldSet) {
  return genSpecs(specs, fieldSet, stats, {
    // TODO: add SpecOption parameter here
  })
}, []);

genScales seems working well. It generated all kinds of possible fieldSets with scale.
But when it goes into genSpecs, it only emits the specs that have all fields. I guess it field's selected : undefined case is not working for genScales now. (It's working well for genScales.)

var data = JSON.parse(fs.readFileSync('./data/cars.json','utf8'));
var fieldDefs = [];
fieldDefs.push({'field': 'Acceleration', 'type': 'quantitative' });
fieldDefs.push({'field': 'Origin', 'type': 'nominal' });

const stats = dl.summary(data).reduce(function(s, profile) {
  s[profile.field] = profile;
  return s;
}, {
  '*': {
    max: data.length,
    min: 0
  }
});

const specs = cp.gen.projections(fieldDefs, stats, {
  maxAdditionalVariables: 3
})
.reduce(function(fieldSets, fieldSet) {
  return genScales(fieldSets, fieldSet, {rescaleQuantitative: [undefined, 'log']});
}, []);

console.log(specs.length); // 5

var specs2 = specs.reduce(function(specs, fieldSet) {
  return cp.gen.specs(specs, fieldSet, stats, {
    // TODO: add SpecOption parameter here
  })
}, []);

console.log(specs2.length); // 2

Should I post this issue on Compass or leave it here?

@kanitw
I figured out why genSpecs didn't work.

export default function genSpecsFromFieldDefs(output, fieldDefs, stats, opt: SpecOption = {}, nested?): any {
  // opt must be augmented before being passed to genEncodings or getMarks
  opt = util.extend({}, DEFAULT_SPEC_OPTION, opt);
  var encodings = genEncodings([], fieldDefs, stats, opt);

  if (nested) {
    return encodings.reduce(function(dict, encoding) {
      var encodingShorthand = shortenEncoding(encoding);
      dict[encodingShorthand] = genSpecsFromEncodings([], encoding, stats, opt);
      return dict;
    }, {});
  } else {
    return encodings.reduce(function(list, encoding) {
      return genSpecsFromEncodings(list, encoding, stats, opt);
    }, []);
  }
}

In the above, it didn't emit the result to output.
So I changed the last else like

var specs = encodings.reduce(function(list, encoding) {
      return genSpecsFromEncodings(list, encoding, stats, opt);
}, []);
output.push(specs);
return output;

and confirmed that it worked for me( in your code above[https://github.com//issues/2#issuecomment-172133665] ).

But I found the other issue that
genAggregate can not add the aggregation on scaled fieldSets.
Here is my code.

var cp = require('./bower_components/viscompass/compass');
var dl = require('./bower_components/datalib/datalib');
var fs = require('fs');
var genScales = require('./bower_components/viscompass/src/gen/scales').default;

var channel_1 = require('./bower_components/vega-lite/src/channel');
var mark_1 = require('./bower_components/vega-lite/src/mark');


var data = JSON.parse(fs.readFileSync('./data/cars.json','utf8'));
var fieldDefs = [];
fieldDefs.push({'field': 'Acceleration', 'type': 'quantitative' });
// fieldDefs.push({'field': 'Horsepower', 'type': 'quantitative' });
fieldDefs.push({'field': 'Origin', 'type': 'nominal' });

// fieldDefs = List of fieldDef object {field:..., type: ...}
const stats = dl.summary(data).reduce(function(s, profile) {
  s[profile.field] = profile;
  return s;
}, {
  '*': {
    max: data.length,
    min: 0
  }
});




var fieldSets = cp.gen.projections(fieldDefs, stats, {
  maxAdditionalVariables: 3
}).reduce(function(fieldSets, fieldSet) {
  return genScales(fieldSets, fieldSet, {rescaleQuantitative: [undefined, 'log']});
}, []);

console.log(fieldSets); // A

fieldSets = fieldSets.reduce(function(fieldSets, fieldSet) {
  return cp.gen.aggregates(fieldSets, fieldSet, stats, {
    // TODO: add AggregationOption parameter here
  });

}, []);

console.log(fieldSets); // B

You can see that B don't include scale which A had.

Now, I figured out the way I avoid. I just changed the order of calling.

var fieldSets = cp.gen.projections(fieldDefs, stats, {
  maxAdditionalVariables: 3
})
.reduce(function(fieldSets, fieldSet) {
  return cp.gen.aggregates(fieldSets, fieldSet, stats, {
    // TODO: add AggregationOption parameter here
  });
}, [])
.reduce(function(fieldSets, fieldSet) {
  return genScales(fieldSets, fieldSet, {rescaleQuantitative: [undefined, 'log']});
}, []);