├── .jshintignore
├── src
├── components
│ ├── schemalist
│ │ ├── schemalist.scss
│ │ ├── schemalist.html
│ │ ├── schemalist.js
│ │ └── schemalist.spec.js
│ ├── propertyeditor
│ │ ├── propertyeditor.scss
│ │ ├── propertyeditor.js
│ │ ├── propertyeditor.html
│ │ └── propertyeditor.spec.js
│ ├── schemalistitem
│ │ ├── schemalistitem.scss
│ │ ├── schemalistitem.html
│ │ ├── schemalistitem.js
│ │ └── schemalistitem.spec.js
│ ├── nullfilterdirective
│ │ ├── nullfilterdirective.scss
│ │ ├── nullfilterdirective.html
│ │ ├── nullfilterdirective.js
│ │ └── nullfilterdirective.spec.js
│ ├── shelves
│ │ ├── shelves.scss
│ │ ├── shelves.js
│ │ ├── shelves.spec.js
│ │ └── shelves.html
│ ├── configurationeditor
│ │ ├── configurationeditor.html
│ │ ├── configurationeditor.js
│ │ └── configurationeditor.spec.js
│ ├── alertmessages
│ │ ├── alertmessages.html
│ │ ├── alertmessages.js
│ │ └── alertmessages.spec.js
│ ├── functionselect
│ │ ├── functionselect.html
│ │ ├── functionselect.spec.js
│ │ └── functionselect.js
│ ├── vgSpecEditor
│ │ ├── vgSpecEditor.js
│ │ ├── vgSpecEditor.html
│ │ └── vgSpecEditor.spec.js
│ ├── jsoninput
│ │ ├── jsoninput.js
│ │ └── jsoninput.spec.js
│ ├── vlSpecEditor
│ │ ├── vlSpecEditor.js
│ │ ├── vlSpecEditor.html
│ │ └── vlSpecEditor.spec.js
│ ├── lyraexport
│ │ ├── lyraexport.spec.js
│ │ └── lyraexport.js
│ └── fielddefeditor
│ │ ├── fielddefeditor.spec.js
│ │ ├── fielddefeditor.scss
│ │ ├── fielddefeditor.js
│ │ └── fielddefeditor.html
├── favicon.ico
├── assets
│ ├── images
│ │ ├── field_geo.png
│ │ ├── field_text.png
│ │ ├── field_time.png
│ │ └── field_number.png
│ └── normalize.scss
├── app
│ ├── main
│ │ ├── main.controller.spec.js
│ │ ├── main.controller.js
│ │ └── main.html
│ ├── pills
│ │ ├── pills.service.spec.js
│ │ └── pills.service.js
│ ├── index.scss
│ ├── spec
│ │ ├── spec.spec.js
│ │ └── spec.service.js
│ └── index.js
├── data
│ ├── crimea.json
│ ├── burtin.json
│ ├── driving.json
│ ├── barley.json
│ ├── iris.json
│ └── population.json
└── index.html
├── .gitignore
├── .bowerrc
├── .travis.yml
├── .bower-postinstall
├── gulpfile.js
├── deploy.sh
├── gulp
├── lint.js
├── unit-tests.js
├── bumpver.js
├── watch.js
├── e2e-tests.js
├── inject.js
├── styles.js
├── server.js
├── proxy.js
├── build.js
└── gen.js
├── .jshintrc
├── e2e
├── main.po.js
└── main.spec.js
├── protractor.conf.js
├── bower.json
├── LICENSE
├── .yo-rc.json
├── package.json
├── karma.conf.js
└── README.md
/.jshintignore:
--------------------------------------------------------------------------------
1 | app/scripts/vendor/*.js
--------------------------------------------------------------------------------
/src/components/schemalist/schemalist.scss:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/components/propertyeditor/propertyeditor.scss:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/components/schemalistitem/schemalistitem.scss:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/components/nullfilterdirective/nullfilterdirective.scss:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/components/shelves/shelves.scss:
--------------------------------------------------------------------------------
1 | .shelf-pane {
2 | margin-bottom: 20px;
3 | }
--------------------------------------------------------------------------------
/src/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sandbox/polestar/master/src/favicon.ico
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | bower_components/
3 | .sass-cache/
4 | .tmp/
5 | dist/
6 | test.log
--------------------------------------------------------------------------------
/src/assets/images/field_geo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sandbox/polestar/master/src/assets/images/field_geo.png
--------------------------------------------------------------------------------
/src/assets/images/field_text.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sandbox/polestar/master/src/assets/images/field_text.png
--------------------------------------------------------------------------------
/src/assets/images/field_time.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sandbox/polestar/master/src/assets/images/field_time.png
--------------------------------------------------------------------------------
/src/assets/images/field_number.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sandbox/polestar/master/src/assets/images/field_number.png
--------------------------------------------------------------------------------
/src/components/configurationeditor/configurationeditor.html:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/.bowerrc:
--------------------------------------------------------------------------------
1 | {
2 | "directory": "bower_components",
3 | "scripts": {
4 | "postinstall": "./.bower-postinstall"
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - "0.10"
4 | before_install:
5 | - npm install -g bower
6 | - npm install
7 | - bower install
8 |
--------------------------------------------------------------------------------
/.bower-postinstall:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | cp bower_components/angular-tooltips/dist/angular-tooltips.min.css bower_components/angular-tooltips/dist/_angular-tooltips.scss
--------------------------------------------------------------------------------
/src/components/nullfilterdirective/nullfilterdirective.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/components/schemalist/schemalist.html:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/src/app/main/main.controller.spec.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | describe('controllers', function() {
4 | var scope;
5 |
6 | beforeEach(module('polestar'));
7 |
8 | beforeEach(inject(function($rootScope) {
9 | scope = $rootScope.$new();
10 | }));
11 | });
12 |
--------------------------------------------------------------------------------
/src/components/alertmessages/alertmessages.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | {{ alert.msg }}
4 |
×
5 |
6 |
7 |
--------------------------------------------------------------------------------
/gulpfile.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var gulp = require('gulp');
4 |
5 | gulp.paths = {
6 | src: 'src',
7 | dist: 'dist',
8 | tmp: '.tmp',
9 | e2e: 'e2e'
10 | };
11 |
12 | require('require-dir')('./gulp');
13 |
14 | gulp.task('default', ['clean'], function () {
15 | gulp.start('build');
16 | });
17 |
--------------------------------------------------------------------------------
/deploy.sh:
--------------------------------------------------------------------------------
1 | set -e
2 |
3 | gitsha=$(git rev-parse HEAD)
4 |
5 | git clone git@github.com:uwdata/polestar.git gh-pages
6 | cd gh-pages
7 | git checkout gh-pages
8 | cd ..
9 | gulp
10 | rm -rf dist/.git
11 | mv gh-pages/.git dist
12 | rm -rf gh-pages
13 | cd dist
14 | git add .
15 | git commit -am "release $gitsha"
16 | git push
17 | cd ..
--------------------------------------------------------------------------------
/src/components/functionselect/functionselect.html:
--------------------------------------------------------------------------------
1 |
2 |
Functions
3 |
7 |
--------------------------------------------------------------------------------
/gulp/lint.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var gulp = require('gulp');
4 | var paths = gulp.paths;
5 | var $ = require('gulp-load-plugins')();
6 |
7 | gulp.task('jshint', function() {
8 | return gulp.src([
9 | paths.src + '/**/*.js',
10 | '!'+ paths.src + '/vendor/*.js'
11 | ])
12 | .pipe($.jshint())
13 | .pipe($.jshint.reporter('jshint-stylish'));
14 | });
15 |
--------------------------------------------------------------------------------
/src/components/alertmessages/alertmessages.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | angular.module('polestar')
4 | .directive('alertMessages', function(Alerts) {
5 | return {
6 | templateUrl: 'components/alertmessages/alertmessages.html',
7 | restrict: 'E',
8 | scope: {},
9 | link: function(scope /*, element, attrs*/) {
10 | scope.Alerts = Alerts;
11 | }
12 | };
13 | });
14 |
--------------------------------------------------------------------------------
/src/components/vgSpecEditor/vgSpecEditor.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | angular.module('polestar')
4 | .directive('vgSpecEditor', function(Spec) {
5 | return {
6 | templateUrl: 'components/vgSpecEditor/vgSpecEditor.html',
7 | restrict: 'E',
8 | scope: {},
9 | link: function postLink(scope /*, element, attrs*/) {
10 | scope.Spec = Spec;
11 | }
12 | };
13 | });
14 |
--------------------------------------------------------------------------------
/src/components/configurationeditor/configurationeditor.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | angular.module('polestar')
4 | .directive('configurationEditor', function() {
5 | return {
6 | templateUrl: 'components/configurationeditor/configurationeditor.html',
7 | restrict: 'E',
8 | scope: {},
9 | controller: function($scope, Config) {
10 | $scope.Config = Config;
11 | }
12 | };
13 | });
14 |
--------------------------------------------------------------------------------
/src/components/schemalistitem/schemalistitem.html:
--------------------------------------------------------------------------------
1 |
10 |
--------------------------------------------------------------------------------
/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "undef": true,
3 | "unused": true,
4 | "eqnull": true,
5 | "freeze": true,
6 | "noarg": true,
7 | "node": true,
8 | "browser": true,
9 | "mocha": true,
10 | "globalstrict":true,
11 | "indent": 2,
12 | "quotmark": "single",
13 | "undef": true,
14 | "globals": {
15 | "angular": false,
16 | // Angular Mocks
17 | "inject": false,
18 | // assert
19 | "expect": false
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/components/vgSpecEditor/vgSpecEditor.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/components/schemalist/schemalist.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | angular.module('polestar')
4 | .directive('schemaList', function(Dataset) {
5 | return {
6 | templateUrl: 'components/schemalist/schemalist.html',
7 | restrict: 'E',
8 | scope: {},
9 | replace: true,
10 | // link: function postLink(scope, element /*, attrs*/) {
11 | // },
12 | controller: function($scope) {
13 | $scope.Dataset = Dataset;
14 | }
15 | };
16 | });
17 |
--------------------------------------------------------------------------------
/src/components/jsoninput/jsoninput.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | angular.module('polestar')
4 | .directive('jsonInput', function() {
5 | return {
6 | restrict: 'A',
7 | require: 'ngModel',
8 | scope: {},
9 | link: function(scope, element, attrs, modelCtrl) {
10 | var format = function(inputValue) {
11 | return JSON.stringify(inputValue, null, ' ', 80);
12 | };
13 | modelCtrl.$formatters.push(format);
14 | }
15 | };
16 | });
17 |
--------------------------------------------------------------------------------
/gulp/unit-tests.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var gulp = require('gulp');
4 | var karma = require('karma').server;
5 |
6 | function runTests (singleRun, done) {
7 | karma.start({
8 | configFile: __dirname + '/../karma.conf.js',
9 | singleRun: singleRun
10 | }, function() { done(); });
11 | }
12 |
13 | gulp.task('test', ['partials'], function (done) {
14 | runTests(true /* singleRun */, done);
15 | });
16 |
17 | gulp.task('test:auto', ['partials'], function (done) {
18 | runTests(false /* singleRun */, done);
19 | });
20 |
--------------------------------------------------------------------------------
/src/app/pills/pills.service.spec.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /* global vl:true */
4 | /* jshint expr:true */
5 |
6 | describe('Service: Pills', function () {
7 |
8 | // load the service's module
9 | beforeEach(module('polestar', function($provide) {
10 | $provide.constant('vl', vl);
11 | }));
12 |
13 | // instantiate service
14 | var Pills;
15 | beforeEach(inject(function (_Pills_) {
16 | Pills = _Pills_;
17 | }));
18 |
19 | it('should do something', function () {
20 | expect(Pills).to.be.ok;
21 | });
22 |
23 | });
--------------------------------------------------------------------------------
/e2e/main.po.js:
--------------------------------------------------------------------------------
1 | /**
2 | * This file uses the Page Object pattern to define the main page for tests
3 | * https://docs.google.com/presentation/d/1B6manhG0zEXkC-H-tPo2vwU06JhL8w9-XCF9oehXzAQ
4 | */
5 |
6 | 'use strict';
7 |
8 | var MainPage = function() {
9 | this.jumbEl = element(by.css('.jumbotron'));
10 | this.h1El = this.jumbEl.element(by.css('h1'));
11 | this.imgEl = this.jumbEl.element(by.css('img'));
12 | this.thumbnailEls = element(by.css('body')).all(by.repeater('awesomeThing in awesomeThings'));
13 | };
14 |
15 | module.exports = new MainPage();
16 |
--------------------------------------------------------------------------------
/src/components/vlSpecEditor/vlSpecEditor.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | angular.module('polestar')
4 | .directive('vlSpecEditor', function(Spec) {
5 | return {
6 | templateUrl: 'components/vlSpecEditor/vlSpecEditor.html',
7 | restrict: 'E',
8 | scope: {},
9 | link: function postLink(scope /*, element, attrs*/) {
10 | scope.Spec = Spec;
11 |
12 | scope.parseShorthand = Spec.parseShorthand;
13 | scope.parseVegalite = function(specJSON) {
14 | Spec.parseSpec(JSON.parse(specJSON));
15 | };
16 | }
17 | };
18 | });
19 |
--------------------------------------------------------------------------------
/gulp/bumpver.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var gulp = require('gulp');
4 | var $ = require('gulp-load-plugins')();
5 |
6 |
7 | function inc(importance) {
8 | // get all the files to bump version in
9 | return gulp.src(['./package.json', './bower.json'])
10 | // bump the version number in those files
11 | .pipe($.bump({type: importance}))
12 | // save it back to filesystem
13 | .pipe(gulp.dest('./'));
14 | }
15 |
16 | gulp.task('patch', function() { return inc('patch'); });
17 | gulp.task('feature', function() { return inc('minor'); });
18 | gulp.task('release', function() { return inc('major'); });
--------------------------------------------------------------------------------
/src/components/propertyeditor/propertyeditor.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /**
4 | * @ngdoc directive
5 | * @name vega-lite-ui.directive:propertyEditor
6 | * @description
7 | * # propertyEditor
8 | */
9 | angular.module('polestar')
10 | .directive('propertyEditor', function () {
11 | return {
12 | templateUrl: 'components/propertyeditor/propertyeditor.html',
13 | restrict: 'E',
14 | scope: {
15 | id: '=',
16 | type: '=',
17 | enum: '=',
18 | propName: '=',
19 | group: '='
20 | },
21 | link: function postLink(/*scope, element, attrs*/) {
22 | }
23 | };
24 | });
--------------------------------------------------------------------------------
/gulp/watch.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var gulp = require('gulp');
4 |
5 | var paths = gulp.paths;
6 |
7 | gulp.task('watch', ['inject'], function () {
8 | gulp.watch([
9 | paths.src + '/*.html',
10 | paths.src + '/{app,components}/**/*.scss',
11 | paths.src + '/{app,components}/**/*.js',
12 | paths.src + '/assets/*.scss',
13 | paths.src + '/bower_components/vega-lite/vega-lite.js',
14 | paths.src + '/bower_components/datalib/datalib.js',
15 | paths.src + '/bower_components/vega-lite-ui/vlui.js',
16 | paths.src + '/bower_components/vega-lite-ui/vlui.scss',
17 | 'bower.json'
18 | ], ['inject', 'jshint']);
19 | });
20 |
--------------------------------------------------------------------------------
/e2e/main.spec.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | describe('The main view', function () {
4 | var page;
5 |
6 | beforeEach(function () {
7 | browser.get('http://localhost:3000/index.html');
8 | page = require('./main.po');
9 | });
10 |
11 | it('should include jumbotron with correct data', function() {
12 | expect(page.h1El.getText()).toBe('\'Allo, \'Allo!');
13 | expect(page.imgEl.getAttribute('src')).toMatch(/assets\/images\/yeoman.png$/);
14 | expect(page.imgEl.getAttribute('alt')).toBe('I\'m Yeoman');
15 | });
16 |
17 | it('list more than 5 awesome things', function () {
18 | expect(page.thumbnailEls.count()).toBeGreaterThan(5);
19 | });
20 |
21 | });
22 |
--------------------------------------------------------------------------------
/src/components/jsoninput/jsoninput.spec.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | describe('Directive: jsonInput', function() {
4 |
5 | // load the directive's module
6 | beforeEach(module('polestar'));
7 |
8 | var element,
9 | scope;
10 |
11 | beforeEach(inject(function($rootScope) {
12 | scope = $rootScope.$new();
13 | scope.foo = {foo: 'bar'};
14 | }));
15 |
16 | it('should make hidden element visible', inject(function($compile) {
17 | element = angular.element('');
18 | element = $compile(element)(scope);
19 | scope.$digest();
20 |
21 | expect(element.val()).to.eql('{"foo": "bar"}');
22 | }));
23 | });
24 |
--------------------------------------------------------------------------------
/src/components/nullfilterdirective/nullfilterdirective.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /**
4 | * @ngdoc directive
5 | * @name polestar.directive:nullFilterDirective
6 | * @description
7 | * # nullFilterDirective
8 | */
9 | angular.module('polestar')
10 | .directive('nullFilterDirective', function (Spec) {
11 | return {
12 | templateUrl: 'components/nullfilterdirective/nullfilterdirective.html',
13 | restrict: 'E',
14 | scope: {},
15 | link: function postLink(scope, element, attrs) {
16 | // jshint unused:false
17 | scope.Spec = Spec;
18 |
19 | scope.updateFilter = function() {
20 | Spec.update();
21 | };
22 | }
23 | };
24 | });
--------------------------------------------------------------------------------
/src/components/propertyeditor/propertyeditor.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/src/components/lyraexport/lyraexport.spec.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | describe('Directive: lyraExport', function() {
4 |
5 | // load the directive's module
6 | beforeEach(module('polestar'));
7 |
8 | beforeEach(module('polestar', function($provide) {
9 | var mock = {
10 | vgSpec: {}
11 | };
12 | $provide.value('Spec', mock);
13 | }));
14 |
15 | var element,
16 | scope;
17 |
18 | beforeEach(inject(function($rootScope) {
19 | scope = $rootScope.$new();
20 | }));
21 |
22 | it('should make hidden element visible', inject(function($compile) {
23 | element = angular.element('');
24 | element = $compile(element)(scope);
25 | expect(element.text()).to.eql('Export to lyra');
26 | }));
27 | });
28 |
--------------------------------------------------------------------------------
/src/components/nullfilterdirective/nullfilterdirective.spec.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | describe('Directive: nullFilterDirective', function () {
4 |
5 | // load the directive's module
6 | beforeEach(module('polestar'));
7 |
8 | var element,
9 | scope;
10 |
11 | beforeEach(module('polestar', function($provide) {
12 | $provide.value('Dataset', {});
13 | $provide.value('Spec', {});
14 | }));
15 |
16 | beforeEach(inject(function ($rootScope) {
17 | scope = $rootScope.$new();
18 | }));
19 |
20 | it('should make hidden element visible', inject(function ($compile) {
21 | element = angular.element('');
22 | element = $compile(element)(scope);
23 | expect(element.length).to.eql(1);
24 | }));
25 | });
--------------------------------------------------------------------------------
/protractor.conf.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var paths = require('./.yo-rc.json')['generator-gulp-angular'].props.paths;
4 |
5 | // An example configuration file.
6 | exports.config = {
7 | // The address of a running selenium server.
8 | //seleniumAddress: 'http://localhost:4444/wd/hub',
9 | //seleniumServerJar: deprecated, this should be set on node_modules/protractor/config.json
10 |
11 | // Capabilities to be passed to the webdriver instance.
12 | capabilities: {
13 | 'browserName': 'chrome'
14 | },
15 |
16 | // Spec patterns are relative to the current working directly when
17 | // protractor is called.
18 | specs: [paths.e2e + '/**/*.js'],
19 |
20 | // Options to be passed to Jasmine-node.
21 | jasmineNodeOpts: {
22 | showColors: true,
23 | defaultTimeoutInterval: 30000
24 | }
25 | };
26 |
--------------------------------------------------------------------------------
/src/components/schemalistitem/schemalistitem.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /**
4 | * @ngdoc directive
5 | * @name polestar.directive:schemaListItem
6 | * @description
7 | * # schemaListItem
8 | */
9 | angular.module('polestar')
10 | .directive('schemaListItem', function (Pills) {
11 | return {
12 | templateUrl: 'components/schemalistitem/schemalistitem.html',
13 | restrict: 'E',
14 | replace: false,
15 | scope: {
16 | field:'='
17 | },
18 | link: function postLink(scope) {
19 | scope.getSchemaPill = Pills.getSchemaPill;
20 |
21 | scope.fieldDragStart = function() {
22 | scope.pill = Pills.getSchemaPill(scope.field);
23 | Pills.dragStart(scope.pill, null);
24 | };
25 |
26 | scope.fieldDragStop = Pills.dragStop;
27 | }
28 | };
29 | });
--------------------------------------------------------------------------------
/src/components/alertmessages/alertmessages.spec.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | describe('Directive: alertMessages', function() {
4 |
5 | // load the directive's module
6 | beforeEach(module('polestar'));
7 |
8 | var element,
9 | scope;
10 |
11 | beforeEach(module('polestar', function($provide) {
12 | var mock = {
13 | alerts: [
14 | {name: 'foo'},
15 | {name: 'bar'}
16 | ]
17 | };
18 | $provide.value('Alerts', mock);
19 | }));
20 |
21 | beforeEach(inject(function($rootScope) {
22 | scope = $rootScope.$new();
23 | }));
24 |
25 | it('should show alert messages', inject(function($compile) {
26 | element = angular.element('');
27 | element = $compile(element)(scope);
28 | scope.$digest();
29 |
30 | expect(element.find('.alert-item').length).to.eql(2);
31 | }));
32 | });
33 |
--------------------------------------------------------------------------------
/src/components/propertyeditor/propertyeditor.spec.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | describe('Directive: propertyEditor', function() {
4 |
5 | // load the directive's module
6 | beforeEach(module('polestar'));
7 |
8 | var element,
9 | scope;
10 |
11 | beforeEach(inject(function($rootScope) {
12 | scope = $rootScope.$new();
13 |
14 | scope.id = 'foo';
15 | scope.type = 'boolean';
16 | scope.name = 'bar';
17 | scope.enum = undefined;
18 | scope.group = {
19 | bar: 'value'
20 | };
21 | }));
22 |
23 | it('should make hidden element visible', inject(function($compile) {
24 | element = angular.element('');
25 | element = $compile(element)(scope);
26 | scope.$digest();
27 |
28 | expect(element.find('#foo').length).to.eql(1);
29 | }));
30 | });
31 |
--------------------------------------------------------------------------------
/src/components/vlSpecEditor/vlSpecEditor.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/components/configurationeditor/configurationeditor.spec.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /* jshint expr:true */
4 |
5 | describe('Directive: configurationEditor', function() {
6 |
7 | // load the directive's module
8 | beforeEach(module('polestar'));
9 |
10 | var element,
11 | scope;
12 |
13 | beforeEach(module('polestar', function($provide) {
14 | var mock = {};
15 | $provide.value('Config', mock);
16 | }));
17 |
18 | beforeEach(inject(function($rootScope, $compile) {
19 | scope = $rootScope.$new();
20 |
21 | element = angular.element('');
22 | element = $compile(element)(scope);
23 | scope.$digest();
24 | }));
25 |
26 | it('should insert form', function() {
27 | expect(element.find('form').length).to.eql(1);
28 | });
29 |
30 | it('should attach config to scope', function() {
31 | var isolateScope = element.isolateScope();
32 | expect(isolateScope.Config).to.be.defined;
33 | });
34 | });
35 |
--------------------------------------------------------------------------------
/src/components/schemalist/schemalist.spec.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /* global vl:true */
4 |
5 | describe('Directive: schemaList', function() {
6 |
7 | // load the directive's module
8 | beforeEach(module('polestar', function($provide) {
9 | $provide.constant('vl', vl);
10 | }));
11 |
12 | var element,
13 | scope;
14 |
15 | beforeEach(module('polestar', function($provide) {
16 | var mockDataset = {
17 | dataschema: ['foo', 'bar', 'baz'],
18 | stats: {
19 | foo: {},
20 | bar: {},
21 | baz: {}
22 | },
23 | onUpdate: []
24 | };
25 | $provide.value('Dataset', mockDataset);
26 | }));
27 |
28 | beforeEach(inject(function($rootScope) {
29 | scope = $rootScope.$new();
30 | }));
31 |
32 | it('should have field', inject(function($compile) {
33 | element = angular.element('');
34 | element = $compile(element)(scope);
35 | scope.$digest();
36 |
37 | expect(element.find('.field-info').length).to.eql(3);
38 | }));
39 | });
40 |
--------------------------------------------------------------------------------
/gulp/e2e-tests.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var gulp = require('gulp');
4 |
5 | var $ = require('gulp-load-plugins')();
6 |
7 | var browserSync = require('browser-sync');
8 |
9 | var paths = gulp.paths;
10 |
11 | // Downloads the selenium webdriver
12 | gulp.task('webdriver-update', $.protractor.webdriver_update);
13 |
14 | gulp.task('webdriver-standalone', $.protractor.webdriver_standalone);
15 |
16 | function runProtractor (done) {
17 |
18 | gulp.src(paths.e2e + '/**/*.js')
19 | .pipe($.protractor.protractor({
20 | configFile: 'protractor.conf.js',
21 | }))
22 | .on('error', function (err) {
23 | // Make sure failed tests cause gulp to exit non-zero
24 | throw err;
25 | })
26 | .on('end', function () {
27 | // Close browser sync server
28 | browserSync.exit();
29 | done();
30 | });
31 | }
32 |
33 | gulp.task('protractor', ['protractor:src']);
34 | gulp.task('protractor:src', ['serve:e2e', 'webdriver-update'], runProtractor);
35 | gulp.task('protractor:dist', ['serve:e2e-dist', 'webdriver-update'], runProtractor);
36 |
--------------------------------------------------------------------------------
/src/components/shelves/shelves.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | angular.module('polestar')
4 | .directive('shelves', function() {
5 |
6 | return {
7 | templateUrl: 'components/shelves/shelves.html',
8 | restrict: 'E',
9 | scope: {},
10 | replace: true,
11 | controller: function($scope, vl, jsondiffpatch, Spec, Config, Dataset, Logger, Pills) {
12 | $scope.Spec = Spec;
13 | $scope.schema = vl.schema.schema;
14 | $scope.pills = Pills;
15 |
16 | $scope.markChange = function() {
17 | Logger.logInteraction(Logger.actions.MARK_CHANGE, Spec.spec.marktype);
18 | };
19 |
20 | $scope.transpose = function(){
21 | vl.Encoding.transpose(Spec.spec);
22 | };
23 |
24 | $scope.clear = function(){
25 | Spec.reset();
26 | };
27 |
28 | $scope.$watch('Spec.spec', function(spec, oldSpec) {
29 | Logger.logInteraction(Logger.actions.SPEC_CHANGE, spec, jsondiffpatch.diff(oldSpec, spec));
30 |
31 | Spec.update(spec);
32 | }, true /* watch equality rather than reference */);
33 | }
34 | };
35 | });
36 |
--------------------------------------------------------------------------------
/src/app/index.scss:
--------------------------------------------------------------------------------
1 | // FIXME should use normalize.scss version instead
2 | // but I got some errors so I don't want to spend too much time here now.
3 | @import "../assets/normalize.scss";
4 |
5 | // injector
6 | // endinjector
7 |
8 | $fa-font-path: "../../bower_components/fontawesome/fonts";
9 | @import "../../bower_components/fontawesome/scss/font-awesome.scss";
10 |
11 | @import "../../bower_components/angular-tooltips/dist/angular-tooltips";
12 |
13 | $iron: #ccc;
14 |
15 | .type-select {
16 | width: 60px;
17 | }
18 |
19 | .vgspec, .vlspec {
20 | min-height: 100px;
21 | }
22 |
23 | null-filter-directive {
24 | display: block;
25 | margin-bottom: 10px;
26 | }
27 |
28 | /** panes **/
29 |
30 | .pane.encoding-pane {
31 | width: 230px;
32 | flex-shrink: 0;
33 | }
34 |
35 |
36 | .pane.data-pane {
37 | width: 200px;
38 | flex-shrink: 0;
39 | }
40 |
41 |
42 | .pane.vis-pane{
43 | flex-grow: 1;
44 | }
45 |
46 | .pane.config-pane {
47 | flex-grow: 0.6;
48 | }
49 |
50 | .pane.vl-pane {
51 | flex-grow: 1;
52 | }
53 |
54 | .pane.vg-pane {
55 | flex-grow: 1.2;
56 | }
57 |
58 | #vis {
59 | @extend .persist-scroll;
60 | overflow: scroll;
61 | }
62 |
63 |
--------------------------------------------------------------------------------
/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "polestar",
3 | "version": "0.6.3",
4 | "authors": [
5 | "Interactive Data Lab (http://idl.cs.washington.edu)"
6 | ],
7 | "dependencies": {
8 | "zeptojs": "~1.1.4",
9 | "angular-cookies": "~1.4.1",
10 | "angular-touch": "~1.4.1",
11 | "angular-sanitize": "~1.4.1",
12 | "angular-ui-router": "~0.2.15",
13 | "angular": "~1.4.1",
14 | "papaparse": "~4.1.1",
15 | "angular-dragdrop": "~1.0.11",
16 | "angular-elastic": "~2.4.2",
17 | "angular-zeroclipboard": "~0.4.0",
18 | "lodash": "~3.10.0",
19 | "d3": "~3.5.6",
20 | "topojson": "~1.6.19",
21 | "fontawesome": "~4.3.0",
22 | "chronicle": "~1.0.9",
23 | "jsondiffpatch": "~0.1.33",
24 | "angular-tooltips": "~0.1.13",
25 | "z-schema": "~3.12.0",
26 | "angular-order-object-by": "~1.1.0",
27 | "angular-websql": "~1.0.2",
28 | "angular-local-storage": "~0.2.2",
29 | "datalib": "^1.3.0",
30 | "vega": "^1.5.0",
31 | "vega-lite-ui": "^0.7.14",
32 | "vega-lite": "^0.7.12"
33 | },
34 | "devDependencies": {
35 | "angular-mocks": "~1.4.1"
36 | },
37 | "resolutions": {
38 | "angular": "~1.4.1"
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/components/vgSpecEditor/vgSpecEditor.spec.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /* global vl:true */
4 |
5 | describe('Directive: vgSpecEditor', function() {
6 |
7 | // load the directive's module
8 | beforeEach(module('polestar'));
9 |
10 | beforeEach(module('polestar', function($provide) {
11 | $provide.constant('vl', vl); // vl is loaded by karma
12 |
13 | // mock directive (trodrigues's answer in http://stackoverflow.com/questions/17533052)
14 | $provide.factory('uiZeroclipDirective', function() {return {
15 | link: function() {}
16 | };});
17 | }));
18 |
19 | var element,
20 | scope;
21 |
22 | beforeEach(module('polestar', function($provide) {
23 | var mock = {
24 | vgSpec: {}
25 | };
26 | $provide.value('Spec', {chart: mock});
27 | }));
28 |
29 | beforeEach(inject(function($rootScope) {
30 | scope = $rootScope.$new();
31 | }));
32 |
33 | it('should show source code', inject(function($compile) {
34 | element = angular.element('');
35 | element = $compile(element)(scope);
36 | scope.$digest();
37 |
38 | expect(element.find('.vgspec').val()).to.eql('{}');
39 | }));
40 | });
41 |
--------------------------------------------------------------------------------
/src/components/lyraexport/lyraexport.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | angular.module('polestar')
4 | .directive('lyraExport', function() {
5 | return {
6 | template: 'Export to lyra',
7 | restrict: 'E',
8 | replace: true,
9 | scope: {},
10 | controller: function($scope, $timeout, Spec, Alerts) {
11 | $scope.export = function() {
12 | var vgSpec = Spec.vgSpec;
13 | if (!vgSpec) {
14 | Alerts.add('No vega spec present.');
15 | }
16 |
17 | // Hack needed. See https://github.com/uwdata/lyra/issues/214
18 | vgSpec.marks[0]['lyra.groupType'] = 'layer';
19 |
20 | var lyraURL = 'http://idl.cs.washington.edu/projects/lyra/app/';
21 | var lyraWindow = window.open(lyraURL, '_blank');
22 |
23 | // HACK
24 | // lyraWindow.onload doesn't work across domains
25 | $timeout(function() {
26 | Alerts.add('Please check whether lyra loaded the vega spec correctly. This feature is experimental and may not work.', 5000);
27 | lyraWindow.postMessage({spec: vgSpec}, lyraURL);
28 | }, 5000);
29 | };
30 | }
31 | };
32 | });
33 |
--------------------------------------------------------------------------------
/src/components/vlSpecEditor/vlSpecEditor.spec.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /* global vl:true */
4 |
5 | describe('Directive: vlSpecEditor', function() {
6 | // load the directive's module
7 | beforeEach(module('polestar'));
8 |
9 | beforeEach(module('polestar', function($provide) {
10 | $provide.constant('vl', vl); // vl is loaded by karma
11 |
12 | // mock directive (trodrigues's answer in http://stackoverflow.com/questions/17533052)
13 | $provide.factory('uiZeroclipDirective', function() {return {};});
14 | }));
15 |
16 |
17 |
18 | var element,
19 | scope;
20 |
21 | beforeEach(module('polestar', function($provide) {
22 | var mock = {
23 | cleanSpec: {},
24 | shorthand: 'point.'
25 | };
26 | $provide.value('Spec', {chart: mock});
27 | }));
28 |
29 | beforeEach(inject(function($rootScope) {
30 | scope = $rootScope.$new();
31 | }));
32 |
33 | it('should show source code', inject(function($compile) {
34 | element = angular.element('');
35 | element = $compile(element)(scope);
36 | scope.$digest();
37 |
38 | expect(element.find('.vlspec').val()).to.eql('{}');
39 | expect(element.find('.shorthand').val()).to.eql('point.');
40 | }));
41 | });
42 |
--------------------------------------------------------------------------------
/src/app/spec/spec.spec.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | /* global vl */
3 | /* jshint expr:true */
4 |
5 | describe('Service: Spec', function() {
6 |
7 | // load the service's module
8 | beforeEach(module('polestar'));
9 |
10 | beforeEach(module('polestar', function($provide) {
11 | $provide.constant('vl', vl); // vl is loaded by karma
12 | }));
13 |
14 | // instantiate service
15 | var Spec;
16 | beforeEach(inject(function(_Spec_) {
17 | Spec = _Spec_;
18 | }));
19 |
20 | it('should be defined', function() {
21 | expect(Spec).to.be.defined;
22 | });
23 |
24 | it('functions should be defined', function() {
25 | expect(Spec.reset).to.be.defined;
26 | expect(Spec.parseShorthand).to.be.defined;
27 | });
28 |
29 | describe('_removeEmptyFieldDefs', function() {
30 | describe('empty spec', function() {
31 | it('should be cleaned', function() {
32 | var spec = vl.schema.instantiate();
33 | Spec._removeEmptyFieldDefs(spec);
34 | expect(vl.keys(spec.encoding).length).to.eql(3); // color, size, shape
35 | });
36 | });
37 | });
38 |
39 | describe('updateSpec', function() {
40 | //TODO write tests
41 | });
42 |
43 | describe('resetSpec', function() {
44 | //TODO write tests
45 | });
46 | });
47 |
--------------------------------------------------------------------------------
/src/components/schemalistitem/schemalistitem.spec.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /* global vl:true */
4 |
5 | describe('Directive: schemaListItem', function () {
6 |
7 | // load the directive's module
8 | beforeEach(module('polestar', function($provide) {
9 | // mock vega
10 | $provide.constant('vg', {
11 | parse: {
12 | spec: function(spec, callback) {
13 | callback(function(opt) {
14 | // jshint unused:false
15 |
16 | return {
17 | width: function() {},
18 | height: function() {},
19 | update: function() {},
20 | renderer: function() {},
21 | on: function() {}
22 | };
23 | });
24 | }
25 | }
26 | });
27 | $provide.constant('vl', vl);
28 | }));
29 |
30 |
31 | var element,
32 | scope;
33 |
34 | beforeEach(inject(function ($rootScope) {
35 | scope = $rootScope.$new();
36 | }));
37 |
38 | it('should make hidden element visible', inject(function ($compile) {
39 | element = angular.element('');
40 | element = $compile(element)(scope);
41 | scope.$digest();
42 | expect(element.find('span.field-info').length).to.eql(1);
43 | }));
44 | });
--------------------------------------------------------------------------------
/gulp/inject.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var gulp = require('gulp');
4 |
5 | var paths = gulp.paths;
6 |
7 | var $ = require('gulp-load-plugins')();
8 |
9 | var wiredep = require('wiredep').stream,
10 | series = require('stream-series');
11 |
12 | gulp.task('inject', ['styles'], function () {
13 |
14 | var injectStyles = gulp.src([
15 | paths.tmp + '/serve/{app,components}/**/*.css',
16 | '!' + paths.tmp + '/serve/app/vendor.css'
17 | ], { read: false });
18 |
19 | var injectVendor = gulp.src([
20 | paths.src + '/vendor/**/*.js'
21 | ], { read: false });
22 |
23 | var injectScripts = gulp.src([
24 | paths.src + '/{app,components}/**/*.js',
25 | '!' + paths.src + '/{app,components}/**/*.spec.js',
26 | '!' + paths.src + '/{app,components}/**/*.mock.js'
27 | ]).pipe($.angularFilesort());
28 |
29 | var injectOptions = {
30 | ignorePath: [paths.src, paths.tmp + '/serve'],
31 | addRootSlash: false
32 | };
33 |
34 | var wiredepOptions = {
35 | directory: 'bower_components',
36 | exclude: [/bootstrap\.css/, /foundation\.css/],
37 | overrides: {
38 | angular: {
39 | dependencies: {
40 | jquery: '*'
41 | }
42 | }
43 | }
44 | };
45 |
46 | return gulp.src(paths.src + '/*.html')
47 | .pipe($.inject(injectStyles, injectOptions))
48 | .pipe($.inject(series(injectVendor, injectScripts), injectOptions))
49 | .pipe(wiredep(wiredepOptions))
50 | .pipe(gulp.dest(paths.tmp + '/serve'));
51 |
52 | });
53 |
--------------------------------------------------------------------------------
/src/components/shelves/shelves.spec.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /* global vl:true */
4 | /* jshint expr:true */
5 |
6 | describe('Directive: shelves', function() {
7 |
8 | // load the directive's module
9 | beforeEach(module('polestar'));
10 |
11 | beforeEach(module('polestar', function($provide) {
12 | $provide.constant('vl', vl); // vl is loaded by karma
13 | }));
14 |
15 | var element,
16 | scope,
17 | deferred;
18 |
19 | beforeEach(module('polestar', function($provide) {
20 | // add Directive suffix to mock directives
21 | $provide.value('fieldDefEditorDirective', {});
22 | $provide.value('functionSelectDirective', {});
23 | $provide.factory('VegaliteSpecSchema', function($q) {
24 | return {
25 | getSchema: function() {
26 | deferred = $q.defer();
27 | return deferred.promise;
28 | }
29 | };
30 | });
31 | }));
32 |
33 | beforeEach(inject(function($rootScope, $compile) {
34 | scope = $rootScope.$new();
35 |
36 | element = angular.element('');
37 | element = $compile(element)(scope);
38 | scope.$digest();
39 | }));
40 |
41 | it('should insert mark select', function() {
42 | expect(element.find('.markselect').length).to.eql(1);
43 | });
44 |
45 | it('should attach Spec and schema to scope', function() {
46 | var isolateScope = element.isolateScope();
47 | expect(isolateScope.Spec).to.be.defined;
48 | expect(isolateScope.schema).to.be.defined;
49 | });
50 | });
51 |
--------------------------------------------------------------------------------
/src/app/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | /* globals window */
3 |
4 | angular.module('polestar', [
5 | 'ngCookies',
6 | 'ngSanitize',
7 | 'ngTouch',
8 | 'ngDragDrop',
9 | 'monospaced.elastic',
10 | 'zeroclipboard',
11 | 'ui.router',
12 | 'ui.select',
13 | 'Chronicle',
14 | 'LocalStorageModule',
15 | '720kb.tooltips',
16 | 'ngOrderObjectBy',
17 | 'angular-websql',
18 | 'vlui'])
19 | .constant('_', window._)
20 | .constant('vl', window.vl)
21 | .constant('vg', window.vg)
22 | .constant('Papa', window.Papa)
23 | .constant('ZSchema', window.ZSchema)
24 | .constant('Tether', window.Tether)
25 | .constant('Drop', window.Drop)
26 | .constant('Blob', window.Blob)
27 | .constant('URL', window.URL)
28 | .constant('dl', window.dl)
29 | .constant('jsondiffpatch', window.jsondiffpatch)
30 | .config(function(consts) {
31 | window.vl.extend(consts, {
32 | appId: 'polestar'
33 | });
34 | })
35 | .config(function(uiZeroclipConfigProvider) {
36 | // config ZeroClipboard
37 | uiZeroclipConfigProvider.setZcConf({
38 | swfPath: 'bower_components/zeroclipboard/dist/ZeroClipboard.swf'
39 | });
40 | })
41 | .config(function(localStorageServiceProvider) {
42 | localStorageServiceProvider.setPrefix('polestar');
43 | })
44 | .config(function($stateProvider, $urlRouterProvider) {
45 | $stateProvider
46 | .state('home', {
47 | url: '/',
48 | templateUrl: 'app/main/main.html',
49 | controller: 'MainCtrl'
50 | });
51 |
52 | $urlRouterProvider.otherwise('/');
53 | });
54 |
--------------------------------------------------------------------------------
/gulp/styles.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var gulp = require('gulp');
4 |
5 | var paths = gulp.paths;
6 |
7 | var $ = require('gulp-load-plugins')();
8 |
9 | gulp.task('styles', function () {
10 |
11 | var sassOptions = {
12 | style: 'expanded'
13 | };
14 |
15 | var injectFiles = gulp.src([
16 | 'bower_components/vega-lite-ui/vlui.scss',
17 | paths.src + '/{app,components}/**/*.scss',
18 | '!' + paths.src + '/app/index.scss',
19 | '!' + paths.src + '/app/vendor.scss'
20 | ], { read: false });
21 |
22 | var injectOptions = {
23 | transform: function(filePath) {
24 | filePath = filePath.replace(paths.src + '/app/', '');
25 | filePath = filePath.replace(paths.src + '/components/', '../components/');
26 | return '@import \'' + filePath + '\';';
27 | },
28 | starttag: '// injector',
29 | endtag: '// endinjector',
30 | addRootSlash: false
31 | };
32 |
33 | var indexFilter = $.filter('index.scss');
34 |
35 | return gulp.src([
36 | paths.src + '/app/index.scss',
37 | paths.src + '/app/vendor.scss'
38 | ])
39 | .pipe(indexFilter)
40 | .pipe($.inject(injectFiles, injectOptions))
41 | .pipe(indexFilter.restore())
42 | // TODO make compass work
43 | // .pipe($.compass({
44 | // project: paths.src +'/app/',
45 | // css: paths.tmp + '/serve/app/'
46 | // }))
47 | .pipe($.sass(sassOptions))
48 |
49 | .pipe($.autoprefixer())
50 | .on('error', function handleError(err) {
51 | console.error(err.toString());
52 | this.emit('end');
53 | })
54 | .pipe(gulp.dest(paths.tmp + '/serve/app/'));
55 | });
56 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2015, University of Washington Interactive Data Lab.
2 | All rights reserved.
3 |
4 | Redistribution and use in source and binary forms, with or without
5 | modification, are permitted provided that the following conditions are met:
6 |
7 | * Redistributions of source code must retain the above copyright notice, this
8 | list of conditions and the following disclaimer.
9 |
10 | * Redistributions in binary form must reproduce the above copyright notice,
11 | this list of conditions and the following disclaimer in the documentation
12 | and/or other materials provided with the distribution.
13 |
14 | * Neither the name of the University of Washington Interactive Data Lab
15 | nor the names of its contributors may be used to endorse or promote products
16 | derived from this software without specific prior written permission.
17 |
18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 |
--------------------------------------------------------------------------------
/gulp/server.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var gulp = require('gulp');
4 |
5 | var paths = gulp.paths;
6 |
7 | var util = require('util');
8 |
9 | var browserSync = require('browser-sync');
10 |
11 | var middleware = require('./proxy');
12 |
13 | function browserSyncInit(baseDir, files, browser) {
14 | browser = browser === undefined ? 'google chrome' : browser;
15 |
16 | var routes = null;
17 | if(baseDir === paths.src || (util.isArray(baseDir) && baseDir.indexOf(paths.src) !== -1)) {
18 | routes = {
19 | '/bower_components': 'bower_components'
20 | };
21 | }
22 |
23 | browserSync.instance = browserSync.init(files, {
24 | startPath: '/',
25 | server: {
26 | baseDir: baseDir,
27 | middleware: middleware,
28 | routes: routes
29 | },
30 | browser: browser
31 | });
32 | }
33 |
34 | gulp.task('serve', ['watch', 'jshint'], function () {
35 | browserSyncInit([
36 | paths.tmp + '/serve',
37 | paths.src
38 | ], [
39 | paths.tmp + '/serve/{app,components}/**/*.css',
40 | paths.src + '/{app,components}/**/*.js',
41 | paths.src + 'src/assets/images/**/*',
42 | paths.src + 'src/assets/data/*',
43 | paths.tmp + '/serve/*.html',
44 | paths.tmp + '/serve/{app,components}/**/*.html',
45 | paths.src + '/{app,components}/**/*.html'
46 | ]);
47 |
48 | gulp.start('test:auto');
49 | });
50 |
51 | gulp.task('serve:dist', ['build'], function () {
52 | browserSyncInit(paths.dist);
53 | });
54 |
55 | gulp.task('serve:e2e', ['inject'], function () {
56 | browserSyncInit([paths.tmp + '/serve', paths.src], null, []);
57 | });
58 |
59 | gulp.task('serve:e2e-dist', ['build'], function () {
60 | browserSyncInit(paths.dist, null, []);
61 | });
62 |
--------------------------------------------------------------------------------
/src/data/crimea.json:
--------------------------------------------------------------------------------
1 | [
2 | { "date": "4/1854", "wounds": 0, "other": 110, "disease": 110 },
3 | { "date": "5/1854", "wounds": 0, "other": 95, "disease": 105 },
4 | { "date": "6/1854", "wounds": 0, "other": 40, "disease": 95 },
5 | { "date": "7/1854", "wounds": 0, "other": 140, "disease": 520 },
6 | { "date": "8/1854", "wounds": 20, "other": 150, "disease": 800 },
7 | { "date": "9/1854", "wounds": 220, "other": 230, "disease": 740 },
8 | { "date": "10/1854", "wounds": 305, "other": 310, "disease": 600 },
9 | { "date": "11/1854", "wounds": 480, "other": 290, "disease": 820 },
10 | { "date": "12/1854", "wounds": 295, "other": 310, "disease": 1100 },
11 | { "date": "1/1855", "wounds": 230, "other": 460, "disease": 1440 },
12 | { "date": "2/1855", "wounds": 180, "other": 520, "disease": 1270 },
13 | { "date": "3/1855", "wounds": 155, "other": 350, "disease": 935 },
14 | { "date": "4/1855", "wounds": 195, "other": 195, "disease": 560 },
15 | { "date": "5/1855", "wounds": 180, "other": 155, "disease": 550 },
16 | { "date": "6/1855", "wounds": 330, "other": 130, "disease": 650 },
17 | { "date": "7/1855", "wounds": 260, "other": 130, "disease": 430 },
18 | { "date": "8/1855", "wounds": 290, "other": 110, "disease": 490 },
19 | { "date": "9/1855", "wounds": 355, "other": 100, "disease": 290 },
20 | { "date": "10/1855", "wounds": 135, "other": 95, "disease": 245 },
21 | { "date": "11/1855", "wounds": 100, "other": 140, "disease": 325 },
22 | { "date": "12/1855", "wounds": 40, "other": 120, "disease": 215 },
23 | { "date": "1/1856", "wounds": 0, "other": 160, "disease": 160 },
24 | { "date": "2/1856", "wounds": 0, "other": 100, "disease": 100 },
25 | { "date": "3/1856", "wounds": 0, "other": 125, "disease": 90 }
26 | ]
--------------------------------------------------------------------------------
/gulp/proxy.js:
--------------------------------------------------------------------------------
1 | /*jshint unused:false */
2 |
3 | /***************
4 |
5 | This file allow to configure a proxy system plugged into BrowserSync
6 | in order to redirect backend requests while still serving and watching
7 | files from the web project
8 |
9 | IMPORTANT: The proxy is disabled by default.
10 |
11 | If you want to enable it, watch at the configuration options and finally
12 | change the `module.exports` at the end of the file
13 |
14 | ***************/
15 |
16 | 'use strict';
17 |
18 | var httpProxy = require('http-proxy');
19 | var chalk = require('chalk');
20 |
21 | /*
22 | * Location of your backend server
23 | */
24 | var proxyTarget = 'http://server/context/';
25 |
26 | var proxy = httpProxy.createProxyServer({
27 | target: proxyTarget
28 | });
29 |
30 | proxy.on('error', function(error, req, res) {
31 | res.writeHead(500, {
32 | 'Content-Type': 'text/plain'
33 | });
34 |
35 | console.error(chalk.red('[Proxy]'), error);
36 | });
37 |
38 | /*
39 | * The proxy middleware is an Express middleware added to BrowserSync to
40 | * handle backend request and proxy them to your backend.
41 | */
42 | function proxyMiddleware(req, res, next) {
43 | /*
44 | * This test is the switch of each request to determine if the request is
45 | * for a static file to be handled by BrowserSync or a backend request to proxy.
46 | *
47 | * The existing test is a standard check on the files extensions but it may fail
48 | * for your needs. If you can, you could also check on a context in the url which
49 | * may be more reliable but can't be generic.
50 | */
51 | if (/\.(html|css|js|png|jpg|jpeg|gif|ico|xml|rss|txt|eot|svg|ttf|woff|cur)(\?((r|v|rel|rev)=[\-\.\w]*)?)?$/.test(req.url)) {
52 | next();
53 | } else {
54 | proxy.web(req, res);
55 | }
56 | }
57 |
58 | /*
59 | * This is where you activate or not your proxy.
60 | *
61 | * The first line activate if and the second one ignored it
62 | */
63 |
64 | //module.exports = [proxyMiddleware];
65 | module.exports = [];
66 |
--------------------------------------------------------------------------------
/src/components/fielddefeditor/fielddefeditor.spec.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /* global vl:true */
4 |
5 | describe('Directive: fieldDefEditor', function() {
6 |
7 | // load the directive's module
8 | beforeEach(module('polestar', function($provide) {
9 | $provide.constant('vl', vl);
10 | $provide.constant('Drop', function() {});
11 | }));
12 |
13 | var element, scope, $compile;
14 |
15 | beforeEach(module('polestar', function($provide) {
16 | $provide.constant('Dataset', {
17 | stats: {
18 | a: {}
19 | },
20 | onUpdate: []
21 | });
22 | }));
23 |
24 | beforeEach(inject(function($rootScope, _$compile_) {
25 | scope = $rootScope.$new();
26 | scope.encType = 'x';
27 | scope.enc = {'x': {}};
28 |
29 | $compile = _$compile_;
30 | }));
31 |
32 | it('should show title', function() {
33 | element = angular.element('');
34 | element = $compile(element)(scope);
35 | scope.$digest();
36 |
37 | expect(element.find('.shelf-label').text().trim()).to.eql('x');
38 | });
39 |
40 | describe('fieldDrop', function() {
41 | it('should initially have placeholder', function() {
42 | element = angular.element('');
43 | element = $compile(element)(scope);
44 | scope.$digest();
45 | expect(element.find('.placeholder').length).to.eql(1);
46 | });
47 |
48 | it('should show correct field name when dropped', function() {
49 | // jshint unused:false
50 | //TODO
51 | });
52 | });
53 |
54 | describe('shelfProperties', function() {
55 | it('should change properties correctly', function() {
56 | // jshint unused:false
57 | //TODO
58 | });
59 | });
60 |
61 | describe('shelfFunctions', function() {
62 | it('should change function correctly', function() {
63 | // jshint unused:false
64 | //TODO
65 | });
66 | });
67 | });
68 |
--------------------------------------------------------------------------------
/.yo-rc.json:
--------------------------------------------------------------------------------
1 | {
2 | "generator-gulp-angular": {
3 | "props": {
4 | "paths": {
5 | "src": "src",
6 | "dist": "dist",
7 | "e2e": "e2e",
8 | "tmp": ".tmp"
9 | },
10 | "angularVersion": "~1.3.4",
11 | "angularModules": [
12 | {
13 | "name": "angular-animate",
14 | "module": "ngAnimate"
15 | },
16 | {
17 | "name": "angular-cookies",
18 | "module": "ngCookies"
19 | },
20 | {
21 | "name": "angular-touch",
22 | "module": "ngTouch"
23 | },
24 | {
25 | "name": "angular-sanitize",
26 | "module": "ngSanitize"
27 | }
28 | ],
29 | "jQuery": {
30 | "name": "zeptojs",
31 | "version": "~1.1.4"
32 | },
33 | "resource": {
34 | "name": null,
35 | "version": null,
36 | "module": null
37 | },
38 | "router": {
39 | "name": "angular-ui-router",
40 | "version": "~0.2.13",
41 | "module": "ui.router"
42 | },
43 | "ui": {
44 | "key": "none",
45 | "name": null,
46 | "version": null,
47 | "module": null
48 | },
49 | "cssPreprocessor": {
50 | "key": "node-sass",
51 | "extension": "scss",
52 | "module": "gulp-sass",
53 | "version": "~1.1.0"
54 | },
55 | "jsPreprocessor": {
56 | "key": "none",
57 | "extension": "js",
58 | "srcExtension": "js",
59 | "module": null,
60 | "version": null
61 | },
62 | "htmlPreprocessor": {
63 | "key": "none",
64 | "extension": "html",
65 | "module": null,
66 | "version": null
67 | },
68 | "bootstrapComponents": {
69 | "name": null,
70 | "version": null,
71 | "key": null,
72 | "module": null
73 | },
74 | "foundationComponents": {
75 | "name": null,
76 | "version": null,
77 | "key": null,
78 | "module": null
79 | }
80 | }
81 | }
82 | }
--------------------------------------------------------------------------------
/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Pole✭
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
57 |
58 |
--------------------------------------------------------------------------------
/src/app/main/main.controller.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | angular.module('polestar')
4 | .controller('MainCtrl', function($scope, $document, Spec, Dataset, Config, consts, Chronicle, Logger, Bookmarks) {
5 | $scope.Spec = Spec;
6 | $scope.Dataset = Dataset;
7 | $scope.Config = Config;
8 | $scope.Logger = Logger;
9 | $scope.Bookmarks = Bookmarks;
10 | $scope.consts = consts;
11 | $scope.showDevPanel = false;
12 |
13 | // undo/redo support
14 |
15 | $scope.canUndo = false;
16 | $scope.canRedo = false;
17 |
18 | // bookmark
19 | $scope.showBookmark = false;
20 | $scope.hideBookmark = function() {
21 | $scope.showBookmark = false;
22 | };
23 |
24 | // load bookmarks from local storage
25 | Bookmarks.load();
26 |
27 | // initialize undo after we have a dataset
28 | Dataset.update(Dataset.dataset).then(function() {
29 | Config.updateDataset(Dataset.dataset);
30 |
31 | $scope.chron = Chronicle.record('Spec.spec', $scope, true,
32 | ['Dataset.dataset', 'Dataset.dataschema','Dataset.stats', 'Config.config']);
33 |
34 | $scope.canUndoRedo = function() {
35 | $scope.canUndo = $scope.chron.canUndo();
36 | $scope.canRedo = $scope.chron.canRedo();
37 | };
38 | $scope.chron.addOnAdjustFunction($scope.canUndoRedo);
39 | $scope.chron.addOnUndoFunction($scope.canUndoRedo);
40 | $scope.chron.addOnRedoFunction($scope.canUndoRedo);
41 |
42 | $scope.chron.addOnUndoFunction(function() {
43 | Logger.logInteraction(Logger.actions.UNDO);
44 | });
45 | $scope.chron.addOnRedoFunction(function() {
46 | Logger.logInteraction(Logger.actions.REDO);
47 | });
48 |
49 | angular.element($document).on('keydown', function(e) {
50 | if (e.keyCode === 'Z'.charCodeAt(0) && (e.ctrlKey || e.metaKey) && !e.shiftKey) {
51 | $scope.chron.undo();
52 | $scope.$digest();
53 | return false;
54 | } else if (e.keyCode === 'Y'.charCodeAt(0) && (e.ctrlKey || e.metaKey)) {
55 | $scope.chron.redo();
56 | $scope.$digest();
57 | return false;
58 | } else if (e.keyCode === 'Z'.charCodeAt(0) && (e.ctrlKey || e.metaKey) && e.shiftKey) {
59 | $scope.chron.redo();
60 | $scope.$digest();
61 | return false;
62 | }
63 | });
64 | });
65 | });
66 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "polestar",
3 | "version": "0.6.3",
4 | "description": "Visualization specification interface.",
5 | "repository": {
6 | "type": "git",
7 | "url": "https://github.com/uwdata/polestar.git"
8 | },
9 | "author": {
10 | "name": "UW Interactive Data Lab",
11 | "url": "http://idl.cs.washington.edu"
12 | },
13 | "collaborators": [
14 | "Dominik Moritz (http://domoritz.de)",
15 | "Kanit Wongsuphasawat (http://kanitw.yellowpigz.com)",
16 | "Jeffrey Heer (http://jheer.org)"
17 | ],
18 | "license": "BSD-3-Clause",
19 | "scripts": {
20 | "test": "gulp test"
21 | },
22 | "devDependencies": {
23 | "browser-sync": "~2.7.13",
24 | "chalk": "~1.0.0",
25 | "del": "~1.2.0",
26 | "gulp": "~3.9.0",
27 | "gulp-angular-filesort": "^1.1.1",
28 | "gulp-angular-templatecache": "^1.7.0",
29 | "gulp-autoprefixer": "~2.3.1",
30 | "gulp-bump": "^0.3.1",
31 | "gulp-compass": "^2.1.0",
32 | "gulp-consolidate": "~0.1.2",
33 | "gulp-csso": "~1.0.0",
34 | "gulp-filter": "~2.0.2",
35 | "gulp-flatten": "~0.1.0",
36 | "gulp-inject": "~1.3.1",
37 | "gulp-jshint": "~1.11.1",
38 | "gulp-karma": "~0.0.4",
39 | "gulp-load-plugins": "~1.0.0-rc",
40 | "gulp-minify-html": "~1.0.3",
41 | "gulp-ng-annotate": "^1.0.0",
42 | "gulp-protractor": "~1.0.0",
43 | "gulp-rename": "~1.2.2",
44 | "gulp-replace": "~0.5.3",
45 | "gulp-rev": "~5.0.1",
46 | "gulp-rev-replace": "~0.4.2",
47 | "gulp-sass": "~2.0.3",
48 | "gulp-size": "~1.2.2",
49 | "gulp-uglify": "~1.2.0",
50 | "gulp-useref": "~1.2.0",
51 | "http-proxy": "~1.11.1",
52 | "jshint-stylish": "~2.0.1",
53 | "karma-chai": "^0.1.0",
54 | "karma-chai-jquery": "^1.0.0",
55 | "karma-chrome-launcher": "^0.2.0",
56 | "karma-jquery": "^0.1.0",
57 | "karma-mocha": "^0.2.0",
58 | "karma-mocha-reporter": "^1.0.2",
59 | "karma-phantomjs-launcher": "~0.2.0",
60 | "karma-sinon-chai": "^1.0.0",
61 | "main-bower-files": "~2.8.2",
62 | "phantomjs-polyfill": "0.0.1",
63 | "protractor": "~2.1.0",
64 | "request": "^2.58.0",
65 | "require-dir": "~0.3.0",
66 | "stream-series": "^0.1.1",
67 | "uglify-save-license": "~0.4.1",
68 | "wiredep": "^3.0.0-beta",
69 | "yargs": "^3.14.0"
70 | },
71 | "engines": {
72 | "node": ">=0.10.0"
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/src/components/fielddefeditor/fielddefeditor.scss:
--------------------------------------------------------------------------------
1 | /* FIXME should be in vl-ui*/
2 | $pill-radius: 3px;
3 | $pill-height: 22px;
4 | $pill-min-width: 150px;
5 | $text-color: #212121;
6 |
7 | .shelf-group{
8 | border: 1px solid #ddd;
9 | border-radius: $pill-radius;
10 | margin-bottom: 5px;
11 | font-size: 11px;
12 | }
13 |
14 | .shelf{
15 | border-radius: $pill-radius;
16 | background-color: #ddd;
17 | width: 100%;
18 | display: flex;
19 | height: 22px;
20 |
21 | &.disabled {
22 | opacity: 0.5;
23 | }
24 |
25 | .shelf-label {
26 | @extend .noselect;
27 | display: block;
28 | width: 40px;
29 | margin: 0 0.2rem;
30 | // text-align: right;
31 | line-height: $pill-height;
32 | cursor: pointer;
33 | flex-shrink: 0;
34 |
35 | .fa {
36 | margin-top: 4px;
37 | opacity: 0.5;
38 | }
39 | &.expanded .fa, &:hover .fa {
40 | opacity: 1;
41 | }
42 | }
43 |
44 | .field-drop {
45 | display: flex;
46 | flex-grow: 1;
47 | width: auto;
48 | box-sizing: border-box;
49 | border: 1px solid transparent;
50 | border-radius: 3px;
51 | height: $pill-height;
52 | line-height: $pill-height;
53 |
54 | .field-info {
55 | margin-right: 0;
56 | }
57 |
58 | .placeholder {
59 | display: block;
60 | width: 100%;
61 | padding: 0 0.5em;
62 | border: 1px solid #ccc;
63 | background-color: white;
64 | line-height: $pill-height - 2;
65 | border-radius: $pill-radius;
66 | text-overflow: ellipsis;
67 | font-weight: normal;
68 | color: #aaa;
69 | }
70 | }
71 |
72 | .field-drop.drop-active {
73 | border: 1px dashed #4CAF50;
74 |
75 | background-color: #C8E6C9;
76 | .placeholder {
77 | background-color: #C8E6C9;
78 | color: $text-color;
79 | }
80 | .field-info {
81 | opacity: 0.5;
82 | }
83 | }
84 | }
85 |
86 | .shelf-properties {
87 | min-width: 250px;
88 | }
89 |
90 | .shelf-functions {
91 | width: 160px;
92 | }
93 |
94 | .shelf-properties, .shelf-functions{
95 | label {
96 | display: inline-block;
97 |
98 | &.prop-label {
99 | width: 60px;
100 | text-align: right;
101 | margin-right: 3px;
102 | }
103 |
104 | &.func-label, &.type-label {
105 | min-width: 75px;
106 | margin-right: 5px;
107 | }
108 | }
109 | }
110 |
--------------------------------------------------------------------------------
/src/components/functionselect/functionselect.spec.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /* global vl:true */
4 |
5 | describe('Directive: functionSelect', function() {
6 |
7 | // load the directive's module
8 | beforeEach(module('polestar', function($provide) {
9 | $provide.constant('vl', vl);
10 | }));
11 |
12 | var element, scope, $compile;
13 |
14 | beforeEach(inject(function($rootScope, _$compile_) {
15 | scope = $rootScope.$new();
16 | scope.schema = {
17 | properties: {
18 | aggregate: {
19 | supportedEnums: {
20 | Q: ['a', 'b'],
21 | undefined: []
22 | }
23 | },
24 | timeUnit: {
25 | supportedEnums: {
26 | T: ['f1','f2']
27 | }
28 | },
29 | bin: {
30 | supportedTypes: {
31 | Q: true
32 | }
33 | }
34 | }
35 | };
36 | scope.pills = {
37 | x: { type: 'Q', name: 'x'},
38 | y: { aggregate: 'count', name:'*'},
39 | color: { type: 'T', name: 'c'},
40 | update: function() {}
41 | };
42 | scope.enc = {
43 | x: { type: 'Q', name: 'x'},
44 | y: { aggregate: 'count', name:'*'},
45 | color: { type: 'T', name: 'c'},
46 | };
47 | scope.encType = 'x';
48 | scope.encType2 = 'y';
49 | scope.encType3 = 'color';
50 |
51 | $compile = _$compile_;
52 | }));
53 |
54 | it('should have correct number of radio', function() {
55 | element = angular.element('');
56 | element = $compile(element)(scope);
57 | scope.$digest();
58 | expect(element.find('input').length).to.eql(4);
59 | });
60 |
61 | it('should have correct number of radio', function() {
62 | element = angular.element('');
63 | element = $compile(element)(scope);
64 | scope.$digest();
65 | expect(element.find('input').length).to.eql(3);
66 | });
67 |
68 | it('should not show other options for count field', function() {
69 | element = angular.element('');
70 | element = $compile(element)(scope);
71 | scope.$digest();
72 | scope.pills.y = { aggregate:'count', name: '*'};
73 | scope.$digest();
74 | expect(element.find('input').length).to.eql(1);
75 | });
76 |
77 | });
78 |
--------------------------------------------------------------------------------
/karma.conf.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var wiredep = require('wiredep');
4 |
5 | var bowerDeps = wiredep({
6 | directory: 'bower_components',
7 | dependencies: true,
8 | devDependencies: true
9 | });
10 |
11 | var src = 'src',
12 | tmp = '.tmp';
13 |
14 | var testFiles = [
15 | // add bind polyfill since Function.prototype.bind is missing from PhantomJS
16 | './node_modules/phantomjs-polyfill/bind-polyfill.js',
17 | ].concat(bowerDeps.js).concat([
18 | src + '/app/index.js',
19 | src + '/**/*.js',
20 | src + '/vendor/*.js',
21 | tmp + '/partials/templateCacheHtml.js'
22 | ]);
23 |
24 | // console.log('testFiles', testFiles);
25 |
26 | module.exports = function(config) {
27 | config.set({
28 |
29 | // base path that will be used to resolve all patterns (eg. files, exclude)
30 | basePath: '',
31 |
32 | // frameworks to use
33 | // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
34 | frameworks: ['mocha', 'chai-jquery', 'jquery-1.8.3', 'sinon-chai'],
35 |
36 | plugins: [
37 | 'karma-mocha',
38 | 'karma-chai',
39 | 'karma-sinon-chai',
40 | 'karma-chrome-launcher',
41 | 'karma-phantomjs-launcher',
42 | 'karma-jquery',
43 | 'karma-chai-jquery',
44 | 'karma-mocha-reporter'
45 | ],
46 |
47 | // list of files / patterns to load in the browser
48 | files: testFiles,
49 |
50 | // list of files to exclude
51 | exclude: [],
52 |
53 | // preprocess matching files before serving them to the browser
54 | // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
55 | preprocessors: {},
56 |
57 | // test results reporter to use
58 | // possible values: 'dots', 'progress'
59 | // available reporters: https://npmjs.org/browse/keyword/karma-reporter
60 | reporters: ['mocha'],
61 |
62 | // web server port
63 | port: 9875,
64 |
65 | // enable / disable colors in the output (reporters and logs)
66 | colors: true,
67 |
68 | // level of logging
69 | // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
70 | logLevel: config.LOG_INFO,
71 |
72 |
73 | // enable / disable watching file and executing tests whenever any file changes
74 | autoWatch: true,
75 |
76 | // start these browsers
77 | // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
78 | browsers: ['PhantomJS'],
79 |
80 | // Continuous Integration mode
81 | // if true, Karma captures browsers, runs the tests and exits
82 | singleRun: false,
83 |
84 | client: {
85 | mocha: {
86 | reporter: 'html', // change Karma's debug.html to the mocha web reporter
87 | ui: 'bdd'
88 | }
89 | }
90 | });
91 | };
92 |
--------------------------------------------------------------------------------
/src/components/shelves/shelves.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/gulp/build.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var gulp = require('gulp');
4 |
5 | var paths = gulp.paths;
6 |
7 | var $ = require('gulp-load-plugins')({
8 | pattern: ['gulp-*', 'main-bower-files', 'uglify-save-license', 'del']
9 | });
10 |
11 | gulp.task('partials', function () {
12 | return gulp.src([
13 | paths.src + '/{app,components}/**/*.html',
14 | paths.tmp + '/{app,components}/**/*.html'
15 | ])
16 | .pipe($.minifyHtml({
17 | empty: true,
18 | spare: true,
19 | quotes: true
20 | }))
21 | .pipe($.angularTemplatecache('templateCacheHtml.js', {
22 | module: 'polestar'
23 | }))
24 | .pipe(gulp.dest(paths.tmp + '/partials/'));
25 | });
26 |
27 | gulp.task('html', ['inject', 'partials'], function () {
28 | var partialsInjectFile = gulp.src(paths.tmp + '/partials/templateCacheHtml.js', { read: false });
29 | var partialsInjectOptions = {
30 | starttag: '',
31 | ignorePath: paths.tmp + '/partials',
32 | addRootSlash: false
33 | };
34 |
35 | var htmlFilter = $.filter('*.html');
36 | var jsFilter = $.filter('**/*.js');
37 | var cssFilter = $.filter('**/*.css');
38 | var assets;
39 |
40 | return gulp.src(paths.tmp + '/serve/*.html')
41 | .pipe($.inject(partialsInjectFile, partialsInjectOptions))
42 | .pipe(assets = $.useref.assets())
43 | .pipe($.rev())
44 | .pipe(jsFilter)
45 | .pipe($.ngAnnotate())
46 | .pipe($.uglify({preserveComments: $.uglifySaveLicense}))
47 | .pipe(jsFilter.restore())
48 | .pipe(cssFilter)
49 | .pipe($.replace('../../bower_components/fontawesome/fonts', '../fonts'))
50 | .pipe($.csso())
51 | .pipe(cssFilter.restore())
52 | .pipe(assets.restore())
53 | .pipe($.useref())
54 | .pipe($.revReplace())
55 | .pipe(htmlFilter)
56 | .pipe($.minifyHtml({
57 | empty: true,
58 | spare: true,
59 | quotes: true
60 | }))
61 | .pipe(htmlFilter.restore())
62 | .pipe(gulp.dest(paths.dist + '/'))
63 | .pipe($.size({ title: paths.dist + '/', showFiles: true }));
64 | });
65 |
66 | gulp.task('assets', function () {
67 | return gulp.src(paths.src + '/assets/**/*')
68 | .pipe(gulp.dest(paths.dist + '/assets/'));
69 | });
70 |
71 | gulp.task('data', function () {
72 | return gulp.src(paths.src + '/data/*')
73 | .pipe(gulp.dest(paths.dist + '/data/'));
74 | });
75 |
76 | gulp.task('fonts', function () {
77 | return gulp.src($.mainBowerFiles())
78 | .pipe($.filter('**/*.{eot,svg,ttf,woff,woff2}'))
79 | .pipe($.flatten())
80 | .pipe(gulp.dest(paths.dist + '/fonts/'));
81 | });
82 |
83 | gulp.task('misc', function () {
84 | return gulp.src(paths.src + '/**/*.ico')
85 | .pipe(gulp.dest(paths.dist + '/'));
86 | });
87 |
88 | gulp.task('zeroclipboard', function () {
89 | return gulp.src('bower_components/zeroclipboard/dist/ZeroClipboard.swf')
90 | .pipe(gulp.dest(paths.dist + '/bower_components/zeroclipboard/dist/'));
91 | });
92 |
93 | gulp.task('clean', function (done) {
94 | $.del([paths.dist + '/', paths.tmp + '/'], done);
95 | });
96 |
97 | gulp.task('build', ['html', 'assets', 'data', 'fonts', 'misc', 'zeroclipboard']);
98 |
--------------------------------------------------------------------------------
/src/app/main/main.html:
--------------------------------------------------------------------------------
1 |
2 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
Data
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
85 |
--------------------------------------------------------------------------------
/src/components/fielddefeditor/fielddefeditor.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | angular.module('polestar')
4 | .directive('fieldDefEditor', function(Dataset, Pills, _, Drop, Logger) {
5 | return {
6 | templateUrl: 'components/fielddefeditor/fielddefeditor.html',
7 | restrict: 'E',
8 | replace: true,
9 | scope: {
10 | encType: '=',
11 | enc: '=',
12 |
13 | schema: '=fieldDefSchema',
14 | marktype: '='
15 | },
16 | link: function(scope, element /*, attrs*/) {
17 | var propsPopup, funcsPopup;
18 |
19 | scope.allowedCasting = {
20 | Q: ['Q', 'O', 'N'],
21 | O: ['O', 'N'],
22 | N: ['N', 'O'],
23 | T: ['T', 'O', 'N'],
24 | G: ['G', 'O', 'N']
25 | };
26 |
27 | scope.Dataset = Dataset;
28 | scope.typeNames = Dataset.typeNames;
29 | scope.pills = Pills.pills;
30 |
31 | function fieldPill(){
32 | return Pills.pills[scope.encType];
33 | }
34 |
35 | propsPopup = new Drop({
36 | content: element.find('.shelf-properties')[0],
37 | target: element.find('.shelf-label')[0],
38 | position: 'bottom left',
39 | openOn: 'click'
40 | });
41 |
42 | scope.fieldInfoPopupContent = element.find('.shelf-functions')[0];
43 |
44 | scope.removeField = function() {
45 | Pills.remove(scope.encType);
46 | };
47 |
48 | scope.fieldDragStart = function() {
49 | Pills.dragStart(Pills[scope.encType], scope.encType);
50 | };
51 |
52 | scope.fieldDragStop = function() {
53 | Pills.dragStop();
54 | };
55 |
56 | scope.fieldDropped = function() {
57 | var pill = fieldPill();
58 | if (funcsPopup) {
59 | funcsPopup = null;
60 | }
61 |
62 | // validate type
63 | var types = scope.schema.properties.type.enum;
64 | if (!_.contains(types, pill.type)) {
65 | // if existing type is not supported
66 | pill.type = types[0];
67 | }
68 |
69 | // TODO validate timeUnit / aggregate
70 |
71 | Pills.dragDrop(scope.encType);
72 | Logger.logInteraction(Logger.actions.FIELD_DROP, scope.enc[scope.encType]);
73 | };
74 |
75 | // when each of the fieldPill property in fieldDef changes, update the pill
76 | // ['name', 'type', 'aggregate', 'bin', 'timeUnit'].forEach( function(prop) {
77 | // scope.$watch('enc[encType].'+prop, function(val){
78 | // var pill = fieldPill();
79 | // if(pill && val !== pill[prop]){
80 | // pill[prop] = val;
81 | // }
82 | // }, true);
83 | // });
84 |
85 | scope.$watch('enc[encType]', function(field) {
86 | Pills.pills[scope.encType] = field ? _.cloneDeep(field) : {};
87 | }, true);
88 |
89 | scope.$watchGroup(['allowedCasting[Dataset.dataschema.byName[enc[encType].name].type]', 'enc[encType].aggregate'], function(arr){
90 | var allowedTypes = arr[0], aggregate=arr[1];
91 | scope.allowedTypes = aggregate === 'count' ? ['Q'] : allowedTypes;
92 | });
93 |
94 |
95 | }
96 |
97 | };
98 | });
99 |
--------------------------------------------------------------------------------
/src/data/burtin.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "Bacteria":"Aerobacter aerogenes",
4 | "Penicilin":870,
5 | "Streptomycin":1,
6 | "Neomycin":1.6,
7 | "Gram_Staining":"negative",
8 | "Genus": "other"
9 | },
10 | {
11 | "Bacteria":"Brucella abortus",
12 | "Penicilin":1,
13 | "Streptomycin":2,
14 | "Neomycin":0.02,
15 | "Gram_Staining":"negative",
16 | "Genus": "other"
17 | },
18 | {
19 | "Bacteria":"Brucella anthracis",
20 | "Penicilin":0.001,
21 | "Streptomycin":0.01,
22 | "Neomycin":0.007,
23 | "Gram_Staining":"positive",
24 | "Genus": "other"
25 | },
26 | {
27 | "Bacteria":"Diplococcus pneumoniae",
28 | "Penicilin":0.005,
29 | "Streptomycin":11,
30 | "Neomycin":10,
31 | "Gram_Staining":"positive",
32 | "Genus": "other"
33 | },
34 | {
35 | "Bacteria":"Escherichia coli",
36 | "Penicilin":100,
37 | "Streptomycin":0.4,
38 | "Neomycin":0.1,
39 | "Gram_Staining":"negative",
40 | "Genus": "other"
41 | },
42 | {
43 | "Bacteria":"Klebsiella pneumoniae",
44 | "Penicilin":850,
45 | "Streptomycin":1.2,
46 | "Neomycin":1,
47 | "Gram_Staining":"negative",
48 | "Genus": "other"
49 | },
50 | {
51 | "Bacteria":"Mycobacterium tuberculosis",
52 | "Penicilin":800,
53 | "Streptomycin":5,
54 | "Neomycin":2,
55 | "Gram_Staining":"negative",
56 | "Genus": "other"
57 | },
58 | {
59 | "Bacteria":"Proteus vulgaris",
60 | "Penicilin":3,
61 | "Streptomycin":0.1,
62 | "Neomycin":0.1,
63 | "Gram_Staining":"negative",
64 | "Genus": "other"
65 | },
66 | {
67 | "Bacteria":"Pseudomonas aeruginosa",
68 | "Penicilin":850,
69 | "Streptomycin":2,
70 | "Neomycin":0.4,
71 | "Gram_Staining":"negative",
72 | "Genus": "other"
73 | },
74 | {
75 | "Bacteria":"Salmonella (Eberthella) typhosa",
76 | "Penicilin":1,
77 | "Streptomycin":0.4,
78 | "Neomycin":0.008,
79 | "Gram_Staining":"negative",
80 | "Genus": "Salmonella"
81 | },
82 | {
83 | "Bacteria":"Salmonella schottmuelleri",
84 | "Penicilin":10,
85 | "Streptomycin":0.8,
86 | "Neomycin":0.09,
87 | "Gram_Staining":"negative",
88 | "Genus": "Salmonella"
89 | },
90 | {
91 | "Bacteria":"Staphylococcus albus",
92 | "Penicilin":0.007,
93 | "Streptomycin":0.1,
94 | "Neomycin":0.001,
95 | "Gram_Staining":"positive",
96 | "Genus": "Staphylococcus"
97 | },
98 | {
99 | "Bacteria":"Staphylococcus aureus",
100 | "Penicilin":0.03,
101 | "Streptomycin":0.03,
102 | "Neomycin":0.001,
103 | "Gram_Staining":"positive",
104 | "Genus": "Staphylococcus"
105 | },
106 | {
107 | "Bacteria":"Streptococcus fecalis",
108 | "Penicilin":1,
109 | "Streptomycin":1,
110 | "Neomycin":0.1,
111 | "Gram_Staining":"positive",
112 | "Genus": "Streptococcus"
113 | },
114 | {
115 | "Bacteria":"Streptococcus hemolyticus",
116 | "Penicilin":0.001,
117 | "Streptomycin":14,
118 | "Neomycin":10,
119 | "Gram_Staining":"positive",
120 | "Genus": "Streptococcus"
121 | },
122 | {
123 | "Bacteria":"Streptococcus viridans",
124 | "Penicilin":0.005,
125 | "Streptomycin":10,
126 | "Neomycin":40,
127 | "Gram_Staining":"positive",
128 | "Genus": "Streptococcus"
129 | }
130 | ]
--------------------------------------------------------------------------------
/src/data/driving.json:
--------------------------------------------------------------------------------
1 | [
2 | {"side": "left", "year": 1956, "miles": 3675, "gas": 2.38},
3 | {"side": "right", "year": 1957, "miles": 3706, "gas": 2.40},
4 | {"side": "bottom", "year": 1958, "miles": 3766, "gas": 2.26},
5 | {"side": "top", "year": 1959, "miles": 3905, "gas": 2.31},
6 | {"side": "right", "year": 1960, "miles": 3935, "gas": 2.27},
7 | {"side": "bottom", "year": 1961, "miles": 3977, "gas": 2.25},
8 | {"side": "right", "year": 1962, "miles": 4085, "gas": 2.22},
9 | {"side": "bottom", "year": 1963, "miles": 4218, "gas": 2.12},
10 | {"side": "bottom", "year": 1964, "miles": 4369, "gas": 2.11},
11 | {"side": "bottom", "year": 1965, "miles": 4538, "gas": 2.14},
12 | {"side": "top", "year": 1966, "miles": 4676, "gas": 2.14},
13 | {"side": "bottom", "year": 1967, "miles": 4827, "gas": 2.14},
14 | {"side": "right", "year": 1968, "miles": 5038, "gas": 2.13},
15 | {"side": "right", "year": 1969, "miles": 5207, "gas": 2.07},
16 | {"side": "right", "year": 1970, "miles": 5376, "gas": 2.01},
17 | {"side": "bottom", "year": 1971, "miles": 5617, "gas": 1.93},
18 | {"side": "bottom", "year": 1972, "miles": 5973, "gas": 1.87},
19 | {"side": "right", "year": 1973, "miles": 6154, "gas": 1.90},
20 | {"side": "left", "year": 1974, "miles": 5943, "gas": 2.34},
21 | {"side": "bottom", "year": 1975, "miles": 6111, "gas": 2.31},
22 | {"side": "bottom", "year": 1976, "miles": 6389, "gas": 2.32},
23 | {"side": "top", "year": 1977, "miles": 6630, "gas": 2.36},
24 | {"side": "bottom", "year": 1978, "miles": 6883, "gas": 2.23},
25 | {"side": "left", "year": 1979, "miles": 6744, "gas": 2.68},
26 | {"side": "left", "year": 1980, "miles": 6672, "gas": 3.30},
27 | {"side": "right", "year": 1981, "miles": 6732, "gas": 3.30},
28 | {"side": "right", "year": 1982, "miles": 6835, "gas": 2.92},
29 | {"side": "right", "year": 1983, "miles": 6943, "gas": 2.66},
30 | {"side": "right", "year": 1984, "miles": 7130, "gas": 2.48},
31 | {"side": "right", "year": 1985, "miles": 7323, "gas": 2.36},
32 | {"side": "left", "year": 1986, "miles": 7558, "gas": 1.76},
33 | {"side": "top", "year": 1987, "miles": 7770, "gas": 1.76},
34 | {"side": "bottom", "year": 1988, "miles": 8089, "gas": 1.68},
35 | {"side": "left", "year": 1989, "miles": 8397, "gas": 1.75},
36 | {"side": "top", "year": 1990, "miles": 8529, "gas": 1.88},
37 | {"side": "right", "year": 1991, "miles": 8535, "gas": 1.78},
38 | {"side": "right", "year": 1992, "miles": 8662, "gas": 1.69},
39 | {"side": "left", "year": 1993, "miles": 8855, "gas": 1.60},
40 | {"side": "bottom", "year": 1994, "miles": 8909, "gas": 1.59},
41 | {"side": "bottom", "year": 1995, "miles": 9150, "gas": 1.60},
42 | {"side": "top", "year": 1996, "miles": 9192, "gas": 1.67},
43 | {"side": "right", "year": 1997, "miles": 9416, "gas": 1.65},
44 | {"side": "bottom", "year": 1998, "miles": 9590, "gas": 1.39},
45 | {"side": "right", "year": 1999, "miles": 9687, "gas": 1.50},
46 | {"side": "top", "year": 2000, "miles": 9717, "gas": 1.89},
47 | {"side": "left", "year": 2001, "miles": 9699, "gas": 1.77},
48 | {"side": "bottom", "year": 2002, "miles": 9814, "gas": 1.64},
49 | {"side": "right", "year": 2003, "miles": 9868, "gas": 1.86},
50 | {"side": "left", "year": 2004, "miles": 9994, "gas": 2.14},
51 | {"side": "left", "year": 2005, "miles": 10067, "gas": 2.53},
52 | {"side": "right", "year": 2006, "miles": 10037, "gas": 2.79},
53 | {"side": "right", "year": 2007, "miles": 10025, "gas": 2.95},
54 | {"side": "left", "year": 2008, "miles": 9880, "gas": 3.31},
55 | {"side": "bottom", "year": 2009, "miles": 9657, "gas": 2.38},
56 | {"side": "left", "year": 2010, "miles": 9596, "gas": 2.61}
57 | ]
--------------------------------------------------------------------------------
/src/components/fielddefeditor/fielddefeditor.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 | {{ encType }}
7 |
8 |
9 |
14 |
15 |
31 |
32 |
33 |
34 | drop a field here
35 |
36 |
37 |
38 |
39 |
57 |
78 |
79 |
80 |
--------------------------------------------------------------------------------
/src/app/spec/spec.service.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /**
4 | * @ngdoc service
5 | * @name polestar.Spec
6 | * @description
7 | * # Spec
8 | * Service in the polestar.
9 | */
10 | angular.module('polestar')
11 | .service('Spec', function(_, vl, ZSchema, Alerts, Config, Dataset) {
12 | var Spec = {
13 | /** @type {Object} verbose spec edited by the UI */
14 | spec: null,
15 | chart:{
16 | /** @type {Object} concise spec generated */
17 | vlSpec: null,
18 | /** @type {Encoding} encoding object from the spec */
19 | encoding: null,
20 | /** @type {String} generated vl shorthand */
21 | shorthand: null,
22 | /** @type {Object} generated vega spec */
23 | vgSpec: null
24 | }
25 | };
26 |
27 | Spec._removeEmptyFieldDefs = function(spec) {
28 | spec.encoding = _.omit(spec.encoding, function(fieldDef, encType) {
29 | return !fieldDef || (fieldDef.name === undefined && fieldDef.value === undefined) ||
30 | (spec.marktype && ! vl.schema.schema.properties.encoding.properties[encType].supportedMarktypes[spec.marktype]);
31 | });
32 | };
33 |
34 | function deleteNulls(spec) {
35 | for (var i in spec) {
36 | if (_.isObject(spec[i])) {
37 | deleteNulls(spec[i]);
38 | }
39 | // This is why I hate js
40 | if (spec[i] === null ||
41 | spec[i] === undefined ||
42 | (_.isObject(spec[i]) && vl.keys(spec[i]).length === 0) ||
43 | spec[i] === []) {
44 | delete spec[i];
45 | }
46 | }
47 | }
48 |
49 | Spec.parseShorthand = function(newShorthand) {
50 | var newSpec = vl.Encoding.parseShorthand(newShorthand, Config.config).toSpec();
51 | Spec.parseSpec(newSpec);
52 | };
53 |
54 | // takes a partial spec
55 | Spec.parseSpec = function(newSpec) {
56 | Spec.spec = vl.schema.util.merge(Spec.instantiate(), newSpec);
57 | };
58 |
59 | Spec.instantiate = function() {
60 | var spec = vl.schema.instantiate();
61 |
62 | // we need to set the marktype because it doesn't have a default.
63 | spec.marktype = vl.schema.schema.properties.marktype.enum[0];
64 | spec.config = Config.config;
65 | spec.data = Config.data;
66 | return spec;
67 | };
68 |
69 | Spec.reset = function() {
70 | Spec.spec = Spec.instantiate();
71 | };
72 |
73 | // takes a full spec, validates it and then rebuilds everything
74 | Spec.update = function(spec) {
75 | spec = _.cloneDeep(spec || Spec.spec);
76 |
77 | Spec._removeEmptyFieldDefs(spec);
78 | deleteNulls(spec);
79 |
80 | // we may have removed enc
81 | if (!('encoding' in spec)) {
82 | spec.encoding = {};
83 | }
84 | var validator = new ZSchema();
85 |
86 | validator.setRemoteReference('http://json-schema.org/draft-04/schema', {});
87 |
88 | var schema = vl.schema.schema;
89 | // now validate the spec
90 | var valid = validator.validate(spec, schema);
91 |
92 | if (!valid) {
93 | //FIXME: move this dependency to directive/controller layer
94 | Alerts.add({
95 | msg: validator.getLastErrors()
96 | });
97 | } else {
98 | vl.extend(spec.config, Config.large());
99 | var encoding = vl.Encoding.fromSpec(spec),
100 | chart = Spec.chart;
101 |
102 | chart.fieldSet = Spec.spec.encoding;
103 | chart.vlSpec = spec;
104 | chart.cleanSpec = encoding.toSpec(false);
105 | chart.shorthand = encoding.toShorthand();
106 | console.log('chart', chart.vgSpec, chart.vlSpec);
107 | }
108 | };
109 |
110 | Spec.reset();
111 | Dataset.onUpdate.push(Spec.reset);
112 |
113 | return Spec;
114 | });
115 |
--------------------------------------------------------------------------------
/src/app/pills/pills.service.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /**
4 | * @ngdoc service
5 | * @name polestar.Pills
6 | * @description
7 | * # Pills
8 | * Service in the polestar.
9 | */
10 | angular.module('polestar')
11 | .service('Pills', function (vl, Spec, _, $window) {
12 | var encSchemaProps = vl.schema.schema.properties.encoding.properties;
13 |
14 | function instantiate(encType) {
15 | return vl.schema.util.instantiate(encSchemaProps[encType]);
16 | }
17 |
18 | var Pills = {
19 | pills: {}
20 | };
21 |
22 | Pills.getSchemaPill = function(field) {
23 | return {
24 | name: field.name,
25 | type: field.type,
26 | aggregate: field.aggregate
27 | };
28 | };
29 |
30 |
31 | /** copy value from the pill to the fieldDef */
32 | function updateFieldDef(enc, pill, encType){
33 | var type = pill.type,
34 | supportedRole = vl.schema.getSupportedRole(encType),
35 | dimensionOnly = supportedRole.dimension && !supportedRole.measure;
36 |
37 | // auto cast binning / time binning for dimension only encoding type.
38 | if (pill.name && dimensionOnly) {
39 | if (pill.aggregate==='count') {
40 | pill = {};
41 | $window.alert('COUNT not supported here!');
42 | } else if (type==='Q' && !pill.bin) {
43 | pill.aggregate = undefined;
44 | pill.bin = {maxbins: vl.schema.MAXBINS_DEFAULT};
45 | } else if(type==='T' && !pill.timeUnit) {
46 | pill.timeUnit = vl.schema.defaultTimeFn;
47 | }
48 | } else if (!pill.name) {
49 | // no name, it's actually the empty shelf that
50 | // got processed in the opposite direction
51 | pill = {};
52 | }
53 |
54 | // filter unsupported properties
55 | var base = instantiate(encType),
56 | shelfProps = encSchemaProps[encType].properties;
57 | // console.log('updateFieldDef', encType, base, '<-', pill);
58 | for (var prop in shelfProps) {
59 | if (pill[prop]) {
60 | if (prop==='value' && pill.name) {
61 | // only copy value if name is not defined
62 | // (which should never be the case)
63 | delete base[prop];
64 | } else {
65 | //FXIME In some case this should be merge / recursive merge instead ?
66 | base[prop] = pill[prop];
67 | }
68 | }
69 | }
70 | enc[encType] = base;
71 | }
72 |
73 | Pills.remove = function (encType) {
74 | delete Pills.pills[encType];
75 | updateFieldDef(Spec.spec.encoding, {}, encType); // remove all pill detail from the fieldDef
76 | };
77 |
78 | Pills.update = function (encType) {
79 | updateFieldDef(Spec.spec.encoding, Pills.pills[encType], encType);
80 | };
81 |
82 | Pills.dragStart = function (pill, encType) {
83 | Pills.pills.dragging = pill;
84 | Pills.pills.etDragFrom = encType;
85 | };
86 |
87 | Pills.dragStop = function () {
88 | delete Pills.pills.dragging;
89 | };
90 |
91 | Pills.dragDrop = function (etDragTo) {
92 | var enc = _.clone(Spec.spec.encoding),
93 | etDragFrom = Pills.pills.etDragFrom;
94 | // update the clone of the enc
95 | // console.log('dragDrop', enc, Pills, 'from:', etDragFrom, Pills.pills[etDragFrom]);
96 | if(etDragFrom){
97 | // if pill is dragged from another shelf, not the schemalist
98 | //
99 | // console.log('pillDragFrom', Pills.pills[etDragFrom]);
100 | updateFieldDef(enc, Pills.pills[etDragFrom] || {}, etDragFrom);
101 | }
102 | updateFieldDef(enc, Pills.pills[etDragTo] || {}, etDragTo);
103 |
104 | // console.log('Pills.dragDrop',
105 | // 'from:', etDragFrom, Pills.pills[etDragFrom], enc[etDragFrom],
106 | // 'to:', etDragTo, Pills.pills[etDragTo], enc[etDragTo]);
107 |
108 | // Finally, update the enc only once to prevent glitches
109 | Spec.spec.encoding = enc;
110 | etDragFrom = null;
111 | };
112 |
113 | return Pills;
114 | });
115 |
--------------------------------------------------------------------------------
/src/components/functionselect/functionselect.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | angular.module('polestar')
4 | .directive('functionSelect', function(_, vl, Pills, Logger) {
5 | return {
6 | templateUrl: 'components/functionselect/functionselect.html',
7 | restrict: 'E',
8 | scope: {
9 | encType: '=',
10 | schema: '=',
11 | field: '='
12 | },
13 | link: function(scope /*,element, attrs*/) {
14 | var BIN='bin', RAW='', COUNT='count', maxbins;
15 |
16 | scope.pills = Pills.pills;
17 | scope.func = {
18 | selected: RAW,
19 | list: [RAW]
20 | };
21 |
22 | function fieldPill() {
23 | return Pills ? Pills.pills[scope.encType] : null;
24 | }
25 |
26 | function getFns(type) {
27 | var schema = (scope.schema || {}).properties;
28 | if (schema && schema.timeUnit && (!schema.timeUnit.supportedTypes || schema.timeUnit.supportedTypes[type])) {
29 | return (schema.timeUnit.supportedEnums ? schema.timeUnit.supportedEnums[type] : schema.timeUnit.enum) || [];
30 | }
31 | return [];
32 | }
33 |
34 | function getAggrs(type) {
35 | if(!type) {
36 | return [COUNT];
37 | }
38 |
39 | var schema = scope.schema.properties;
40 |
41 | if (schema && schema.aggregate && (!schema.aggregate.supportedTypes || schema.aggregate.supportedTypes[type])){
42 | return (schema.aggregate.supportedEnums ? schema.aggregate.supportedEnums[type] : schema.aggregate.enum) || [];
43 | }
44 | return [];
45 | }
46 |
47 | scope.selectChanged = function() {
48 | Logger.logInteraction(Logger.actions.FUNC_CHANGE, scope.func.selected);
49 | };
50 |
51 | // FIXME func.selected logic should be all moved to selectChanged
52 | // when the function select is updated, propagates change the parent
53 | scope.$watch('func.selected', function(selectedFunc) {
54 | var oldPill = fieldPill(),
55 | pill = _.clone(oldPill),
56 | type = pill ? pill.type : '';
57 |
58 | if(!pill){
59 | return; // not ready
60 | }
61 |
62 | // reset field def
63 | // HACK: we're temporarily storing the maxbins in the pill
64 | pill.bin = selectedFunc === BIN ? {maxbins: maxbins || vl.schema.MAXBINS_DEFAULT} : undefined;
65 | pill.aggregate = getAggrs(type).indexOf(selectedFunc) !== -1 ? selectedFunc : undefined;
66 | pill.timeUnit = getFns(type).indexOf(selectedFunc) !== -1 ? selectedFunc : undefined;
67 |
68 | if(!_.isEqual(oldPill, pill)){
69 | Pills.pills[scope.encType] = pill;
70 | Pills.update(scope.encType);
71 | }
72 | });
73 |
74 | // when parent objects modify the field
75 | scope.$watch('field', function(pill) {
76 | // only run this if schema is not null
77 | if (!scope.schema || !pill) {
78 | return;
79 | }
80 |
81 | var type = pill.name ? pill.type : '';
82 | var schema = scope.schema.properties;
83 |
84 | // hack: save the maxbins
85 | if (pill.bin) {
86 | maxbins = pill.bin.maxbins;
87 | }
88 |
89 | var isOrdinalShelf = ['row','col','shape'].indexOf(scope.encType) !== -1,
90 | isQ = type==='Q', isT = type==='T';
91 |
92 | if(pill.name==='*' && pill.aggregate===COUNT){
93 | scope.func.list=[COUNT];
94 | scope.func.selected = COUNT;
95 | } else {
96 | scope.func.list = ( isOrdinalShelf && (isQ||isT) ? [] : [''])
97 | .concat(getFns(type))
98 | .concat(getAggrs(type).filter(function(x) { return x !== COUNT; }))
99 | .concat(schema.bin && schema.bin.supportedTypes[type] ? ['bin'] : []);
100 |
101 | var defaultVal = (isOrdinalShelf &&
102 | (isQ && BIN) || (isT && vl.schema.defaultTimeFn)
103 | )|| RAW;
104 |
105 | var selected = pill.bin ? 'bin' :
106 | pill.aggregate || pill.timeUnit ||
107 | defaultVal;
108 |
109 | if (scope.func.list.indexOf(selected) >= 0) {
110 | scope.func.selected = selected;
111 | } else {
112 | scope.func.selected = defaultVal;
113 | }
114 |
115 | }
116 | }, true);
117 | }
118 | };
119 | });
120 |
--------------------------------------------------------------------------------
/gulp/gen.js:
--------------------------------------------------------------------------------
1 | /**
2 | * script for generating angular primitives
3 | *
4 | * gulp gen -d directiveName (or --directive)
5 | * gulp gen -s serviceName (or --service)
6 | * gulp gen -c controllerName (or --controller)
7 | * gulp gen --fi filterName (or --filter)
8 | * gulp gen --fa factoryName (or --factory)
9 | */
10 |
11 | 'use strict';
12 |
13 | var gulp = require('gulp'),
14 | argv = require('yargs').argv,
15 | fs = require('fs'),
16 | request = require('request'),
17 | pack = require('../package.json');
18 |
19 | var APP_NAME = pack.name;
20 | var SRC_PATH = 'src/';
21 | var APP_PATH = 'app/';
22 | var COMP_PATH = 'components/';
23 |
24 | var GIST_URL = 'https://gist.githubusercontent.com/kanitw/15256571933310366d00/raw/';
25 |
26 | function createFile(path){
27 | fs.closeSync(fs.openSync(path, 'w'));
28 | }
29 |
30 | function fetchUrl(url, callback){
31 | console.log('fetching', url);
32 | request.get(url, function (error, response, body) {
33 | if (!error && response.statusCode === 200) {
34 | callback(body);
35 | }
36 | })
37 | .on('error', function(err){
38 | console.log(err);
39 | });
40 | }
41 |
42 | function replace(str, template){
43 | for(var key in template){
44 | str = str.replace(new RegExp(key, 'g'), template[key]);
45 | }
46 | return str;
47 | }
48 |
49 | function getAppName() {
50 | return argv.a || argv.appname || APP_NAME;
51 | }
52 |
53 | function genDirective(dir){
54 | var ldir = dir.toLowerCase(),
55 | dirpath = SRC_PATH + COMP_PATH + ldir +'/',
56 | dirdash = dir.replace(/([A-Z])/g, ' $1') // insert a space before all caps
57 | .toLowerCase()
58 | .split(' ')
59 | .join('-');
60 |
61 | if(! fs.existsSync(dirpath)){
62 | fs.mkdirSync(dirpath);
63 | }
64 | // create template, scss
65 | createFile(dirpath+ ldir +'.scss');
66 | fs.writeFileSync(dirpath + ldir + '.html' , '');
67 |
68 | // create directive file
69 | fetchUrl(GIST_URL + 'directive.js', function(str) {
70 | fs.writeFileSync(dirpath + ldir + '.js' , replace(str, {
71 | __appname__: getAppName(),
72 | __directive__: dir,
73 | __component__dir__: COMP_PATH,
74 | '__directive_lower__': ldir,
75 | '__directive_dash__': dirdash
76 | }));
77 | });
78 |
79 | // create spec file
80 | fetchUrl(GIST_URL + 'directive.spec.js', function(str) {
81 | fs.writeFileSync(dirpath + ldir + '.spec.js' , replace(str, {
82 | __appname__: getAppName(),
83 | __directive__: dir,
84 | '__directive_lower__': ldir,
85 | '__directive_dash__': dirdash
86 | }));
87 | });
88 | }
89 |
90 | function genItem(rootpath, item, fileurl, specurl, itemtype){
91 | var filename = item.toLowerCase(),
92 | dirpath = SRC_PATH + rootpath + filename +'/',
93 | template = { __appname__: getAppName() };
94 |
95 | if(! fs.existsSync(dirpath)){
96 | fs.mkdirSync(dirpath);
97 | }
98 |
99 | template['__'+itemtype+'__'] = item;
100 |
101 | // create directive file
102 | fetchUrl(fileurl, function(str) {
103 | fs.writeFileSync(dirpath + filename + '.' + itemtype + '.js' , replace(str, template));
104 | });
105 |
106 | // create spec file
107 | fetchUrl(specurl, function(str) {
108 | fs.writeFileSync(dirpath + filename + '.' + itemtype + '.spec.js' , replace(str, template));
109 | });
110 | }
111 |
112 | function genService(srv){
113 | genItem(APP_PATH, srv, GIST_URL + 'service.js',
114 | GIST_URL + 'service.spec.js', 'service');
115 | }
116 |
117 | function genFilter(f){
118 | genItem(COMP_PATH, f, GIST_URL + 'filter.js', GIST_URL + 'filter.spec.js', 'filter');
119 | }
120 |
121 | function genFactory(f){
122 | genItem(APP_PATH, f, GIST_URL + 'factory.js', GIST_URL + 'factory.spec.js', 'factory');
123 | }
124 |
125 | function genController(c){
126 | // controller name should be title case (Ctrl suffix is already appended in the template)
127 | var Cc = c.substr(0,1).toUpperCase() + c.substr(1);
128 |
129 | genItem(APP_PATH, Cc, GIST_URL + 'controller.js', GIST_URL + 'controller.spec.js', 'controller');
130 | }
131 |
132 | gulp.task('gen', function() {
133 | if (argv.d || argv.directive) {
134 | genDirective(argv.d || argv.directive);
135 | } else if (argv.s || argv.service) {
136 | genService(argv.s || argv.service);
137 | } else if (argv.c || argv.controller) {
138 | genController(argv.c || argv.controller);
139 | } else if (argv.fi || argv.filter) {
140 | genFilter(argv.fi || argv.filter);
141 | } else if (argv.fa || argv.factory) {
142 | genFactory(argv.fa || argv.factory);
143 | } else {
144 | console.log('please supply flag to generate an angular object you want');
145 | }
146 | });
147 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Pole✭ (Polestar) -- Alpha
2 |
3 | [](https://travis-ci.org/uwdata/polestar)
4 |
5 | PoleStar is Tableau-style User Interface for visual analysis, building on top
6 | of [Vega-lite](https://github.com/uwdata/vega-lite). Try our [online
7 | demo](http://uwdata.github.io/polestar/). Also, be sure to check out [related
8 | projects](https://vega.github.io/).
9 |
10 | **This project is an [alpha](http://en.wikipedia.org/wiki/Software_release_life_cycle#Alpha) software.
11 | We are working on improving its code and documentation.**
12 |
13 | If you are using Polestar for your project(s), please let us know what are you using it for by emailing us at [Vega-lite \[at\] cs.washington.edu](mailto:vega-lite@cs.washington.edu). Feedbacks are also welcomed.
14 | If you find a bug or have a feature request, please [create an issue](https://github.com/uwdata/polestar/issues/new).
15 |
16 | ## Team
17 |
18 | Polestar's development is led by Dominik Moritz, Kanit Wongsuphasawat, and Jeffrey Heer at the University of Washington [Interactive Data Lab](http://idl.cs.washington.edu), in collaboration with [UW eScience Institute](http://escience.washington.edu/) and [Tableau Research](http://research.tableau.com)
19 |
20 | ## Setup Instruction
21 |
22 | ### Install Dependencies
23 |
24 | Make sure you have node.js. (We recommend using [homebrew](http://brew.sh) and simply run `brew install node`.)
25 |
26 | Install gulp + bower globally by running
27 |
28 | ```sh
29 | npm install -g bower
30 | npm install -g gulp
31 | ```
32 |
33 | Then install all the npm, bower dependencies:
34 |
35 | ```sh
36 | npm install
37 | bower install
38 | ```
39 |
40 | Now you should have all dependencies and should be ready to work.
41 |
42 | ### Running
43 |
44 | You can run `gulp serve`, which serves the site as well as running tests in the background.
45 | If you edit any file, our gulp task runner should automatically refresh the browser and re-run tests.
46 |
47 | ## Development Guide
48 |
49 | ### Folder Structure
50 |
51 | We try to follow [Google's Angular Best Practice for Angular App Structure](https://docs.google.com/document/d/1XXMvReO8-Awi1EZXAXS4PzDzdNvV6pGcuaF4Q9821Es/pub) and use [generator-gulp-angular](https://github.com/Swiip/generator-gulp-angular) to setup the project.
52 |
53 | All source code are under `src/`
54 |
55 | - `src/app/` contains our main classes
56 | - `src/components` contains our other components
57 | - `src/assets/images/` contains relevant images
58 | - `src/data/` contains all data that we use in the application
59 | - `src/vendor` contains
60 |
61 | @kanitw created [`gulp/gen.js`](https://github.com/uwdata/polestar/blob/master/gulp/gen.js) for help generating angular components.
62 | For example, you can run `gulp gen -d directiveName` and this would create all relevant files including the javascript file, the template file, the stylesheet file and the test spec.
63 |
64 | #### Coding Style
65 |
66 | We use jshint as our linter for coding in the project.
67 |
68 | #### Stylesheets
69 |
70 | We use [sass](http://sass-lang.com) as it is a better syntax for css.
71 |
72 | #### Dependencies
73 |
74 | This project depends on [Datalib](https://github.com/uwdata/datalib) for data processing, [Vega-lite](https://github.com/uwdata/vega-lite) as a formal model for visualization, and [Vega-lite-ui](https://github.com/uwdata/vega-lite-ui), which contains shared components between Polestar and Voyager.
75 |
76 | If you plan to make changes to these dependencies and observe the changes without publishing / copying compiled libraries all the time, use [`bower link`](https://oncletom.io/2013/live-development-bower-component/).
77 |
78 | In each of your dependency repository, run
79 |
80 | ```
81 | cd path/to/dependency-repo
82 | bower link
83 | ```
84 |
85 | Then go to this project's directory and run
86 |
87 | ```
88 | bower link datalib
89 | bower link vega-lite
90 | bower link vega-lite-ui
91 | ```
92 |
93 | Now all the changes you make in each repo will be reflected in your Vega-lite automatically.
94 |
95 | Since bower uses the compiled main file, make sure that each repos is compiled everytime you run `gulp serve`.
96 | Otherwise, you will get errors for missing libraries.
97 |
98 | ### Releasing / Github Pages
99 |
100 | `gh-pages` branch is for releasing a stable version.
101 | `gh-pages` should only contain the dist folder.
102 |
103 | Use `publish.sh` to:
104 |
105 | 1. publish the current version to npm
106 | 2. deploy the current branch to gh-pages and
107 | 3. create a release tag for github and bower.
108 |
109 |
110 | ## Acknowledgement
111 |
112 | We used [generator-gulp-angular](https://github.com/Swiip/generator-gulp-angular) for bootstraping our project.
113 |
114 |
115 |
--------------------------------------------------------------------------------
/src/data/barley.json:
--------------------------------------------------------------------------------
1 | [{"yield":27,"variety":"Manchuria","year":1931,"site":"University Farm"},
2 | {"yield":48.86667,"variety":"Manchuria","year":1931,"site":"Waseca"},
3 | {"yield":27.43334,"variety":"Manchuria","year":1931,"site":"Morris"},
4 | {"yield":39.93333,"variety":"Manchuria","year":1931,"site":"Crookston"},
5 | {"yield":32.96667,"variety":"Manchuria","year":1931,"site":"Grand Rapids"},
6 | {"yield":28.96667,"variety":"Manchuria","year":1931,"site":"Duluth"},
7 | {"yield":43.06666,"variety":"Glabron","year":1931,"site":"University Farm"},
8 | {"yield":55.2,"variety":"Glabron","year":1931,"site":"Waseca"},
9 | {"yield":28.76667,"variety":"Glabron","year":1931,"site":"Morris"},
10 | {"yield":38.13333,"variety":"Glabron","year":1931,"site":"Crookston"},
11 | {"yield":29.13333,"variety":"Glabron","year":1931,"site":"Grand Rapids"},
12 | {"yield":29.66667,"variety":"Glabron","year":1931,"site":"Duluth"},
13 | {"yield":35.13333,"variety":"Svansota","year":1931,"site":"University Farm"},
14 | {"yield":47.33333,"variety":"Svansota","year":1931,"site":"Waseca"},
15 | {"yield":25.76667,"variety":"Svansota","year":1931,"site":"Morris"},
16 | {"yield":40.46667,"variety":"Svansota","year":1931,"site":"Crookston"},
17 | {"yield":29.66667,"variety":"Svansota","year":1931,"site":"Grand Rapids"},
18 | {"yield":25.7,"variety":"Svansota","year":1931,"site":"Duluth"},
19 | {"yield":39.9,"variety":"Velvet","year":1931,"site":"University Farm"},
20 | {"yield":50.23333,"variety":"Velvet","year":1931,"site":"Waseca"},
21 | {"yield":26.13333,"variety":"Velvet","year":1931,"site":"Morris"},
22 | {"yield":41.33333,"variety":"Velvet","year":1931,"site":"Crookston"},
23 | {"yield":23.03333,"variety":"Velvet","year":1931,"site":"Grand Rapids"},
24 | {"yield":26.3,"variety":"Velvet","year":1931,"site":"Duluth"},
25 | {"yield":36.56666,"variety":"Trebi","year":1931,"site":"University Farm"},
26 | {"yield":63.8333,"variety":"Trebi","year":1931,"site":"Waseca"},
27 | {"yield":43.76667,"variety":"Trebi","year":1931,"site":"Morris"},
28 | {"yield":46.93333,"variety":"Trebi","year":1931,"site":"Crookston"},
29 | {"yield":29.76667,"variety":"Trebi","year":1931,"site":"Grand Rapids"},
30 | {"yield":33.93333,"variety":"Trebi","year":1931,"site":"Duluth"},
31 | {"yield":43.26667,"variety":"No. 457","year":1931,"site":"University Farm"},
32 | {"yield":58.1,"variety":"No. 457","year":1931,"site":"Waseca"},
33 | {"yield":28.7,"variety":"No. 457","year":1931,"site":"Morris"},
34 | {"yield":45.66667,"variety":"No. 457","year":1931,"site":"Crookston"},
35 | {"yield":32.16667,"variety":"No. 457","year":1931,"site":"Grand Rapids"},
36 | {"yield":33.6,"variety":"No. 457","year":1931,"site":"Duluth"},
37 | {"yield":36.6,"variety":"No. 462","year":1931,"site":"University Farm"},
38 | {"yield":65.7667,"variety":"No. 462","year":1931,"site":"Waseca"},
39 | {"yield":30.36667,"variety":"No. 462","year":1931,"site":"Morris"},
40 | {"yield":48.56666,"variety":"No. 462","year":1931,"site":"Crookston"},
41 | {"yield":24.93334,"variety":"No. 462","year":1931,"site":"Grand Rapids"},
42 | {"yield":28.1,"variety":"No. 462","year":1931,"site":"Duluth"},
43 | {"yield":32.76667,"variety":"Peatland","year":1931,"site":"University Farm"},
44 | {"yield":48.56666,"variety":"Peatland","year":1931,"site":"Waseca"},
45 | {"yield":29.86667,"variety":"Peatland","year":1931,"site":"Morris"},
46 | {"yield":41.6,"variety":"Peatland","year":1931,"site":"Crookston"},
47 | {"yield":34.7,"variety":"Peatland","year":1931,"site":"Grand Rapids"},
48 | {"yield":32,"variety":"Peatland","year":1931,"site":"Duluth"},
49 | {"yield":24.66667,"variety":"No. 475","year":1931,"site":"University Farm"},
50 | {"yield":46.76667,"variety":"No. 475","year":1931,"site":"Waseca"},
51 | {"yield":22.6,"variety":"No. 475","year":1931,"site":"Morris"},
52 | {"yield":44.1,"variety":"No. 475","year":1931,"site":"Crookston"},
53 | {"yield":19.7,"variety":"No. 475","year":1931,"site":"Grand Rapids"},
54 | {"yield":33.06666,"variety":"No. 475","year":1931,"site":"Duluth"},
55 | {"yield":39.3,"variety":"Wisconsin No. 38","year":1931,"site":"University Farm"},
56 | {"yield":58.8,"variety":"Wisconsin No. 38","year":1931,"site":"Waseca"},
57 | {"yield":29.46667,"variety":"Wisconsin No. 38","year":1931,"site":"Morris"},
58 | {"yield":49.86667,"variety":"Wisconsin No. 38","year":1931,"site":"Crookston"},
59 | {"yield":34.46667,"variety":"Wisconsin No. 38","year":1931,"site":"Grand Rapids"},
60 | {"yield":31.6,"variety":"Wisconsin No. 38","year":1931,"site":"Duluth"},
61 | {"yield":26.9,"variety":"Manchuria","year":1932,"site":"University Farm"},
62 | {"yield":33.46667,"variety":"Manchuria","year":1932,"site":"Waseca"},
63 | {"yield":34.36666,"variety":"Manchuria","year":1932,"site":"Morris"},
64 | {"yield":32.96667,"variety":"Manchuria","year":1932,"site":"Crookston"},
65 | {"yield":22.13333,"variety":"Manchuria","year":1932,"site":"Grand Rapids"},
66 | {"yield":22.56667,"variety":"Manchuria","year":1932,"site":"Duluth"},
67 | {"yield":36.8,"variety":"Glabron","year":1932,"site":"University Farm"},
68 | {"yield":37.73333,"variety":"Glabron","year":1932,"site":"Waseca"},
69 | {"yield":35.13333,"variety":"Glabron","year":1932,"site":"Morris"},
70 | {"yield":26.16667,"variety":"Glabron","year":1932,"site":"Crookston"},
71 | {"yield":14.43333,"variety":"Glabron","year":1932,"site":"Grand Rapids"},
72 | {"yield":25.86667,"variety":"Glabron","year":1932,"site":"Duluth"},
73 | {"yield":27.43334,"variety":"Svansota","year":1932,"site":"University Farm"},
74 | {"yield":38.5,"variety":"Svansota","year":1932,"site":"Waseca"},
75 | {"yield":35.03333,"variety":"Svansota","year":1932,"site":"Morris"},
76 | {"yield":20.63333,"variety":"Svansota","year":1932,"site":"Crookston"},
77 | {"yield":16.63333,"variety":"Svansota","year":1932,"site":"Grand Rapids"},
78 | {"yield":22.23333,"variety":"Svansota","year":1932,"site":"Duluth"},
79 | {"yield":26.8,"variety":"Velvet","year":1932,"site":"University Farm"},
80 | {"yield":37.4,"variety":"Velvet","year":1932,"site":"Waseca"},
81 | {"yield":38.83333,"variety":"Velvet","year":1932,"site":"Morris"},
82 | {"yield":32.06666,"variety":"Velvet","year":1932,"site":"Crookston"},
83 | {"yield":32.23333,"variety":"Velvet","year":1932,"site":"Grand Rapids"},
84 | {"yield":22.46667,"variety":"Velvet","year":1932,"site":"Duluth"},
85 | {"yield":29.06667,"variety":"Trebi","year":1932,"site":"University Farm"},
86 | {"yield":49.2333,"variety":"Trebi","year":1932,"site":"Waseca"},
87 | {"yield":46.63333,"variety":"Trebi","year":1932,"site":"Morris"},
88 | {"yield":41.83333,"variety":"Trebi","year":1932,"site":"Crookston"},
89 | {"yield":20.63333,"variety":"Trebi","year":1932,"site":"Grand Rapids"},
90 | {"yield":30.6,"variety":"Trebi","year":1932,"site":"Duluth"},
91 | {"yield":26.43334,"variety":"No. 457","year":1932,"site":"University Farm"},
92 | {"yield":42.2,"variety":"No. 457","year":1932,"site":"Waseca"},
93 | {"yield":43.53334,"variety":"No. 457","year":1932,"site":"Morris"},
94 | {"yield":34.33333,"variety":"No. 457","year":1932,"site":"Crookston"},
95 | {"yield":19.46667,"variety":"No. 457","year":1932,"site":"Grand Rapids"},
96 | {"yield":22.7,"variety":"No. 457","year":1932,"site":"Duluth"},
97 | {"yield":25.56667,"variety":"No. 462","year":1932,"site":"University Farm"},
98 | {"yield":44.7,"variety":"No. 462","year":1932,"site":"Waseca"},
99 | {"yield":47,"variety":"No. 462","year":1932,"site":"Morris"},
100 | {"yield":30.53333,"variety":"No. 462","year":1932,"site":"Crookston"},
101 | {"yield":19.9,"variety":"No. 462","year":1932,"site":"Grand Rapids"},
102 | {"yield":22.5,"variety":"No. 462","year":1932,"site":"Duluth"},
103 | {"yield":28.06667,"variety":"Peatland","year":1932,"site":"University Farm"},
104 | {"yield":36.03333,"variety":"Peatland","year":1932,"site":"Waseca"},
105 | {"yield":43.2,"variety":"Peatland","year":1932,"site":"Morris"},
106 | {"yield":25.23333,"variety":"Peatland","year":1932,"site":"Crookston"},
107 | {"yield":26.76667,"variety":"Peatland","year":1932,"site":"Grand Rapids"},
108 | {"yield":31.36667,"variety":"Peatland","year":1932,"site":"Duluth"},
109 | {"yield":30,"variety":"No. 475","year":1932,"site":"University Farm"},
110 | {"yield":41.26667,"variety":"No. 475","year":1932,"site":"Waseca"},
111 | {"yield":44.23333,"variety":"No. 475","year":1932,"site":"Morris"},
112 | {"yield":32.13333,"variety":"No. 475","year":1932,"site":"Crookston"},
113 | {"yield":15.23333,"variety":"No. 475","year":1932,"site":"Grand Rapids"},
114 | {"yield":27.36667,"variety":"No. 475","year":1932,"site":"Duluth"},
115 | {"yield":38,"variety":"Wisconsin No. 38","year":1932,"site":"University Farm"},
116 | {"yield":58.16667,"variety":"Wisconsin No. 38","year":1932,"site":"Waseca"},
117 | {"yield":47.16667,"variety":"Wisconsin No. 38","year":1932,"site":"Morris"},
118 | {"yield":35.9,"variety":"Wisconsin No. 38","year":1932,"site":"Crookston"},
119 | {"yield":20.66667,"variety":"Wisconsin No. 38","year":1932,"site":"Grand Rapids"},
120 | {"yield":29.33333,"variety":"Wisconsin No. 38","year":1932,"site":"Duluth"}]
--------------------------------------------------------------------------------
/src/assets/normalize.scss:
--------------------------------------------------------------------------------
1 | // copied directly from normalize.css
2 |
3 | /*! normalize.css v3.0.2 | MIT License | git.io/normalize */
4 |
5 | /**
6 | * 1. Set default font family to sans-serif.
7 | * 2. Prevent iOS text size adjust after orientation change, without disabling
8 | * user zoom.
9 | */
10 |
11 | html {
12 | font-family: sans-serif; /* 1 */
13 | -ms-text-size-adjust: 100%; /* 2 */
14 | -webkit-text-size-adjust: 100%; /* 2 */
15 | }
16 |
17 | /**
18 | * Remove default margin.
19 | */
20 |
21 | body {
22 | margin: 0;
23 | }
24 |
25 | /* HTML5 display definitions
26 | ========================================================================== */
27 |
28 | /**
29 | * Correct `block` display not defined for any HTML5 element in IE 8/9.
30 | * Correct `block` display not defined for `details` or `summary` in IE 10/11
31 | * and Firefox.
32 | * Correct `block` display not defined for `main` in IE 11.
33 | */
34 |
35 | article,
36 | aside,
37 | details,
38 | figcaption,
39 | figure,
40 | footer,
41 | header,
42 | hgroup,
43 | main,
44 | menu,
45 | nav,
46 | section,
47 | summary {
48 | display: block;
49 | }
50 |
51 | /**
52 | * 1. Correct `inline-block` display not defined in IE 8/9.
53 | * 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera.
54 | */
55 |
56 | audio,
57 | canvas,
58 | progress,
59 | video {
60 | display: inline-block; /* 1 */
61 | vertical-align: baseline; /* 2 */
62 | }
63 |
64 | /**
65 | * Prevent modern browsers from displaying `audio` without controls.
66 | * Remove excess height in iOS 5 devices.
67 | */
68 |
69 | audio:not([controls]) {
70 | display: none;
71 | height: 0;
72 | }
73 |
74 | /**
75 | * Address `[hidden]` styling not present in IE 8/9/10.
76 | * Hide the `template` element in IE 8/9/11, Safari, and Firefox < 22.
77 | */
78 |
79 | [hidden],
80 | template {
81 | display: none;
82 | }
83 |
84 | /* Links
85 | ========================================================================== */
86 |
87 | /**
88 | * Remove the gray background color from active links in IE 10.
89 | */
90 |
91 | a {
92 | background-color: transparent;
93 | }
94 |
95 | /**
96 | * Improve readability when focused and also mouse hovered in all browsers.
97 | */
98 |
99 | a:active,
100 | a:hover {
101 | outline: 0;
102 | }
103 |
104 | /* Text-level semantics
105 | ========================================================================== */
106 |
107 | /**
108 | * Address styling not present in IE 8/9/10/11, Safari, and Chrome.
109 | */
110 |
111 | abbr[title] {
112 | border-bottom: 1px dotted;
113 | }
114 |
115 | /**
116 | * Address style set to `bolder` in Firefox 4+, Safari, and Chrome.
117 | */
118 |
119 | b,
120 | strong {
121 | font-weight: bold;
122 | }
123 |
124 | /**
125 | * Address styling not present in Safari and Chrome.
126 | */
127 |
128 | dfn {
129 | font-style: italic;
130 | }
131 |
132 | /**
133 | * Address variable `h1` font-size and margin within `section` and `article`
134 | * contexts in Firefox 4+, Safari, and Chrome.
135 | */
136 |
137 | h1 {
138 | font-size: 2em;
139 | margin: 0.67em 0;
140 | }
141 |
142 | /**
143 | * Address styling not present in IE 8/9.
144 | */
145 |
146 | mark {
147 | background: #ff0;
148 | color: #000;
149 | }
150 |
151 | /**
152 | * Address inconsistent and variable font size in all browsers.
153 | */
154 |
155 | small {
156 | font-size: 80%;
157 | }
158 |
159 | /**
160 | * Prevent `sub` and `sup` affecting `line-height` in all browsers.
161 | */
162 |
163 | sub,
164 | sup {
165 | font-size: 75%;
166 | line-height: 0;
167 | position: relative;
168 | vertical-align: baseline;
169 | }
170 |
171 | sup {
172 | top: -0.5em;
173 | }
174 |
175 | sub {
176 | bottom: -0.25em;
177 | }
178 |
179 | /* Embedded content
180 | ========================================================================== */
181 |
182 | /**
183 | * Remove border when inside `a` element in IE 8/9/10.
184 | */
185 |
186 | img {
187 | border: 0;
188 | }
189 |
190 | /**
191 | * Correct overflow not hidden in IE 9/10/11.
192 | */
193 |
194 | svg:not(:root) {
195 | overflow: hidden;
196 | }
197 |
198 | /* Grouping content
199 | ========================================================================== */
200 |
201 | /**
202 | * Address margin not present in IE 8/9 and Safari.
203 | */
204 |
205 | figure {
206 | margin: 1em 40px;
207 | }
208 |
209 | /**
210 | * Address differences between Firefox and other browsers.
211 | */
212 |
213 | hr {
214 | -moz-box-sizing: content-box;
215 | box-sizing: content-box;
216 | height: 0;
217 | }
218 |
219 | /**
220 | * Contain overflow in all browsers.
221 | */
222 |
223 | pre {
224 | overflow: auto;
225 | }
226 |
227 | /**
228 | * Address odd `em`-unit font size rendering in all browsers.
229 | */
230 |
231 | code,
232 | kbd,
233 | pre,
234 | samp {
235 | font-family: monospace, monospace;
236 | font-size: 1em;
237 | }
238 |
239 | /* Forms
240 | ========================================================================== */
241 |
242 | /**
243 | * Known limitation: by default, Chrome and Safari on OS X allow very limited
244 | * styling of `select`, unless a `border` property is set.
245 | */
246 |
247 | /**
248 | * 1. Correct color not being inherited.
249 | * Known issue: affects color of disabled elements.
250 | * 2. Correct font properties not being inherited.
251 | * 3. Address margins set differently in Firefox 4+, Safari, and Chrome.
252 | */
253 |
254 | button,
255 | input,
256 | optgroup,
257 | select,
258 | textarea {
259 | color: inherit; /* 1 */
260 | font: inherit; /* 2 */
261 | margin: 0; /* 3 */
262 | }
263 |
264 | /**
265 | * Address `overflow` set to `hidden` in IE 8/9/10/11.
266 | */
267 |
268 | button {
269 | overflow: visible;
270 | }
271 |
272 | /**
273 | * Address inconsistent `text-transform` inheritance for `button` and `select`.
274 | * All other form control elements do not inherit `text-transform` values.
275 | * Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera.
276 | * Correct `select` style inheritance in Firefox.
277 | */
278 |
279 | button,
280 | select {
281 | text-transform: none;
282 | }
283 |
284 | /**
285 | * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`
286 | * and `video` controls.
287 | * 2. Correct inability to style clickable `input` types in iOS.
288 | * 3. Improve usability and consistency of cursor style between image-type
289 | * `input` and others.
290 | */
291 |
292 | button,
293 | html input[type="button"], /* 1 */
294 | input[type="reset"],
295 | input[type="submit"] {
296 | -webkit-appearance: button; /* 2 */
297 | cursor: pointer; /* 3 */
298 | }
299 |
300 | /**
301 | * Re-set default cursor for disabled elements.
302 | */
303 |
304 | button[disabled],
305 | html input[disabled] {
306 | cursor: default;
307 | }
308 |
309 | /**
310 | * Remove inner padding and border in Firefox 4+.
311 | */
312 |
313 | button::-moz-focus-inner,
314 | input::-moz-focus-inner {
315 | border: 0;
316 | padding: 0;
317 | }
318 |
319 | /**
320 | * Address Firefox 4+ setting `line-height` on `input` using `!important` in
321 | * the UA stylesheet.
322 | */
323 |
324 | input {
325 | line-height: normal;
326 | }
327 |
328 | /**
329 | * It's recommended that you don't attempt to style these elements.
330 | * Firefox's implementation doesn't respect box-sizing, padding, or width.
331 | *
332 | * 1. Address box sizing set to `content-box` in IE 8/9/10.
333 | * 2. Remove excess padding in IE 8/9/10.
334 | */
335 |
336 | input[type="checkbox"],
337 | input[type="radio"] {
338 | box-sizing: border-box; /* 1 */
339 | padding: 0; /* 2 */
340 | }
341 |
342 | /**
343 | * Fix the cursor style for Chrome's increment/decrement buttons. For certain
344 | * `font-size` values of the `input`, it causes the cursor style of the
345 | * decrement button to change from `default` to `text`.
346 | */
347 |
348 | input[type="number"]::-webkit-inner-spin-button,
349 | input[type="number"]::-webkit-outer-spin-button {
350 | height: auto;
351 | }
352 |
353 | /**
354 | * 1. Address `appearance` set to `searchfield` in Safari and Chrome.
355 | * 2. Address `box-sizing` set to `border-box` in Safari and Chrome
356 | * (include `-moz` to future-proof).
357 | */
358 |
359 | input[type="search"] {
360 | -webkit-appearance: textfield; /* 1 */
361 | -moz-box-sizing: content-box;
362 | -webkit-box-sizing: content-box; /* 2 */
363 | box-sizing: content-box;
364 | }
365 |
366 | /**
367 | * Remove inner padding and search cancel button in Safari and Chrome on OS X.
368 | * Safari (but not Chrome) clips the cancel button when the search input has
369 | * padding (and `textfield` appearance).
370 | */
371 |
372 | input[type="search"]::-webkit-search-cancel-button,
373 | input[type="search"]::-webkit-search-decoration {
374 | -webkit-appearance: none;
375 | }
376 |
377 | /**
378 | * Define consistent border, margin, and padding.
379 | */
380 |
381 | fieldset {
382 | border: 1px solid #c0c0c0;
383 | margin: 0 2px;
384 | padding: 0.35em 0.625em 0.75em;
385 | }
386 |
387 | /**
388 | * 1. Correct `color` not being inherited in IE 8/9/10/11.
389 | * 2. Remove padding so people aren't caught out if they zero out fieldsets.
390 | */
391 |
392 | legend {
393 | border: 0; /* 1 */
394 | padding: 0; /* 2 */
395 | }
396 |
397 | /**
398 | * Remove default vertical scrollbar in IE 8/9/10/11.
399 | */
400 |
401 | textarea {
402 | overflow: auto;
403 | }
404 |
405 | /**
406 | * Don't inherit the `font-weight` (applied by a rule above).
407 | * NOTE: the default cannot safely be changed in Chrome and Safari on OS X.
408 | */
409 |
410 | optgroup {
411 | font-weight: bold;
412 | }
413 |
414 | /* Tables
415 | ========================================================================== */
416 |
417 | /**
418 | * Remove most spacing between table cells.
419 | */
420 |
421 | table {
422 | border-collapse: collapse;
423 | border-spacing: 0;
424 | }
425 |
426 | td,
427 | th {
428 | padding: 0;
429 | }
430 |
--------------------------------------------------------------------------------
/src/data/iris.json:
--------------------------------------------------------------------------------
1 | [
2 | {"sepalLength": 5.1, "sepalWidth": 3.5, "petalLength": 1.4, "petalWidth": 0.2, "species": "setosa"},
3 | {"sepalLength": 4.9, "sepalWidth": 3.0, "petalLength": 1.4, "petalWidth": 0.2, "species": "setosa"},
4 | {"sepalLength": 4.7, "sepalWidth": 3.2, "petalLength": 1.3, "petalWidth": 0.2, "species": "setosa"},
5 | {"sepalLength": 4.6, "sepalWidth": 3.1, "petalLength": 1.5, "petalWidth": 0.2, "species": "setosa"},
6 | {"sepalLength": 5.0, "sepalWidth": 3.6, "petalLength": 1.4, "petalWidth": 0.2, "species": "setosa"},
7 | {"sepalLength": 5.4, "sepalWidth": 3.9, "petalLength": 1.7, "petalWidth": 0.4, "species": "setosa"},
8 | {"sepalLength": 4.6, "sepalWidth": 3.4, "petalLength": 1.4, "petalWidth": 0.3, "species": "setosa"},
9 | {"sepalLength": 5.0, "sepalWidth": 3.4, "petalLength": 1.5, "petalWidth": 0.2, "species": "setosa"},
10 | {"sepalLength": 4.4, "sepalWidth": 2.9, "petalLength": 1.4, "petalWidth": 0.2, "species": "setosa"},
11 | {"sepalLength": 4.9, "sepalWidth": 3.1, "petalLength": 1.5, "petalWidth": 0.1, "species": "setosa"},
12 | {"sepalLength": 5.4, "sepalWidth": 3.7, "petalLength": 1.5, "petalWidth": 0.2, "species": "setosa"},
13 | {"sepalLength": 4.8, "sepalWidth": 3.4, "petalLength": 1.6, "petalWidth": 0.2, "species": "setosa"},
14 | {"sepalLength": 4.8, "sepalWidth": 3.0, "petalLength": 1.4, "petalWidth": 0.1, "species": "setosa"},
15 | {"sepalLength": 4.3, "sepalWidth": 3.0, "petalLength": 1.1, "petalWidth": 0.1, "species": "setosa"},
16 | {"sepalLength": 5.8, "sepalWidth": 4.0, "petalLength": 1.2, "petalWidth": 0.2, "species": "setosa"},
17 | {"sepalLength": 5.7, "sepalWidth": 4.4, "petalLength": 1.5, "petalWidth": 0.4, "species": "setosa"},
18 | {"sepalLength": 5.4, "sepalWidth": 3.9, "petalLength": 1.3, "petalWidth": 0.4, "species": "setosa"},
19 | {"sepalLength": 5.1, "sepalWidth": 3.5, "petalLength": 1.4, "petalWidth": 0.3, "species": "setosa"},
20 | {"sepalLength": 5.7, "sepalWidth": 3.8, "petalLength": 1.7, "petalWidth": 0.3, "species": "setosa"},
21 | {"sepalLength": 5.1, "sepalWidth": 3.8, "petalLength": 1.5, "petalWidth": 0.3, "species": "setosa"},
22 | {"sepalLength": 5.4, "sepalWidth": 3.4, "petalLength": 1.7, "petalWidth": 0.2, "species": "setosa"},
23 | {"sepalLength": 5.1, "sepalWidth": 3.7, "petalLength": 1.5, "petalWidth": 0.4, "species": "setosa"},
24 | {"sepalLength": 4.6, "sepalWidth": 3.6, "petalLength": 1.0, "petalWidth": 0.2, "species": "setosa"},
25 | {"sepalLength": 5.1, "sepalWidth": 3.3, "petalLength": 1.7, "petalWidth": 0.5, "species": "setosa"},
26 | {"sepalLength": 4.8, "sepalWidth": 3.4, "petalLength": 1.9, "petalWidth": 0.2, "species": "setosa"},
27 | {"sepalLength": 5.0, "sepalWidth": 3.0, "petalLength": 1.6, "petalWidth": 0.2, "species": "setosa"},
28 | {"sepalLength": 5.0, "sepalWidth": 3.4, "petalLength": 1.6, "petalWidth": 0.4, "species": "setosa"},
29 | {"sepalLength": 5.2, "sepalWidth": 3.5, "petalLength": 1.5, "petalWidth": 0.2, "species": "setosa"},
30 | {"sepalLength": 5.2, "sepalWidth": 3.4, "petalLength": 1.4, "petalWidth": 0.2, "species": "setosa"},
31 | {"sepalLength": 4.7, "sepalWidth": 3.2, "petalLength": 1.6, "petalWidth": 0.2, "species": "setosa"},
32 | {"sepalLength": 4.8, "sepalWidth": 3.1, "petalLength": 1.6, "petalWidth": 0.2, "species": "setosa"},
33 | {"sepalLength": 5.4, "sepalWidth": 3.4, "petalLength": 1.5, "petalWidth": 0.4, "species": "setosa"},
34 | {"sepalLength": 5.2, "sepalWidth": 4.1, "petalLength": 1.5, "petalWidth": 0.1, "species": "setosa"},
35 | {"sepalLength": 5.5, "sepalWidth": 4.2, "petalLength": 1.4, "petalWidth": 0.2, "species": "setosa"},
36 | {"sepalLength": 4.9, "sepalWidth": 3.1, "petalLength": 1.5, "petalWidth": 0.2, "species": "setosa"},
37 | {"sepalLength": 5.0, "sepalWidth": 3.2, "petalLength": 1.2, "petalWidth": 0.2, "species": "setosa"},
38 | {"sepalLength": 5.5, "sepalWidth": 3.5, "petalLength": 1.3, "petalWidth": 0.2, "species": "setosa"},
39 | {"sepalLength": 4.9, "sepalWidth": 3.6, "petalLength": 1.4, "petalWidth": 0.1, "species": "setosa"},
40 | {"sepalLength": 4.4, "sepalWidth": 3.0, "petalLength": 1.3, "petalWidth": 0.2, "species": "setosa"},
41 | {"sepalLength": 5.1, "sepalWidth": 3.4, "petalLength": 1.5, "petalWidth": 0.2, "species": "setosa"},
42 | {"sepalLength": 5.0, "sepalWidth": 3.5, "petalLength": 1.3, "petalWidth": 0.3, "species": "setosa"},
43 | {"sepalLength": 4.5, "sepalWidth": 2.3, "petalLength": 1.3, "petalWidth": 0.3, "species": "setosa"},
44 | {"sepalLength": 4.4, "sepalWidth": 3.2, "petalLength": 1.3, "petalWidth": 0.2, "species": "setosa"},
45 | {"sepalLength": 5.0, "sepalWidth": 3.5, "petalLength": 1.6, "petalWidth": 0.6, "species": "setosa"},
46 | {"sepalLength": 5.1, "sepalWidth": 3.8, "petalLength": 1.9, "petalWidth": 0.4, "species": "setosa"},
47 | {"sepalLength": 4.8, "sepalWidth": 3.0, "petalLength": 1.4, "petalWidth": 0.3, "species": "setosa"},
48 | {"sepalLength": 5.1, "sepalWidth": 3.8, "petalLength": 1.6, "petalWidth": 0.2, "species": "setosa"},
49 | {"sepalLength": 4.6, "sepalWidth": 3.2, "petalLength": 1.4, "petalWidth": 0.2, "species": "setosa"},
50 | {"sepalLength": 5.3, "sepalWidth": 3.7, "petalLength": 1.5, "petalWidth": 0.2, "species": "setosa"},
51 | {"sepalLength": 5.0, "sepalWidth": 3.3, "petalLength": 1.4, "petalWidth": 0.2, "species": "setosa"},
52 | {"sepalLength": 7.0, "sepalWidth": 3.2, "petalLength": 4.7, "petalWidth": 1.4, "species": "versicolor"},
53 | {"sepalLength": 6.4, "sepalWidth": 3.2, "petalLength": 4.5, "petalWidth": 1.5, "species": "versicolor"},
54 | {"sepalLength": 6.9, "sepalWidth": 3.1, "petalLength": 4.9, "petalWidth": 1.5, "species": "versicolor"},
55 | {"sepalLength": 5.5, "sepalWidth": 2.3, "petalLength": 4.0, "petalWidth": 1.3, "species": "versicolor"},
56 | {"sepalLength": 6.5, "sepalWidth": 2.8, "petalLength": 4.6, "petalWidth": 1.5, "species": "versicolor"},
57 | {"sepalLength": 5.7, "sepalWidth": 2.8, "petalLength": 4.5, "petalWidth": 1.3, "species": "versicolor"},
58 | {"sepalLength": 6.3, "sepalWidth": 3.3, "petalLength": 4.7, "petalWidth": 1.6, "species": "versicolor"},
59 | {"sepalLength": 4.9, "sepalWidth": 2.4, "petalLength": 3.3, "petalWidth": 1.0, "species": "versicolor"},
60 | {"sepalLength": 6.6, "sepalWidth": 2.9, "petalLength": 4.6, "petalWidth": 1.3, "species": "versicolor"},
61 | {"sepalLength": 5.2, "sepalWidth": 2.7, "petalLength": 3.9, "petalWidth": 1.4, "species": "versicolor"},
62 | {"sepalLength": 5.0, "sepalWidth": 2.0, "petalLength": 3.5, "petalWidth": 1.0, "species": "versicolor"},
63 | {"sepalLength": 5.9, "sepalWidth": 3.0, "petalLength": 4.2, "petalWidth": 1.5, "species": "versicolor"},
64 | {"sepalLength": 6.0, "sepalWidth": 2.2, "petalLength": 4.0, "petalWidth": 1.0, "species": "versicolor"},
65 | {"sepalLength": 6.1, "sepalWidth": 2.9, "petalLength": 4.7, "petalWidth": 1.4, "species": "versicolor"},
66 | {"sepalLength": 5.6, "sepalWidth": 2.9, "petalLength": 3.6, "petalWidth": 1.3, "species": "versicolor"},
67 | {"sepalLength": 6.7, "sepalWidth": 3.1, "petalLength": 4.4, "petalWidth": 1.4, "species": "versicolor"},
68 | {"sepalLength": 5.6, "sepalWidth": 3.0, "petalLength": 4.5, "petalWidth": 1.5, "species": "versicolor"},
69 | {"sepalLength": 5.8, "sepalWidth": 2.7, "petalLength": 4.1, "petalWidth": 1.0, "species": "versicolor"},
70 | {"sepalLength": 6.2, "sepalWidth": 2.2, "petalLength": 4.5, "petalWidth": 1.5, "species": "versicolor"},
71 | {"sepalLength": 5.6, "sepalWidth": 2.5, "petalLength": 3.9, "petalWidth": 1.1, "species": "versicolor"},
72 | {"sepalLength": 5.9, "sepalWidth": 3.2, "petalLength": 4.8, "petalWidth": 1.8, "species": "versicolor"},
73 | {"sepalLength": 6.1, "sepalWidth": 2.8, "petalLength": 4.0, "petalWidth": 1.3, "species": "versicolor"},
74 | {"sepalLength": 6.3, "sepalWidth": 2.5, "petalLength": 4.9, "petalWidth": 1.5, "species": "versicolor"},
75 | {"sepalLength": 6.1, "sepalWidth": 2.8, "petalLength": 4.7, "petalWidth": 1.2, "species": "versicolor"},
76 | {"sepalLength": 6.4, "sepalWidth": 2.9, "petalLength": 4.3, "petalWidth": 1.3, "species": "versicolor"},
77 | {"sepalLength": 6.6, "sepalWidth": 3.0, "petalLength": 4.4, "petalWidth": 1.4, "species": "versicolor"},
78 | {"sepalLength": 6.8, "sepalWidth": 2.8, "petalLength": 4.8, "petalWidth": 1.4, "species": "versicolor"},
79 | {"sepalLength": 6.7, "sepalWidth": 3.0, "petalLength": 5.0, "petalWidth": 1.7, "species": "versicolor"},
80 | {"sepalLength": 6.0, "sepalWidth": 2.9, "petalLength": 4.5, "petalWidth": 1.5, "species": "versicolor"},
81 | {"sepalLength": 5.7, "sepalWidth": 2.6, "petalLength": 3.5, "petalWidth": 1.0, "species": "versicolor"},
82 | {"sepalLength": 5.5, "sepalWidth": 2.4, "petalLength": 3.8, "petalWidth": 1.1, "species": "versicolor"},
83 | {"sepalLength": 5.5, "sepalWidth": 2.4, "petalLength": 3.7, "petalWidth": 1.0, "species": "versicolor"},
84 | {"sepalLength": 5.8, "sepalWidth": 2.7, "petalLength": 3.9, "petalWidth": 1.2, "species": "versicolor"},
85 | {"sepalLength": 6.0, "sepalWidth": 2.7, "petalLength": 5.1, "petalWidth": 1.6, "species": "versicolor"},
86 | {"sepalLength": 5.4, "sepalWidth": 3.0, "petalLength": 4.5, "petalWidth": 1.5, "species": "versicolor"},
87 | {"sepalLength": 6.0, "sepalWidth": 3.4, "petalLength": 4.5, "petalWidth": 1.6, "species": "versicolor"},
88 | {"sepalLength": 6.7, "sepalWidth": 3.1, "petalLength": 4.7, "petalWidth": 1.5, "species": "versicolor"},
89 | {"sepalLength": 6.3, "sepalWidth": 2.3, "petalLength": 4.4, "petalWidth": 1.3, "species": "versicolor"},
90 | {"sepalLength": 5.6, "sepalWidth": 3.0, "petalLength": 4.1, "petalWidth": 1.3, "species": "versicolor"},
91 | {"sepalLength": 5.5, "sepalWidth": 2.5, "petalLength": 4.0, "petalWidth": 1.3, "species": "versicolor"},
92 | {"sepalLength": 5.5, "sepalWidth": 2.6, "petalLength": 4.4, "petalWidth": 1.2, "species": "versicolor"},
93 | {"sepalLength": 6.1, "sepalWidth": 3.0, "petalLength": 4.6, "petalWidth": 1.4, "species": "versicolor"},
94 | {"sepalLength": 5.8, "sepalWidth": 2.6, "petalLength": 4.0, "petalWidth": 1.2, "species": "versicolor"},
95 | {"sepalLength": 5.0, "sepalWidth": 2.3, "petalLength": 3.3, "petalWidth": 1.0, "species": "versicolor"},
96 | {"sepalLength": 5.6, "sepalWidth": 2.7, "petalLength": 4.2, "petalWidth": 1.3, "species": "versicolor"},
97 | {"sepalLength": 5.7, "sepalWidth": 3.0, "petalLength": 4.2, "petalWidth": 1.2, "species": "versicolor"},
98 | {"sepalLength": 5.7, "sepalWidth": 2.9, "petalLength": 4.2, "petalWidth": 1.3, "species": "versicolor"},
99 | {"sepalLength": 6.2, "sepalWidth": 2.9, "petalLength": 4.3, "petalWidth": 1.3, "species": "versicolor"},
100 | {"sepalLength": 5.1, "sepalWidth": 2.5, "petalLength": 3.0, "petalWidth": 1.1, "species": "versicolor"},
101 | {"sepalLength": 5.7, "sepalWidth": 2.8, "petalLength": 4.1, "petalWidth": 1.3, "species": "versicolor"},
102 | {"sepalLength": 6.3, "sepalWidth": 3.3, "petalLength": 6.0, "petalWidth": 2.5, "species": "virginica"},
103 | {"sepalLength": 5.8, "sepalWidth": 2.7, "petalLength": 5.1, "petalWidth": 1.9, "species": "virginica"},
104 | {"sepalLength": 7.1, "sepalWidth": 3.0, "petalLength": 5.9, "petalWidth": 2.1, "species": "virginica"},
105 | {"sepalLength": 6.3, "sepalWidth": 2.9, "petalLength": 5.6, "petalWidth": 1.8, "species": "virginica"},
106 | {"sepalLength": 6.5, "sepalWidth": 3.0, "petalLength": 5.8, "petalWidth": 2.2, "species": "virginica"},
107 | {"sepalLength": 7.6, "sepalWidth": 3.0, "petalLength": 6.6, "petalWidth": 2.1, "species": "virginica"},
108 | {"sepalLength": 4.9, "sepalWidth": 2.5, "petalLength": 4.5, "petalWidth": 1.7, "species": "virginica"},
109 | {"sepalLength": 7.3, "sepalWidth": 2.9, "petalLength": 6.3, "petalWidth": 1.8, "species": "virginica"},
110 | {"sepalLength": 6.7, "sepalWidth": 2.5, "petalLength": 5.8, "petalWidth": 1.8, "species": "virginica"},
111 | {"sepalLength": 7.2, "sepalWidth": 3.6, "petalLength": 6.1, "petalWidth": 2.5, "species": "virginica"},
112 | {"sepalLength": 6.5, "sepalWidth": 3.2, "petalLength": 5.1, "petalWidth": 2.0, "species": "virginica"},
113 | {"sepalLength": 6.4, "sepalWidth": 2.7, "petalLength": 5.3, "petalWidth": 1.9, "species": "virginica"},
114 | {"sepalLength": 6.8, "sepalWidth": 3.0, "petalLength": 5.5, "petalWidth": 2.1, "species": "virginica"},
115 | {"sepalLength": 5.7, "sepalWidth": 2.5, "petalLength": 5.0, "petalWidth": 2.0, "species": "virginica"},
116 | {"sepalLength": 5.8, "sepalWidth": 2.8, "petalLength": 5.1, "petalWidth": 2.4, "species": "virginica"},
117 | {"sepalLength": 6.4, "sepalWidth": 3.2, "petalLength": 5.3, "petalWidth": 2.3, "species": "virginica"},
118 | {"sepalLength": 6.5, "sepalWidth": 3.0, "petalLength": 5.5, "petalWidth": 1.8, "species": "virginica"},
119 | {"sepalLength": 7.7, "sepalWidth": 3.8, "petalLength": 6.7, "petalWidth": 2.2, "species": "virginica"},
120 | {"sepalLength": 7.7, "sepalWidth": 2.6, "petalLength": 6.9, "petalWidth": 2.3, "species": "virginica"},
121 | {"sepalLength": 6.0, "sepalWidth": 2.2, "petalLength": 5.0, "petalWidth": 1.5, "species": "virginica"},
122 | {"sepalLength": 6.9, "sepalWidth": 3.2, "petalLength": 5.7, "petalWidth": 2.3, "species": "virginica"},
123 | {"sepalLength": 5.6, "sepalWidth": 2.8, "petalLength": 4.9, "petalWidth": 2.0, "species": "virginica"},
124 | {"sepalLength": 7.7, "sepalWidth": 2.8, "petalLength": 6.7, "petalWidth": 2.0, "species": "virginica"},
125 | {"sepalLength": 6.3, "sepalWidth": 2.7, "petalLength": 4.9, "petalWidth": 1.8, "species": "virginica"},
126 | {"sepalLength": 6.7, "sepalWidth": 3.3, "petalLength": 5.7, "petalWidth": 2.1, "species": "virginica"},
127 | {"sepalLength": 7.2, "sepalWidth": 3.2, "petalLength": 6.0, "petalWidth": 1.8, "species": "virginica"},
128 | {"sepalLength": 6.2, "sepalWidth": 2.8, "petalLength": 4.8, "petalWidth": 1.8, "species": "virginica"},
129 | {"sepalLength": 6.1, "sepalWidth": 3.0, "petalLength": 4.9, "petalWidth": 1.8, "species": "virginica"},
130 | {"sepalLength": 6.4, "sepalWidth": 2.8, "petalLength": 5.6, "petalWidth": 2.1, "species": "virginica"},
131 | {"sepalLength": 7.2, "sepalWidth": 3.0, "petalLength": 5.8, "petalWidth": 1.6, "species": "virginica"},
132 | {"sepalLength": 7.4, "sepalWidth": 2.8, "petalLength": 6.1, "petalWidth": 1.9, "species": "virginica"},
133 | {"sepalLength": 7.9, "sepalWidth": 3.8, "petalLength": 6.4, "petalWidth": 2.0, "species": "virginica"},
134 | {"sepalLength": 6.4, "sepalWidth": 2.8, "petalLength": 5.6, "petalWidth": 2.2, "species": "virginica"},
135 | {"sepalLength": 6.3, "sepalWidth": 2.8, "petalLength": 5.1, "petalWidth": 1.5, "species": "virginica"},
136 | {"sepalLength": 6.1, "sepalWidth": 2.6, "petalLength": 5.6, "petalWidth": 1.4, "species": "virginica"},
137 | {"sepalLength": 7.7, "sepalWidth": 3.0, "petalLength": 6.1, "petalWidth": 2.3, "species": "virginica"},
138 | {"sepalLength": 6.3, "sepalWidth": 3.4, "petalLength": 5.6, "petalWidth": 2.4, "species": "virginica"},
139 | {"sepalLength": 6.4, "sepalWidth": 3.1, "petalLength": 5.5, "petalWidth": 1.8, "species": "virginica"},
140 | {"sepalLength": 6.0, "sepalWidth": 3.0, "petalLength": 4.8, "petalWidth": 1.8, "species": "virginica"},
141 | {"sepalLength": 6.9, "sepalWidth": 3.1, "petalLength": 5.4, "petalWidth": 2.1, "species": "virginica"},
142 | {"sepalLength": 6.7, "sepalWidth": 3.1, "petalLength": 5.6, "petalWidth": 2.4, "species": "virginica"},
143 | {"sepalLength": 6.9, "sepalWidth": 3.1, "petalLength": 5.1, "petalWidth": 2.3, "species": "virginica"},
144 | {"sepalLength": 5.8, "sepalWidth": 2.7, "petalLength": 5.1, "petalWidth": 1.9, "species": "virginica"},
145 | {"sepalLength": 6.8, "sepalWidth": 3.2, "petalLength": 5.9, "petalWidth": 2.3, "species": "virginica"},
146 | {"sepalLength": 6.7, "sepalWidth": 3.3, "petalLength": 5.7, "petalWidth": 2.5, "species": "virginica"},
147 | {"sepalLength": 6.7, "sepalWidth": 3.0, "petalLength": 5.2, "petalWidth": 2.3, "species": "virginica"},
148 | {"sepalLength": 6.3, "sepalWidth": 2.5, "petalLength": 5.0, "petalWidth": 1.9, "species": "virginica"},
149 | {"sepalLength": 6.5, "sepalWidth": 3.0, "petalLength": 5.2, "petalWidth": 2.0, "species": "virginica"},
150 | {"sepalLength": 6.2, "sepalWidth": 3.4, "petalLength": 5.4, "petalWidth": 2.3, "species": "virginica"},
151 | {"sepalLength": 5.9, "sepalWidth": 3.0, "petalLength": 5.1, "petalWidth": 1.8, "species": "virginica"}
152 | ]
--------------------------------------------------------------------------------
/src/data/population.json:
--------------------------------------------------------------------------------
1 | [{"year":1850,"age":0,"sex":1,"people":1483789},
2 | {"year":1850,"age":0,"sex":2,"people":1450376},
3 | {"year":1850,"age":5,"sex":1,"people":1411067},
4 | {"year":1850,"age":5,"sex":2,"people":1359668},
5 | {"year":1850,"age":10,"sex":1,"people":1260099},
6 | {"year":1850,"age":10,"sex":2,"people":1216114},
7 | {"year":1850,"age":15,"sex":1,"people":1077133},
8 | {"year":1850,"age":15,"sex":2,"people":1110619},
9 | {"year":1850,"age":20,"sex":1,"people":1017281},
10 | {"year":1850,"age":20,"sex":2,"people":1003841},
11 | {"year":1850,"age":25,"sex":1,"people":862547},
12 | {"year":1850,"age":25,"sex":2,"people":799482},
13 | {"year":1850,"age":30,"sex":1,"people":730638},
14 | {"year":1850,"age":30,"sex":2,"people":639636},
15 | {"year":1850,"age":35,"sex":1,"people":588487},
16 | {"year":1850,"age":35,"sex":2,"people":505012},
17 | {"year":1850,"age":40,"sex":1,"people":475911},
18 | {"year":1850,"age":40,"sex":2,"people":428185},
19 | {"year":1850,"age":45,"sex":1,"people":384211},
20 | {"year":1850,"age":45,"sex":2,"people":341254},
21 | {"year":1850,"age":50,"sex":1,"people":321343},
22 | {"year":1850,"age":50,"sex":2,"people":286580},
23 | {"year":1850,"age":55,"sex":1,"people":194080},
24 | {"year":1850,"age":55,"sex":2,"people":187208},
25 | {"year":1850,"age":60,"sex":1,"people":174976},
26 | {"year":1850,"age":60,"sex":2,"people":162236},
27 | {"year":1850,"age":65,"sex":1,"people":106827},
28 | {"year":1850,"age":65,"sex":2,"people":105534},
29 | {"year":1850,"age":70,"sex":1,"people":73677},
30 | {"year":1850,"age":70,"sex":2,"people":71762},
31 | {"year":1850,"age":75,"sex":1,"people":40834},
32 | {"year":1850,"age":75,"sex":2,"people":40229},
33 | {"year":1850,"age":80,"sex":1,"people":23449},
34 | {"year":1850,"age":80,"sex":2,"people":22949},
35 | {"year":1850,"age":85,"sex":1,"people":8186},
36 | {"year":1850,"age":85,"sex":2,"people":10511},
37 | {"year":1850,"age":90,"sex":1,"people":5259},
38 | {"year":1850,"age":90,"sex":2,"people":6569},
39 | {"year":1860,"age":0,"sex":1,"people":2120846},
40 | {"year":1860,"age":0,"sex":2,"people":2092162},
41 | {"year":1860,"age":5,"sex":1,"people":1804467},
42 | {"year":1860,"age":5,"sex":2,"people":1778772},
43 | {"year":1860,"age":10,"sex":1,"people":1612640},
44 | {"year":1860,"age":10,"sex":2,"people":1540350},
45 | {"year":1860,"age":15,"sex":1,"people":1438094},
46 | {"year":1860,"age":15,"sex":2,"people":1495999},
47 | {"year":1860,"age":20,"sex":1,"people":1351121},
48 | {"year":1860,"age":20,"sex":2,"people":1370462},
49 | {"year":1860,"age":25,"sex":1,"people":1217615},
50 | {"year":1860,"age":25,"sex":2,"people":1116373},
51 | {"year":1860,"age":30,"sex":1,"people":1043174},
52 | {"year":1860,"age":30,"sex":2,"people":936055},
53 | {"year":1860,"age":35,"sex":1,"people":866910},
54 | {"year":1860,"age":35,"sex":2,"people":737136},
55 | {"year":1860,"age":40,"sex":1,"people":699434},
56 | {"year":1860,"age":40,"sex":2,"people":616826},
57 | {"year":1860,"age":45,"sex":1,"people":552404},
58 | {"year":1860,"age":45,"sex":2,"people":461739},
59 | {"year":1860,"age":50,"sex":1,"people":456176},
60 | {"year":1860,"age":50,"sex":2,"people":407305},
61 | {"year":1860,"age":55,"sex":1,"people":292417},
62 | {"year":1860,"age":55,"sex":2,"people":267224},
63 | {"year":1860,"age":60,"sex":1,"people":260887},
64 | {"year":1860,"age":60,"sex":2,"people":249735},
65 | {"year":1860,"age":65,"sex":1,"people":149331},
66 | {"year":1860,"age":65,"sex":2,"people":141405},
67 | {"year":1860,"age":70,"sex":1,"people":98465},
68 | {"year":1860,"age":70,"sex":2,"people":101778},
69 | {"year":1860,"age":75,"sex":1,"people":56699},
70 | {"year":1860,"age":75,"sex":2,"people":57597},
71 | {"year":1860,"age":80,"sex":1,"people":29007},
72 | {"year":1860,"age":80,"sex":2,"people":29506},
73 | {"year":1860,"age":85,"sex":1,"people":10434},
74 | {"year":1860,"age":85,"sex":2,"people":14053},
75 | {"year":1860,"age":90,"sex":1,"people":7232},
76 | {"year":1860,"age":90,"sex":2,"people":6622},
77 | {"year":1870,"age":0,"sex":1,"people":2800083},
78 | {"year":1870,"age":0,"sex":2,"people":2717102},
79 | {"year":1870,"age":5,"sex":1,"people":2428469},
80 | {"year":1870,"age":5,"sex":2,"people":2393680},
81 | {"year":1870,"age":10,"sex":1,"people":2427341},
82 | {"year":1870,"age":10,"sex":2,"people":2342670},
83 | {"year":1870,"age":15,"sex":1,"people":1958390},
84 | {"year":1870,"age":15,"sex":2,"people":2077248},
85 | {"year":1870,"age":20,"sex":1,"people":1805303},
86 | {"year":1870,"age":20,"sex":2,"people":1909382},
87 | {"year":1870,"age":25,"sex":1,"people":1509059},
88 | {"year":1870,"age":25,"sex":2,"people":1574285},
89 | {"year":1870,"age":30,"sex":1,"people":1251534},
90 | {"year":1870,"age":30,"sex":2,"people":1275629},
91 | {"year":1870,"age":35,"sex":1,"people":1185336},
92 | {"year":1870,"age":35,"sex":2,"people":1137490},
93 | {"year":1870,"age":40,"sex":1,"people":968861},
94 | {"year":1870,"age":40,"sex":2,"people":944401},
95 | {"year":1870,"age":45,"sex":1,"people":852672},
96 | {"year":1870,"age":45,"sex":2,"people":747916},
97 | {"year":1870,"age":50,"sex":1,"people":736387},
98 | {"year":1870,"age":50,"sex":2,"people":637801},
99 | {"year":1870,"age":55,"sex":1,"people":486036},
100 | {"year":1870,"age":55,"sex":2,"people":407819},
101 | {"year":1870,"age":60,"sex":1,"people":399264},
102 | {"year":1870,"age":60,"sex":2,"people":374801},
103 | {"year":1870,"age":65,"sex":1,"people":260829},
104 | {"year":1870,"age":65,"sex":2,"people":239080},
105 | {"year":1870,"age":70,"sex":1,"people":173364},
106 | {"year":1870,"age":70,"sex":2,"people":165501},
107 | {"year":1870,"age":75,"sex":1,"people":86929},
108 | {"year":1870,"age":75,"sex":2,"people":89540},
109 | {"year":1870,"age":80,"sex":1,"people":47427},
110 | {"year":1870,"age":80,"sex":2,"people":54190},
111 | {"year":1870,"age":85,"sex":1,"people":15891},
112 | {"year":1870,"age":85,"sex":2,"people":19302},
113 | {"year":1870,"age":90,"sex":1,"people":8649},
114 | {"year":1870,"age":90,"sex":2,"people":13068},
115 | {"year":1880,"age":0,"sex":1,"people":3533662},
116 | {"year":1880,"age":0,"sex":2,"people":3421597},
117 | {"year":1880,"age":5,"sex":1,"people":3297503},
118 | {"year":1880,"age":5,"sex":2,"people":3179142},
119 | {"year":1880,"age":10,"sex":1,"people":2911924},
120 | {"year":1880,"age":10,"sex":2,"people":2813550},
121 | {"year":1880,"age":15,"sex":1,"people":2457734},
122 | {"year":1880,"age":15,"sex":2,"people":2527818},
123 | {"year":1880,"age":20,"sex":1,"people":2547780},
124 | {"year":1880,"age":20,"sex":2,"people":2512803},
125 | {"year":1880,"age":25,"sex":1,"people":2119393},
126 | {"year":1880,"age":25,"sex":2,"people":1974241},
127 | {"year":1880,"age":30,"sex":1,"people":1749107},
128 | {"year":1880,"age":30,"sex":2,"people":1596772},
129 | {"year":1880,"age":35,"sex":1,"people":1540772},
130 | {"year":1880,"age":35,"sex":2,"people":1483717},
131 | {"year":1880,"age":40,"sex":1,"people":1237347},
132 | {"year":1880,"age":40,"sex":2,"people":1239435},
133 | {"year":1880,"age":45,"sex":1,"people":1065973},
134 | {"year":1880,"age":45,"sex":2,"people":1003711},
135 | {"year":1880,"age":50,"sex":1,"people":964484},
136 | {"year":1880,"age":50,"sex":2,"people":863012},
137 | {"year":1880,"age":55,"sex":1,"people":679147},
138 | {"year":1880,"age":55,"sex":2,"people":594843},
139 | {"year":1880,"age":60,"sex":1,"people":580298},
140 | {"year":1880,"age":60,"sex":2,"people":526956},
141 | {"year":1880,"age":65,"sex":1,"people":369398},
142 | {"year":1880,"age":65,"sex":2,"people":346303},
143 | {"year":1880,"age":70,"sex":1,"people":255422},
144 | {"year":1880,"age":70,"sex":2,"people":251860},
145 | {"year":1880,"age":75,"sex":1,"people":141628},
146 | {"year":1880,"age":75,"sex":2,"people":143513},
147 | {"year":1880,"age":80,"sex":1,"people":67526},
148 | {"year":1880,"age":80,"sex":2,"people":77290},
149 | {"year":1880,"age":85,"sex":1,"people":22437},
150 | {"year":1880,"age":85,"sex":2,"people":31227},
151 | {"year":1880,"age":90,"sex":1,"people":10272},
152 | {"year":1880,"age":90,"sex":2,"people":15451},
153 | {"year":1900,"age":0,"sex":1,"people":4619544},
154 | {"year":1900,"age":0,"sex":2,"people":4589196},
155 | {"year":1900,"age":5,"sex":1,"people":4465783},
156 | {"year":1900,"age":5,"sex":2,"people":4390483},
157 | {"year":1900,"age":10,"sex":1,"people":4057669},
158 | {"year":1900,"age":10,"sex":2,"people":4001749},
159 | {"year":1900,"age":15,"sex":1,"people":3774846},
160 | {"year":1900,"age":15,"sex":2,"people":3801743},
161 | {"year":1900,"age":20,"sex":1,"people":3694038},
162 | {"year":1900,"age":20,"sex":2,"people":3751061},
163 | {"year":1900,"age":25,"sex":1,"people":3389280},
164 | {"year":1900,"age":25,"sex":2,"people":3236056},
165 | {"year":1900,"age":30,"sex":1,"people":2918964},
166 | {"year":1900,"age":30,"sex":2,"people":2665174},
167 | {"year":1900,"age":35,"sex":1,"people":2633883},
168 | {"year":1900,"age":35,"sex":2,"people":2347737},
169 | {"year":1900,"age":40,"sex":1,"people":2261070},
170 | {"year":1900,"age":40,"sex":2,"people":2004987},
171 | {"year":1900,"age":45,"sex":1,"people":1868413},
172 | {"year":1900,"age":45,"sex":2,"people":1648025},
173 | {"year":1900,"age":50,"sex":1,"people":1571038},
174 | {"year":1900,"age":50,"sex":2,"people":1411981},
175 | {"year":1900,"age":55,"sex":1,"people":1161908},
176 | {"year":1900,"age":55,"sex":2,"people":1064632},
177 | {"year":1900,"age":60,"sex":1,"people":916571},
178 | {"year":1900,"age":60,"sex":2,"people":887508},
179 | {"year":1900,"age":65,"sex":1,"people":672663},
180 | {"year":1900,"age":65,"sex":2,"people":640212},
181 | {"year":1900,"age":70,"sex":1,"people":454747},
182 | {"year":1900,"age":70,"sex":2,"people":440007},
183 | {"year":1900,"age":75,"sex":1,"people":268211},
184 | {"year":1900,"age":75,"sex":2,"people":265879},
185 | {"year":1900,"age":80,"sex":1,"people":127435},
186 | {"year":1900,"age":80,"sex":2,"people":132449},
187 | {"year":1900,"age":85,"sex":1,"people":44008},
188 | {"year":1900,"age":85,"sex":2,"people":48614},
189 | {"year":1900,"age":90,"sex":1,"people":15164},
190 | {"year":1900,"age":90,"sex":2,"people":20093},
191 | {"year":1910,"age":0,"sex":1,"people":5296823},
192 | {"year":1910,"age":0,"sex":2,"people":5287477},
193 | {"year":1910,"age":5,"sex":1,"people":4991803},
194 | {"year":1910,"age":5,"sex":2,"people":4866139},
195 | {"year":1910,"age":10,"sex":1,"people":4650747},
196 | {"year":1910,"age":10,"sex":2,"people":4471887},
197 | {"year":1910,"age":15,"sex":1,"people":4566154},
198 | {"year":1910,"age":15,"sex":2,"people":4592269},
199 | {"year":1910,"age":20,"sex":1,"people":4637632},
200 | {"year":1910,"age":20,"sex":2,"people":4447683},
201 | {"year":1910,"age":25,"sex":1,"people":4257755},
202 | {"year":1910,"age":25,"sex":2,"people":3946153},
203 | {"year":1910,"age":30,"sex":1,"people":3658125},
204 | {"year":1910,"age":30,"sex":2,"people":3295220},
205 | {"year":1910,"age":35,"sex":1,"people":3427518},
206 | {"year":1910,"age":35,"sex":2,"people":3088990},
207 | {"year":1910,"age":40,"sex":1,"people":2860229},
208 | {"year":1910,"age":40,"sex":2,"people":2471267},
209 | {"year":1910,"age":45,"sex":1,"people":2363801},
210 | {"year":1910,"age":45,"sex":2,"people":2114930},
211 | {"year":1910,"age":50,"sex":1,"people":2126516},
212 | {"year":1910,"age":50,"sex":2,"people":1773592},
213 | {"year":1910,"age":55,"sex":1,"people":1508358},
214 | {"year":1910,"age":55,"sex":2,"people":1317651},
215 | {"year":1910,"age":60,"sex":1,"people":1189421},
216 | {"year":1910,"age":60,"sex":2,"people":1090697},
217 | {"year":1910,"age":65,"sex":1,"people":850159},
218 | {"year":1910,"age":65,"sex":2,"people":813868},
219 | {"year":1910,"age":70,"sex":1,"people":557936},
220 | {"year":1910,"age":70,"sex":2,"people":547623},
221 | {"year":1910,"age":75,"sex":1,"people":322679},
222 | {"year":1910,"age":75,"sex":2,"people":350900},
223 | {"year":1910,"age":80,"sex":1,"people":161715},
224 | {"year":1910,"age":80,"sex":2,"people":174315},
225 | {"year":1910,"age":85,"sex":1,"people":59699},
226 | {"year":1910,"age":85,"sex":2,"people":62725},
227 | {"year":1910,"age":90,"sex":1,"people":23929},
228 | {"year":1910,"age":90,"sex":2,"people":28965},
229 | {"year":1920,"age":0,"sex":1,"people":5934792},
230 | {"year":1920,"age":0,"sex":2,"people":5694244},
231 | {"year":1920,"age":5,"sex":1,"people":5789008},
232 | {"year":1920,"age":5,"sex":2,"people":5693960},
233 | {"year":1920,"age":10,"sex":1,"people":5401156},
234 | {"year":1920,"age":10,"sex":2,"people":5293057},
235 | {"year":1920,"age":15,"sex":1,"people":4724365},
236 | {"year":1920,"age":15,"sex":2,"people":4779936},
237 | {"year":1920,"age":20,"sex":1,"people":4549411},
238 | {"year":1920,"age":20,"sex":2,"people":4742632},
239 | {"year":1920,"age":25,"sex":1,"people":4565066},
240 | {"year":1920,"age":25,"sex":2,"people":4529382},
241 | {"year":1920,"age":30,"sex":1,"people":4110771},
242 | {"year":1920,"age":30,"sex":2,"people":3982426},
243 | {"year":1920,"age":35,"sex":1,"people":4081543},
244 | {"year":1920,"age":35,"sex":2,"people":3713810},
245 | {"year":1920,"age":40,"sex":1,"people":3321923},
246 | {"year":1920,"age":40,"sex":2,"people":3059757},
247 | {"year":1920,"age":45,"sex":1,"people":3143891},
248 | {"year":1920,"age":45,"sex":2,"people":2669089},
249 | {"year":1920,"age":50,"sex":1,"people":2546035},
250 | {"year":1920,"age":50,"sex":2,"people":2200491},
251 | {"year":1920,"age":55,"sex":1,"people":1880975},
252 | {"year":1920,"age":55,"sex":2,"people":1674672},
253 | {"year":1920,"age":60,"sex":1,"people":1587549},
254 | {"year":1920,"age":60,"sex":2,"people":1382877},
255 | {"year":1920,"age":65,"sex":1,"people":1095956},
256 | {"year":1920,"age":65,"sex":2,"people":989901},
257 | {"year":1920,"age":70,"sex":1,"people":714618},
258 | {"year":1920,"age":70,"sex":2,"people":690097},
259 | {"year":1920,"age":75,"sex":1,"people":417292},
260 | {"year":1920,"age":75,"sex":2,"people":439465},
261 | {"year":1920,"age":80,"sex":1,"people":187000},
262 | {"year":1920,"age":80,"sex":2,"people":211110},
263 | {"year":1920,"age":85,"sex":1,"people":75991},
264 | {"year":1920,"age":85,"sex":2,"people":92829},
265 | {"year":1920,"age":90,"sex":1,"people":22398},
266 | {"year":1920,"age":90,"sex":2,"people":32085},
267 | {"year":1930,"age":0,"sex":1,"people":5875250},
268 | {"year":1930,"age":0,"sex":2,"people":5662530},
269 | {"year":1930,"age":5,"sex":1,"people":6542592},
270 | {"year":1930,"age":5,"sex":2,"people":6129561},
271 | {"year":1930,"age":10,"sex":1,"people":6064820},
272 | {"year":1930,"age":10,"sex":2,"people":5986529},
273 | {"year":1930,"age":15,"sex":1,"people":5709452},
274 | {"year":1930,"age":15,"sex":2,"people":5769587},
275 | {"year":1930,"age":20,"sex":1,"people":5305992},
276 | {"year":1930,"age":20,"sex":2,"people":5565382},
277 | {"year":1930,"age":25,"sex":1,"people":4929853},
278 | {"year":1930,"age":25,"sex":2,"people":5050229},
279 | {"year":1930,"age":30,"sex":1,"people":4424408},
280 | {"year":1930,"age":30,"sex":2,"people":4455213},
281 | {"year":1930,"age":35,"sex":1,"people":4576531},
282 | {"year":1930,"age":35,"sex":2,"people":4593776},
283 | {"year":1930,"age":40,"sex":1,"people":4075139},
284 | {"year":1930,"age":40,"sex":2,"people":3754022},
285 | {"year":1930,"age":45,"sex":1,"people":3633152},
286 | {"year":1930,"age":45,"sex":2,"people":3396558},
287 | {"year":1930,"age":50,"sex":1,"people":3128108},
288 | {"year":1930,"age":50,"sex":2,"people":2809191},
289 | {"year":1930,"age":55,"sex":1,"people":2434077},
290 | {"year":1930,"age":55,"sex":2,"people":2298614},
291 | {"year":1930,"age":60,"sex":1,"people":1927564},
292 | {"year":1930,"age":60,"sex":2,"people":1783515},
293 | {"year":1930,"age":65,"sex":1,"people":1397275},
294 | {"year":1930,"age":65,"sex":2,"people":1307312},
295 | {"year":1930,"age":70,"sex":1,"people":919045},
296 | {"year":1930,"age":70,"sex":2,"people":918509},
297 | {"year":1930,"age":75,"sex":1,"people":536375},
298 | {"year":1930,"age":75,"sex":2,"people":522716},
299 | {"year":1930,"age":80,"sex":1,"people":246708},
300 | {"year":1930,"age":80,"sex":2,"people":283579},
301 | {"year":1930,"age":85,"sex":1,"people":88978},
302 | {"year":1930,"age":85,"sex":2,"people":109210},
303 | {"year":1930,"age":90,"sex":1,"people":30338},
304 | {"year":1930,"age":90,"sex":2,"people":43483},
305 | {"year":1940,"age":0,"sex":1,"people":5294628},
306 | {"year":1940,"age":0,"sex":2,"people":5124653},
307 | {"year":1940,"age":5,"sex":1,"people":5468378},
308 | {"year":1940,"age":5,"sex":2,"people":5359099},
309 | {"year":1940,"age":10,"sex":1,"people":5960416},
310 | {"year":1940,"age":10,"sex":2,"people":5868532},
311 | {"year":1940,"age":15,"sex":1,"people":6165109},
312 | {"year":1940,"age":15,"sex":2,"people":6193701},
313 | {"year":1940,"age":20,"sex":1,"people":5682414},
314 | {"year":1940,"age":20,"sex":2,"people":5896002},
315 | {"year":1940,"age":25,"sex":1,"people":5438166},
316 | {"year":1940,"age":25,"sex":2,"people":5664244},
317 | {"year":1940,"age":30,"sex":1,"people":5040048},
318 | {"year":1940,"age":30,"sex":2,"people":5171522},
319 | {"year":1940,"age":35,"sex":1,"people":4724804},
320 | {"year":1940,"age":35,"sex":2,"people":4791809},
321 | {"year":1940,"age":40,"sex":1,"people":4437392},
322 | {"year":1940,"age":40,"sex":2,"people":4394061},
323 | {"year":1940,"age":45,"sex":1,"people":4190187},
324 | {"year":1940,"age":45,"sex":2,"people":4050290},
325 | {"year":1940,"age":50,"sex":1,"people":3785735},
326 | {"year":1940,"age":50,"sex":2,"people":3488396},
327 | {"year":1940,"age":55,"sex":1,"people":2972069},
328 | {"year":1940,"age":55,"sex":2,"people":2810000},
329 | {"year":1940,"age":60,"sex":1,"people":2370232},
330 | {"year":1940,"age":60,"sex":2,"people":2317790},
331 | {"year":1940,"age":65,"sex":1,"people":1897678},
332 | {"year":1940,"age":65,"sex":2,"people":1911117},
333 | {"year":1940,"age":70,"sex":1,"people":1280023},
334 | {"year":1940,"age":70,"sex":2,"people":1287711},
335 | {"year":1940,"age":75,"sex":1,"people":713875},
336 | {"year":1940,"age":75,"sex":2,"people":764915},
337 | {"year":1940,"age":80,"sex":1,"people":359418},
338 | {"year":1940,"age":80,"sex":2,"people":414761},
339 | {"year":1940,"age":85,"sex":1,"people":127303},
340 | {"year":1940,"age":85,"sex":2,"people":152131},
341 | {"year":1940,"age":90,"sex":1,"people":42263},
342 | {"year":1940,"age":90,"sex":2,"people":58119},
343 | {"year":1950,"age":0,"sex":1,"people":8211806},
344 | {"year":1950,"age":0,"sex":2,"people":7862267},
345 | {"year":1950,"age":5,"sex":1,"people":6706601},
346 | {"year":1950,"age":5,"sex":2,"people":6450863},
347 | {"year":1950,"age":10,"sex":1,"people":5629744},
348 | {"year":1950,"age":10,"sex":2,"people":5430835},
349 | {"year":1950,"age":15,"sex":1,"people":5264129},
350 | {"year":1950,"age":15,"sex":2,"people":5288742},
351 | {"year":1950,"age":20,"sex":1,"people":5573308},
352 | {"year":1950,"age":20,"sex":2,"people":5854227},
353 | {"year":1950,"age":25,"sex":1,"people":6007254},
354 | {"year":1950,"age":25,"sex":2,"people":6317332},
355 | {"year":1950,"age":30,"sex":1,"people":5676022},
356 | {"year":1950,"age":30,"sex":2,"people":5895178},
357 | {"year":1950,"age":35,"sex":1,"people":5511364},
358 | {"year":1950,"age":35,"sex":2,"people":5696261},
359 | {"year":1950,"age":40,"sex":1,"people":5076985},
360 | {"year":1950,"age":40,"sex":2,"people":5199224},
361 | {"year":1950,"age":45,"sex":1,"people":4533177},
362 | {"year":1950,"age":45,"sex":2,"people":4595842},
363 | {"year":1950,"age":50,"sex":1,"people":4199164},
364 | {"year":1950,"age":50,"sex":2,"people":4147295},
365 | {"year":1950,"age":55,"sex":1,"people":3667351},
366 | {"year":1950,"age":55,"sex":2,"people":3595158},
367 | {"year":1950,"age":60,"sex":1,"people":3035038},
368 | {"year":1950,"age":60,"sex":2,"people":3009768},
369 | {"year":1950,"age":65,"sex":1,"people":2421234},
370 | {"year":1950,"age":65,"sex":2,"people":2548250},
371 | {"year":1950,"age":70,"sex":1,"people":1627920},
372 | {"year":1950,"age":70,"sex":2,"people":1786831},
373 | {"year":1950,"age":75,"sex":1,"people":1006530},
374 | {"year":1950,"age":75,"sex":2,"people":1148469},
375 | {"year":1950,"age":80,"sex":1,"people":511727},
376 | {"year":1950,"age":80,"sex":2,"people":637717},
377 | {"year":1950,"age":85,"sex":1,"people":182821},
378 | {"year":1950,"age":85,"sex":2,"people":242798},
379 | {"year":1950,"age":90,"sex":1,"people":54836},
380 | {"year":1950,"age":90,"sex":2,"people":90766},
381 | {"year":1960,"age":0,"sex":1,"people":10374975},
382 | {"year":1960,"age":0,"sex":2,"people":10146999},
383 | {"year":1960,"age":5,"sex":1,"people":9495503},
384 | {"year":1960,"age":5,"sex":2,"people":9250741},
385 | {"year":1960,"age":10,"sex":1,"people":8563700},
386 | {"year":1960,"age":10,"sex":2,"people":8310764},
387 | {"year":1960,"age":15,"sex":1,"people":6620902},
388 | {"year":1960,"age":15,"sex":2,"people":6617493},
389 | {"year":1960,"age":20,"sex":1,"people":5268384},
390 | {"year":1960,"age":20,"sex":2,"people":5513495},
391 | {"year":1960,"age":25,"sex":1,"people":5311805},
392 | {"year":1960,"age":25,"sex":2,"people":5548259},
393 | {"year":1960,"age":30,"sex":1,"people":5801342},
394 | {"year":1960,"age":30,"sex":2,"people":6090862},
395 | {"year":1960,"age":35,"sex":1,"people":6063063},
396 | {"year":1960,"age":35,"sex":2,"people":6431337},
397 | {"year":1960,"age":40,"sex":1,"people":5657943},
398 | {"year":1960,"age":40,"sex":2,"people":5940520},
399 | {"year":1960,"age":45,"sex":1,"people":5345658},
400 | {"year":1960,"age":45,"sex":2,"people":5516028},
401 | {"year":1960,"age":50,"sex":1,"people":4763364},
402 | {"year":1960,"age":50,"sex":2,"people":4928844},
403 | {"year":1960,"age":55,"sex":1,"people":4170581},
404 | {"year":1960,"age":55,"sex":2,"people":4402878},
405 | {"year":1960,"age":60,"sex":1,"people":3405293},
406 | {"year":1960,"age":60,"sex":2,"people":3723839},
407 | {"year":1960,"age":65,"sex":1,"people":2859371},
408 | {"year":1960,"age":65,"sex":2,"people":3268699},
409 | {"year":1960,"age":70,"sex":1,"people":2115763},
410 | {"year":1960,"age":70,"sex":2,"people":2516479},
411 | {"year":1960,"age":75,"sex":1,"people":1308913},
412 | {"year":1960,"age":75,"sex":2,"people":1641371},
413 | {"year":1960,"age":80,"sex":1,"people":619923},
414 | {"year":1960,"age":80,"sex":2,"people":856952},
415 | {"year":1960,"age":85,"sex":1,"people":253245},
416 | {"year":1960,"age":85,"sex":2,"people":384572},
417 | {"year":1960,"age":90,"sex":1,"people":75908},
418 | {"year":1960,"age":90,"sex":2,"people":135774},
419 | {"year":1970,"age":0,"sex":1,"people":8685121},
420 | {"year":1970,"age":0,"sex":2,"people":8326887},
421 | {"year":1970,"age":5,"sex":1,"people":10411131},
422 | {"year":1970,"age":5,"sex":2,"people":10003293},
423 | {"year":1970,"age":10,"sex":1,"people":10756403},
424 | {"year":1970,"age":10,"sex":2,"people":10343538},
425 | {"year":1970,"age":15,"sex":1,"people":9605399},
426 | {"year":1970,"age":15,"sex":2,"people":9414284},
427 | {"year":1970,"age":20,"sex":1,"people":7729202},
428 | {"year":1970,"age":20,"sex":2,"people":8341830},
429 | {"year":1970,"age":25,"sex":1,"people":6539301},
430 | {"year":1970,"age":25,"sex":2,"people":6903041},
431 | {"year":1970,"age":30,"sex":1,"people":5519879},
432 | {"year":1970,"age":30,"sex":2,"people":5851441},
433 | {"year":1970,"age":35,"sex":1,"people":5396732},
434 | {"year":1970,"age":35,"sex":2,"people":5708021},
435 | {"year":1970,"age":40,"sex":1,"people":5718538},
436 | {"year":1970,"age":40,"sex":2,"people":6129319},
437 | {"year":1970,"age":45,"sex":1,"people":5794120},
438 | {"year":1970,"age":45,"sex":2,"people":6198742},
439 | {"year":1970,"age":50,"sex":1,"people":5298312},
440 | {"year":1970,"age":50,"sex":2,"people":5783817},
441 | {"year":1970,"age":55,"sex":1,"people":4762911},
442 | {"year":1970,"age":55,"sex":2,"people":5222164},
443 | {"year":1970,"age":60,"sex":1,"people":4037643},
444 | {"year":1970,"age":60,"sex":2,"people":4577251},
445 | {"year":1970,"age":65,"sex":1,"people":3142606},
446 | {"year":1970,"age":65,"sex":2,"people":3894827},
447 | {"year":1970,"age":70,"sex":1,"people":2340826},
448 | {"year":1970,"age":70,"sex":2,"people":3138009},
449 | {"year":1970,"age":75,"sex":1,"people":1599269},
450 | {"year":1970,"age":75,"sex":2,"people":2293376},
451 | {"year":1970,"age":80,"sex":1,"people":886155},
452 | {"year":1970,"age":80,"sex":2,"people":1417553},
453 | {"year":1970,"age":85,"sex":1,"people":371123},
454 | {"year":1970,"age":85,"sex":2,"people":658511},
455 | {"year":1970,"age":90,"sex":1,"people":186502},
456 | {"year":1970,"age":90,"sex":2,"people":314929},
457 | {"year":1980,"age":0,"sex":1,"people":8439366},
458 | {"year":1980,"age":0,"sex":2,"people":8081854},
459 | {"year":1980,"age":5,"sex":1,"people":8680730},
460 | {"year":1980,"age":5,"sex":2,"people":8275881},
461 | {"year":1980,"age":10,"sex":1,"people":9452338},
462 | {"year":1980,"age":10,"sex":2,"people":9048483},
463 | {"year":1980,"age":15,"sex":1,"people":10698856},
464 | {"year":1980,"age":15,"sex":2,"people":10410271},
465 | {"year":1980,"age":20,"sex":1,"people":10486776},
466 | {"year":1980,"age":20,"sex":2,"people":10614947},
467 | {"year":1980,"age":25,"sex":1,"people":9624053},
468 | {"year":1980,"age":25,"sex":2,"people":9827903},
469 | {"year":1980,"age":30,"sex":1,"people":8705835},
470 | {"year":1980,"age":30,"sex":2,"people":8955225},
471 | {"year":1980,"age":35,"sex":1,"people":6852069},
472 | {"year":1980,"age":35,"sex":2,"people":7134239},
473 | {"year":1980,"age":40,"sex":1,"people":5692148},
474 | {"year":1980,"age":40,"sex":2,"people":5953910},
475 | {"year":1980,"age":45,"sex":1,"people":5342469},
476 | {"year":1980,"age":45,"sex":2,"people":5697543},
477 | {"year":1980,"age":50,"sex":1,"people":5603709},
478 | {"year":1980,"age":50,"sex":2,"people":6110117},
479 | {"year":1980,"age":55,"sex":1,"people":5485098},
480 | {"year":1980,"age":55,"sex":2,"people":6160229},
481 | {"year":1980,"age":60,"sex":1,"people":4696140},
482 | {"year":1980,"age":60,"sex":2,"people":5456885},
483 | {"year":1980,"age":65,"sex":1,"people":3893510},
484 | {"year":1980,"age":65,"sex":2,"people":4896947},
485 | {"year":1980,"age":70,"sex":1,"people":2857774},
486 | {"year":1980,"age":70,"sex":2,"people":3963441},
487 | {"year":1980,"age":75,"sex":1,"people":1840438},
488 | {"year":1980,"age":75,"sex":2,"people":2951759},
489 | {"year":1980,"age":80,"sex":1,"people":1012886},
490 | {"year":1980,"age":80,"sex":2,"people":1919292},
491 | {"year":1980,"age":85,"sex":1,"people":472338},
492 | {"year":1980,"age":85,"sex":2,"people":1023115},
493 | {"year":1980,"age":90,"sex":1,"people":204148},
494 | {"year":1980,"age":90,"sex":2,"people":499046},
495 | {"year":1990,"age":0,"sex":1,"people":9307465},
496 | {"year":1990,"age":0,"sex":2,"people":8894007},
497 | {"year":1990,"age":5,"sex":1,"people":9274732},
498 | {"year":1990,"age":5,"sex":2,"people":8799955},
499 | {"year":1990,"age":10,"sex":1,"people":8782542},
500 | {"year":1990,"age":10,"sex":2,"people":8337284},
501 | {"year":1990,"age":15,"sex":1,"people":9020572},
502 | {"year":1990,"age":15,"sex":2,"people":8590991},
503 | {"year":1990,"age":20,"sex":1,"people":9436188},
504 | {"year":1990,"age":20,"sex":2,"people":9152644},
505 | {"year":1990,"age":25,"sex":1,"people":10658027},
506 | {"year":1990,"age":25,"sex":2,"people":10587292},
507 | {"year":1990,"age":30,"sex":1,"people":11028712},
508 | {"year":1990,"age":30,"sex":2,"people":11105750},
509 | {"year":1990,"age":35,"sex":1,"people":9853933},
510 | {"year":1990,"age":35,"sex":2,"people":10038644},
511 | {"year":1990,"age":40,"sex":1,"people":8712632},
512 | {"year":1990,"age":40,"sex":2,"people":8928252},
513 | {"year":1990,"age":45,"sex":1,"people":6848082},
514 | {"year":1990,"age":45,"sex":2,"people":7115129},
515 | {"year":1990,"age":50,"sex":1,"people":5553992},
516 | {"year":1990,"age":50,"sex":2,"people":5899925},
517 | {"year":1990,"age":55,"sex":1,"people":4981670},
518 | {"year":1990,"age":55,"sex":2,"people":5460506},
519 | {"year":1990,"age":60,"sex":1,"people":4953822},
520 | {"year":1990,"age":60,"sex":2,"people":5663205},
521 | {"year":1990,"age":65,"sex":1,"people":4538398},
522 | {"year":1990,"age":65,"sex":2,"people":5594108},
523 | {"year":1990,"age":70,"sex":1,"people":3429420},
524 | {"year":1990,"age":70,"sex":2,"people":4610222},
525 | {"year":1990,"age":75,"sex":1,"people":2344932},
526 | {"year":1990,"age":75,"sex":2,"people":3723980},
527 | {"year":1990,"age":80,"sex":1,"people":1342996},
528 | {"year":1990,"age":80,"sex":2,"people":2545730},
529 | {"year":1990,"age":85,"sex":1,"people":588790},
530 | {"year":1990,"age":85,"sex":2,"people":1419494},
531 | {"year":1990,"age":90,"sex":1,"people":238459},
532 | {"year":1990,"age":90,"sex":2,"people":745146},
533 | {"year":2000,"age":0,"sex":1,"people":9735380},
534 | {"year":2000,"age":0,"sex":2,"people":9310714},
535 | {"year":2000,"age":5,"sex":1,"people":10552146},
536 | {"year":2000,"age":5,"sex":2,"people":10069564},
537 | {"year":2000,"age":10,"sex":1,"people":10563233},
538 | {"year":2000,"age":10,"sex":2,"people":10022524},
539 | {"year":2000,"age":15,"sex":1,"people":10237419},
540 | {"year":2000,"age":15,"sex":2,"people":9692669},
541 | {"year":2000,"age":20,"sex":1,"people":9731315},
542 | {"year":2000,"age":20,"sex":2,"people":9324244},
543 | {"year":2000,"age":25,"sex":1,"people":9659493},
544 | {"year":2000,"age":25,"sex":2,"people":9518507},
545 | {"year":2000,"age":30,"sex":1,"people":10205879},
546 | {"year":2000,"age":30,"sex":2,"people":10119296},
547 | {"year":2000,"age":35,"sex":1,"people":11475182},
548 | {"year":2000,"age":35,"sex":2,"people":11635647},
549 | {"year":2000,"age":40,"sex":1,"people":11320252},
550 | {"year":2000,"age":40,"sex":2,"people":11488578},
551 | {"year":2000,"age":45,"sex":1,"people":9925006},
552 | {"year":2000,"age":45,"sex":2,"people":10261253},
553 | {"year":2000,"age":50,"sex":1,"people":8507934},
554 | {"year":2000,"age":50,"sex":2,"people":8911133},
555 | {"year":2000,"age":55,"sex":1,"people":6459082},
556 | {"year":2000,"age":55,"sex":2,"people":6921268},
557 | {"year":2000,"age":60,"sex":1,"people":5123399},
558 | {"year":2000,"age":60,"sex":2,"people":5668961},
559 | {"year":2000,"age":65,"sex":1,"people":4453623},
560 | {"year":2000,"age":65,"sex":2,"people":4804784},
561 | {"year":2000,"age":70,"sex":1,"people":3792145},
562 | {"year":2000,"age":70,"sex":2,"people":5184855},
563 | {"year":2000,"age":75,"sex":1,"people":2912655},
564 | {"year":2000,"age":75,"sex":2,"people":4355644},
565 | {"year":2000,"age":80,"sex":1,"people":1902638},
566 | {"year":2000,"age":80,"sex":2,"people":3221898},
567 | {"year":2000,"age":85,"sex":1,"people":970357},
568 | {"year":2000,"age":85,"sex":2,"people":1981156},
569 | {"year":2000,"age":90,"sex":1,"people":336303},
570 | {"year":2000,"age":90,"sex":2,"people":1064581}]
--------------------------------------------------------------------------------