compassql
Version:
CompassQL visualization query language
186 lines (134 loc) • 7.64 kB
Markdown
# CompassQL
CompassQL is a visualization query language that powers chart specifications and recommendations in [Voyager 2](https://github.com/vega/voyager2).
As described in our [vision paper](https://idl.cs.washington.edu/papers/compassql) and [Voyager 2](https://idl.cs.washington.edu/papers/voyager2) paper, a CompassQL query is a JSON object that contains the following components:
- **Specification** (`spec`) for describing a collection of queried visualizations. This `spec`'s syntax follows a structure similar to [Vega-Lite](https://vega.github.io/vega-lite)'s single view specification. However, `spec` in CompassQL can have *enumeration specifiers* (or *wildcards*) describing properties that can be enumerated.<sup>1</sup>
- **Grouping/Nesting** method names (`groupBy` and `nest`) for grouping queried visualizations into groups or hierarchical groups.
- **Ranking** method names (`orderBy` and `chooseBy`) for ordering queried visualizations or choose a top visualization from the collection.
- **Config** (`config`) for customizing query parameters.
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`](https://github.com/vega/compassql/tree/master/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](https://github.com/vega/compassql/blob/master/src/query/query.ts).
- A query's `spec` property implements `SpecQuery` interface, which follows the same structure as [Vega-Lite](https://github.com/vega/vega-lite)'s `UnitSpec` (single view specification) but most of `SpecQuery`'s properties have `-Query` suffixes to hint that its instance is a query that can contain wildcards to describe a collection of specifications.
- Since multiple encoding channels can be a wildcard, the `encoding` object in Vega-Lite is flatten as `encodings` which is an array of Encoding in CompassQL's `spec`.
## 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)
```js
var opt = {}; // Use all default query configs
```
For all query configuration properties, see [`src/config.ts`](https://github.com/vega/compassql/blob/master/src/config.ts).
2) Build a data schema.
```js
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.
3) Specify a query. For example, this is a query for automatically selecting a mark:
```js
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"
};
```
4) Execute a CompassQL `query`.
```js
var output = cql.recommend(query, schema);
var result = output.result; // recommendation result
```
The `result` object is an instance of [`SpecQueryModelGroup` (`ResultGroup<SpecQueryModel>`)](https://github.com/vega/compassql/blob/master/src/resultgroup.ts), 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.
5) Convert instances of `SpecQueryModel` in the tree, using `SpecQueryModel`'s `toSpec()` class method and the `mapLeaves` method.
```js
var vlTree = cql.result.mapLeaves(result, function(item) {
return item.toSpec();
});
```
6) 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`](https://github.com/vega/compassql/blob/master/index.html).
```js
var topVlSpec = vlTree.items[0];
```
# Note for Developers
- The root file of our project is `src/cql.ts`, which defines the top-level namespace `cql` for the compiled files. Other files under `src/` reflect namespace structure. All methods for `cql.xxx` will be in either `src/xxx.ts` or `src/xxx/xxx.ts`. For example, `cql.util.*` methods are in `src/util.ts`, `cql.query` is in `src/query/query.ts`.
- TODO: constraints
- List in Vy2 paper supplement..
## Development Instructions
You can install dependencies with:
```sh
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](http://github.com/kanitw/vega-editor/), 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`](https://github.com/vega/vega-editor/tree/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](https://github.com/vega/vega-editor/tree/compassql#local-testing--debugging) as well.)
## Main API
The main method is `cql.recommend`, which is in `src/recommend.ts`.
## Directory Structure
- `examples` - Example CompassQL queries
- `examples/specs` – All JSON files for CompassQL queries
- `examples/cql-examples.json` - A json files listing all CompasssQL examples that should be shown in Vega-editor.
- `src/` - Main source code directory.
- `src/cql.ts` is the root file for CompassQL codebase that exports the global `cql` object. Other files under `src/` reflect namespace structure.
- All interface for CompassQL syntax should be declared at the top-level of the `src/` folder.
- `test/` - Code for unit testing. `test`'s structure reflects `src`'s' directory structure.
For example, `test/constraint/` test files inside `src/constraint/`.
- `typings/` - TypeScript typing declaration for dependencies.
Some of them are downloaded from the TypeStrong community.
## Pro-Tip
- When you add a new source file to the project, don't forget to the file to `files` in `tsconfig.json`.