vega-lite
Advanced tools
Comparing version 0.7.16 to 0.7.17
{ | ||
"name": "vega-lite", | ||
"main": "vega-lite.js", | ||
"version": "0.7.16", | ||
"version": "0.7.17", | ||
"homepage": "https://github.com/vega/vega-lite", | ||
@@ -6,0 +6,0 @@ "authors": [ |
{ | ||
"name": "vega-lite", | ||
"author": "Jeffrey Heer, Dominik Moritz, Kanit \"Ham\" Wongsuphasawat", | ||
"version": "0.7.16", | ||
"version": "0.7.17", | ||
"collaborators": [ | ||
@@ -6,0 +6,0 @@ "Kanit Wongsuphasawat <kanitw@gmail.com> (http://kanitw.yellowpigz.com)", |
@@ -8,7 +8,8 @@ # Vega-lite | ||
**Vega-lite is still in alpha phase and we are working on improving the code and documentation. | ||
Note that our syntax might change slight before we release 1.0.** | ||
Provides a higher-level grammar for visual analysis, comparable to ggplot or Tableau, that generates complete [Vega](https://vega.github.io/) specifications. | ||
**Vega-lite is still in alpha phase and we are working on improving the code and [documentation](Documentation). | ||
Note that our syntax might change slightly before we release 1.0.** | ||
Vega-lite provides a higher-level grammar for visual analysis, comparable to ggplot or Tableau, that generates complete [Vega](https://vega.github.io/) specifications. | ||
Vega-lite specifications consist of simple mappings of variables in a data set to visual encoding channels such as position (`x`,`y`), `size`, `color` and `shape`. These mappings are then translated into full visualization specifications using the Vega visualization grammar. These resulting visualizations can then be exported or further modified to customize the display. | ||
@@ -54,5 +55,5 @@ | ||
"values": [ | ||
{"x":"A", "y":28}, {"x":"B", "y":55}, {"x":"C", "y":43}, | ||
{"x":"D", "y":91}, {"x":"E", "y":81}, {"x":"F", "y":53}, | ||
{"x":"G", "y":19}, {"x":"H", "y":87}, {"x":"I", "y":52} | ||
{"a":"A", "b":28}, {"a":"B", "b":55}, {"a":"C", "b":43}, | ||
{"a":"D", "b":91}, {"a":"E", "b":81}, {"a":"F", "b":53}, | ||
{"a":"G", "b":19}, {"a":"H", "b":87}, {"a":"I", "b":52} | ||
] | ||
@@ -62,4 +63,4 @@ }, | ||
"encoding": { | ||
"y": {"type": "Q","name": "y"}, | ||
"x": {"type": "O","name": "x"} | ||
"x": {"type": "O","name": "a"}, | ||
"y": {"type": "Q","name": "b"} | ||
} | ||
@@ -66,0 +67,0 @@ } |
@@ -60,6 +60,6 @@ 'use strict'; | ||
if (name===COL) return 'top'; | ||
if (name === COL) return 'top'; | ||
// x-axis for long y - put on top | ||
if (name===X && encoding.has(Y) && encoding.isOrdinalScale(Y) && encoding.cardinality(Y, stats) > 30) { | ||
if (name === X && encoding.has(Y) && encoding.isOrdinalScale(Y) && encoding.cardinality(Y, stats) > 30) { | ||
return 'top'; | ||
@@ -66,0 +66,0 @@ } |
@@ -7,2 +7,5 @@ 'use strict'; | ||
/** | ||
* Module for compiling Vega-lite spec into Vega spec. | ||
*/ | ||
var compiler = module.exports = {}; | ||
@@ -18,3 +21,2 @@ | ||
compiler.facet = require('./facet'); | ||
compiler.group = require('./group'); | ||
compiler.layout = require('./layout'); | ||
@@ -35,3 +37,5 @@ compiler.sort = require('./sort'); | ||
/** | ||
* Create a Vega specification from a Vega-lite Encoding object. | ||
*/ | ||
compiler.compileEncoding = function (encoding, stats) { | ||
@@ -58,5 +62,17 @@ // no need to pass stats if you pass in the data | ||
// global scales contains only time unit scales | ||
scales: compiler.time.scales(encoding) | ||
scales: compiler.time.scales(encoding), | ||
marks: [{ | ||
_name: 'cell', | ||
type: 'group', | ||
properties: { | ||
enter: { | ||
width: layout.cellWidth ? {value: layout.cellWidth} : {group: 'width'}, | ||
height: layout.cellHeight ? {value: layout.cellHeight} : {group: 'height'} | ||
} | ||
} | ||
}] | ||
}; | ||
var group = spec.marks[0]; | ||
// FIXME remove compiler.sort after migrating to vega 2. | ||
@@ -66,18 +82,6 @@ spec.data = compiler.sort(spec.data, encoding, stats); // append new data | ||
// marks | ||
// TODO this line is temporary and should be refactored | ||
spec.marks = [compiler.group.def('cell', { | ||
width: layout.cellWidth ? {value: layout.cellWidth} : undefined, | ||
height: layout.cellHeight ? {value: layout.cellHeight} : undefined | ||
})]; | ||
var style = compiler.style(encoding, stats), | ||
group = spec.marks[0], | ||
mdefs = marks.def(encoding, layout, style, stats), | ||
mdefs = group.marks = marks.def(encoding, layout, style, stats), | ||
mdef = mdefs[mdefs.length - 1]; // TODO: remove this dirty hack by refactoring the whole flow | ||
for (var i = 0; i < mdefs.length; i++) { | ||
group.marks.push(mdefs[i]); | ||
} | ||
var lineType = marks[encoding.marktype()].line; | ||
@@ -122,6 +126,4 @@ | ||
return spec; | ||
}; | ||
@@ -11,2 +11,11 @@ 'use strict'; | ||
/** | ||
* Create Vega's data array from a given encoding. | ||
* | ||
* @param {Encoding} encoding | ||
* @return {Array} Array of Vega data. | ||
* This always includes a "raw" data table. | ||
* If the encoding contains aggregate value, this will also create | ||
* aggregate table as well. | ||
*/ | ||
function data(encoding) { | ||
@@ -37,3 +46,3 @@ var def = [data.raw(encoding)]; | ||
// Set format.parse if needed | ||
// Set data's format.parse if needed | ||
var parse = data.raw.formatParse(encoding); | ||
@@ -66,5 +75,11 @@ if (parse) { | ||
/** | ||
* Generate Vega transforms for the raw data table. This can include | ||
* transforms for time unit, binning and filtering. | ||
*/ | ||
data.raw.transform = function(encoding) { | ||
// null filter comes first so transforms are not performed on null values | ||
// time and bin should come before filter so we can filter by time and bin | ||
return data.raw.transform.time(encoding).concat( | ||
return data.raw.transform.nullFilter(encoding).concat( | ||
data.raw.transform.time(encoding), | ||
data.raw.transform.bin(encoding), | ||
@@ -90,3 +105,5 @@ data.raw.transform.filter(encoding) | ||
field: encoding.fieldRef(encType), | ||
expr: time.formula(field.timeUnit, encoding.fieldRef(encType, {nofn: true, d: true})) | ||
expr: time.formula(field.timeUnit, | ||
encoding.fieldRef(encType, {nofn: true, d: true}) | ||
) | ||
}); | ||
@@ -112,2 +129,29 @@ } | ||
/** | ||
* @return {Object} An array that might contain a filter transform for filtering null value based on filterNul config | ||
*/ | ||
data.raw.transform.nullFilter = function(encoding) { | ||
var filteredFields = util.reduce(encoding.fields(), | ||
function(filteredFields, fieldList, fieldName) { | ||
if (fieldName === '*') return filteredFields; //count | ||
// TODO(#597) revise how filterNull is structured. | ||
if ((encoding.config('filterNull').Q && fieldList.containsType[Q]) || | ||
(encoding.config('filterNull').T && fieldList.containsType[T]) || | ||
(encoding.config('filterNull').O && fieldList.containsType[O]) || | ||
(encoding.config('filterNull').N && fieldList.containsType[N])) { | ||
filteredFields.push(fieldName); | ||
} | ||
return filteredFields; | ||
}, []); | ||
return filteredFields.length > 0 ? | ||
[{ | ||
type: 'filter', | ||
test: filteredFields.map(function(fieldName) { | ||
return fieldName + '!==null'; | ||
}).join(' && ') | ||
}] : []; | ||
}; | ||
data.raw.transform.filter = function(encoding) { | ||
@@ -130,10 +174,2 @@ var filters = encoding.filter().reduce(function(f, filter) { | ||
condition = d + op1 + ' ' + operator + ' ' + op2; | ||
} else if (operator === 'notNull') { | ||
// expects a number of fields | ||
for (var j=0; j<operands.length; j++) { | ||
condition += d + operands[j] + '!==null'; | ||
if (j < operands.length - 1) { | ||
condition += ' && '; | ||
} | ||
} | ||
} else { | ||
@@ -140,0 +176,0 @@ util.warn('Unsupported operator: ', operator); |
@@ -8,3 +8,2 @@ 'use strict'; | ||
var axis = require('./axis'), | ||
groupdef = require('./group').def, | ||
scale = require('./scale'); | ||
@@ -14,2 +13,22 @@ | ||
function groupdef(name, opt) { | ||
opt = opt || {}; | ||
return { | ||
_name: name || undefined, | ||
type: 'group', | ||
from: opt.from, | ||
properties: { | ||
enter: { | ||
x: opt.x || undefined, | ||
y: opt.y || undefined, | ||
width: opt.width || {group: 'width'}, | ||
height: opt.height || {group: 'height'} | ||
} | ||
}, | ||
scales: opt.scales || undefined, | ||
axes: opt.axes || undefined, | ||
marks: opt.marks || [] | ||
}; | ||
} | ||
function faceting(group, encoding, layout, spec, singleScaleNames, stack, stats) { | ||
@@ -16,0 +35,0 @@ var enter = group.properties.enter; |
@@ -102,2 +102,3 @@ 'use strict'; | ||
// TODO(#600) revise this | ||
function getMaxLength(encoding, stats, et) { | ||
@@ -104,0 +105,0 @@ var field = encoding.field(et), |
@@ -5,13 +5,21 @@ 'use strict'; | ||
var groupdef = require('./group').def; | ||
module.exports = subfaceting; | ||
function subfaceting(group, mdef, details, stack, encoding) { | ||
var m = group.marks, | ||
g = groupdef('subfacet', {marks: m}); | ||
var m = group.marks; | ||
var g = { | ||
_name: 'subfacet', | ||
type: 'group', | ||
from: mdef.from, | ||
properties: { | ||
enter: { | ||
width: {group: 'width'}, | ||
height: {group: 'height'} | ||
} | ||
}, | ||
marks: m | ||
}; | ||
group.marks = [g]; | ||
g.from = mdef.from; | ||
delete mdef.from; | ||
delete mdef.from; // (move to the new g) | ||
@@ -18,0 +26,0 @@ //TODO test LOD -- we should support stack / line without color (LOD) field |
@@ -8,3 +8,6 @@ 'use strict'; | ||
var LONG_DATE = new Date(2014, 8, 17); | ||
// 'Wednesday September 17 04:00:00 2014' | ||
// Wednesday is the longest date | ||
// September is the longest month (8 in javascript as it is zero-indexed). | ||
var LONG_DATE = new Date(Date.UTC(2014, 8, 17)); | ||
@@ -57,2 +60,3 @@ time.cardinality = function(field, stats, filterNull, type) { | ||
} | ||
// TODO(#600) revise this | ||
// no time unit | ||
@@ -59,0 +63,0 @@ var timeFormat = encoding.config('timeFormat'); |
@@ -103,21 +103,3 @@ 'use strict'; | ||
proto.filter = function() { | ||
var filterNull = [], | ||
fields = this.fields(), | ||
self = this; | ||
util.forEach(fields, function(fieldList, fieldName) { | ||
if (fieldName === '*') return; //count | ||
if ((self.config('filterNull').Q && fieldList.containsType[Q]) || | ||
(self.config('filterNull').T && fieldList.containsType[T]) || | ||
(self.config('filterNull').O && fieldList.containsType[O]) || | ||
(self.config('filterNull').N && fieldList.containsType[N])) { | ||
filterNull.push({ | ||
operands: [fieldName], | ||
operator: 'notNull' | ||
}); | ||
} | ||
}); | ||
return filterNull.concat(this._filter); | ||
return this._filter; | ||
}; | ||
@@ -124,0 +106,0 @@ |
@@ -94,2 +94,3 @@ // Package of defining Vega-lite Specification's json schema | ||
properties: { | ||
/* Common Scale Properties */ | ||
type: schema.scale_type, | ||
@@ -101,2 +102,9 @@ reverse: { | ||
}, | ||
/* Quantitative Scale Properties */ | ||
nice: { | ||
type: 'string', | ||
enum: ['second', 'minute', 'hour', 'day', 'week', 'month', 'year'], | ||
supportedTypes: toMap([T]) | ||
}, | ||
zero: { | ||
@@ -108,7 +116,4 @@ type: 'boolean', | ||
}, | ||
nice: { | ||
type: 'string', | ||
enum: ['second', 'minute', 'hour', 'day', 'week', 'month', 'year'], | ||
supportedTypes: toMap([T]) | ||
}, | ||
/* Vega-lite only Properties */ | ||
useRawDomain: { | ||
@@ -155,2 +160,11 @@ type: 'boolean', | ||
properties: { | ||
/* Vega Axis Properties */ | ||
format: { | ||
type: 'string', | ||
default: undefined, // auto | ||
description: 'The formatting pattern for axis labels. '+ | ||
'If not undefined, this will be determined by ' + | ||
'small/largeNumberFormat and the max value ' + | ||
'of the field.' | ||
}, | ||
grid: { | ||
@@ -164,3 +178,3 @@ type: 'boolean', | ||
default: 'back', | ||
description: 'A string indicating if the axis (and any gridlines) should be placed above or below the data marks.' | ||
description: 'A string indicating if the axis (and any gridlines) should be placed above or below the data marks. One of "front" (default) or "back".' | ||
}, | ||
@@ -179,2 +193,3 @@ orient: { | ||
}, | ||
/* Vega Axis Properties that are automatically populated by Vega-lite */ | ||
title: { | ||
@@ -185,21 +200,3 @@ type: 'string', | ||
}, | ||
titleMaxLength: { | ||
type: 'integer', | ||
default: undefined, | ||
minimum: 0, | ||
description: 'Max length for axis title if the title is automatically generated from the field\'s description' | ||
}, | ||
titleOffset: { | ||
type: 'integer', | ||
default: undefined, // auto | ||
description: 'A title offset value for the axis.' | ||
}, | ||
format: { | ||
type: 'string', | ||
default: undefined, // auto | ||
description: 'The formatting pattern for axis labels. '+ | ||
'If not undefined, this will be determined by ' + | ||
'small/largeNumberFormat and the max value ' + | ||
'of the field.' | ||
}, | ||
/* Vega-lite only */ | ||
maxLabelLength: { | ||
@@ -218,2 +215,13 @@ type: 'integer', | ||
}, | ||
titleMaxLength: { | ||
type: 'integer', | ||
default: undefined, | ||
minimum: 0, | ||
description: 'Max length for axis title if the title is automatically generated from the field\'s description' | ||
}, | ||
titleOffset: { | ||
type: 'integer', | ||
default: undefined, // auto | ||
description: 'A title offset value for the axis.' | ||
}, | ||
} | ||
@@ -613,5 +621,7 @@ } | ||
// filter null | ||
// TODO(#597) revise this config | ||
filterNull: { | ||
type: 'object', | ||
properties: { | ||
N: {type:'boolean', default: false}, | ||
O: {type:'boolean', default: false}, | ||
@@ -618,0 +628,0 @@ Q: {type:'boolean', default: true}, |
@@ -132,13 +132,45 @@ 'use strict'; | ||
describe('filter', function () { | ||
it('should return filter transform that include filter null', function () { | ||
var transform = data.raw.transform.filter(encoding); | ||
describe('nullFilter', function() { | ||
var spec = { | ||
marktype: 'point', | ||
encoding: { | ||
y: {name: 'Q', type:'Q'}, | ||
x: {name: 'T', type:'T'}, | ||
color: {name: 'O', type:'O'} | ||
} | ||
}; | ||
expect(transform[0]).to.eql({ | ||
type: 'filter', | ||
test: '(d.data.a!==null) && (d.data.Acceleration!==null)' + | ||
' && (d.data.a > b) && (d.data.c == d)' | ||
it('should add filterNull for Q and T by default', function () { | ||
var encoding = Encoding.fromSpec(spec); | ||
expect(data.raw.transform.nullFilter(encoding)) | ||
.to.eql([{ | ||
type: 'filter', | ||
test: 'T!==null && Q!==null' | ||
}]); | ||
}); | ||
it('should add filterNull for O when specified', function () { | ||
var encoding = Encoding.fromSpec(spec, { | ||
config: { | ||
filterNull: {O: true} | ||
} | ||
}); | ||
expect(data.raw.transform.nullFilter(encoding)) | ||
.to.eql([{ | ||
type: 'filter', | ||
test:'T!==null && Q!==null && O!==null' | ||
}]); | ||
}); | ||
// }); | ||
}); | ||
describe('filter', function () { | ||
it('should return array that contains a filter transform', function () { | ||
expect(data.raw.transform.filter(encoding)) | ||
.to.eql([{ | ||
type: 'filter', | ||
test: '(d.data.a > b) && (d.data.c == d)' | ||
}]); | ||
}); | ||
it('should exclude unsupported operator', function () { | ||
@@ -169,7 +201,8 @@ var badEncoding = Encoding.fromSpec({ | ||
it('should time and bin before filter', function () { | ||
it('should have null filter, timeUnit, bin then filter', function () { | ||
var transform = data.raw.transform(encoding); | ||
expect(transform[0].type).to.eql('formula'); | ||
expect(transform[1].type).to.eql('bin'); | ||
expect(transform[2].type).to.eql('filter'); | ||
expect(transform[0].type).to.eql('filter'); | ||
expect(transform[1].type).to.eql('formula'); | ||
expect(transform[2].type).to.eql('bin'); | ||
expect(transform[3].type).to.eql('filter'); | ||
}); | ||
@@ -176,0 +209,0 @@ |
@@ -17,27 +17,1 @@ 'use strict'; | ||
describe('encoding.filter()', function () { | ||
var spec = { | ||
marktype: 'point', | ||
encoding: { | ||
y: {name: 'Q', type:'Q'}, | ||
x: {name: 'T', type:'T'}, | ||
color: {name: 'O', type:'O'} | ||
} | ||
}; | ||
it('should add filterNull for Q and T by default', function () { | ||
var encoding = Encoding.fromSpec(spec), | ||
filter = encoding.filter(); | ||
expect(filter.length).to.equal(2); | ||
expect(filter.indexOf({name: 'O', type:'O'})).to.equal(-1); | ||
}); | ||
it('should add filterNull for O when specified', function () { | ||
var encoding = Encoding.fromSpec(spec, { | ||
config: { | ||
filterNull: {O: true} | ||
} | ||
}); | ||
var filter = encoding.filter(); | ||
expect(filter.length).to.equal(3); | ||
}); | ||
}); |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
7539565
120666
106
94