vega / compassql

CompassQL Query Language for visualization recommendation.
Other
273 stars 43 forks source link

CompassQL

CompassQL is a visualization query language that powers chart specifications and recommendations in Voyager 2.

As described in our vision paper and Voyager 2 paper, a CompassQL query is a JSON object that contains the following components:

Internally, CompassQL engine contains a collection of constraints for enumerating a set of candidate visualizations based on the input specification, and methods for grouping and ranking visualization.

For example, the following CompassQL query has one wildcard for the mark property. The system will automatically generate different marks and choose the top visual encodings based on the effectiveness score.

{
  "spec": {
    "data": {"url": "data/cars.json"},
    "mark": "?",
    "encodings": [
      {
        "channel": "x",
        "aggregate": "mean",
        "field": "Horsepower",
        "type": "quantitative"
      },{
        "channel": "y",
        "field": "Cylinders",
        "type": "ordinal"
      }
    ]
  },
  "chooseBy": "effectiveness"
}

The examples/specs directory contains a number of example CompassQL queries.

To understand more about the structure of a CompassQL Query, look at the Query interface declaration.

Usage

Given a row-based array of data object, here are the steps to use CompassQL:

  1. Specify a query config (or use an empty object to use the default configs)
var opt = {}; // Use all default query configs

For all query configuration properties, see src/config.ts.

  1. Build a data schema.
var schema = cql.schema.build(data);

The data property is a row-based array of data objects where each object represents a row in the data table (e.g., [{"a": 1, "b":2}, {"a": 2, "b": 3}]).

You can reuse the same schema for querying the same dataset multiple times.

  1. Specify a query. For example, this is a query for automatically selecting a mark:
var query = {
  spec: {
    data: { url: "node_modules/vega-datasets/data/cars.json" },
    mark: "?",
    encodings: [
      {
        channel: "x",
        aggregate: "mean",
        field: "Horsepower",
        type: "quantitative",
      },
      {
        channel: "y",
        field: "Cylinders",
        type: "ordinal",
      },
    ],
  },
  chooseBy: "effectiveness",
};
  1. Execute a CompassQL query.
var output = cql.recommend(query, schema);
var result = output.result; // recommendation result

The result object is an instance of SpecQueryModelGroup (ResultGroup<SpecQueryModel>), which is a root of the output ordered tree. Its items property can be either an array of SpecQueryModel or an array of SpecQueryModelGroup (for hierarchical groupings).

The SpecQueryModel is an class instance of a SpecQuery with helper methods. Note that, in the result, all of spec query models are completely enumerated and there would be no wildcard left.

  1. Convert instances of SpecQueryModel in the tree, using SpecQueryModel's toSpec() class method and the mapLeaves method.
var vlTree = cql.result.mapLeaves(result, function (item) {
  return item.toSpec();
});
  1. Now you can use the result. In this case, the tree has only 2 levels (the root and leaves). We can just get the top visualization by accessing the 0-th item.

For a full source code, please see index.html.

var topVlSpec = vlTree.items[0];

Note for Developers

Development Instructions

You can install dependencies with:

yarn install

You can use the following npm commands such as

npm run build
npm run lint
npm run test
npm run cover       // see test coverage  (see coverage/lcov-report/index.html)
npm run watch       // watcher that build, lint, and test
npm run test-debug  // useful for debugging unit-test with vscode
npm run clean       // useful for wiping out js files that's created from other branch

(See package.json for Full list of commands.)

To play with latest CompassQL in the vega-editor, use branch cql-vl3 in kanitw's fork, which has been updated to use Vega-Lite 3, Vega 5, and CompassQL ^0.21.1. (For CompassQL 0.7 or older, use branch compassql, which uses Vega-Lite 1.x).

Make sure to link CompassQL to the editor

cd COMPASSQL_DIR
npm link

cd VEGA_EDITOR_DIR
npm run vendor -- -l compassql

(You might want to link your local version of Vega-Lite as well.)

Main API

The main method is cql.recommend, which is in src/recommend.ts.

Directory Structure

Pro-Tip