├── .DS_Store ├── .gitattributes ├── .gitignore ├── .jshintrc ├── Gruntfile.js ├── README.md ├── app ├── 404.html ├── data │ ├── Untitled-2.json │ ├── default0.json │ ├── default1.json │ ├── default2.json │ ├── default3.json │ ├── default4.json │ ├── default5.json │ ├── editor.json │ ├── enumerate.json │ ├── fluctuation.json │ ├── horizontal_unit_column.json │ ├── maxfill_aspect.json │ ├── mosaic.json │ ├── size_sum_notShared.json │ ├── size_sum_shared.json │ ├── size_uniform_notShared.json │ ├── size_uniform_shared.json │ ├── square_aspect.json │ ├── squarified.json │ ├── titanic.csv │ ├── titanic3.csv │ ├── titanic_spec1.json │ ├── titanic_spec2.json │ ├── titanic_spec3.json │ ├── titanic_spec4.json │ ├── titanic_spec_packxy_hierarchy.json │ ├── titanic_spec_packxy_isolated.json │ ├── titanic_spec_packxy_mixed.json │ ├── unit_column_chart.json │ ├── unit_column_chart_shared.json │ ├── unit_column_chart_shared_mark.json │ ├── unit_small_multiple.json │ └── violin.json ├── favicon.ico ├── images │ ├── process.png │ ├── vcd-mosaic.png │ └── yeoman.png ├── index.html ├── robots.txt ├── scripts │ ├── app.js │ ├── controllers │ │ ├── about.js │ │ ├── enum.js │ │ ├── example.js │ │ ├── live.js │ │ └── main.js │ └── services │ │ ├── treemap-squarify.js │ │ └── unitchart.js ├── styles │ └── main.css └── views │ ├── enum.html │ ├── example.html │ ├── live.html │ └── main.html ├── bower.json ├── package-lock.json ├── package.json ├── python ├── .ipynb_checkpoints │ └── data script-checkpoint.ipynb ├── data script.ipynb └── untitled.txt └── test ├── .jshintrc ├── karma.conf.js └── spec ├── controllers ├── about.js ├── enum.js ├── example.js ├── live.js └── main.js └── services └── unitchart.js /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intuinno/unit/186ed809d4a7bce0c1aba99da5de4d997e2d3fbe/.DS_Store -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | *.swp 3 | .tmp 4 | bower_components 5 | test/bower_components 6 | dist/ 7 | .grunt 8 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | // JSHint Default Configuration File (as on JSHint website) 3 | // See http://jshint.com/docs/ for more details 4 | 5 | "maxerr" : 50, // {int} Maximum error before stopping 6 | 7 | // Enforcing 8 | "bitwise" : true, // true: Prohibit bitwise operators (&, |, ^, etc.) 9 | "camelcase" : false, // true: Identifiers must be in camelCase 10 | "curly" : true, // true: Require {} for every new block or scope 11 | "eqeqeq" : true, // true: Require triple equals (===) for comparison 12 | "forin" : true, // true: Require filtering for..in loops with obj.hasOwnProperty() 13 | "freeze" : true, // true: prohibits overwriting prototypes of native objects such as Array, Date etc. 14 | "immed" : false, // true: Require immediate invocations to be wrapped in parens e.g. `(function () { } ());` 15 | "latedef" : false, // true: Require variables/functions to be defined before being used 16 | "newcap" : false, // true: Require capitalization of all constructor functions e.g. `new F()` 17 | "noarg" : true, // true: Prohibit use of `arguments.caller` and `arguments.callee` 18 | "noempty" : true, // true: Prohibit use of empty blocks 19 | "nonbsp" : true, // true: Prohibit "non-breaking whitespace" characters. 20 | "nonew" : false, // true: Prohibit use of constructors for side-effects (without assignment) 21 | "plusplus" : false, // true: Prohibit use of `++` and `--` 22 | "quotmark" : false, // Quotation mark consistency: 23 | // false : do nothing (default) 24 | // true : ensure whatever is used is consistent 25 | // "single" : require single quotes 26 | // "double" : require double quotes 27 | "undef" : true, // true: Require all non-global variables to be declared (prevents global leaks) 28 | "unused" : true, // Unused variables: 29 | // true : all variables, last function parameter 30 | // "vars" : all variables only 31 | // "strict" : all variables, all function parameters 32 | "strict" : true, // true: Requires all functions run in ES5 Strict Mode 33 | "maxparams" : false, // {int} Max number of formal params allowed per function 34 | "maxdepth" : false, // {int} Max depth of nested blocks (within functions) 35 | "maxstatements" : false, // {int} Max number statements per function 36 | "maxcomplexity" : false, // {int} Max cyclomatic complexity per function 37 | "maxlen" : false, // {int} Max number of characters per line 38 | "varstmt" : false, // true: Disallow any var statements. Only `let` and `const` are allowed. 39 | 40 | // Relaxing 41 | "asi" : false, // true: Tolerate Automatic Semicolon Insertion (no semicolons) 42 | "boss" : false, // true: Tolerate assignments where comparisons would be expected 43 | "debug" : false, // true: Allow debugger statements e.g. browser breakpoints. 44 | "eqnull" : false, // true: Tolerate use of `== null` 45 | "esversion" : 5, // {int} Specify the ECMAScript version to which the code must adhere. 46 | "moz" : false, // true: Allow Mozilla specific syntax (extends and overrides esnext features) 47 | // (ex: `for each`, multiple try/catch, function expression…) 48 | "evil" : false, // true: Tolerate use of `eval` and `new Function()` 49 | "expr" : false, // true: Tolerate `ExpressionStatement` as Programs 50 | "funcscope" : false, // true: Tolerate defining variables inside control statements 51 | "globalstrict" : false, // true: Allow global "use strict" (also enables 'strict') 52 | "iterator" : false, // true: Tolerate using the `__iterator__` property 53 | "lastsemic" : false, // true: Tolerate omitting a semicolon for the last statement of a 1-line block 54 | "laxbreak" : false, // true: Tolerate possibly unsafe line breakings 55 | "laxcomma" : false, // true: Tolerate comma-first style coding 56 | "loopfunc" : false, // true: Tolerate functions being defined in loops 57 | "multistr" : false, // true: Tolerate multi-line strings 58 | "noyield" : false, // true: Tolerate generator functions with no yield statement in them. 59 | "notypeof" : false, // true: Tolerate invalid typeof operator values 60 | "proto" : false, // true: Tolerate using the `__proto__` property 61 | "scripturl" : false, // true: Tolerate script-targeted URLs 62 | "shadow" : false, // true: Allows re-define variables later in code e.g. `var x=1; x=2;` 63 | "sub" : false, // true: Tolerate using `[]` notation when it can still be expressed in dot notation 64 | "supernew" : false, // true: Tolerate `new function () { ... };` and `new Object;` 65 | "validthis" : false, // true: Tolerate using this in a non-constructor function 66 | 67 | // Environments 68 | "browser" : true, // Web Browser (window, document, etc) 69 | "browserify" : false, // Browserify (node.js code in the browser) 70 | "couch" : false, // CouchDB 71 | "devel" : true, // Development/debugging (alert, confirm, etc) 72 | "dojo" : false, // Dojo Toolkit 73 | "jasmine" : false, // Jasmine 74 | "jquery" : false, // jQuery 75 | "mocha" : true, // Mocha 76 | "mootools" : false, // MooTools 77 | "node" : false, // Node.js 78 | "nonstandard" : false, // Widely adopted globals (escape, unescape, etc) 79 | "phantom" : false, // PhantomJS 80 | "prototypejs" : false, // Prototype and Scriptaculous 81 | "qunit" : false, // QUnit 82 | "rhino" : false, // Rhino 83 | "shelljs" : false, // ShellJS 84 | "typed" : false, // Globals for typed array constructions 85 | "worker" : false, // Web Workers 86 | "wsh" : false, // Windows Scripting Host 87 | "yui" : false, // Yahoo User Interface 88 | 89 | // Custom Globals 90 | "globals" : {} // additional predefined global variables 91 | } 92 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | // Generated on 2016-08-23 using generator-angular 0.15.1 2 | 'use strict'; 3 | 4 | // # Globbing 5 | // for performance reasons we're only matching one level down: 6 | // 'test/spec/{,*/}*.js' 7 | // use this if you want to recursively match all subfolders: 8 | // 'test/spec/**/*.js' 9 | 10 | module.exports = function(grunt) { 11 | 12 | // Time how long tasks take. Can help when optimizing build times 13 | require('time-grunt')(grunt); 14 | 15 | // Automatically load required Grunt tasks 16 | require('jit-grunt')(grunt, { 17 | useminPrepare: 'grunt-usemin', 18 | ngtemplates: 'grunt-angular-templates', 19 | cdnify: 'grunt-google-cdn' 20 | }); 21 | 22 | // grunt.loadNpmTasks('grunt-gh-pages'); 23 | 24 | // Configurable paths for the application 25 | var appConfig = { 26 | app: require('./bower.json').appPath || 'app', 27 | dist: 'dist' 28 | }; 29 | 30 | // Define the configuration for all the tasks 31 | grunt.initConfig({ 32 | 33 | // Project settings 34 | yeoman: appConfig, 35 | 36 | // Watches files for changes and runs tasks based on the changed files 37 | 38 | 'gh-pages': { 39 | options: { 40 | base: 'dist' 41 | }, 42 | src: ['**'] 43 | }, 44 | watch: { 45 | bower: { 46 | files: ['bower.json'], 47 | tasks: ['wiredep'] 48 | }, 49 | js: { 50 | files: ['<%= yeoman.app %>/scripts/{,*/}*.js'], 51 | tasks: ['newer:jshint:all', 'newer:jscs:all'], 52 | options: { 53 | livereload: '<%= connect.options.livereload %>' 54 | } 55 | }, 56 | jsTest: { 57 | files: ['test/spec/{,*/}*.js'], 58 | tasks: ['newer:jshint:test', 'newer:jscs:test', 'karma'] 59 | }, 60 | styles: { 61 | files: ['<%= yeoman.app %>/styles/{,*/}*.css'], 62 | tasks: ['newer:copy:styles', 'postcss'] 63 | }, 64 | gruntfile: { 65 | files: ['Gruntfile.js'] 66 | }, 67 | livereload: { 68 | options: { 69 | livereload: '<%= connect.options.livereload %>' 70 | }, 71 | files: [ 72 | '<%= yeoman.app %>/{,*/}*.html', 73 | '.tmp/styles/{,*/}*.css', 74 | '<%= yeoman.app %>/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}' 75 | ] 76 | } 77 | }, 78 | // The actual grunt server settings 79 | connect: { 80 | options: { 81 | port: 9000, 82 | // Change this to '0.0.0.0' to access the server from outside. 83 | hostname: 'localhost', 84 | livereload: 35729 85 | }, 86 | livereload: { 87 | options: { 88 | open: true, 89 | middleware: function(connect) { 90 | return [ 91 | connect.static('.tmp'), 92 | connect().use( 93 | '/bower_components', 94 | connect.static('./bower_components') 95 | ), 96 | connect().use( 97 | '/app/styles', 98 | connect.static('./app/styles') 99 | ), 100 | connect.static(appConfig.app) 101 | ]; 102 | } 103 | } 104 | }, 105 | test: { 106 | options: { 107 | port: 9001, 108 | middleware: function(connect) { 109 | return [ 110 | connect.static('.tmp'), 111 | connect.static('test'), 112 | connect().use( 113 | '/bower_components', 114 | connect.static('./bower_components') 115 | ), 116 | connect.static(appConfig.app) 117 | ]; 118 | } 119 | } 120 | }, 121 | dist: { 122 | options: { 123 | open: true, 124 | base: '<%= yeoman.dist %>' 125 | } 126 | } 127 | }, 128 | 129 | // Make sure there are no obvious mistakes 130 | jshint: { 131 | options: { 132 | jshintrc: '.jshintrc', 133 | reporter: require('jshint-stylish') 134 | }, 135 | all: { 136 | src: [ 137 | 'Gruntfile.js', 138 | '<%= yeoman.app %>/scripts/{,*/}*.js' 139 | ] 140 | }, 141 | test: { 142 | options: { 143 | jshintrc: 'test/.jshintrc' 144 | }, 145 | src: ['test/spec/{,*/}*.js'] 146 | } 147 | }, 148 | 149 | // Make sure code styles are up to par 150 | jscs: { 151 | options: { 152 | config: '.jscsrc', 153 | verbose: true 154 | }, 155 | all: { 156 | src: [ 157 | 'Gruntfile.js', 158 | '<%= yeoman.app %>/scripts/{,*/}*.js' 159 | ] 160 | }, 161 | test: { 162 | src: ['test/spec/{,*/}*.js'] 163 | } 164 | }, 165 | 166 | // Empties folders to start fresh 167 | clean: { 168 | dist: { 169 | files: [{ 170 | dot: true, 171 | src: [ 172 | '.tmp', 173 | '<%= yeoman.dist %>/{,*/}*', 174 | '!<%= yeoman.dist %>/.git{,*/}*' 175 | ] 176 | }] 177 | }, 178 | server: '.tmp' 179 | }, 180 | 181 | // Add vendor prefixed styles 182 | postcss: { 183 | options: { 184 | processors: [ 185 | require('autoprefixer-core')({ 186 | browsers: ['last 1 version'] 187 | }) 188 | ] 189 | }, 190 | server: { 191 | options: { 192 | map: true 193 | }, 194 | files: [{ 195 | expand: true, 196 | cwd: '.tmp/styles/', 197 | src: '{,*/}*.css', 198 | dest: '.tmp/styles/' 199 | }] 200 | }, 201 | dist: { 202 | files: [{ 203 | expand: true, 204 | cwd: '.tmp/styles/', 205 | src: '{,*/}*.css', 206 | dest: '.tmp/styles/' 207 | }] 208 | } 209 | }, 210 | 211 | // Automatically inject Bower components into the app 212 | wiredep: { 213 | app: { 214 | src: ['<%= yeoman.app %>/index.html'], 215 | ignorePath: /\.\.\// 216 | }, 217 | test: { 218 | devDependencies: true, 219 | src: '<%= karma.unit.configFile %>', 220 | ignorePath: /\.\.\//, 221 | fileTypes: { 222 | js: { 223 | block: /(([\s\t]*)\/{2}\s*?bower:\s*?(\S*))(\n|\r|.)*?(\/{2}\s*endbower)/gi, 224 | detect: { 225 | js: /'(.*\.js)'/gi 226 | }, 227 | replace: { 228 | js: '\'{{filePath}}\',' 229 | } 230 | } 231 | } 232 | } 233 | }, 234 | 235 | // Renames files for browser caching purposes 236 | filerev: { 237 | dist: { 238 | src: [ 239 | '<%= yeoman.dist %>/scripts/{,*/}*.js', 240 | '<%= yeoman.dist %>/styles/{,*/}*.css', 241 | '<%= yeoman.dist %>/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}', 242 | '<%= yeoman.dist %>/styles/fonts/*' 243 | ] 244 | } 245 | }, 246 | 247 | // Reads HTML for usemin blocks to enable smart builds that automatically 248 | // concat, minify and revision files. Creates configurations in memory so 249 | // additional tasks can operate on them 250 | useminPrepare: { 251 | html: '<%= yeoman.app %>/index.html', 252 | options: { 253 | dest: '<%= yeoman.dist %>', 254 | flow: { 255 | html: { 256 | steps: { 257 | js: ['concat', 'uglifyjs'], 258 | css: ['cssmin'] 259 | }, 260 | post: {} 261 | } 262 | } 263 | } 264 | }, 265 | 266 | // Performs rewrites based on filerev and the useminPrepare configuration 267 | usemin: { 268 | html: ['<%= yeoman.dist %>/{,*/}*.html'], 269 | css: ['<%= yeoman.dist %>/styles/{,*/}*.css'], 270 | js: ['<%= yeoman.dist %>/scripts/{,*/}*.js'], 271 | options: { 272 | assetsDirs: [ 273 | '<%= yeoman.dist %>', 274 | '<%= yeoman.dist %>/images', 275 | '<%= yeoman.dist %>/styles' 276 | ], 277 | patterns: { 278 | js: [ 279 | [/(images\/[^''""]*\.(png|jpg|jpeg|gif|webp|svg))/g, 'Replacing references to images'] 280 | ] 281 | } 282 | } 283 | }, 284 | 285 | // The following *-min tasks will produce minified files in the dist folder 286 | // By default, your `index.html`'s will take care of 287 | // minification. These next options are pre-configured if you do not wish 288 | // to use the Usemin blocks. 289 | // cssmin: { 290 | // dist: { 291 | // files: { 292 | // '<%= yeoman.dist %>/styles/main.css': [ 293 | // '.tmp/styles/{,*/}*.css' 294 | // ] 295 | // } 296 | // } 297 | // }, 298 | // uglify: { 299 | // dist: { 300 | // files: { 301 | // '<%= yeoman.dist %>/scripts/scripts.js': [ 302 | // '<%= yeoman.dist %>/scripts/scripts.js' 303 | // ] 304 | // } 305 | // } 306 | // }, 307 | // concat: { 308 | // dist: {} 309 | // }, 310 | 311 | imagemin: { 312 | dist: { 313 | files: [{ 314 | expand: true, 315 | cwd: '<%= yeoman.app %>/images', 316 | src: '{,*/}*.{png,jpg,jpeg,gif}', 317 | dest: '<%= yeoman.dist %>/images' 318 | }] 319 | } 320 | }, 321 | 322 | svgmin: { 323 | dist: { 324 | files: [{ 325 | expand: true, 326 | cwd: '<%= yeoman.app %>/images', 327 | src: '{,*/}*.svg', 328 | dest: '<%= yeoman.dist %>/images' 329 | }] 330 | } 331 | }, 332 | 333 | htmlmin: { 334 | dist: { 335 | options: { 336 | collapseWhitespace: true, 337 | conservativeCollapse: true, 338 | collapseBooleanAttributes: true, 339 | removeCommentsFromCDATA: true 340 | }, 341 | files: [{ 342 | expand: true, 343 | cwd: '<%= yeoman.dist %>', 344 | src: ['*.html'], 345 | dest: '<%= yeoman.dist %>' 346 | }] 347 | } 348 | }, 349 | 350 | ngtemplates: { 351 | dist: { 352 | options: { 353 | module: 'unitApp', 354 | htmlmin: '<%= htmlmin.dist.options %>', 355 | usemin: 'scripts/scripts.js' 356 | }, 357 | cwd: '<%= yeoman.app %>', 358 | src: 'views/{,*/}*.html', 359 | dest: '.tmp/templateCache.js' 360 | } 361 | }, 362 | 363 | // ng-annotate tries to make the code safe for minification automatically 364 | // by using the Angular long form for dependency injection. 365 | ngAnnotate: { 366 | dist: { 367 | files: [{ 368 | expand: true, 369 | cwd: '.tmp/concat/scripts', 370 | src: '*.js', 371 | dest: '.tmp/concat/scripts' 372 | }] 373 | } 374 | }, 375 | 376 | // Replace Google CDN references 377 | cdnify: { 378 | dist: { 379 | html: ['<%= yeoman.dist %>/*.html'] 380 | } 381 | }, 382 | 383 | // Copies remaining files to places other tasks can use 384 | copy: { 385 | dist: { 386 | files: [{ 387 | expand: true, 388 | dot: true, 389 | cwd: '<%= yeoman.app %>', 390 | dest: '<%= yeoman.dist %>', 391 | src: [ 392 | '*.{ico,png,txt}', 393 | '*.html', 394 | 'images/{,*/}*.{webp}', 395 | 'styles/fonts/{,*/}*.*', 396 | 'data/{,*/}*.*' 397 | ] 398 | }, { 399 | expand: true, 400 | cwd: '.tmp/images', 401 | dest: '<%= yeoman.dist %>/images', 402 | src: ['generated/*'] 403 | },{ 404 | expand: true, 405 | cwd: 'bower_components/jsoneditor/dist', 406 | src: 'img/*', 407 | dest: '<%= yeoman.dist %>' 408 | },{ 409 | expand: true, 410 | cwd: 'bower_components/jsoneditor/dist', 411 | src: 'img/*', 412 | dest: '<%= yeoman.dist %>/styles' 413 | }, 414 | { 415 | expand: true, 416 | cwd: '.tmp/images', 417 | dest: '<%= yeoman.dist %>/images', 418 | src: ['generated/*'] 419 | }, { 420 | expand: true, 421 | cwd: 'bower_components/bootstrap/dist', 422 | src: 'fonts/*', 423 | dest: '<%= yeoman.dist %>' 424 | }] 425 | }, 426 | styles: { 427 | expand: true, 428 | cwd: '<%= yeoman.app %>/styles', 429 | dest: '.tmp/styles/', 430 | src: '{,*/}*.css' 431 | } 432 | }, 433 | 434 | // Run some tasks in parallel to speed up the build process 435 | concurrent: { 436 | server: [ 437 | 'copy:styles' 438 | ], 439 | test: [ 440 | 'copy:styles' 441 | ], 442 | dist: [ 443 | 'copy:styles', 444 | 'imagemin', 445 | 'svgmin' 446 | ] 447 | }, 448 | 449 | // Test settings 450 | karma: { 451 | unit: { 452 | configFile: 'test/karma.conf.js', 453 | singleRun: true 454 | } 455 | } 456 | }); 457 | 458 | 459 | 460 | grunt.registerTask('serve', 'Compile then start a connect web server', function(target) { 461 | if (target === 'dist') { 462 | return grunt.task.run(['build', 'connect:dist:keepalive']); 463 | } 464 | 465 | grunt.task.run([ 466 | 'clean:server', 467 | 'wiredep', 468 | 'concurrent:server', 469 | 'postcss:server', 470 | 'connect:livereload', 471 | 'watch' 472 | ]); 473 | }); 474 | 475 | grunt.registerTask('server', 'DEPRECATED TASK. Use the "serve" task instead', function(target) { 476 | grunt.log.warn('The `server` task has been deprecated. Use `grunt serve` to start a server.'); 477 | grunt.task.run(['serve:' + target]); 478 | }); 479 | 480 | grunt.registerTask('test', [ 481 | 'clean:server', 482 | 'wiredep', 483 | 'concurrent:test', 484 | 'postcss', 485 | 'connect:test', 486 | 'karma' 487 | ]); 488 | 489 | grunt.registerTask('build', [ 490 | 'clean:dist', 491 | 'wiredep', 492 | 'useminPrepare', 493 | 'concurrent:dist', 494 | 'postcss', 495 | 'ngtemplates', 496 | 'concat', 497 | 'ngAnnotate', 498 | 'copy:dist', 499 | 'cdnify', 500 | 'cssmin', 501 | 'uglify', 502 | 'filerev', 503 | 'usemin', 504 | 'htmlmin' 505 | ]); 506 | 507 | grunt.registerTask('default', [ 508 | //'newer:jshint', 509 | 'newer:jscs', 510 | 'test', 511 | 'build' 512 | ]); 513 | }; 514 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # unit 2 | 3 | This project is generated with [yo angular generator](https://github.com/yeoman/generator-angular) 4 | version 0.15.1. 5 | 6 | ## Build & development 7 | 8 | Run `grunt` for building and `grunt serve` for preview. 9 | 10 | ## Testing 11 | 12 | Running `grunt test` will run the unit tests with karma. 13 | -------------------------------------------------------------------------------- /app/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Page Not Found :( 6 | 136 | 137 | 138 |
139 |

Not found :(

140 |

Sorry, but the page you were trying to view does not exist.

141 |

It looks like this was the result of either:

142 | 146 | 149 | 150 |
151 | 152 | 153 | -------------------------------------------------------------------------------- /app/data/Untitled-2.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://vega.github.io/schema/vega-lite/v2.json", 3 | "description": "A simple bar chart with embedded data.", 4 | "data": { 5 | "values": [ 6 | {"a": "A","b": 28}, {"a": "B","b": 55}, {"a": "C","b": 43}, 7 | {"a": "D","b": 91}, {"a": "E","b": 81}, {"a": "F","b": 53}, 8 | {"a": "G","b": 19}, {"a": "H","b": 87}, {"a": "I","b": 52} 9 | ] 10 | }, 11 | "mark": "bar", 12 | "encoding": { 13 | "x": {"field": "a", "type": "ordinal"}, 14 | "y": {"field": "b", "type": "quantitative"} 15 | } 16 | } -------------------------------------------------------------------------------- /app/data/default0.json: -------------------------------------------------------------------------------- 1 | { 2 | // This is an empty json spec. 3 | // For grammar is about specification. 4 | } 5 | -------------------------------------------------------------------------------- /app/data/default1.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": "data/titanic3.csv", 3 | "layouts": [ 4 | { 5 | "subgroup": { 6 | "type": "flatten" 7 | } 8 | } 9 | ] 10 | } -------------------------------------------------------------------------------- /app/data/default2.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": "data/titanic3.csv", 3 | "layouts": [ 4 | { 5 | "subgroup": { 6 | "type": "flatten" 7 | } 8 | } 9 | ], 10 | "mark": { 11 | "color": { 12 | "key": "survived_text", 13 | "type": "categorical" 14 | } 15 | } 16 | } -------------------------------------------------------------------------------- /app/data/default3.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": "data/titanic3.csv", 3 | "layouts": [ 4 | { 5 | "subgroup": { 6 | "type": "groupby", 7 | "key": "pclass" 8 | }, 9 | "aspect_ratio": "fillX" 10 | }, 11 | 12 | { 13 | "subgroup": { 14 | "type": "flatten" 15 | }, 16 | "aspect_ratio": "maxfill" 17 | } 18 | ], 19 | "mark": { 20 | "color": { 21 | "key": "survived_text", 22 | "type": "categorical" 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /app/data/default4.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": "data/titanic3.csv", 3 | "layouts": [ 4 | { 5 | "subgroup": { 6 | "type": "groupby", 7 | "key": "pclass" 8 | }, 9 | "aspect_ratio": "fillX" 10 | }, 11 | { 12 | "subgroup": { 13 | "type": "bin", 14 | "key": "age", 15 | "numBin": 10 16 | }, 17 | "aspect_ratio": "fillY" 18 | }, 19 | 20 | { 21 | "subgroup": { 22 | "type": "flatten" 23 | }, 24 | "aspect_ratio": "maxfill" 25 | } 26 | ], 27 | "mark": { 28 | "color": { 29 | "key": "survived_text", 30 | "type": "categorical" 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /app/data/default5.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": "data/titanic3.csv", 3 | "layouts": [{ 4 | "subgroup": { 5 | "type": "groupby", 6 | "key": "pclass" 7 | }, 8 | "aspect_ratio": "fillX" 9 | }, 10 | { 11 | "subgroup": { 12 | "type": "bin", 13 | "key": "age", 14 | "numBin": 20 15 | }, 16 | "aspect_ratio": "fillY" 17 | }, 18 | { 19 | "subgroup": { 20 | "type": "passthrough" 21 | }, 22 | "aspect_ratio": "fillX", 23 | "size": { 24 | "type": "count" 25 | }, 26 | "align": "center" 27 | }, 28 | { 29 | "subgroup": { 30 | "type": "flatten" 31 | }, 32 | "aspect_ratio": "maxfill", 33 | "size": { 34 | "isShared": false 35 | } 36 | } 37 | ], 38 | "mark": { 39 | "color": { 40 | "key": "survived_text", 41 | "type": "categorical" 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /app/data/editor.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Titanic", 3 | "data": "data/titanic3.csv", 4 | "width": 1000, 5 | "height": 320, 6 | "padding": { 7 | "top": 5, 8 | "left": 5, 9 | "bottom": 5, 10 | "right": 5 11 | }, 12 | "layouts": [{ 13 | "name": "layout1", 14 | "type": "gridxy", 15 | "subgroup": { 16 | "type": "groupby", 17 | "key": "pclass", 18 | "isShared": false 19 | }, 20 | "aspect_ratio": "fillX", 21 | "size": { 22 | "type": "uniform", 23 | "isShared": true 24 | }, 25 | "direction": "LRBT", 26 | "align": "LB", 27 | "margin": { 28 | "top": 5, 29 | "left": 5, 30 | "bottom": 5, 31 | "right": 5 32 | }, 33 | "padding": { 34 | "top": 5, 35 | "left": 5, 36 | "bottom": 5, 37 | "right": 5 38 | }, 39 | "box": { 40 | "fill": "blue", 41 | "stroke": "black", 42 | "stroke-width": 1, 43 | "opacity": 0.3 44 | }, 45 | "sort": { 46 | "key": "pclass", 47 | "direction": "ascending" 48 | } 49 | }, { 50 | "name": "layout2", 51 | "type": "gridxy", 52 | "subgroup": { 53 | "type": "bin", 54 | "key": "age", 55 | "numBin": 19, 56 | "isShared": true 57 | }, 58 | "aspect_ratio": "fillY", 59 | "size": { 60 | "type": "uniform", 61 | "isShared": true 62 | }, 63 | "direction": "BT", 64 | "align": "bottom", 65 | "margin": { 66 | "top": 0, 67 | "left": 0, 68 | "bottom": 0, 69 | "right": 0 70 | }, 71 | "padding": { 72 | "top": 0, 73 | "left": 0, 74 | "bottom": 0, 75 | "right": 0 76 | }, 77 | "box": { 78 | "fill": "green", 79 | "stroke": "red", 80 | "stroke-width": 1, 81 | "opacity": 0.5 82 | }, 83 | "sort": { 84 | "key": "age", 85 | "direction": "ascending" 86 | } 87 | }, { 88 | "name": "layout3", 89 | "type": "gridxy", 90 | "subgroup": { 91 | "type": "passthrough", 92 | "isShared": true 93 | }, 94 | "aspect_ratio": "fillX", 95 | "size": { 96 | "type": "count", 97 | "isShared": true 98 | }, 99 | "direction": "LR", 100 | "align": "center", 101 | "margin": { 102 | "top": 0, 103 | "left": 0, 104 | "bottom": 0, 105 | "right": 0 106 | }, 107 | "padding": { 108 | "top": 0, 109 | "left": 0, 110 | "bottom": 0, 111 | "right": 0 112 | }, 113 | "box": { 114 | "fill": "yellow", 115 | "stroke": "blue", 116 | "stroke-width": 1, 117 | "opacity": 0.5 118 | } 119 | }, { 120 | "name": "layout4", 121 | "type": "gridxy", 122 | "subgroup": { 123 | "type": "flatten" 124 | }, 125 | "aspect_ratio": "maxfill", 126 | "size": { 127 | "type": "uniform", 128 | "isShared": false 129 | }, 130 | "direction": "BTLR", 131 | "align": "LB", 132 | "margin": { 133 | "top": 0, 134 | "left": 0, 135 | "bottom": 0, 136 | "right": 0 137 | }, 138 | "padding": { 139 | "top": 0, 140 | "left": 0, 141 | "bottom": 0, 142 | "right": 0 143 | }, 144 | "box": { 145 | "fill": "yellow", 146 | "stroke": "red", 147 | "stroke-width": 0, 148 | "opacity": 0.5 149 | }, 150 | "sort": { 151 | "type": "categorical", 152 | "key": "survived", 153 | "direction": "ascending" 154 | } 155 | }], 156 | "mark": { 157 | "shape": "circle", 158 | "color": { 159 | "key": "survived", 160 | "type": "categorical" 161 | }, 162 | "size": { 163 | "type": "max", 164 | "isShared": false 165 | }, 166 | "isColorScaleShared": true 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /app/data/enumerate.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Titanic", 3 | "data": "data/titanic3.csv", 4 | "width": 640, 5 | "height": 480, 6 | "padding": { 7 | "top": 0, 8 | "left": 0, 9 | "bottom": 0, 10 | "right": 0 11 | }, 12 | "layouts": [], 13 | "mark": { 14 | "shape": "circle", 15 | "color": { 16 | "key": "survived", 17 | "type": "categorical", 18 | "isShared": true 19 | }, 20 | "size": { 21 | "type": "max", 22 | "isShared": false 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /app/data/fluctuation.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Titanic", 3 | "data": "data/titanic.csv", 4 | "width": 800, 5 | "height": 600, 6 | "padding": { 7 | "top": 5, 8 | "left": 5, 9 | "bottom": 5, 10 | "right": 5 11 | }, 12 | "layouts": [{ 13 | "name": "layout1", 14 | "type": "gridxy", 15 | "subgroup": { 16 | "type": "groupby", 17 | "key": "Sex", 18 | "isShared": false 19 | }, 20 | "aspect_ratio": "fillY", 21 | "size": { 22 | "type": "uniform", 23 | "isShared": false 24 | }, 25 | "direction": "LRBT", 26 | "align": "LB", 27 | "margin": { 28 | "top": 0, 29 | "left": 0, 30 | "bottom": 0, 31 | "right": 0 32 | }, 33 | "padding": { 34 | "top": 0, 35 | "left": 0, 36 | "bottom": 0, 37 | "right": 0 38 | } 39 | }, { 40 | "name": "layout2", 41 | "type": "gridxy", 42 | "subgroup": { 43 | "type": "groupby", 44 | "key": "Class", 45 | "isShared": true 46 | }, 47 | "aspect_ratio": "fillX", 48 | "size": { 49 | "type": "uniform", 50 | "isShared": true 51 | }, 52 | "direction": "LRTB", 53 | "align": "LB", 54 | "margin": { 55 | "top": 5, 56 | "left": 5, 57 | "bottom": 5, 58 | "right": 5 59 | }, 60 | "padding": { 61 | "top": 5, 62 | "left": 5, 63 | "bottom": 5, 64 | "right": 5 65 | } 66 | }, { 67 | "name": "layout3", 68 | "type": "gridxy", 69 | "subgroup": { 70 | "type": "passthrough", 71 | "isShared": true 72 | }, 73 | "aspect_ratio": "square", 74 | "size": { 75 | "type": "count", 76 | "isShared": true 77 | }, 78 | "direction": "LRBT", 79 | "align": "center", 80 | "margin": { 81 | "top": 1, 82 | "left": 1, 83 | "bottom": 1, 84 | "right": 1 85 | }, 86 | "padding": { 87 | "top": 2, 88 | "left": 2, 89 | "bottom": 2, 90 | "right": 2 91 | }, 92 | "box": { 93 | "fill": "none", 94 | "stroke": "black", 95 | "stroke-width": 0, 96 | "opacity": 0.3 97 | } 98 | },{ 99 | "name": "layout4", 100 | "type": "gridxy", 101 | "subgroup": { 102 | "type": "flatten" 103 | }, 104 | "aspect_ratio": "maxfill", 105 | "size": { 106 | "type": "uniform", 107 | "isShared": false 108 | }, 109 | "direction": "LRBT", 110 | "align": "LB", 111 | "margin": { 112 | "top": 5, 113 | "left": 5, 114 | "bottom": 5, 115 | "right": 5 116 | }, 117 | "padding": { 118 | "top": 5, 119 | "left": 5, 120 | "bottom": 5, 121 | "right": 5 122 | }, 123 | "sort": { 124 | "key": "Survived" 125 | } 126 | }], 127 | "mark": { 128 | "shape": "circle", 129 | "color": { 130 | "key": "Survived", 131 | "type": "categorical" 132 | }, 133 | "size": { 134 | "type": "max", 135 | "isShared": false 136 | }, 137 | "isColorScaleShared": true 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /app/data/horizontal_unit_column.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Titanic", 3 | "data": "data/titanic3.csv", 4 | "width": 320, 5 | "height": 240, 6 | "padding": { 7 | "top": 5, 8 | "left": 5, 9 | "bottom": 5, 10 | "right": 5 11 | }, 12 | "layouts": [{ 13 | "name": "layout1", 14 | "type": "gridxy", 15 | "subgroup": { 16 | "type":"groupby", 17 | "key": "pclass", 18 | "isShared": false 19 | }, 20 | "aspect_ratio": "fillY", 21 | "size": { 22 | "type": "uniform", 23 | "isShared": true 24 | }, 25 | "direction": "LRBT", 26 | "align": "LB", 27 | "margin": { 28 | "top": 5, 29 | "left": 5, 30 | "bottom": 5, 31 | "right": 5 32 | }, 33 | "padding": { 34 | "top": 5, 35 | "left": 5, 36 | "bottom": 5, 37 | "right": 5 38 | }, 39 | "box": { 40 | "fill": "blue", 41 | "stroke": "black", 42 | "stroke-width": 1, 43 | "opacity": 0.3 44 | } 45 | }, { 46 | "name": "layout2", 47 | "type": "gridxy", 48 | "subgroup": { 49 | "type":"flatten" 50 | }, 51 | "aspect_ratio": "maxfill", 52 | "size": { 53 | "type": "uniform", 54 | "isShared": true 55 | }, 56 | "direction": "BTLR", 57 | "align": "LT", 58 | "margin": { 59 | "top": 0, 60 | "left": 0, 61 | "bottom": 0, 62 | "right": 0 63 | }, 64 | "padding": { 65 | "top": 0, 66 | "left": 0, 67 | "bottom": 0, 68 | "right": 0 69 | }, 70 | "box": { 71 | "fill": "white", 72 | "stroke": "red", 73 | "stroke-width": 0, 74 | "opacity": 0.5 75 | }, 76 | "sort":{ 77 | "key":"survived" 78 | } 79 | }], 80 | "mark": { 81 | "shape": "circle", 82 | "color": { 83 | "key":"survived", 84 | "type":"categorical" 85 | }, 86 | "size": { 87 | "type": "max", 88 | "isShared": false 89 | }, 90 | "isColorScaleShared": true 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /app/data/maxfill_aspect.json: -------------------------------------------------------------------------------- 1 | { 2 | "title" : "Titanic", 3 | "data": "data/titanic3.csv", 4 | "width": 500, 5 | "height": 240, 6 | "padding": {"top": 5, "left": 5, "bottom": 5, "right": 5}, 7 | "layouts": [ 8 | { 9 | "name": "layout1", 10 | "type": "gridxy", 11 | "subgroup": { 12 | "key": "age", 13 | "type": "bin", 14 | "numBin": 15, 15 | "isShared": false 16 | }, 17 | "aspect_ratio":"parent", 18 | "size": { 19 | "type":"uniform", 20 | "isShared": false 21 | }, 22 | "direction": "LRBT", 23 | "align": "LB", 24 | "margin": {"top": 5, "left": 5, "bottom": 5, "right": 5}, 25 | "padding": {"top": 5, "left": 5, "bottom": 5, "right": 5}, 26 | "box": { 27 | "fill": "none", 28 | "stroke": "black", 29 | "stroke-width": 0, 30 | "opacity":0.3 31 | } 32 | }, 33 | { 34 | "name": "layout2", 35 | "type": "gridxy", 36 | "subgroup": { 37 | "type":"groupby", 38 | "key": "pclass", 39 | "isShared": false 40 | }, 41 | "aspect_ratio":"fillX", 42 | "size": { 43 | "type": "uniform", 44 | "isShared": false 45 | }, 46 | "direction": "LRTB", 47 | "align": "LB", 48 | "margin": {"top": 5, "left": 5, "bottom": 5, "right": 5}, 49 | "padding": {"top": 5, "left": 5, "bottom": 5, "right": 5}, 50 | "box": { 51 | "fill": "none", 52 | "stroke": "green", 53 | "stroke-width": 1, 54 | "opacity":1 55 | } 56 | }, 57 | { 58 | "name": "layout3", 59 | "type": "gridxy", 60 | "subgroup": { 61 | "type":"flatten" 62 | }, 63 | "aspect_ratio":"maxfill", 64 | "size": { 65 | "type":"uniform", 66 | "isShared": false 67 | }, 68 | "direction": "LRBT", 69 | "align": "LB", 70 | "margin": {"top": 5, "left": 5, "bottom": 5, "right": 5}, 71 | "padding": {"top": 5, "left": 5, "bottom": 5, "right": 5}, 72 | "box": { 73 | "fill": "none", 74 | "stroke": "black", 75 | "stroke-width": 1, 76 | "opacity":1 77 | }, 78 | "sort":{ 79 | "key":"survived" 80 | } 81 | }], 82 | "mark": { 83 | "shape": "circle", 84 | "color": { 85 | "key":"survived", 86 | "type":"categorical" 87 | }, 88 | "size": { 89 | "type": "max", 90 | "isShared": false 91 | }, 92 | "isColorScaleShared": true 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /app/data/mosaic.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Titanic", 3 | "data": "data/titanic3.csv", 4 | "width": 840, 5 | "height": 840, 6 | "padding": { 7 | "top": 5, 8 | "left": 5, 9 | "bottom": 5, 10 | "right": 5 11 | }, 12 | "layouts": [{ 13 | "name": "layout1", 14 | "type": "gridxy", 15 | "subgroup": { 16 | "type": "groupby", 17 | "key": "pclass", 18 | "isShared": false 19 | }, 20 | "aspect_ratio": "fillY", 21 | "size": { 22 | "type": "count", 23 | "isShared": true 24 | }, 25 | "direction": "LRBT", 26 | "align": "LB", 27 | "margin": { 28 | "top": 1, 29 | "left": 1, 30 | "bottom": 1, 31 | "right": 1 32 | }, 33 | "padding": { 34 | "top": 2, 35 | "left": 2, 36 | "bottom": 2, 37 | "right": 2 38 | }, 39 | "box": { 40 | "fill": "none", 41 | "stroke": "black", 42 | "stroke-width": 0, 43 | "opacity": 0.3 44 | } 45 | }, { 46 | "name": "layout2", 47 | "type": "gridxy", 48 | "subgroup": { 49 | "type": "groupby", 50 | "key": "survived", 51 | "isShared": true 52 | }, 53 | "aspect_ratio": "fillX", 54 | "size": { 55 | "type": "count", 56 | "isShared": false 57 | }, 58 | "direction": "LRBT", 59 | "align": "LB", 60 | "margin": { 61 | "top": 1, 62 | "left": 1, 63 | "bottom": 1, 64 | "right": 1 65 | }, 66 | "padding": { 67 | "top": 1, 68 | "left": 1, 69 | "bottom": 1, 70 | "right": 1 71 | }, 72 | "box": { 73 | "fill": "none", 74 | "stroke": "black", 75 | "stroke-width": 0, 76 | "opacity": 0.3 77 | } 78 | }, { 79 | "name": "layout3", 80 | "type": "gridxy", 81 | "subgroup": { 82 | "type": "groupby", 83 | "key": "sex", 84 | "isShared": true 85 | }, 86 | "aspect_ratio": "fillY", 87 | "size": { 88 | "type": "count", 89 | "isShared": false 90 | }, 91 | "direction": "LRBT", 92 | "align": "LB", 93 | "margin": { 94 | "top": 3, 95 | "left": 3, 96 | "bottom": 3, 97 | "right": 3 98 | }, 99 | "padding": { 100 | "top": 1, 101 | "left": 1, 102 | "bottom": 1, 103 | "right": 1 104 | }, 105 | "box": { 106 | "fill": "blue", 107 | "stroke": "red", 108 | "stroke-width": 3, 109 | "opacity": 0.3 110 | } 111 | }, { 112 | "name": "layout4", 113 | "type": "gridxy", 114 | "subgroup": { 115 | "type": "flatten" 116 | }, 117 | "aspect_ratio": "maxfill", 118 | "size": { 119 | "type": "uniform", 120 | "isShared": false 121 | }, 122 | "direction": "LRBT", 123 | "align": "LT", 124 | "margin": { 125 | "top": 0, 126 | "left": 0, 127 | "bottom": 0, 128 | "right": 0 129 | }, 130 | "padding": { 131 | "top": 0, 132 | "left": 0, 133 | "bottom": 0, 134 | "right": 0 135 | }, 136 | "box": { 137 | "fill": "blue", 138 | "stroke": "red", 139 | "stroke-width": 0, 140 | "opacity": 0.01 141 | } 142 | }], 143 | "mark": { 144 | "shape": "circle", 145 | "color": { 146 | "key": "survived", 147 | "type": "categorical" 148 | }, 149 | "size": { 150 | "type": "max", 151 | "isShared": false 152 | }, 153 | "isColorScaleShared": true 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /app/data/size_sum_notShared.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Titanic", 3 | "data": "data/titanic3.csv", 4 | "width": 320, 5 | "height": 240, 6 | "padding": { 7 | "top": 5, 8 | "left": 5, 9 | "bottom": 5, 10 | "right": 5 11 | }, 12 | "layouts": [{ 13 | "name": "layout1", 14 | "type": "gridxy", 15 | "subgroup": { 16 | "type": "groupby", 17 | "key": "pclass", 18 | "isShared": false 19 | }, 20 | "aspect_ratio": "fillX", 21 | "size": { 22 | "type": "uniform", 23 | "isShared": false 24 | }, 25 | "direction": "LRBT", 26 | "align": "LB", 27 | "margin": { 28 | "top": 5, 29 | "left": 5, 30 | "bottom": 5, 31 | "right": 5 32 | }, 33 | "padding": { 34 | "top": 5, 35 | "left": 5, 36 | "bottom": 5, 37 | "right": 5 38 | }, 39 | "box": { 40 | "fill": "blue", 41 | "stroke": "black", 42 | "stroke-width": 1, 43 | "opacity": 0.3 44 | } 45 | }, { 46 | "name": "layout2", 47 | "type": "gridxy", 48 | "subgroup": { 49 | "type": "flatten" 50 | }, 51 | "aspect_ratio": "fillY", 52 | "size": { 53 | "type": "sum", 54 | "key":"fare", 55 | "isShared": false 56 | }, 57 | "direction": "LRTB", 58 | "align": "LB", 59 | "margin": { 60 | "top": 0, 61 | "left": 0, 62 | "bottom": 0, 63 | "right": 0 64 | }, 65 | "padding": { 66 | "top": 0, 67 | "left": 0, 68 | "bottom": 0, 69 | "right": 0 70 | }, 71 | "box": { 72 | "fill": "green", 73 | "stroke": "green", 74 | "stroke-width": 0, 75 | "opacity": 0.5 76 | }, 77 | "sort": { 78 | "key":"fare", 79 | "type":"numerical" 80 | } 81 | }], 82 | "mark": { 83 | "shape": "circle", 84 | "color": { 85 | "key": "survived", 86 | "type": "categorical" 87 | }, 88 | "size": { 89 | "type": "max", 90 | "isShared": false 91 | }, 92 | "isColorScaleShared": true 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /app/data/size_sum_shared.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Titanic", 3 | "data": "data/titanic3.csv", 4 | "width": 320, 5 | "height": 240, 6 | "padding": { 7 | "top": 5, 8 | "left": 5, 9 | "bottom": 5, 10 | "right": 5 11 | }, 12 | "layouts": [{ 13 | "name": "layout1", 14 | "type": "gridxy", 15 | "subgroup": { 16 | "type": "groupby", 17 | "key": "pclass", 18 | "isShared": false 19 | }, 20 | "aspect_ratio": "fillX", 21 | "size": { 22 | "type": "uniform", 23 | "isShared": false 24 | }, 25 | "direction": "LRBT", 26 | "align": "LB", 27 | "margin": { 28 | "top": 5, 29 | "left": 5, 30 | "bottom": 5, 31 | "right": 5 32 | }, 33 | "padding": { 34 | "top": 5, 35 | "left": 5, 36 | "bottom": 5, 37 | "right": 5 38 | }, 39 | "box": { 40 | "fill": "blue", 41 | "stroke": "black", 42 | "stroke-width": 1, 43 | "opacity": 0.3 44 | } 45 | }, { 46 | "name": "layout2", 47 | "type": "gridxy", 48 | "subgroup": { 49 | "type": "flatten" 50 | }, 51 | "aspect_ratio": "fillY", 52 | "size": { 53 | "type": "sum", 54 | "key":"fare", 55 | "isShared": true 56 | }, 57 | "direction": "LRTB", 58 | "align": "LB", 59 | "margin": { 60 | "top": 0, 61 | "left": 0, 62 | "bottom": 0, 63 | "right": 0 64 | }, 65 | "padding": { 66 | "top": 0, 67 | "left": 0, 68 | "bottom": 0, 69 | "right": 0 70 | }, 71 | "box": { 72 | "fill": "green", 73 | "stroke": "green", 74 | "stroke-width": 0, 75 | "opacity": 0.5 76 | }, 77 | "sort": { 78 | "key":"fare", 79 | "type":"numerical" 80 | } 81 | }], 82 | "mark": { 83 | "shape": "circle", 84 | "color": { 85 | "key": "survived", 86 | "type": "categorical" 87 | }, 88 | "size": { 89 | "type": "max", 90 | "isShared": false 91 | }, 92 | "isColorScaleShared": true 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /app/data/size_uniform_notShared.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Titanic", 3 | "data": "data/titanic3.csv", 4 | "width": 320, 5 | "height": 240, 6 | "padding": { 7 | "top": 5, 8 | "left": 5, 9 | "bottom": 5, 10 | "right": 5 11 | }, 12 | "layouts": [{ 13 | "name": "layout1", 14 | "type": "gridxy", 15 | "subgroup": { 16 | "type": "groupby", 17 | "key": "pclass", 18 | "isShared": false 19 | }, 20 | "aspect_ratio": "fillX", 21 | "size": { 22 | "type": "uniform", 23 | "isShared": false 24 | }, 25 | "direction": "LRBT", 26 | "align": "LB", 27 | "margin": { 28 | "top": 5, 29 | "left": 5, 30 | "bottom": 5, 31 | "right": 5 32 | }, 33 | "padding": { 34 | "top": 5, 35 | "left": 5, 36 | "bottom": 5, 37 | "right": 5 38 | }, 39 | "box": { 40 | "fill": "blue", 41 | "stroke": "black", 42 | "stroke-width": 1, 43 | "opacity": 0.3 44 | } 45 | }, { 46 | "name": "layout2", 47 | "type": "gridxy", 48 | "subgroup": { 49 | "type": "flatten" 50 | }, 51 | "aspect_ratio": "fillY", 52 | "size": { 53 | "type": "uniform", 54 | "isShared": false 55 | }, 56 | "direction": "LRTB", 57 | "align": "LB", 58 | "margin": { 59 | "top": 0, 60 | "left": 0, 61 | "bottom": 0, 62 | "right": 0 63 | }, 64 | "padding": { 65 | "top": 0, 66 | "left": 0, 67 | "bottom": 0, 68 | "right": 0 69 | }, 70 | "box": { 71 | "fill": "green", 72 | "stroke": "green", 73 | "stroke-width": 0, 74 | "opacity": 0.5 75 | }, 76 | "sort": { 77 | "key":"fare", 78 | "type":"numerical" 79 | } 80 | }], 81 | "mark": { 82 | "shape": "circle", 83 | "color": { 84 | "key": "survived", 85 | "type": "categorical" 86 | }, 87 | "size": { 88 | "type": "max", 89 | "isShared": false 90 | }, 91 | "isColorScaleShared": true 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /app/data/size_uniform_shared.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Titanic", 3 | "data": "data/titanic3.csv", 4 | "width": 320, 5 | "height": 240, 6 | "padding": { 7 | "top": 5, 8 | "left": 5, 9 | "bottom": 5, 10 | "right": 5 11 | }, 12 | "layouts": [{ 13 | "name": "layout1", 14 | "type": "gridxy", 15 | "subgroup": { 16 | "type": "groupby", 17 | "key": "pclass", 18 | "isShared": false 19 | }, 20 | "aspect_ratio": "fillX", 21 | "size": { 22 | "type": "uniform", 23 | "isShared": false 24 | }, 25 | "direction": "LRBT", 26 | "align": "LB", 27 | "margin": { 28 | "top": 5, 29 | "left": 5, 30 | "bottom": 5, 31 | "right": 5 32 | }, 33 | "padding": { 34 | "top": 5, 35 | "left": 5, 36 | "bottom": 5, 37 | "right": 5 38 | }, 39 | "box": { 40 | "fill": "blue", 41 | "stroke": "black", 42 | "stroke-width": 1, 43 | "opacity": 0.3 44 | } 45 | }, { 46 | "name": "layout2", 47 | "type": "gridxy", 48 | "subgroup": { 49 | "type": "flatten" 50 | }, 51 | "aspect_ratio": "fillY", 52 | "size": { 53 | "type": "uniform", 54 | "isShared": true 55 | }, 56 | "direction": "LRTB", 57 | "align": "LB", 58 | "margin": { 59 | "top": 0, 60 | "left": 0, 61 | "bottom": 0, 62 | "right": 0 63 | }, 64 | "padding": { 65 | "top": 0, 66 | "left": 0, 67 | "bottom": 0, 68 | "right": 0 69 | }, 70 | "box": { 71 | "fill": "green", 72 | "stroke": "green", 73 | "stroke-width": 0, 74 | "opacity": 0.5 75 | }, 76 | "sort": { 77 | "key":"fare", 78 | "type":"numerical" 79 | } 80 | }], 81 | "mark": { 82 | "shape": "circle", 83 | "color": { 84 | "key": "survived", 85 | "type": "categorical" 86 | }, 87 | "size": { 88 | "type": "max", 89 | "isShared": false 90 | }, 91 | "isColorScaleShared": true 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /app/data/square_aspect.json: -------------------------------------------------------------------------------- 1 | { 2 | "title" : "Titanic", 3 | "data": "data/titanic3.csv", 4 | "width": 500, 5 | "height": 240, 6 | "padding": {"top": 5, "left": 5, "bottom": 5, "right": 5}, 7 | "layouts": [ 8 | { 9 | "name": "layout1", 10 | "type": "gridxy", 11 | "subgroup": { 12 | "key": "age", 13 | "type": "bin", 14 | "numBin": 15, 15 | "isShared": false 16 | }, 17 | "aspect_ratio":"parent", 18 | "size": { 19 | "type":"uniform", 20 | "isShared": false 21 | }, 22 | "direction": "LRBT", 23 | "align": "LB", 24 | "margin": {"top": 5, "left": 5, "bottom": 5, "right": 5}, 25 | "padding": {"top": 5, "left": 5, "bottom": 5, "right": 5}, 26 | "box": { 27 | "fill": "none", 28 | "stroke": "black", 29 | "stroke-width": 0, 30 | "opacity":0.3 31 | } 32 | }, 33 | { 34 | "name": "layout2", 35 | "type": "gridxy", 36 | "subgroup": { 37 | "type":"groupby", 38 | "key": "pclass", 39 | "isShared": false 40 | }, 41 | "aspect_ratio":"fillX", 42 | "size": { 43 | "type": "uniform", 44 | "isShared": false 45 | }, 46 | "direction": "LRTB", 47 | "align": "LB", 48 | "margin": {"top": 5, "left": 5, "bottom": 5, "right": 5}, 49 | "padding": {"top": 5, "left": 5, "bottom": 5, "right": 5}, 50 | "box": { 51 | "fill": "none", 52 | "stroke": "green", 53 | "stroke-width": 1, 54 | "opacity":0.5 55 | } 56 | }, 57 | { 58 | "name": "layout3", 59 | "type": "gridxy", 60 | "subgroup": { 61 | "type":"flatten" 62 | }, 63 | "aspect_ratio":"square", 64 | "size": { 65 | "type":"uniform", 66 | "isShared": false 67 | }, 68 | "direction": "LRBT", 69 | "align": "LB", 70 | "margin": {"top": 5, "left": 5, "bottom": 5, "right": 5}, 71 | "padding": {"top": 5, "left": 5, "bottom": 5, "right": 5}, 72 | "box": { 73 | "fill": "none", 74 | "stroke": "black", 75 | "stroke-width": 1, 76 | "opacity":1 77 | }, 78 | "sort":{ 79 | "key":"survived" 80 | } 81 | }], 82 | "mark": { 83 | "shape": "circle", 84 | "color": { 85 | "key":"survived", 86 | "type":"categorical" 87 | }, 88 | "size": { 89 | "type": "max", 90 | "isShared": false 91 | }, 92 | "isColorScaleShared": true 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /app/data/squarified.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Titanic", 3 | "data": "data/titanic3.csv", 4 | "width": 1000, 5 | "height": 320, 6 | "padding": { 7 | "top": 5, 8 | "left": 5, 9 | "bottom": 5, 10 | "right": 5 11 | }, 12 | "layouts": [{ 13 | "name": "layout1", 14 | "type": "gridxy", 15 | "subgroup": { 16 | "type": "groupby", 17 | "key": "pclass", 18 | "isShared": false 19 | }, 20 | "aspect_ratio": "fillX", 21 | "size": { 22 | "type": "uniform", 23 | "isShared": true 24 | }, 25 | "direction": "LRBT", 26 | "align": "LB", 27 | "margin": { 28 | "top": 5, 29 | "left": 5, 30 | "bottom": 5, 31 | "right": 5 32 | }, 33 | "padding": { 34 | "top": 5, 35 | "left": 5, 36 | "bottom": 5, 37 | "right": 5 38 | }, 39 | "box": { 40 | "fill": "white", 41 | "stroke": "black", 42 | "stroke-width": 0, 43 | "opacity": 0.3 44 | }, 45 | "sort": { 46 | "key": "pclass", 47 | "direction": "ascending" 48 | } 49 | }, { 50 | "name": "layout2", 51 | "type": "gridxy", 52 | "subgroup": { 53 | "type": "passthrough", 54 | "isShared": true 55 | }, 56 | "aspect_ratio": "fillY", 57 | "size": { 58 | "type": "sum", 59 | "key":"fare", 60 | "isShared": true 61 | }, 62 | "direction": "BT", 63 | "align": "bottom", 64 | "margin": { 65 | "top": 0, 66 | "left": 0, 67 | "bottom": 0, 68 | "right": 0 69 | }, 70 | "padding": { 71 | "top": 0, 72 | "left": 0, 73 | "bottom": 0, 74 | "right": 0 75 | }, 76 | "box": { 77 | "fill": "white", 78 | "stroke": "black", 79 | "stroke-width": 0.5, 80 | "opacity": 0.5 81 | }, 82 | "sort": { 83 | "key": "age", 84 | "direction": "ascending" 85 | } 86 | }, { 87 | "name": "layout4", 88 | "type": "gridxy", 89 | "subgroup": { 90 | "type": "flatten" 91 | }, 92 | "aspect_ratio": "maxfill", 93 | "size": { 94 | "type": "sum", 95 | "key": "fare", 96 | "isShared": true 97 | }, 98 | "direction": "LRBT", 99 | "align": "LB", 100 | "margin": { 101 | "top": 0, 102 | "left": 0, 103 | "bottom": 0, 104 | "right": 0 105 | }, 106 | "padding": { 107 | "top": 0, 108 | "left": 0, 109 | "bottom": 0, 110 | "right": 0 111 | }, 112 | "box": { 113 | "fill": "white", 114 | "stroke": "red", 115 | "stroke-width": 0, 116 | "opacity": 0.5 117 | }, 118 | "sort": { 119 | "type": "categorical", 120 | "key": "survived", 121 | "direction": "ascending" 122 | } 123 | }], 124 | "mark": { 125 | "shape": "circle", 126 | "color": { 127 | "key": "survived_text", 128 | "type": "categorical" 129 | }, 130 | "size": { 131 | "type": "max", 132 | "isShared": false 133 | }, 134 | "isColorScaleShared": true 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /app/data/titanic_spec1.json: -------------------------------------------------------------------------------- 1 | { 2 | "title" : "Titanic", 3 | "data": "data/titanic.csv", 4 | "width": 1000, 5 | "height": 480, 6 | "padding": {"top": 10, "left": 30, "bottom": 30, "right": 10}, 7 | "layouts": [ 8 | { 9 | "name": "layout1", 10 | "type": "gridxy", 11 | "groupby": { 12 | "key": "Class", 13 | "isKeyShared": true 14 | }, 15 | "aspect_ratio":"fillX", 16 | "size": { 17 | "type":"uniform", 18 | "isShared": false 19 | }, 20 | "direction": "LRBT", 21 | "align": "LB", 22 | "margin": {"top": 10, "left": 30, "bottom": 30, "right": 10}, 23 | "padding": {"top": 10, "left": 30, "bottom": 30, "right": 10} 24 | }, 25 | { 26 | "name": "layout2", 27 | "type": "gridxy", 28 | "groupby": { 29 | "key": "Sex", 30 | "isKeyShared": true 31 | }, 32 | "aspect_ratio":"fillY", 33 | "size": { 34 | "type": "uniform", 35 | "isShared": false 36 | }, 37 | "direction": "LRBT", 38 | "align": "LB", 39 | "margin": {"top": 10, "left": 30, "bottom": 30, "right": 10}, 40 | "padding": {"top": 10, "left": 30, "bottom": 30, "right": 10} 41 | }, 42 | { 43 | "name": "layout3", 44 | "type": "gridxy", 45 | "groupby": { 46 | "key": "id", 47 | "isKeyShared": false 48 | }, 49 | "aspect_ratio":"fillX", 50 | "size": { 51 | "type":"uniform", 52 | "isShare": false 53 | }, 54 | "direction": "LRBT", 55 | "align": "LB", 56 | "margin": {"top": 10, "left": 30, "bottom": 30, "right": 10}, 57 | "padding": {"top": 10, "left": 30, "bottom": 30, "right": 10} 58 | }], 59 | "mark": { 60 | "shape": "circle", 61 | "color": "survival", 62 | "size": { 63 | "type": "max", 64 | "isShared": false 65 | }, 66 | "isColorScaleShared": true 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /app/data/titanic_spec2.json: -------------------------------------------------------------------------------- 1 | { 2 | "title" : "Titanic", 3 | "data": "data/titanic.csv", 4 | "width": 1000, 5 | "height": 480, 6 | "padding": {"top": 10, "left": 30, "bottom": 30, "right": 10}, 7 | "layouts": [ 8 | { 9 | "name": "layout1", 10 | "type": "gridxy", 11 | "groupby": { 12 | "key": "Class", 13 | "isKeyShared": true 14 | }, 15 | "aspect_ratio":"fillX", 16 | "size": { 17 | "type":"uniform", 18 | "isShared": false 19 | }, 20 | "direction": "LRBT", 21 | "align": "LB", 22 | "margin": {"top": 10, "left": 30, "bottom": 30, "right": 10}, 23 | "padding": {"top": 10, "left": 30, "bottom": 30, "right": 10} 24 | }, 25 | { 26 | "name": "layout2", 27 | "type": "gridxy", 28 | "groupby": { 29 | "key": "Sex", 30 | "isKeyShared": true 31 | }, 32 | "aspect_ratio":"fillY", 33 | "size": { 34 | "type": "uniform", 35 | "isShared": false 36 | }, 37 | "direction": "LRBT", 38 | "align": "LB", 39 | "margin": {"top": 10, "left": 30, "bottom": 30, "right": 10}, 40 | "padding": {"top": 10, "left": 30, "bottom": 30, "right": 10} 41 | }, 42 | { 43 | "name": "layout3", 44 | "type": "gridxy", 45 | "groupby": { 46 | "key": "id", 47 | "isKeyShared": false 48 | }, 49 | "aspect_ratio":"fillX", 50 | "size": { 51 | "type":"uniform", 52 | "isShare": false 53 | }, 54 | "direction": "LRBT", 55 | "align": "LB", 56 | "margin": {"top": 10, "left": 30, "bottom": 30, "right": 10}, 57 | "padding": {"top": 10, "left": 30, "bottom": 30, "right": 10} 58 | }], 59 | "mark": { 60 | "shape": "circle", 61 | "color": "survival", 62 | "size": { 63 | "type": "max", 64 | "isShared": true 65 | }, 66 | "isColorScaleShared": true 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /app/data/titanic_spec3.json: -------------------------------------------------------------------------------- 1 | { 2 | "title" : "Titanic", 3 | "data": "data/titanic.csv", 4 | "width": 1000, 5 | "height": 480, 6 | "padding": {"top": 10, "left": 30, "bottom": 30, "right": 10}, 7 | "layouts": [ 8 | { 9 | "name": "layout1", 10 | "type": "gridxy", 11 | "groupby": { 12 | "key": "Class", 13 | "isKeyShared": true 14 | }, 15 | "aspect_ratio":"fillX", 16 | "size": { 17 | "type":"uniform", 18 | "isShared": false 19 | }, 20 | "direction": "LRBT", 21 | "align": "LB", 22 | "margin": {"top": 10, "left": 30, "bottom": 30, "right": 10}, 23 | "padding": {"top": 10, "left": 30, "bottom": 30, "right": 10} 24 | }, 25 | { 26 | "name": "layout2", 27 | "type": "gridxy", 28 | "groupby": { 29 | "key": "Sex", 30 | "isKeyShared": true 31 | }, 32 | "aspect_ratio":"fillY", 33 | "size": { 34 | "type": "uniform", 35 | "isShared": false 36 | }, 37 | "direction": "LRTB", 38 | "align": "LB", 39 | "margin": {"top": 10, "left": 30, "bottom": 30, "right": 10}, 40 | "padding": {"top": 10, "left": 30, "bottom": 30, "right": 10} 41 | }, 42 | { 43 | "name": "layout3", 44 | "type": "gridxy", 45 | "groupby": { 46 | "key": "id", 47 | "isKeyShared": false 48 | }, 49 | "aspect_ratio":"square", 50 | "size": { 51 | "type":"uniform", 52 | "isShared": false 53 | }, 54 | "direction": "LRTB", 55 | "align": "LB", 56 | "margin": {"top": 10, "left": 30, "bottom": 30, "right": 10}, 57 | "padding": {"top": 10, "left": 30, "bottom": 30, "right": 10} 58 | }], 59 | "mark": { 60 | "shape": "circle", 61 | "color": "survival", 62 | "size": { 63 | "type": "max", 64 | "isShared": false 65 | }, 66 | "isColorScaleShared": true 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /app/data/titanic_spec4.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Titanic", 3 | "data": "data/titanic.csv", 4 | "width": 320, 5 | "height": 240, 6 | "padding": { 7 | "top": 5, 8 | "left": 5, 9 | "bottom": 5, 10 | "right": 5 11 | }, 12 | "layouts": [{ 13 | "name": "layout1", 14 | "type": "gridxy", 15 | "subgroup": { 16 | "type": "groupby", 17 | "key": "Sex", 18 | "isShared": false 19 | }, 20 | "aspect_ratio": "fillY", 21 | "size": { 22 | "type": "uniform", 23 | "isShared": false 24 | }, 25 | "direction": "LRBT", 26 | "align": "LB", 27 | "margin": { 28 | "top": 0, 29 | "left": 0, 30 | "bottom": 0, 31 | "right": 0 32 | }, 33 | "padding": { 34 | "top": 0, 35 | "left": 0, 36 | "bottom": 0, 37 | "right": 0 38 | } 39 | }, { 40 | "name": "layout2", 41 | "type": "gridxy", 42 | "subgroup": { 43 | "type": "groupby", 44 | "key": "Class", 45 | "isShared": true 46 | }, 47 | "aspect_ratio": "fillX", 48 | "size": { 49 | "type": "uniform", 50 | "isShared": true 51 | }, 52 | "direction": "LRTB", 53 | "align": "LB", 54 | "margin": { 55 | "top": 5, 56 | "left": 5, 57 | "bottom": 5, 58 | "right": 5 59 | }, 60 | "padding": { 61 | "top": 5, 62 | "left": 5, 63 | "bottom": 5, 64 | "right": 5 65 | } 66 | }, { 67 | "name": "layout3", 68 | "type": "gridxy", 69 | "subgroup": { 70 | "type": "flatten" 71 | }, 72 | "aspect_ratio": "maxfill", 73 | "size": { 74 | "type": "uniform", 75 | "isShared": false 76 | }, 77 | "direction": "LRBT", 78 | "align": "LB", 79 | "margin": { 80 | "top": 5, 81 | "left": 5, 82 | "bottom": 5, 83 | "right": 5 84 | }, 85 | "padding": { 86 | "top": 5, 87 | "left": 5, 88 | "bottom": 5, 89 | "right": 5 90 | }, 91 | "sort": { 92 | "key": "Survived" 93 | } 94 | }], 95 | "mark": { 96 | "shape": "circle", 97 | "color": { 98 | "key": "Survived", 99 | "type": "categorical" 100 | }, 101 | "size": { 102 | "type": "max", 103 | "isShared": false 104 | }, 105 | "isColorScaleShared": true 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /app/data/titanic_spec_packxy_hierarchy.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Titanic", 3 | "data": "data/titanic.csv", 4 | "width": 320, 5 | "height": 240, 6 | "padding": { 7 | "top": 5, 8 | "left": 5, 9 | "bottom": 5, 10 | "right": 5 11 | }, 12 | "layouts": [{ 13 | "name": "layout1", 14 | "type": "gridxy", 15 | "subgroup": { 16 | "type": "groupby", 17 | "key": "Sex", 18 | "isShared": false 19 | }, 20 | "aspect_ratio": "fillY", 21 | "size": { 22 | "type": "uniform", 23 | "isShared": false 24 | }, 25 | "direction": "LRBT", 26 | "align": "LB", 27 | "margin": { 28 | "top": 0, 29 | "left": 0, 30 | "bottom": 0, 31 | "right": 0 32 | }, 33 | "padding": { 34 | "top": 0, 35 | "left": 0, 36 | "bottom": 0, 37 | "right": 0 38 | } 39 | }, { 40 | "name": "layout2", 41 | "type": "gridxy", 42 | "subgroup": { 43 | "type": "groupby", 44 | "key": "Class", 45 | "isShared": true 46 | }, 47 | "aspect_ratio": "fillX", 48 | "size": { 49 | "type": "uniform", 50 | "isShared": false 51 | }, 52 | "direction": "LRTB", 53 | "align": "LB", 54 | "margin": { 55 | "top": 5, 56 | "left": 5, 57 | "bottom": 5, 58 | "right": 5 59 | }, 60 | "padding": { 61 | "top": 5, 62 | "left": 5, 63 | "bottom": 5, 64 | "right": 5 65 | } 66 | }, { 67 | "name": "layout3", 68 | "type": "gridxy", 69 | "subgroup": { 70 | "type": "flatten" 71 | }, 72 | "aspect_ratio": "maxfill", 73 | "size": { 74 | "type": "uniform", 75 | "isShared": true 76 | }, 77 | "direction": "LRBT", 78 | "align": "LB", 79 | "margin": { 80 | "top": 5, 81 | "left": 5, 82 | "bottom": 5, 83 | "right": 5 84 | }, 85 | "padding": { 86 | "top": 5, 87 | "left": 5, 88 | "bottom": 5, 89 | "right": 5 90 | }, 91 | "sort": { 92 | "key": "Survived" 93 | } 94 | }], 95 | "mark": { 96 | "shape": "circle", 97 | "color": { 98 | "key": "Survived", 99 | "type": "categorical" 100 | }, 101 | "size": { 102 | "type": "max", 103 | "isShared": false 104 | }, 105 | "isColorScaleShared": true 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /app/data/titanic_spec_packxy_isolated.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Titanic", 3 | "data": "data/titanic.csv", 4 | "width": 320, 5 | "height": 240, 6 | "padding": { 7 | "top": 5, 8 | "left": 5, 9 | "bottom": 5, 10 | "right": 5 11 | }, 12 | "layouts": [{ 13 | "name": "layout1", 14 | "type": "gridxy", 15 | "subgroup": { 16 | "type": "groupby", 17 | "key": "Sex", 18 | "isShared": false 19 | }, 20 | "aspect_ratio": "fillY", 21 | "size": { 22 | "type": "uniform", 23 | "isShared": false 24 | }, 25 | "direction": "LRBT", 26 | "align": "LB", 27 | "margin": { 28 | "top": 0, 29 | "left": 0, 30 | "bottom": 0, 31 | "right": 0 32 | }, 33 | "padding": { 34 | "top": 0, 35 | "left": 0, 36 | "bottom": 0, 37 | "right": 0 38 | } 39 | }, { 40 | "name": "layout2", 41 | "type": "gridxy", 42 | "subgroup": { 43 | "type": "groupby", 44 | "key": "Class", 45 | "isShared": true 46 | }, 47 | "aspect_ratio": "fillX", 48 | "size": { 49 | "type": "uniform", 50 | "isShared": true 51 | }, 52 | "direction": "LRTB", 53 | "align": "LB", 54 | "margin": { 55 | "top": 5, 56 | "left": 5, 57 | "bottom": 5, 58 | "right": 5 59 | }, 60 | "padding": { 61 | "top": 5, 62 | "left": 5, 63 | "bottom": 5, 64 | "right": 5 65 | } 66 | }, { 67 | "name": "layout3", 68 | "type": "gridxy", 69 | "subgroup": { 70 | "type": "flatten" 71 | }, 72 | "aspect_ratio": "maxfill", 73 | "size": { 74 | "type": "uniform", 75 | "isShared": true 76 | }, 77 | "direction": "LRBT", 78 | "align": "LB", 79 | "margin": { 80 | "top": 5, 81 | "left": 5, 82 | "bottom": 5, 83 | "right": 5 84 | }, 85 | "padding": { 86 | "top": 5, 87 | "left": 5, 88 | "bottom": 5, 89 | "right": 5 90 | }, 91 | "sort": { 92 | "key": "Survived" 93 | } 94 | }], 95 | "mark": { 96 | "shape": "circle", 97 | "color": { 98 | "key": "Survived", 99 | "type": "categorical" 100 | }, 101 | "size": { 102 | "type": "max", 103 | "isShared": false 104 | }, 105 | "isColorScaleShared": true 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /app/data/titanic_spec_packxy_mixed.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Titanic", 3 | "data": "data/titanic.csv", 4 | "width": 320, 5 | "height": 240, 6 | "padding": { 7 | "top": 5, 8 | "left": 5, 9 | "bottom": 5, 10 | "right": 5 11 | }, 12 | "layouts": [{ 13 | "name": "layout1", 14 | "type": "gridxy", 15 | "subgroup": { 16 | "type": "groupby", 17 | "key": "Sex", 18 | "isShared": false 19 | }, 20 | "aspect_ratio": "fillY", 21 | "size": { 22 | "type": "uniform", 23 | "isShared": false 24 | }, 25 | "direction": "LRBT", 26 | "align": "LB", 27 | "margin": { 28 | "top": 0, 29 | "left": 0, 30 | "bottom": 0, 31 | "right": 0 32 | }, 33 | "padding": { 34 | "top": 0, 35 | "left": 0, 36 | "bottom": 0, 37 | "right": 0 38 | } 39 | }, { 40 | "name": "layout2", 41 | "type": "gridxy", 42 | "subgroup": { 43 | "type": "groupby", 44 | "key": "Class", 45 | "isShared": true 46 | }, 47 | "aspect_ratio": "fillX", 48 | "size": { 49 | "type": "uniform", 50 | "isShared": false 51 | }, 52 | "direction": "LRTB", 53 | "align": "LB", 54 | "margin": { 55 | "top": 5, 56 | "left": 5, 57 | "bottom": 5, 58 | "right": 5 59 | }, 60 | "padding": { 61 | "top": 5, 62 | "left": 5, 63 | "bottom": 5, 64 | "right": 5 65 | } 66 | }, { 67 | "name": "layout3", 68 | "type": "gridxy", 69 | "subgroup": { 70 | "type": "flatten" 71 | }, 72 | "aspect_ratio": "maxfill", 73 | "size": { 74 | "type": "uniform", 75 | "isShared": false 76 | }, 77 | "direction": "LRBT", 78 | "align": "LB", 79 | "margin": { 80 | "top": 5, 81 | "left": 5, 82 | "bottom": 5, 83 | "right": 5 84 | }, 85 | "padding": { 86 | "top": 5, 87 | "left": 5, 88 | "bottom": 5, 89 | "right": 5 90 | }, 91 | "sort": { 92 | "key": "Survived" 93 | } 94 | }], 95 | "mark": { 96 | "shape": "circle", 97 | "color": { 98 | "key": "Survived", 99 | "type": "categorical" 100 | }, 101 | "size": { 102 | "type": "max", 103 | "isShared": false 104 | }, 105 | "isColorScaleShared": true 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /app/data/unit_column_chart.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Titanic", 3 | "data": "data/titanic3.csv", 4 | "width": 320, 5 | "height": 240, 6 | "padding": { 7 | "top": 10, 8 | "left": 30, 9 | "bottom": 30, 10 | "right": 10 11 | }, 12 | "layouts": [{ 13 | "name": "layout1", 14 | "type": "gridxy", 15 | "subgroup": { 16 | "type": "groupby", 17 | "key": "pclass", 18 | "isShared": false 19 | }, 20 | "aspect_ratio": "fillX", 21 | "size": { 22 | "type": "uniform", 23 | "isShared": false 24 | }, 25 | "direction": "LRBT", 26 | "align": "LB", 27 | "margin": { 28 | "top": 10, 29 | "left": 5, 30 | "bottom": 5, 31 | "right": 10 32 | }, 33 | "padding": { 34 | "top": 10, 35 | "left": 30, 36 | "bottom": 30, 37 | "right": 10 38 | } 39 | }, { 40 | "name": "layout2", 41 | "type": "gridxy", 42 | "subgroup": { 43 | "type": "flatten" 44 | }, 45 | "aspect_ratio": "maxfill", 46 | "size": { 47 | "type": "uniform", 48 | "isShared": false 49 | }, 50 | "direction": "LRBT", 51 | "align": "LB", 52 | "margin": { 53 | "top": 10, 54 | "left": 30, 55 | "bottom": 30, 56 | "right": 10 57 | }, 58 | "padding": { 59 | "top": 10, 60 | "left": 30, 61 | "bottom": 30, 62 | "right": 10 63 | }, 64 | "sort": { 65 | "key":"survived" 66 | } 67 | }], 68 | "mark": { 69 | "shape": "circle", 70 | "color": { 71 | "key": "survived", 72 | "type": "categorical" 73 | }, 74 | "size": { 75 | "type": "max", 76 | "isShared": false 77 | }, 78 | "isColorScaleShared": true 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /app/data/unit_column_chart_shared.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Titanic", 3 | "data": "data/titanic3.csv", 4 | "width": 320, 5 | "height": 240, 6 | "padding": { 7 | "top": 10, 8 | "left": 30, 9 | "bottom": 30, 10 | "right": 10 11 | }, 12 | "layouts": [{ 13 | "name": "layout1", 14 | "type": "gridxy", 15 | "subgroup": { 16 | "type": "groupby", 17 | "key": "pclass", 18 | "isShared": false 19 | }, 20 | "aspect_ratio": "fillX", 21 | "size": { 22 | "type": "uniform", 23 | "isShared": false 24 | }, 25 | "direction": "LRBT", 26 | "align": "LB", 27 | "margin": { 28 | "top": 5, 29 | "left": 5, 30 | "bottom": 5, 31 | "right": 5 32 | }, 33 | "padding": { 34 | "top": 0, 35 | "left": 0, 36 | "bottom": 0, 37 | "right": 0 38 | } 39 | }, { 40 | "name": "layout2", 41 | "type": "gridxy", 42 | "subgroup": { 43 | "type": "flatten" 44 | }, 45 | "aspect_ratio": "maxfill", 46 | "size": { 47 | "type": "uniform", 48 | "isShared": true 49 | }, 50 | "direction": "LRBT", 51 | "align": "LB", 52 | "margin": { 53 | "top": 0, 54 | "left": 0, 55 | "bottom": 0, 56 | "right": 0 57 | }, 58 | "padding": { 59 | "top": 0, 60 | "left": 0, 61 | "bottom": 0, 62 | "right": 0 63 | }, 64 | "sort": { 65 | "key": "survived" 66 | } 67 | }], 68 | "mark": { 69 | "shape": "circle", 70 | "color": { 71 | "key": "survived", 72 | "type": "categorical" 73 | }, 74 | "size": { 75 | "type": "max", 76 | "isShared": false 77 | }, 78 | "isColorScaleShared": true 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /app/data/unit_column_chart_shared_mark.json: -------------------------------------------------------------------------------- 1 | { 2 | "title" : "Titanic", 3 | "data": "data/titanic3.csv", 4 | "width": 320, 5 | "height": 240, 6 | "padding": {"top": 10, "left": 30, "bottom": 30, "right": 10}, 7 | "layouts": [ 8 | { 9 | "name": "layout1", 10 | "type": "gridxy", 11 | "subgroup": { 12 | "type":"groupby", 13 | "key": "pclass", 14 | "isShared": false 15 | }, 16 | "aspect_ratio":"fillX", 17 | "size": { 18 | "type":"uniform", 19 | "isShared": false 20 | }, 21 | "direction": "LRBT", 22 | "align": "LB", 23 | "margin": {"top": 5, "left": 5, "bottom": 5, "right": 5}, 24 | "padding": {"top": 5, "left": 5, "bottom": 5, "right": 5} 25 | }, 26 | { 27 | "name": "layout2", 28 | "type": "gridxy", 29 | "subgroup": { 30 | "type":"flatten" }, 31 | "aspect_ratio":"maxfill", 32 | "size": { 33 | "type":"uniform", 34 | "isShared": false 35 | }, 36 | "direction": "LRBT", 37 | "align": "LB", 38 | "margin": {"top": 10, "left": 30, "bottom": 30, "right": 10}, 39 | "padding": {"top": 10, "left": 30, "bottom": 30, "right": 10}, 40 | "sort":{ 41 | "key":"survived" 42 | } 43 | }], 44 | "mark": { 45 | "shape": "rect", 46 | "color": { 47 | "key":"survived", 48 | "type":"categorical" 49 | }, 50 | "size": { 51 | "type": "max", 52 | "isShared": true 53 | }, 54 | "isColorScaleShared": true 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /app/data/unit_small_multiple.json: -------------------------------------------------------------------------------- 1 | { 2 | "title" : "Titanic", 3 | "data": "data/titanic3.csv", 4 | "width": 500, 5 | "height": 240, 6 | "padding": {"top": 5, "left": 5, "bottom": 5, "right": 5}, 7 | "layouts": [ 8 | { 9 | "name": "layout1", 10 | "type": "gridxy", 11 | "subgroup": { 12 | "key": "age", 13 | "type": "bin", 14 | "numBin": 15, 15 | "isShared": false 16 | }, 17 | "aspect_ratio":"parent", 18 | "size": { 19 | "type":"uniform", 20 | "isShared": true 21 | }, 22 | "direction": "LRBT", 23 | "align": "LB", 24 | "margin": {"top": 5, "left": 5, "bottom": 5, "right": 5}, 25 | "padding": {"top": 5, "left": 5, "bottom": 5, "right": 5}, 26 | "box": { 27 | "fill": "none", 28 | "stroke": "black", 29 | "stroke-width": 0, 30 | "opacity":0.3 31 | } 32 | }, 33 | { 34 | "name": "layout2", 35 | "type": "gridxy", 36 | "subgroup": { 37 | "type":"groupby", 38 | "key": "pclass", 39 | "isShared": true 40 | }, 41 | "aspect_ratio":"fillX", 42 | "size": { 43 | "type": "uniform", 44 | "isShared": true 45 | }, 46 | "direction": "LRTB", 47 | "align": "LB", 48 | "margin": {"top": 5, "left": 5, "bottom": 5, "right": 5}, 49 | "padding": {"top": 5, "left": 5, "bottom": 5, "right": 5}, 50 | "box": { 51 | "fill": "none", 52 | "stroke": "green", 53 | "stroke-width": 1, 54 | "opacity":1 55 | } 56 | }, 57 | { 58 | "name": "layout3", 59 | "type": "gridxy", 60 | "subgroup": { 61 | "type":"flatten" 62 | }, 63 | "aspect_ratio":"maxfill", 64 | "size": { 65 | "type":"uniform", 66 | "isShared": true 67 | }, 68 | "direction": "LRBT", 69 | "align": "LB", 70 | "margin": {"top": 5, "left": 5, "bottom": 5, "right": 5}, 71 | "padding": {"top": 5, "left": 5, "bottom": 5, "right": 5}, 72 | "box": { 73 | "fill": "none", 74 | "stroke": "black", 75 | "stroke-width": 0, 76 | "opacity":1 77 | }, 78 | "sort":{ 79 | "key":"survived" 80 | } 81 | }], 82 | "mark": { 83 | "shape": "circle", 84 | "color": { 85 | "key":"survived", 86 | "type":"categorical" 87 | }, 88 | "size": { 89 | "type": "max", 90 | "isShared": false 91 | }, 92 | "isColorScaleShared": true 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /app/data/violin.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Titanic", 3 | "data": "data/titanic3.csv", 4 | "width": 1000, 5 | "height": 320, 6 | "padding": { 7 | "top": 5, 8 | "left": 5, 9 | "bottom": 5, 10 | "right": 5 11 | }, 12 | "layouts": [{ 13 | "name": "layout1", 14 | "type": "gridxy", 15 | "subgroup": { 16 | "type": "groupby", 17 | "key": "pclass", 18 | "isShared": false 19 | }, 20 | "aspect_ratio": "fillX", 21 | "size": { 22 | "type": "uniform", 23 | "isShared": true 24 | }, 25 | "direction": "LRBT", 26 | "align": "LB", 27 | "margin": { 28 | "top": 5, 29 | "left": 5, 30 | "bottom": 5, 31 | "right": 5 32 | }, 33 | "padding": { 34 | "top": 5, 35 | "left": 5, 36 | "bottom": 5, 37 | "right": 5 38 | }, 39 | "box": { 40 | "fill": "white", 41 | "stroke": "black", 42 | "stroke-width": 0, 43 | "opacity": 0.3 44 | }, 45 | "sort": { 46 | "key": "pclass", 47 | "direction": "ascending" 48 | } 49 | }, { 50 | "name": "layout2", 51 | "type": "gridxy", 52 | "subgroup": { 53 | "type": "bin", 54 | "key": "age", 55 | "numBin": 19, 56 | "isShared": true 57 | }, 58 | "aspect_ratio": "fillY", 59 | "size": { 60 | "type": "uniform", 61 | "isShared": true 62 | }, 63 | "direction": "BT", 64 | "align": "bottom", 65 | "margin": { 66 | "top": 0, 67 | "left": 0, 68 | "bottom": 0, 69 | "right": 0 70 | }, 71 | "padding": { 72 | "top": 0, 73 | "left": 0, 74 | "bottom": 0, 75 | "right": 0 76 | }, 77 | "box": { 78 | "fill": "white", 79 | "stroke": "black", 80 | "stroke-width": 0.5, 81 | "opacity": 0.5 82 | }, 83 | "sort": { 84 | "key": "age", 85 | "direction": "ascending" 86 | } 87 | }, { 88 | "name": "layout3", 89 | "type": "gridxy", 90 | "subgroup": { 91 | "type": "passthrough", 92 | "isShared": true 93 | }, 94 | "aspect_ratio": "fillX", 95 | "size": { 96 | "type": "count", 97 | "isShared": true 98 | }, 99 | "direction": "LR", 100 | "align": "center", 101 | "margin": { 102 | "top": 0, 103 | "left": 0, 104 | "bottom": 0, 105 | "right": 0 106 | }, 107 | "padding": { 108 | "top": 0, 109 | "left": 0, 110 | "bottom": 0, 111 | "right": 0 112 | }, 113 | "box": { 114 | "fill": "white", 115 | "stroke": "blue", 116 | "stroke-width": 0, 117 | "opacity": 0.5 118 | } 119 | }, { 120 | "name": "layout4", 121 | "type": "gridxy", 122 | "subgroup": { 123 | "type": "flatten" 124 | }, 125 | "aspect_ratio": "maxfill", 126 | "size": { 127 | "type": "uniform", 128 | "isShared": false 129 | }, 130 | "direction": "BTLR", 131 | "align": "LB", 132 | "margin": { 133 | "top": 0, 134 | "left": 0, 135 | "bottom": 0, 136 | "right": 0 137 | }, 138 | "padding": { 139 | "top": 0, 140 | "left": 0, 141 | "bottom": 0, 142 | "right": 0 143 | }, 144 | "box": { 145 | "fill": "white", 146 | "stroke": "red", 147 | "stroke-width": 0, 148 | "opacity": 0.5 149 | }, 150 | "sort": { 151 | "type": "categorical", 152 | "key": "survived", 153 | "direction": "ascending" 154 | } 155 | }], 156 | "mark": { 157 | "shape": "circle", 158 | "color": { 159 | "key": "survived_text", 160 | "type": "categorical" 161 | }, 162 | "size": { 163 | "type": "max", 164 | "isShared": false 165 | }, 166 | "isColorScaleShared": true 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intuinno/unit/186ed809d4a7bce0c1aba99da5de4d997e2d3fbe/app/favicon.ico -------------------------------------------------------------------------------- /app/images/process.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intuinno/unit/186ed809d4a7bce0c1aba99da5de4d997e2d3fbe/app/images/process.png -------------------------------------------------------------------------------- /app/images/vcd-mosaic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intuinno/unit/186ed809d4a7bce0c1aba99da5de4d997e2d3fbe/app/images/vcd-mosaic.png -------------------------------------------------------------------------------- /app/images/yeoman.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intuinno/unit/186ed809d4a7bce0c1aba99da5de4d997e2d3fbe/app/images/yeoman.png -------------------------------------------------------------------------------- /app/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 24 | 25 | 26 |
27 | 52 |
53 | 54 | Fork me on GitHub 55 | 56 |
57 |
58 |
59 | 60 | 65 | 66 | 67 | 68 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | -------------------------------------------------------------------------------- /app/robots.txt: -------------------------------------------------------------------------------- 1 | # robotstxt.org 2 | 3 | User-agent: * 4 | Disallow: 5 | -------------------------------------------------------------------------------- /app/scripts/app.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * @ngdoc overview 5 | * @name unitApp 6 | * @description 7 | * # unitApp 8 | * 9 | * Main module of the application. 10 | */ 11 | angular 12 | .module('unitApp', [ 13 | 'ngAnimate', 14 | 'ngCookies', 15 | 'ngResource', 16 | 'ngRoute', 17 | 'ngSanitize', 18 | 'ngTouch' 19 | ]) 20 | .config(function ($routeProvider) { 21 | $routeProvider 22 | .when('/', { 23 | templateUrl: 'views/main.html', 24 | controller: 'MainCtrl', 25 | controllerAs: 'main' 26 | }) 27 | .when('/example', { 28 | templateUrl: 'views/example.html', 29 | controller: 'ExampleCtrl', 30 | controllerAs: 'example' 31 | }) 32 | .when('/example', { 33 | templateUrl: 'views/example.html', 34 | controller: 'ExampleCtrl', 35 | controllerAs: 'example' 36 | }) 37 | .when('/live', { 38 | templateUrl: 'views/live.html', 39 | controller: 'LiveCtrl', 40 | controllerAs: 'live' 41 | }) 42 | .when('/enum', { 43 | templateUrl: 'views/enum.html', 44 | controller: 'EnumCtrl', 45 | controllerAs: 'enum' 46 | }) 47 | .otherwise({ 48 | redirectTo: '/' 49 | }); 50 | }); 51 | -------------------------------------------------------------------------------- /app/scripts/controllers/about.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * @ngdoc function 5 | * @name unitApp.controller:AboutCtrl 6 | * @description 7 | * # AboutCtrl 8 | * Controller of the unitApp 9 | */ 10 | angular.module('unitApp') 11 | .controller('AboutCtrl', function () { 12 | this.awesomeThings = [ 13 | 'HTML5 Boilerplate', 14 | 'AngularJS', 15 | 'Karma' 16 | ]; 17 | }); 18 | -------------------------------------------------------------------------------- /app/scripts/controllers/enum.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * @ngdoc function 5 | * @name unitApp.controller:EnumCtrl 6 | * @description 7 | * # EnumCtrl 8 | * Controller of the unitApp 9 | */ 10 | angular.module('unitApp') 11 | .controller('EnumCtrl', function(unit) { 12 | //Enumeration 13 | d3.csv('./data/titanic3.csv', function(error, data) { 14 | 15 | var keys = Object.keys(data[0]); 16 | 17 | d3.select("#control_enumeration").selectAll("input") 18 | .data(keys) 19 | .enter() 20 | .append('label') 21 | .attr('for', function(d, i) { 22 | return 'a' + i; 23 | }) 24 | .text(function(d) { 25 | return d; 26 | }) 27 | .append('input') 28 | .property("checked", function(d, i) { 29 | return false; 30 | }) 31 | .attr("type", "checkbox") 32 | .attr("id", function(d, i) { 33 | return 'a' + i; 34 | }); 35 | 36 | }); 37 | 38 | var update_enumeration_button = d3.select('#updatebutton_enumeration'); 39 | 40 | update_enumeration_button.on('click', function() { 41 | var inputs = d3.select('#control_enumeration').selectAll("input"); 42 | console.log(inputs); 43 | var selectedInputs = []; 44 | inputs.each(function(d, i) { 45 | if (d3.select(this).property("checked")) { 46 | selectedInputs.push(d); 47 | } 48 | }); 49 | var numLayer = d3.select("#nLayer").property("value"); 50 | numLayer = +numLayer; 51 | console.log(selectedInputs); 52 | enumerate(selectedInputs, numLayer, 'unit_enumerate'); 53 | }); 54 | 55 | var UnitChart = unit.UnitChart; 56 | 57 | var enumerate = function(selectedInputs, numLayer, divId) { 58 | 59 | d3.json('./data/enumerate.json', function(error, data) { 60 | var base = data; 61 | var flattenLayers, markPolicies; 62 | var specs = [] 63 | switch (numLayer) { 64 | case 1: 65 | flattenLayers = getFlattenLayers(selectedInputs); 66 | markPolicies = getMarkPolicies(selectedInputs); 67 | specs = enumeratePolicyForSingleLayer(flattenLayers, markPolicies); 68 | break; 69 | 70 | case 2: 71 | var firstLayers = getFirstLayers(selectedInputs); 72 | flattenLayers = getFlattenLayers(selectedInputs); 73 | markPolicies = getMarkPolicies(selectedInputs); 74 | specs = enumeratePolicyForDoubleLayers(firstLayers, flattenLayers, markPolicies); 75 | break; 76 | 77 | default: 78 | var firstLayers = getFirstLayers(selectedInputs); 79 | var middleLayers = getMiddleLayers(selectedInputs, numLayer); 80 | flattenLayers = getFlattenLayers(selectedInputs); 81 | markPolicies = getMarkPolicies(selectedInputs); 82 | specs = enumeratePolicyForGeneralLayers(firstLayers,middleLayers, flattenLayers, markPolicies); 83 | 84 | } 85 | console.log("Number of Enumerations:", specs.length); 86 | 87 | 88 | d3.select('#num_enumeration').text(specs.length); 89 | 90 | if (!d3.select('#enumerate_draw').property("checked")) { 91 | drawSpecs(specs, divId); 92 | 93 | } 94 | 95 | }); 96 | 97 | }; 98 | 99 | 100 | function enumeratePolicyForDoubleLayers(firstLayers, flattenLayers, markPolicies) { 101 | var specs = []; 102 | firstLayers.forEach(function(aFirstLayer) { 103 | flattenLayers.forEach(function(aFlattenLayer) { 104 | markPolicies.forEach(function(aMarkPolicy) { 105 | var newFirstLayer = JSON.parse(JSON.stringify(aFirstLayer)); 106 | var newFlattenLayer = JSON.parse(JSON.stringify(aFlattenLayer)); 107 | var aSpec = { 108 | "title": "Titanic", 109 | "data": "data/titanic3.csv", 110 | "width": 1000, 111 | "height": 320, 112 | "padding": { 113 | "top": 5, 114 | "left": 5, 115 | "bottom": 5, 116 | "right": 5 117 | }, 118 | "layouts": [] 119 | }; 120 | aSpec.layouts = [newFirstLayer, newFlattenLayer]; 121 | aSpec.mark = aMarkPolicy; 122 | specs.push(aSpec); 123 | }); 124 | }); 125 | }); 126 | 127 | return specs; 128 | } 129 | 130 | function enumeratePolicyForGeneralLayers(firstLayers, middleLayers, flattenLayers, markPolicies, numLayer) { 131 | var specs = []; 132 | firstLayers.forEach(function(aFirstLayer) { 133 | middleLayers.forEach(function(aMiddleLayer) { 134 | flattenLayers.forEach(function(aFlattenLayer) { 135 | markPolicies.forEach(function(aMarkPolicy) { 136 | var newFirstLayer = JSON.parse(JSON.stringify(aFirstLayer)); 137 | var newFlattenLayer = JSON.parse(JSON.stringify(aFlattenLayer)); 138 | var newMiddleLayer = JSON.parse(JSON.stringify(aMiddleLayer)); 139 | var aSpec = { 140 | "title": "Titanic", 141 | "data": "data/titanic3.csv", 142 | "width": 1000, 143 | "height": 320, 144 | "padding": { 145 | "top": 5, 146 | "left": 5, 147 | "bottom": 5, 148 | "right": 5 149 | }, 150 | "layouts": [] 151 | }; 152 | aSpec.layouts = [newFirstLayer]; 153 | aSpec.layouts = aSpec.layouts.concat( newMiddleLayer); 154 | aSpec.layouts = aSpec.layouts.push( newMiddleLayer); 155 | 156 | aSpec.mark = aMarkPolicy; 157 | specs.push(aSpec); 158 | }); 159 | }); 160 | }); 161 | }); 162 | 163 | return specs; 164 | } 165 | 166 | function enumeratePolicyForSingleLayer(flattenLayers, markPolicies) { 167 | var specs = [] 168 | flattenLayers.forEach(function(aFlattenLayer) { 169 | markPolicies.forEach(function(aMarkPolicy) { 170 | var aSpec = { 171 | "title": "Titanic", 172 | "data": "data/titanic3.csv", 173 | "width": 1000, 174 | "height": 320, 175 | "padding": { 176 | "top": 5, 177 | "left": 5, 178 | "bottom": 5, 179 | "right": 5 180 | }, 181 | "layouts": [] 182 | }; 183 | aSpec.layouts.push(aFlattenLayer); 184 | aSpec.mark = aMarkPolicy; 185 | specs.push(aSpec); 186 | }); 187 | }); 188 | return specs; 189 | 190 | } 191 | 192 | 193 | 194 | function drawSpecs(specs, divId) { 195 | d3.select("#" + divId).selectAll("div") 196 | .data(specs) 197 | .enter() 198 | .append("div") 199 | .attr("id", function(d, i) { 200 | return "enum" + i; 201 | }); 202 | 203 | specs.forEach(function(spec, i) { 204 | UnitChart('enum' + i, spec); 205 | }) 206 | } 207 | 208 | function getFlattenLayers(selectedInputs) { 209 | 210 | var enum_aspect_ratio = ['fillX', 'fillY', 'maxfill', 'square', 'parent']; 211 | var enum_size_type = ['uniform']; 212 | var enum_size_isShared = [true, false]; 213 | var enum_direction = ['LRTB']; 214 | var enum_align = ['LB']; 215 | var enum_sort_key = selectedInputs; 216 | 217 | var layers = []; 218 | 219 | enum_aspect_ratio.forEach(function(a_aspect_ratio) { 220 | enum_size_type.forEach(function(a_size_type) { 221 | enum_size_isShared.forEach(function(a_size_isShared) { 222 | enum_direction.forEach(function(a_direction) { 223 | enum_align.forEach(function(a_align) { 224 | enum_sort_key.forEach(function(a_sort_key) { 225 | var aLayer = { 226 | "name": "flattenLayer", 227 | "type": "gridxy", 228 | "subgroup": { 229 | "type": "flatten" 230 | }, 231 | "aspect_ratio": a_aspect_ratio, 232 | "size": { 233 | "type": a_size_type, 234 | "isShared": a_size_isShared 235 | }, 236 | "direction": a_direction, 237 | "align": a_align, 238 | "margin": { 239 | "top": 0, 240 | "left": 0, 241 | "bottom": 0, 242 | "right": 0 243 | }, 244 | "padding": { 245 | "top": 0, 246 | "left": 0, 247 | "bottom": 0, 248 | "right": 0 249 | }, 250 | "box": { 251 | "fill": "yellow", 252 | "stroke": "red", 253 | "stroke-width": 0, 254 | "opacity": 0.1 255 | }, 256 | "sort": { 257 | "type": isCategorical(a_sort_key) ? "categorical" : "numerical", 258 | "key": a_sort_key 259 | } 260 | }; 261 | 262 | layers.push(aLayer); 263 | 264 | }); 265 | }); 266 | }); 267 | }); 268 | }); 269 | }); 270 | 271 | return layers; 272 | } 273 | 274 | function getFirstLayers(selectedInputs) { 275 | 276 | var enum_aspect_ratio = ['fillX', 'fillY', 'maxfill', 'square', 'parent']; 277 | var enum_groupby_key = selectedInputs; 278 | var enum_groupby_isShared = [true] 279 | var enum_size_type = [{ 280 | 'type': 'uniform' 281 | }, { 282 | 'type': 'count' 283 | }]; 284 | 285 | enum_size_type = enum_size_type.concat(selectedInputs.map(function(d) { 286 | return { 287 | 'type': 'sum', 288 | 'key': d 289 | }; 290 | })); 291 | 292 | var enum_size_sum_key = selectedInputs; 293 | var enum_size_isShared = [true]; 294 | var enum_direction = ['LRTB']; 295 | var enum_align = ['LB']; 296 | var enum_sort_key = selectedInputs; 297 | 298 | var layers = []; 299 | 300 | enum_aspect_ratio.forEach(function(a_aspect_ratio, i) { 301 | enum_size_type.forEach(function(a_size_type) { 302 | enum_size_isShared.forEach(function(a_size_isShared) { 303 | enum_direction.forEach(function(a_direction) { 304 | enum_align.forEach(function(a_align) { 305 | enum_sort_key.forEach(function(a_sort_key) { 306 | enum_groupby_key.forEach(function(a_groupby_key) { 307 | enum_groupby_isShared.forEach(function(a_groupby_isShared) { 308 | var aLayer = { 309 | "name": "firstlayer", 310 | "type": "gridxy", 311 | "subgroup": { 312 | "type": "groupby", 313 | "key": a_groupby_key, 314 | "isShared": a_groupby_isShared 315 | }, 316 | "aspect_ratio": a_aspect_ratio, 317 | "size": { 318 | "type": a_size_type.type, 319 | "isShared": a_size_isShared, 320 | "key": (a_size_type.type === 'sum') ? a_size_type.key : '' 321 | }, 322 | "direction": a_direction, 323 | "align": a_align, 324 | "margin": { 325 | "top": 0, 326 | "left": 0, 327 | "bottom": 0, 328 | "right": 0 329 | }, 330 | "padding": { 331 | "top": 0, 332 | "left": 0, 333 | "bottom": 0, 334 | "right": 0 335 | }, 336 | "box": { 337 | "fill": "yellow", 338 | "stroke": "red", 339 | "stroke-width": 0, 340 | "opacity": 0.1 341 | }, 342 | "sort": { 343 | "type": isCategorical(a_sort_key) ? "categorical" : "numerical", 344 | "key": a_sort_key 345 | } 346 | }; 347 | 348 | layers.push(aLayer); 349 | }); 350 | }); 351 | }); 352 | }); 353 | }); 354 | }); 355 | }); 356 | }); 357 | 358 | return layers; 359 | } 360 | 361 | function getMiddleLayers(selectedInputs, numLayer) { 362 | 363 | var enum_aspect_ratio = ['fillX', 'fillY', 'maxfill', 'square', 'parent']; 364 | var enum_groupby_key = [{ 365 | 'type': 'passthrough' 366 | }]; 367 | 368 | enum_groupby_key = enum_groupby_key.concat(selectedInputs.map(function(d) { 369 | return { 370 | 'type': 'groupby', 371 | 'key': d 372 | } 373 | })); 374 | 375 | selectedInputs; 376 | var enum_groupby_isShared = [true] 377 | var enum_size_type = [{ 378 | 'type': 'uniform' 379 | }, { 380 | 'type': 'count' 381 | }]; 382 | 383 | enum_size_type = enum_size_type.concat(selectedInputs.map(function(d) { 384 | return { 385 | 'type': 'sum', 386 | 'key': d 387 | }; 388 | })); 389 | 390 | var enum_size_sum_key = selectedInputs; 391 | var enum_size_isShared = [true]; 392 | var enum_direction = ['LRTB']; 393 | var enum_align = ['LB']; 394 | var enum_sort_key = selectedInputs; 395 | 396 | var layers = []; 397 | 398 | enum_aspect_ratio.forEach(function(a_aspect_ratio, i) { 399 | enum_size_type.forEach(function(a_size_type) { 400 | enum_size_isShared.forEach(function(a_size_isShared) { 401 | enum_direction.forEach(function(a_direction) { 402 | enum_align.forEach(function(a_align) { 403 | enum_sort_key.forEach(function(a_sort_key) { 404 | enum_groupby_key.forEach(function(a_groupby_key) { 405 | enum_groupby_isShared.forEach(function(a_groupby_isShared) { 406 | var aLayer = { 407 | "name": "firstlayer", 408 | "type": "gridxy", 409 | "subgroup": { 410 | "type": a_groupby_key.type, 411 | "key": (a_groupby_key.type === 'groupby') ? a_groupby_key.key : '', 412 | "isShared": a_groupby_isShared 413 | }, 414 | "aspect_ratio": a_aspect_ratio, 415 | "size": { 416 | "type": a_size_type.type, 417 | "isShared": a_size_isShared, 418 | "key": (a_size_type.type === 'sum') ? a_size_type.key : '' 419 | }, 420 | "direction": a_direction, 421 | "align": a_align, 422 | "margin": { 423 | "top": 0, 424 | "left": 0, 425 | "bottom": 0, 426 | "right": 0 427 | }, 428 | "padding": { 429 | "top": 0, 430 | "left": 0, 431 | "bottom": 0, 432 | "right": 0 433 | }, 434 | "box": { 435 | "fill": "yellow", 436 | "stroke": "red", 437 | "stroke-width": 0, 438 | "opacity": 0.1 439 | }, 440 | "sort": { 441 | "type": isCategorical(a_sort_key) ? "categorical" : "numerical", 442 | "key": a_sort_key 443 | } 444 | }; 445 | 446 | layers.push(aLayer); 447 | }); 448 | }); 449 | }); 450 | }); 451 | }); 452 | }); 453 | }); 454 | }); 455 | 456 | layers = getCombi(layers, numLayer -2); 457 | return layers; 458 | } 459 | 460 | function getCombi(layers, depth) { 461 | 462 | if (depth == 1){ 463 | return layers; 464 | } else { 465 | var newLayers = getCombi(layers, depth-1); 466 | var resultLayers = [] 467 | 468 | layers.forEach(function(aLayer) { 469 | newLayers.forEach(function(aNewLayer) { 470 | aCopyLayer = JSON.parse(JSON.stringify(aLayer)); 471 | var newArr = [aCopyLayer]; 472 | aNewCopyLayer = JSON.parse(JSON.stringify(aNewLayer)); 473 | newArr = newArr.concat(aNewCopyLayer); 474 | 475 | resultLayers.push(newArr); 476 | }); 477 | }); 478 | 479 | return resultLayers; 480 | } 481 | } 482 | 483 | function isCategorical(key) { 484 | 485 | var numericalVariables = ['age', 'fare']; 486 | 487 | if (numericalVariables.indexOf(key) == -1) { 488 | return true; 489 | } else { 490 | return false; 491 | } 492 | } 493 | 494 | function getMarkPolicies(keys) { 495 | var enum_color_key = keys; 496 | var enum_size_isShared = [true, false]; 497 | var enum_color_isShared = [true]; 498 | var enum_shape = ['circle', 'rect']; 499 | var marks = []; 500 | 501 | enum_color_key.forEach(function(a_color_key) { 502 | enum_size_isShared.forEach(function(a_size_isShared) { 503 | enum_color_isShared.forEach(function(a_color_isShared) { 504 | enum_shape.forEach(function(a_shape) { 505 | var aMark = { 506 | "shape": a_shape, 507 | "color": { 508 | "key": a_color_key, 509 | "type": (isCategorical(a_color_key)) ? "categorical" : "numerical", 510 | "isShared": a_color_isShared 511 | }, 512 | "size": { 513 | "type": "max", 514 | "isShared": a_size_isShared 515 | }, 516 | "isColorScaleShared": true 517 | }; 518 | marks.push(aMark); 519 | }); 520 | }); 521 | }); 522 | }); 523 | 524 | return marks; 525 | } 526 | 527 | }); 528 | -------------------------------------------------------------------------------- /app/scripts/controllers/example.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * @ngdoc function 5 | * @name unitApp.controller:ExampleCtrl 6 | * @description 7 | * # ExampleCtrl 8 | * Controller of the unitApp 9 | */ 10 | angular.module('unitApp') 11 | .controller('ExampleCtrl', ['unit', function (unit) { 12 | 13 | var UnitChart = unit.UnitChart; 14 | 15 | //Unit Column Chart 16 | d3.json('./data/unit_column_chart_shared.json', function(error,data){ 17 | UnitChart('unit_column_chart_shared', data); 18 | }); 19 | d3.json('./data/unit_column_chart.json', function(error,data){ 20 | UnitChart('unit_column_chart', data); 21 | }); 22 | d3.json('./data/unit_column_chart_shared_mark.json', function(error,data){ 23 | UnitChart('unit_column_chart_shared_mark', data); 24 | }); 25 | d3.json('./data/horizontal_unit_column.json', function(error,data){ 26 | UnitChart('horizontal_unit_column', data); 27 | }); 28 | 29 | 30 | //Hierarchy 31 | d3.json('./data/titanic_spec_packxy_hierarchy.json', function(error,data){ 32 | UnitChart('packxy_hierarchy', data); 33 | }); 34 | d3.json('./data/titanic_spec_packxy_isolated.json', function(error,data){ 35 | UnitChart('packxy_isolated', data); 36 | }); 37 | d3.json('./data/titanic_spec4.json', function(error,data){ 38 | UnitChart('packxy2', data); 39 | }); 40 | d3.json('./data/titanic_spec_packxy_mixed.json', function(error,data){ 41 | UnitChart('packxy_mixed', data); 42 | }); 43 | 44 | //Aspect ratio 45 | d3.json('./data/square_aspect.json', function(error,data){ 46 | UnitChart('square_aspect', data); 47 | }); 48 | d3.json('./data/maxfill_aspect.json', function(error,data){ 49 | UnitChart('maxfill_aspect', data); 50 | }); 51 | d3.json('./data/unit_small_multiple.json', function(error,data){ 52 | UnitChart('unit_small_multiple', data); 53 | }); 54 | 55 | //size 56 | d3.json('./data/size_uniform_notShared.json', function(error,data){ 57 | UnitChart('size_uniform_notshared', data); 58 | }); 59 | d3.json('./data/size_sum_notShared.json', function(error,data){ 60 | UnitChart('size_sum_notshared', data); 61 | }); 62 | d3.json('./data/size_uniform_shared.json', function(error,data){ 63 | UnitChart('size_uniform_shared', data); 64 | }); 65 | d3.json('./data/size_sum_shared.json', function(error,data){ 66 | UnitChart('size_sum_shared', data); 67 | }); 68 | 69 | //violin 70 | d3.json('./data/violin.json', function(error,data){ 71 | UnitChart('violin', data); 72 | }); 73 | 74 | //Squarified 75 | d3.json('./data/squarified.json', function(error,data){ 76 | UnitChart('squarified', data); 77 | }); 78 | 79 | //Fluctuation 80 | d3.json('./data/fluctuation.json', function(error,data){ 81 | UnitChart('fluctuation', data); 82 | }); 83 | 84 | //Mosaic 85 | d3.json('./data/mosaic.json', function(error,data){ 86 | UnitChart('mosaic', data); 87 | }); 88 | 89 | 90 | }]); 91 | -------------------------------------------------------------------------------- /app/scripts/controllers/live.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * @ngdoc function 5 | * @name unitApp.controller:LiveCtrl 6 | * @description 7 | * # LiveCtrl 8 | * Controller of the unitApp 9 | */ 10 | angular.module('unitApp') 11 | .controller('LiveCtrl', function(unit) { 12 | //editor 13 | 14 | var UnitChart = unit.UnitChart; 15 | 16 | d3.json('./data/default5.json',function(error, data) { 17 | UnitChart('editorchart', data); 18 | }) 19 | 20 | var container = document.getElementById('jsoneditor'); 21 | var options = { 22 | "mode": "code", 23 | "indentation": 2 24 | }; 25 | var editor = new JSONEditor(container, options); 26 | 27 | d3.json('./data/default5.json', function(error, json) { 28 | editor.set(json); 29 | }); 30 | 31 | var button = d3.select('#updatebutton'); 32 | 33 | button.on('click', function() { 34 | var json = editor.get(); 35 | console.log(json); 36 | d3.select('#editorchart').select('svg').remove(); 37 | UnitChart('editorchart', json); 38 | }); 39 | 40 | }); 41 | -------------------------------------------------------------------------------- /app/scripts/controllers/main.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * @ngdoc function 5 | * @name unitApp.controller:MainCtrl 6 | * @description 7 | * # MainCtrl 8 | * Controller of the unitApp 9 | */ 10 | angular.module('unitApp') 11 | .controller('MainCtrl', function () { 12 | this.awesomeThings = [ 13 | 'HTML5 Boilerplate', 14 | 'AngularJS', 15 | 'Karma' 16 | ]; 17 | }); 18 | -------------------------------------------------------------------------------- /app/scripts/services/treemap-squarify.js: -------------------------------------------------------------------------------- 1 | /* 2 | * treemap-squarify.js - open source implementation of squarified treemaps 3 | * 4 | * Treemap Squared 0.5 - Treemap Charting library 5 | * 6 | * https://github.com/imranghory/treemap-squared/ 7 | * 8 | * Copyright (c) 2012 Imran Ghory (imranghory@gmail.com) 9 | * Licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) license. 10 | * 11 | * 12 | * Implementation of the squarify treemap algorithm described in: 13 | * 14 | * Bruls, Mark; Huizing, Kees; van Wijk, Jarke J. (2000), "Squarified treemaps" 15 | * in de Leeuw, W.; van Liere, R., Data Visualization 2000: 16 | * Proc. Joint Eurographics and IEEE TCVG Symp. on Visualization, Springer-Verlag, pp. 33–42. 17 | * 18 | * Paper is available online at: http://www.win.tue.nl/~vanwijk/stm.pdf 19 | * 20 | * The code in this file is completeley decoupled from the drawing code so it should be trivial 21 | * to port it to any other vector drawing library. Given an array of datapoints this library returns 22 | * an array of cartesian coordinates that represent the rectangles that make up the treemap. 23 | * 24 | * The library also supports multidimensional data (nested treemaps) and performs normalization on the data. 25 | * 26 | * See the README file for more details. 27 | */ 28 | 29 | var Treemap = {}; 30 | 31 | (function() { 32 | "use strict"; 33 | Treemap.generate = function(){ 34 | 35 | function Container(xoffset, yoffset, width, height) { 36 | this.xoffset = xoffset; // offset from the the top left hand corner 37 | this.yoffset = yoffset; // ditto 38 | this.height = height; 39 | this.width = width; 40 | 41 | this.shortestEdge = function () { 42 | return Math.min(this.height, this.width); 43 | }; 44 | 45 | // getCoordinates - for a row of boxes which we've placed 46 | // return an array of their cartesian coordinates 47 | this.getCoordinates = function (row) { 48 | var coordinates = []; 49 | var subxoffset = this.xoffset, subyoffset = this.yoffset; //our offset within the container 50 | var areawidth = sumArray(row) / this.height; 51 | var areaheight = sumArray(row) / this.width; 52 | var i; 53 | 54 | if (this.width >= this.height) { 55 | for (i = 0; i < row.length; i++) { 56 | coordinates.push([subxoffset, subyoffset, subxoffset + areawidth, subyoffset + row[i] / areawidth]); 57 | subyoffset = subyoffset + row[i] / areawidth; 58 | } 59 | } else { 60 | for (i = 0; i < row.length; i++) { 61 | coordinates.push([subxoffset, subyoffset, subxoffset + row[i] / areaheight, subyoffset + areaheight]); 62 | subxoffset = subxoffset + row[i] / areaheight; 63 | } 64 | } 65 | return coordinates; 66 | }; 67 | 68 | // cutArea - once we've placed some boxes into an row we then need to identify the remaining area, 69 | // this function takes the area of the boxes we've placed and calculates the location and 70 | // dimensions of the remaining space and returns a container box defined by the remaining area 71 | this.cutArea = function (area) { 72 | var newcontainer; 73 | 74 | if (this.width >= this.height) { 75 | var areawidth = area / this.height; 76 | var newwidth = this.width - areawidth; 77 | newcontainer = new Container(this.xoffset + areawidth, this.yoffset, newwidth, this.height); 78 | } else { 79 | var areaheight = area / this.width; 80 | var newheight = this.height - areaheight; 81 | newcontainer = new Container(this.xoffset, this.yoffset + areaheight, this.width, newheight); 82 | } 83 | return newcontainer; 84 | }; 85 | } 86 | 87 | 88 | 89 | // normalize - the Bruls algorithm assumes we're passing in areas that nicely fit into our 90 | // container box, this method takes our raw data and normalizes the data values into 91 | // area values so that this assumption is valid. 92 | function normalize(data, area) { 93 | var normalizeddata = []; 94 | var sum = sumArray(data); 95 | var multiplier = area / sum; 96 | var i; 97 | 98 | for (i = 0; i < data.length; i++) { 99 | normalizeddata[i] = data[i] * multiplier; 100 | } 101 | return normalizeddata; 102 | } 103 | 104 | // treemapMultidimensional - takes multidimensional data (aka [[23,11],[11,32]] - nested array) 105 | // and recursively calls itself using treemapSingledimensional 106 | // to create a patchwork of treemaps and merge them 107 | function treemapMultidimensional(data, width, height, xoffset, yoffset) { 108 | xoffset = (typeof xoffset === "undefined") ? 0 : xoffset; 109 | yoffset = (typeof yoffset === "undefined") ? 0 : yoffset; 110 | 111 | var mergeddata = []; 112 | var mergedtreemap; 113 | var results = []; 114 | var i; 115 | 116 | if(isArray(data[0])) { // if we've got more dimensions of depth 117 | for(i=0; i= newratio; 202 | } 203 | 204 | // calculateRatio - calculates the maximum width to height ratio of the 205 | // boxes in this row 206 | function calculateRatio(row, length) { 207 | var min = Math.min.apply(Math, row); 208 | var max = Math.max.apply(Math, row); 209 | var sum = sumArray(row); 210 | return Math.max(Math.pow(length, 2) * max / Math.pow(sum, 2), Math.pow(sum, 2) / (Math.pow(length, 2) * min)); 211 | } 212 | 213 | // isArray - checks if arr is an array 214 | function isArray(arr) { 215 | return arr && arr.constructor === Array; 216 | } 217 | 218 | // sumArray - sums a single dimensional array 219 | function sumArray(arr) { 220 | var sum = 0; 221 | var i; 222 | 223 | for (i = 0; i < arr.length; i++) { 224 | sum += arr[i]; 225 | } 226 | return sum; 227 | } 228 | 229 | // sumMultidimensionalArray - sums the values in a nested array (aka [[0,1],[[2,3]]]) 230 | function sumMultidimensionalArray(arr) { 231 | var i, total = 0; 232 | 233 | if(isArray(arr[0])) { 234 | for(i=0; i 1) { 118 | var firstLayout = spec.layouts[0]; 119 | 120 | firstLayout.margin = { 121 | "top": 5, 122 | "left": 5, 123 | "bottom": 5, 124 | "right": 5 125 | }; 126 | 127 | firstLayout.padding = { 128 | "top": 5, 129 | "left": 5, 130 | "bottom": 5, 131 | "right": 5 132 | }; 133 | 134 | } 135 | 136 | } 137 | 138 | applyDefault(spec); 139 | 140 | d3.csv(spec.data, function (error, csv_data) { 141 | 142 | try { 143 | 144 | console.log(JSON.stringify(spec)); 145 | 146 | } catch (e) { 147 | console.log(e); 148 | } 149 | csv_data.forEach(function (d, i) { 150 | d.id = i; 151 | }); 152 | 153 | var rootContainer = buildRootContainer(csv_data, spec); 154 | var layoutList = buildLayoutList(spec.layouts); 155 | 156 | var childContainers = [rootContainer]; 157 | var currentLayout = layoutList.head; 158 | 159 | while (currentLayout !== 'EndOfLayout') { 160 | childContainers = applyLayout(childContainers, currentLayout); 161 | currentLayout = currentLayout.child; 162 | } 163 | 164 | drawUnit(rootContainer, spec, layoutList, divId); 165 | }); 166 | 167 | 168 | }; 169 | 170 | function applyLayout(containerList, layout) { 171 | 172 | var childContainers = []; 173 | var newSizeSharingAncestor; 174 | var oldSizeSharingAncestor = getSharingAncestorContainer(containerList[0], layout, 'size'); 175 | 176 | containerList.forEach(function (container, i, all) { 177 | 178 | newSizeSharingAncestor = getSharingAncestorContainer(container, layout, 'size'); 179 | if (newSizeSharingAncestor !== oldSizeSharingAncestor) { 180 | applySharedSize(layout); 181 | oldSizeSharingAncestor = newSizeSharingAncestor; 182 | } 183 | 184 | var newContainers = makeContainers(container, layout); 185 | 186 | if (newContainers.length > 0) { 187 | calcVisualSpace(container, newContainers, layout); 188 | } 189 | container.contents = newContainers; 190 | handleSharedSize(container, layout); 191 | childContainers = childContainers.concat(newContainers); 192 | 193 | }); 194 | 195 | applySharedSize(layout); 196 | 197 | return childContainers; 198 | } 199 | 200 | function handleSharedSize(container, layout) { 201 | 202 | if (layout.size.isShared) { 203 | if (!layout.hasOwnProperty('sizeSharingGroup')) { 204 | layout.sizeSharingGroup = []; 205 | } 206 | layout.sizeSharingGroup = layout.sizeSharingGroup.concat(container.contents); 207 | } 208 | } 209 | 210 | var defaultSetting = { 211 | layout: { 212 | box: { 213 | 'fill': 'blue', 214 | 'stroke': 'black', 215 | 'stroke-width': 1, 216 | 'opacity': 0.03 217 | } 218 | } 219 | } 220 | 221 | function buildRootContainer(csv_data, spec) { 222 | var myContainer = {}; 223 | myContainer.contents = csv_data; 224 | myContainer.label = 'root'; 225 | if (!spec.hasOwnProperty('padding')) { 226 | spec.padding = { 227 | 'top': 10, 228 | 'left': 30, 229 | 'bottom': 30, 230 | 'right': 10 231 | }; 232 | } 233 | 234 | myContainer.visualspace = { 235 | 'width': spec.width, 236 | 'height': spec.height, 237 | 'posX': 0, 238 | 'posY': 0, 239 | 'padding': spec.padding 240 | }; 241 | myContainer.layout = 'StartOfLayout'; 242 | myContainer.parent = 'RootContainer'; 243 | 244 | return myContainer; 245 | } 246 | 247 | function buildLayoutList(layouts, rootLayout) { 248 | 249 | var layoutList = {}; 250 | 251 | layoutList.head = layouts[0]; 252 | 253 | layouts.forEach(function (layout, i, all) { 254 | 255 | if (i > 0) { 256 | layout.parent = all[i - 1]; 257 | } else { 258 | layout.parent = 'StartOfLayout'; 259 | } 260 | if (i < all.length - 1) { 261 | layout.child = all[i + 1]; 262 | } else { 263 | layout.child = 'EndOfLayout'; 264 | } 265 | }); 266 | return layoutList; 267 | } 268 | 269 | function getKeys(data, groupby) { 270 | var myNest = d3.nest() 271 | .key(function (d) { 272 | return d[groupby] 273 | }) 274 | .entries(data); 275 | return myNest.map(function (d) { 276 | return d.key; 277 | }); 278 | } 279 | 280 | function emptyContainersFromKeys(data, groupby) { 281 | 282 | return getKeys(data, groupby) 283 | .map(function (key) { 284 | return { 285 | 'contents': [], 286 | 'label': key, 287 | 'visualspace': {} 288 | }; 289 | }); 290 | } 291 | 292 | function calcVisualSpace(parentContainer, childContainers, layout) { 293 | 294 | layout.containers = childContainers; 295 | 296 | switch (layout.type) { 297 | case 'gridxy': 298 | calcGridxyVisualSpace(parentContainer, childContainers, layout); 299 | break; 300 | default: 301 | console.log('Unsupported Layout type'); 302 | break; 303 | } 304 | } 305 | 306 | function calcGridxyVisualSpace(parentContainer, childContainers, layout) { 307 | switch (layout.aspect_ratio) { 308 | case 'fillX': 309 | case 'fillY': 310 | calcFillGridxyVisualSpace(parentContainer, childContainers, layout); 311 | break; 312 | case 'square': 313 | case 'parent': 314 | case 'custom': 315 | calcPackGridxyVisualSpace(parentContainer, childContainers, layout); 316 | break; 317 | case 'maxfill': 318 | calcPackGridxyMaxFillVisualSpace(parentContainer, childContainers, layout); 319 | } 320 | } 321 | 322 | function calcPackGridxyMaxFillVisualSpace(parentContainer, childContainers, layout) { 323 | if (layout.size.type === 'uniform') { 324 | calcPackGridxyMaxFillVisualSpaceUniform(parentContainer, childContainers, layout); 325 | } else { 326 | calcPackGridxyMaxFillVisualSpaceFunction(parentContainer, childContainers, layout); 327 | } 328 | } 329 | 330 | function calcPackGridxyMaxFillVisualSpaceFunction(parentContainer, childContainers, layout) { 331 | 332 | childContainers = childContainers.filter(function (d) { 333 | return Number(d['contents'][0][layout.size.key] > 0); 334 | }); 335 | 336 | childContainers.sort(function (c, d) { 337 | return d['contents'][0][layout.size.key] - c['contents'][0][layout.size.key]; 338 | }); 339 | 340 | var data = childContainers.map(function (d) { 341 | return Number(d['contents'][0][layout.size.key]); 342 | }); 343 | 344 | var coord = Treemap.generate(data, parentContainer.visualspace.width, parentContainer.visualspace.height); 345 | 346 | childContainers.forEach(function (c, i, all) { 347 | var rect = coord[i]; 348 | c.visualspace.width = rect[2] - rect[0]; 349 | c.visualspace.height = rect[3] - rect[1]; 350 | c.visualspace.posX = rect[0]; 351 | c.visualspace.posY = rect[1] 352 | c.visualspace.padding = layout.padding; 353 | }) 354 | 355 | } 356 | function calcPackGridxyMaxFillVisualSpaceUniform(parentContainer, childContainers, layout) { 357 | 358 | var edgeInfo = buildEdgeInfoForMaxFill(parentContainer, childContainers, layout); 359 | 360 | applyEdgeInfo(parentContainer, childContainers, layout, edgeInfo); 361 | 362 | } 363 | 364 | function buildEdgeInfoForMaxFill(parentContainer, childContainers, layout) { 365 | 366 | var combinations = getCombination(childContainers.length); 367 | 368 | var combinationForWidthAndHeight = combinations.map(function (d) { 369 | return { 370 | 'width': parentContainer.visualspace.width / d.a, 371 | 'height': parentContainer.visualspace.height / d.b, 372 | 'horizontalRepetitionCount': d.a, 373 | 'verticalRepetitionCount': d.b 374 | }; 375 | }); 376 | 377 | combinationForWidthAndHeight.forEach(function (d) { 378 | d.minEdge = (d.width > d.height) ? d.height : d.width; 379 | }) 380 | 381 | var minCombi = d3.scan(combinationForWidthAndHeight, function (a, b) { 382 | return b.minEdge - a.minEdge; 383 | }); 384 | 385 | var edgeInfo = combinationForWidthAndHeight[minCombi]; 386 | 387 | return buildEdgeInfoByDirection(edgeInfo.horizontalRepetitionCount, edgeInfo.verticalRepetitionCount, edgeInfo.width, edgeInfo.height, layout); 388 | 389 | } 390 | 391 | function getCombination(n) { 392 | var combi = d3.range(1, n + 1); 393 | 394 | combi = combi.map(function (d) { 395 | return { 396 | 'a': d, 397 | 'b': Math.ceil(n / d) 398 | }; 399 | }); 400 | 401 | return combi; 402 | } 403 | 404 | 405 | function calcFillGridxyVisualSpace(parentContainer, childContainers, layout) { 406 | 407 | var availableSpace = getAvailableSpace(parentContainer, layout); 408 | 409 | var unitLength = getUnit(availableSpace, childContainers, layout); 410 | 411 | calcFillGridxyVisualSpaceWithUnitLength(parentContainer, childContainers, layout, unitLength); 412 | 413 | } 414 | 415 | function calcFillGridxyVisualSpaceWithUnitLength(parentContainer, childContainers, layout, unitLength) { 416 | var parentVisualSpace = parentContainer.visualspace; 417 | 418 | if (layout.aspect_ratio === 'fillX') { 419 | 420 | var unitWidth = unitLength; 421 | 422 | childContainers.forEach(function (c, i, all) { 423 | c.visualspace.width = unitWidth * getValue(c, layout) - layout.margin.left - layout.margin.right; 424 | 425 | c.visualspace.height = parentVisualSpace.height - parentVisualSpace.padding.top - parentVisualSpace.padding.bottom - layout.margin.top - layout.margin.bottom; 426 | 427 | 428 | c.visualspace.posY = parentVisualSpace.padding.top + layout.margin.top; 429 | 430 | c.visualspace.padding = layout.padding; 431 | }); 432 | 433 | getPosXforFillX(parentVisualSpace, layout, childContainers); 434 | 435 | } else if (layout.aspect_ratio === 'fillY') { 436 | 437 | var unitHeight = unitLength; 438 | 439 | childContainers.forEach(function (c, i, all) { 440 | c.visualspace.height = unitHeight * getValue(c, layout) - layout.margin.top - layout.margin.bottom; 441 | 442 | c.visualspace.width = parentVisualSpace.width - parentVisualSpace.padding.left - parentVisualSpace.padding.right - layout.margin.left - layout.margin.right; 443 | 444 | c.visualspace.posX = parentVisualSpace.padding.left + layout.margin.left; 445 | 446 | c.visualspace.padding = layout.padding; 447 | }); 448 | 449 | getPosYforFillY(parentVisualSpace, layout, childContainers); 450 | 451 | } else { 452 | console.log('TODO'); 453 | } 454 | 455 | } 456 | 457 | function getPosXforFillX(parentVisualspace, layout, childContainers) { 458 | 459 | var start, direction, offset; 460 | 461 | switch (layout.direction) { 462 | case 'LRTB': 463 | case 'LRBT': 464 | case 'TBLR': 465 | case 'BTLR': 466 | case 'LR': 467 | start = 0; 468 | direction = 1; 469 | break; 470 | case 'RLBT': 471 | case 'RLTB': 472 | case 'BTRL': 473 | case 'TBRL': 474 | case 'RL': 475 | start = childContainers.length - 1; 476 | direction = -1; 477 | break; 478 | default: 479 | console.log('Unsupported Layout Direction', layout); 480 | } 481 | 482 | var totalwidth = d3.sum(childContainers, function (c) { 483 | return c.visualspace.width + layout.margin.left + layout.margin.right; 484 | }); 485 | 486 | switch (layout.align) { 487 | case 'left': 488 | case 'LT': 489 | case 'LM': 490 | case 'LB': 491 | offset = parentVisualspace.padding.left; 492 | break; 493 | case 'center': 494 | case 'CT': 495 | case 'CM': 496 | case 'CB': 497 | offset = parentVisualspace.padding.left + (parentVisualspace.width - parentVisualspace.padding.left - parentVisualspace.padding.right) / 2 - totalwidth / 2; 498 | break; 499 | case 'right': 500 | case 'RT': 501 | case 'RM': 502 | case 'RB': 503 | offset = parentVisualspace.width - parentVisualspace.padding.right - totalwidth; 504 | break; 505 | } 506 | 507 | childContainers.forEach(function (c, i, all) { 508 | var index = start + direction * i; 509 | if (i === 0) { 510 | all[index].visualspace.posX = offset + layout.margin.left; 511 | } else { 512 | all[index].visualspace.posX = all[index - direction].visualspace.posX + all[index - direction].visualspace.width + layout.margin.right + layout.margin.left; 513 | } 514 | }); 515 | 516 | } 517 | 518 | 519 | function getPosYforFillY(parentVisualspace, layout, childContainers) { 520 | 521 | var start, direction, offset; 522 | 523 | switch (layout.direction) { 524 | case 'LRTB': 525 | case 'RLTB': 526 | case 'TBLR': 527 | case 'TBRL': 528 | case 'TB': 529 | start = 0; 530 | direction = 1; 531 | break; 532 | case 'LRBT': 533 | case 'RLBT': 534 | case 'BTLR': 535 | case 'BTRL': 536 | case 'BT': 537 | start = childContainers.length - 1; 538 | direction = -1; 539 | break; 540 | default: 541 | console.log('Unsupported Layout Direction', layout); 542 | } 543 | 544 | var totalheight = d3.sum(childContainers, function (c) { 545 | return c.visualspace.height + layout.margin.top + layout.margin.bottom; 546 | }); 547 | 548 | switch (layout.align) { 549 | case 'top': 550 | case 'RT': 551 | case 'CT': 552 | case 'LT': 553 | offset = parentVisualspace.padding.top; 554 | break; 555 | case 'middle': 556 | case 'LM': 557 | case 'RM': 558 | case 'CM': 559 | offset = parentVisualspace.padding.top + (parentVisualspace.height - parentVisualspace.padding.top - parentVisualspace.padding.bottom) / 2 - totalheight / 2; 560 | break; 561 | case 'bottom': 562 | case 'LB': 563 | case 'CB': 564 | case 'RB': 565 | offset = parentVisualspace.height - parentVisualspace.padding.bottom - totalheight; 566 | break; 567 | } 568 | 569 | childContainers.forEach(function (c, i, all) { 570 | var index = start + direction * i; 571 | if (i === 0) { 572 | all[index].visualspace.posY = offset + layout.margin.top; 573 | } else { 574 | all[index].visualspace.posY = all[index - direction].visualspace.posY + all[index - direction].visualspace.height + layout.margin.bottom + layout.margin.top; 575 | } 576 | }); 577 | 578 | } 579 | 580 | 581 | function getUnit(availableSpace, childContainers, layout) { 582 | 583 | var sum = d3.sum(childContainers, function (d) { 584 | return getValue(d, layout); 585 | }); 586 | return availableSpace / sum; 587 | } 588 | 589 | function getValue(container, layout) { 590 | switch (layout.size.type) { 591 | case 'uniform': 592 | return 1; 593 | break; 594 | case 'sum': 595 | return d3.sum(container.contents, function (d) { 596 | return d[layout.size.key]; 597 | }); 598 | break; 599 | case 'count': 600 | return container.contents.length; 601 | break; 602 | } 603 | } 604 | 605 | function calcPackGridxyVisualSpace(parentContainer, childContainers, layout) { 606 | 607 | var aspect_ratio; 608 | 609 | switch (layout.aspect_ratio) { 610 | case 'square': 611 | aspect_ratio = 1; 612 | break; 613 | case 'parent': 614 | aspect_ratio = (parentContainer.visualspace.width / parentContainer.visualspace.height); 615 | break; 616 | } 617 | var edgeInfo = calcEdgeInfo(parentContainer, childContainers, layout, aspect_ratio) 618 | applyEdgeInfo(parentContainer, childContainers, layout, edgeInfo); 619 | } 620 | 621 | function calcEdgeInfo(parentContainer, childContainers, layout, aspect_ratio) { 622 | if (isVerticalDirection(layout.direction)) { 623 | var edgeInfo = getRepetitionCountForFillingEdge(parentContainer.visualspace.width, parentContainer.visualspace.height, childContainers.length, aspect_ratio); 624 | } else { 625 | var edgeInfo = getRepetitionCountForFillingEdge(parentContainer.visualspace.height, parentContainer.visualspace.width, childContainers.length, 1 / aspect_ratio); 626 | } 627 | return edgeInfo; 628 | } 629 | 630 | function calcPackGridxyVisualSpaceWithUnitLength(parentContainer, childContainers, layout, unitLength) { 631 | switch (layout.aspect_ratio) { 632 | case 'square': 633 | childContainers.forEach(function (c, i, all) { 634 | c.visualspace.width = Math.sqrt(unitLength * getValue(c, layout)); 635 | c.visualspace.height = Math.sqrt(unitLength * getValue(c, layout)); 636 | c.visualspace.posX = parentContainer.visualspace.padding.left + layout.margin.left + 0.5 * (parentContainer.visualspace.width - c.visualspace.width - parentContainer.visualspace.padding.left - parentContainer.visualspace.padding.right); 637 | c.visualspace.posY = parentContainer.visualspace.padding.top + layout.margin.top + 0.5 * (parentContainer.visualspace.height - c.visualspace.height - parentContainer.visualspace.padding.top - parentContainer.visualspace.padding.right) 638 | }); 639 | 640 | } 641 | } 642 | 643 | function applyEdgeInfo(parentContainer, childContainers, layout, edgeInfo) { 644 | if (isVerticalDirection(layout.direction)) { 645 | applyEdgeInfoVerticalDirection(parentContainer, childContainers, layout, edgeInfo); 646 | } else { 647 | applyEdgeInfoHorizontalDirection(parentContainer, childContainers, layout, edgeInfo); 648 | } 649 | } 650 | 651 | function applyEdgeInfoHorizontalDirection(parentContainer, childContainers, layout, edgeInfo) { 652 | 653 | var xOrig, yOrig, xInc, yInc, numVerticalElement, yOffset; 654 | 655 | switch (layout.direction) { 656 | case 'TBLR': 657 | xOrig = 0; 658 | yOrig = 0; 659 | xInc = edgeInfo.remainingEdgeSideUnitLength; 660 | yInc = edgeInfo.fillingEdgeSideUnitLength; 661 | numVerticalElement = edgeInfo.fillingEdgeRepetitionCount; 662 | break; 663 | case 'BTLR': 664 | xOrig = 0; 665 | yOrig = parentContainer.visualspace.height - edgeInfo.remainingEdgeSideUnitLength; 666 | xInc = edgeInfo.remainingEdgeSideUnitLength; 667 | yInc = (-1.0) * edgeInfo.fillingEdgeSideUnitLength; 668 | numVerticalElement = edgeInfo.fillingEdgeRepetitionCount; 669 | break; 670 | case 'TBRL': 671 | case 'BTRL': 672 | console.log('TODO'); 673 | break; 674 | } 675 | 676 | childContainers.forEach(function (c, i, all) { 677 | c.visualspace.width = edgeInfo.remainingEdgeSideUnitLength; 678 | c.visualspace.height = edgeInfo.fillingEdgeSideUnitLength; 679 | c.visualspace.posX = xOrig + xInc * (Math.floor(i / numVerticalElement)); 680 | c.visualspace.posY = yOrig + yInc * (i % numVerticalElement); 681 | c.visualspace.padding = layout.padding; 682 | }) 683 | } 684 | 685 | function applyEdgeInfoVerticalDirection(parentContainer, childContainers, layout, edgeInfo) { 686 | 687 | var xOrig, yOrig, xInc, yInc, numHoriElement, yOffset; 688 | 689 | switch (layout.direction) { 690 | case 'LRTB': 691 | xOrig = 0; 692 | yOrig = 0; 693 | xInc = edgeInfo.fillingEdgeSideUnitLength; 694 | yInc = edgeInfo.remainingEdgeSideUnitLength; 695 | numHoriElement = edgeInfo.fillingEdgeRepetitionCount; 696 | break; 697 | case 'LRBT': 698 | xOrig = 0; 699 | yOrig = parentContainer.visualspace.height - edgeInfo.remainingEdgeSideUnitLength; 700 | xInc = edgeInfo.fillingEdgeSideUnitLength; 701 | yInc = (-1.0) * edgeInfo.remainingEdgeSideUnitLength; 702 | numHoriElement = edgeInfo.fillingEdgeRepetitionCount; 703 | break; 704 | case 'RLBT': 705 | case 'RLTB': 706 | console.log('TODO'); 707 | break; 708 | } 709 | 710 | childContainers.forEach(function (c, i, all) { 711 | c.visualspace.width = edgeInfo.fillingEdgeSideUnitLength; 712 | c.visualspace.height = edgeInfo.remainingEdgeSideUnitLength; 713 | c.visualspace.posX = xOrig + xInc * (i % numHoriElement); 714 | c.visualspace.posY = yOrig + yInc * (Math.floor(i / numHoriElement)); 715 | c.visualspace.padding = layout.padding; 716 | }) 717 | } 718 | 719 | //Here ratio means the apect ratio of unit. 720 | //ratio = Filling Edge side divided by RemainingEdge side 721 | 722 | function getRepetitionCountForFillingEdge(fillingEdge, remainingEdge, numElement, ratio) { 723 | 724 | var fillingEdgeRepetitionCount = 0; 725 | var remainingEdgeSideUnitLength, remainingEdgeRepetitionCount, numPossibleContainers, fillingEdgeSideUnitLength; 726 | 727 | do { 728 | 729 | fillingEdgeRepetitionCount++; 730 | fillingEdgeSideUnitLength = 1.0 * fillingEdge / fillingEdgeRepetitionCount; 731 | 732 | remainingEdgeSideUnitLength = fillingEdgeSideUnitLength / ratio; 733 | 734 | remainingEdgeRepetitionCount = Math.floor(remainingEdge * fillingEdgeRepetitionCount * ratio / fillingEdge); 735 | 736 | numPossibleContainers = remainingEdgeRepetitionCount * fillingEdgeRepetitionCount; 737 | 738 | } 739 | while (numElement > numPossibleContainers); 740 | 741 | return { 742 | 'fillingEdgeRepetitionCount': fillingEdgeRepetitionCount, 743 | 'remainingEdgeRepetitionCount': remainingEdgeRepetitionCount, 744 | 'fillingEdgeSideUnitLength': fillingEdgeSideUnitLength, 745 | 'remainingEdgeSideUnitLength': remainingEdgeSideUnitLength 746 | }; 747 | 748 | } 749 | 750 | function isVerticalDirection(direction) { 751 | 752 | switch (direction) { 753 | case 'LRBT': 754 | case 'LRTB': 755 | case 'RLBT': 756 | case 'RLTB': 757 | return true; 758 | break; 759 | case 'BTLR': 760 | case 'BTRL': 761 | case 'TBLR': 762 | case 'TBLR': 763 | return false; 764 | break; 765 | } 766 | } 767 | 768 | function getMinAmongContainers(layout) { 769 | 770 | var shared_containers = layout.sizeSharingGroup; 771 | 772 | var minSizeItemIndex; 773 | 774 | switch (layout.aspect_ratio) { 775 | case 'square': 776 | case 'parent': 777 | case 'custom': 778 | minSizeItemIndex = d3.scan(shared_containers, function (a, b) { 779 | return a.visualspace.width - b.visualspace.width; 780 | }); 781 | return { 782 | 'width': shared_containers[minSizeItemIndex].visualspace.width, 783 | 'height': shared_containers[minSizeItemIndex].visualspace.height 784 | }; 785 | break; 786 | case 'maxfill': 787 | var tempMinorSide = shared_containers.map(function (d) { 788 | return (d.visualspace.width > d.visualspace.height) ? d.visualspace.height : d.visualspace.width; 789 | }); 790 | minSizeItemIndex = d3.scan(tempMinorSide, function (a, b) { 791 | return a - b; 792 | }); 793 | 794 | var minContainer = shared_containers.reduce(function (pre, cur) { 795 | 796 | var minPre, maxPre, minCur, maxCur; 797 | 798 | if (pre.visualspace.height > pre.visualspace.width) { 799 | minPre = pre.visualspace.width; 800 | maxPre = pre.visualspace.height; 801 | } else { 802 | minPre = pre.visualspace.height; 803 | maxPre = pre.visualspace.width; 804 | } 805 | 806 | if (cur.visualspace.height > cur.visualspace.width) { 807 | minCur = cur.visualspace.width; 808 | maxCur = cur.visualspace.height; 809 | } else { 810 | minCur = cur.visualspace.height; 811 | maxCur = cur.visualspace.width; 812 | } 813 | 814 | if (minCur < minPre) { 815 | return cur; 816 | } else if (minCur == minPre) { 817 | if (maxCur < maxPre) { 818 | return cur; 819 | } 820 | } 821 | return pre; 822 | }); 823 | 824 | return { 825 | 'width': minContainer.visualspace.width, 826 | 'height': minContainer.visualspace.height 827 | }; 828 | } 829 | 830 | } 831 | 832 | function applySharedSizeOnContainers(minSize, layout) { 833 | 834 | var parentContainers = getParents(layout.sizeSharingGroup); 835 | 836 | parentContainers.forEach(function (c) { 837 | 838 | var edgeInfo = buildEdgeInfoFromMinSize(c, minSize, layout); 839 | 840 | applyEdgeInfo(c, c.contents, layout, edgeInfo); 841 | }); 842 | } 843 | 844 | function getParents(containers) { 845 | var mySet = new Set(); 846 | 847 | containers.forEach(function (d) { 848 | mySet.add(d.parent); 849 | }); 850 | 851 | var myArr = []; 852 | 853 | mySet.forEach(function (d) { myArr.push(d); }); 854 | return myArr; 855 | } 856 | 857 | function buildEdgeInfoFromMinSize(parentContainer, minSize, layout) { 858 | var horizontalRepetitionCount = Math.floor(parentContainer.visualspace.width / minSize.width); 859 | var verticalRepetitionCount = Math.floor(parentContainer.visualspace.height / minSize.height); 860 | 861 | 862 | return buildEdgeInfoByDirection(horizontalRepetitionCount, verticalRepetitionCount, minSize.width, minSize.height, layout); 863 | } 864 | 865 | function buildEdgeInfoByDirection(horizontalRepetitionCount, verticalRepetitionCount, width, height, layout) { 866 | 867 | var fillingEdgeRepetitionCount, remainingEdgeRepetitionCount, fillingEdgeSideUnitLength, remainingEdgeSideUnitLength; 868 | 869 | if (isVerticalDirection(layout.direction)) { 870 | fillingEdgeRepetitionCount = horizontalRepetitionCount; 871 | remainingEdgeRepetitionCount = verticalRepetitionCount; 872 | fillingEdgeSideUnitLength = width; 873 | remainingEdgeSideUnitLength = height; 874 | } else { 875 | fillingEdgeRepetitionCount = verticalRepetitionCount; 876 | remainingEdgeRepetitionCount = horizontalRepetitionCount; 877 | fillingEdgeSideUnitLength = height; 878 | remainingEdgeSideUnitLength = width; 879 | } 880 | return { 881 | 'fillingEdgeRepetitionCount': fillingEdgeRepetitionCount, 882 | 'remainingEdgeRepetitionCount': remainingEdgeRepetitionCount, 883 | 'fillingEdgeSideUnitLength': fillingEdgeSideUnitLength, 884 | 'remainingEdgeSideUnitLength': remainingEdgeSideUnitLength 885 | }; 886 | } 887 | 888 | function applySharedSize(layout) { 889 | 890 | if (layout === 'EndOfLayout' || layout.size.isShared !== true) { 891 | return; 892 | } 893 | 894 | makeSharedSize(layout); 895 | layout.sizeSharingGroup = []; 896 | } 897 | 898 | function makeSharedSize(layout) { 899 | switch (layout.aspect_ratio) { 900 | case 'fillX': 901 | case 'fillY': 902 | makeSharedSizeFill(layout); 903 | break; 904 | case 'square': 905 | case 'parent': 906 | case 'custom': 907 | case 'maxfill': 908 | makeSharedSizePack(layout); 909 | break; 910 | } 911 | } 912 | 913 | function makeSharedSizeFill(layout) { 914 | 915 | var minUnit = getMinUnitAmongContainers(layout); 916 | 917 | applySharedUnitOnContainers(minUnit, layout); 918 | 919 | } 920 | 921 | function applySharedUnitOnContainers(minUnit, layout) { 922 | 923 | var parentContainers = getParents(layout.sizeSharingGroup); 924 | 925 | parentContainers.forEach(function (d) { 926 | switch (layout.aspect_ratio) { 927 | case 'fillX': 928 | case 'fillY': 929 | calcFillGridxyVisualSpaceWithUnitLength(d, d.contents, layout, minUnit); 930 | break; 931 | case 'square': 932 | case 'parent': 933 | case 'custom': 934 | case 'maxfill': 935 | calcPackGridxyVisualSpaceWithUnitLength(d, d.contents, layout, minUnit); 936 | } 937 | }); 938 | } 939 | 940 | function getMinUnitAmongContainers(layout) { 941 | var parentContainers = getParents(layout.sizeSharingGroup); 942 | 943 | var minUnit = d3.min(parentContainers, function (d) { 944 | var availableSpace = getAvailableSpace(d, layout); 945 | var unit = getUnit(availableSpace, d.contents, layout); 946 | return unit; 947 | }); 948 | return minUnit; 949 | } 950 | 951 | function getAvailableSpace(container, layout) { 952 | switch (layout.aspect_ratio) { 953 | case 'fillX': 954 | return container.visualspace.width - container.visualspace.padding.left - container.visualspace.padding.right; 955 | case 'fillY': 956 | return container.visualspace.height - container.visualspace.padding.top - container.visualspace.padding.bottom; 957 | case 'maxfill': 958 | case 'parent': 959 | var width = container.visualspace.width - container.visualspace.padding.left - container.visualspace.padding.right; 960 | var height = container.visualspace.height - container.visualspace.padding.top - container.visualspace.padding.bottom; 961 | return width * height; 962 | case 'square': 963 | var width = container.visualspace.width - container.visualspace.padding.left - container.visualspace.padding.right; 964 | var height = container.visualspace.height - container.visualspace.padding.top - container.visualspace.padding.bottom; 965 | return Math.pow(d3.min([width, height]), 2); 966 | } 967 | } 968 | 969 | function makeSharedSizePack(layout) { 970 | if (layout.size.type === 'uniform') { 971 | var minSize = getMinAmongContainers(layout); 972 | applySharedSizeOnContainers(minSize, layout); 973 | } else { 974 | var minUnit = getMinUnitAmongContainers(layout); 975 | applySharedUnitOnContainers(minUnit, layout); 976 | } 977 | } 978 | 979 | function makeContainers(container, layout) { 980 | 981 | var sharingAncestorContainer = getSharingAncestorContainer(container, layout, 'subgroup'); 982 | 983 | var sharingDomain = getSharingDomain(sharingAncestorContainer); 984 | var childContainers; 985 | 986 | switch (layout.subgroup.type) { 987 | case 'groupby': 988 | childContainers = makeContainersForCategoricalVar(sharingDomain, container, layout); 989 | break; 990 | case 'bin': 991 | childContainers = makeContainersForNumericalVar(sharingDomain, container, layout); 992 | break; 993 | case 'passthrough': 994 | childContainers = makeContainersForPassthrough(container, layout); 995 | break; 996 | case 'flatten': 997 | childContainers = makeContainersForFlatten(container, layout); 998 | break; 999 | } 1000 | 1001 | return childContainers; 1002 | } 1003 | 1004 | 1005 | 1006 | 1007 | function makeContainersForPassthrough(container, layout) { 1008 | return [{ 1009 | 'contents': container.contents, 1010 | 'label': container.label, 1011 | 'visualspace': {}, 1012 | 'parent': container 1013 | }]; 1014 | } 1015 | 1016 | function makeContainersForFlatten(container, layout) { 1017 | var leaves = container.contents.map(function (c, i) { 1018 | return { 1019 | 'contents': [c], 1020 | 'label': i, 1021 | 'visualspace': {}, 1022 | 'parent': container 1023 | }; 1024 | }); 1025 | 1026 | if (layout.hasOwnProperty('sort')) { 1027 | leaves.sort(function (a, b) { 1028 | var Avalue = a.contents[0][layout.sort.key]; 1029 | var Bvalue = b.contents[0][layout.sort.key]; 1030 | 1031 | if (layout.sort.type === 'numerical') { 1032 | Avalue = Number(Avalue); 1033 | Bvalue = Number(Bvalue); 1034 | } 1035 | 1036 | var ascending = (layout.sort.direction === 'ascending') ? 1 : -1 1037 | 1038 | return (Avalue > Bvalue) ? ascending : -1 * ascending; 1039 | }); 1040 | } 1041 | 1042 | return leaves; 1043 | } 1044 | 1045 | function makeContainersForCategoricalVar(sharingDomain, container, layout) { 1046 | 1047 | var newContainers = emptyContainersFromKeys(sharingDomain, layout.subgroup.key); 1048 | 1049 | newContainers.forEach(function (c, i, all) { 1050 | c.contents = container.contents.filter(function (d) { 1051 | return d[layout.subgroup.key] == c.label; 1052 | }); 1053 | c.parent = container; 1054 | }); 1055 | return newContainers; 1056 | } 1057 | 1058 | function makeContainersForNumericalVar(sharingDomain, container, layout) { 1059 | 1060 | var subgroup = layout.subgroup; 1061 | 1062 | var extent = d3.extent(sharingDomain, function (d) { 1063 | return +d[subgroup.key]; 1064 | }); 1065 | 1066 | var tempScale = d3.scaleLinear().domain([0, subgroup.numBin]).range(extent); 1067 | var tickArray = d3.range(subgroup.numBin + 1).map(tempScale); 1068 | 1069 | 1070 | 1071 | var nullGroup = container.contents.filter(function (d) { 1072 | return d[subgroup.key] == ''; 1073 | 1074 | }); 1075 | 1076 | var valueGroup = container.contents.filter(function (d) { 1077 | return d[subgroup.key] != ''; 1078 | }); 1079 | 1080 | var bins = d3.histogram() 1081 | .domain(extent) 1082 | .thresholds(tickArray) 1083 | .value(function (d) { 1084 | return +d[subgroup.key]; 1085 | })(valueGroup); 1086 | 1087 | nullGroup = [nullGroup]; 1088 | nullGroup.x0 = ''; 1089 | nullGroup.x1 = ''; 1090 | 1091 | var containers = nullGroup.concat(bins); 1092 | 1093 | containers = containers.map(function (d) { 1094 | return { 1095 | 'contents': d, 1096 | 'label': d.x0 + '-' + d.x1, 1097 | 'visualspace': {}, 1098 | 'parent': container 1099 | } 1100 | }); 1101 | 1102 | return containers; 1103 | 1104 | } 1105 | 1106 | function getSharingAncestorContainer(container, layout, item) { 1107 | 1108 | if (layout.type === 'flatten') { 1109 | return container; 1110 | } 1111 | 1112 | if (layout[item].isShared) { 1113 | if (container.parent !== 'RootContainer') { 1114 | return getSharingAncestorContainer(container.parent, layout.parent, item); 1115 | } 1116 | } 1117 | return container; 1118 | } 1119 | 1120 | function getSharingDomain(container) { 1121 | 1122 | if (isContainer(container)) { 1123 | 1124 | var leafs = []; 1125 | container.contents.forEach(function (c) { 1126 | var newLeaves = getSharingDomain(c); 1127 | 1128 | newLeaves.forEach(function (d) { 1129 | leafs.push(d); 1130 | }); 1131 | }); 1132 | return leafs; 1133 | 1134 | } else { 1135 | return [container]; 1136 | } 1137 | } 1138 | 1139 | 1140 | function isContainer(container) { 1141 | 1142 | if (container.hasOwnProperty('contents') && container.hasOwnProperty('visualspace') && container.hasOwnProperty('parent')) { 1143 | 1144 | return true; 1145 | } 1146 | return false; 1147 | } 1148 | 1149 | function drawUnit(container, spec, layoutList, divId) { 1150 | 1151 | var layouts = spec.layouts; 1152 | var markPolicy = spec.mark; 1153 | 1154 | var svg = d3.select('#' + divId).append('svg') 1155 | .attr('width', spec.width) 1156 | .attr('height', spec.height); 1157 | 1158 | var rootGroup = svg.selectAll('.root') 1159 | .data([container]) 1160 | .enter().append('g') 1161 | .attr('class', 'root') 1162 | .attr('transform', function (d) { 1163 | return 'translate(' + d.visualspace.posX + ', ' + d.visualspace.posY + ')'; 1164 | }) 1165 | 1166 | var currentGroup = rootGroup; 1167 | layouts.forEach(function (layout) { 1168 | 1169 | var tempGroup = currentGroup.selectAll('.' + layout.name) 1170 | .data(function (d) { 1171 | return d.contents; 1172 | }) 1173 | .enter().append('g') 1174 | .attr('class', layout.name) 1175 | .attr('transform', function (d) { 1176 | 1177 | if (isNaN(d.visualspace.posX) || isNaN(d.visualspace.posY)) { 1178 | console.log('NaN happened'); 1179 | console.log(spec); 1180 | } 1181 | return 'translate(' + d.visualspace.posX + ', ' + d.visualspace.posY + ')'; 1182 | }); 1183 | 1184 | tempGroup.append('rect') 1185 | .attr('x', 0) 1186 | .attr('y', 0) 1187 | .attr('width', function (d) { 1188 | return d.visualspace.width; 1189 | }) 1190 | .attr('height', function (d) { 1191 | return d.visualspace.height; 1192 | }) 1193 | .style('opacity', function (d) { 1194 | if (layout.hasOwnProperty('box') && layout.box.hasOwnProperty('opacity')) { 1195 | return layout.box.opacity; 1196 | } else { 1197 | return defaultSetting.layout.box.opacity; 1198 | } 1199 | }) 1200 | .style('fill', function (d) { 1201 | if (layout.hasOwnProperty('box') && layout.box.hasOwnProperty('fill')) { 1202 | return layout.box.fill; 1203 | } else { 1204 | return defaultSetting.layout.box.fill; 1205 | } 1206 | }) 1207 | .style('stroke', function (d) { 1208 | if (layout.hasOwnProperty('box') && layout.box.hasOwnProperty('stroke')) { 1209 | return layout.box.stroke; 1210 | } else { 1211 | return defaultSetting.layout.box.stroke; 1212 | } 1213 | }) 1214 | .style('stroke-width', function (d) { 1215 | if (layout.hasOwnProperty('box') && layout.box.hasOwnProperty('stroke-width')) { 1216 | return layout.box['stroke-width']; 1217 | } else { 1218 | return defaultSetting.layout.box['stroke-width']; 1219 | } 1220 | }); 1221 | 1222 | currentGroup = tempGroup; 1223 | 1224 | }); 1225 | 1226 | switch (markPolicy.shape) { 1227 | case "circle": 1228 | var marks = currentGroup.append('circle') 1229 | .attr('cx', function (d) { 1230 | return d.visualspace.width / 2; 1231 | }) 1232 | .attr('cy', function (d) { 1233 | return d.visualspace.height / 2; 1234 | }) 1235 | .attr('r', function (d) { 1236 | return calcRadius(d, container, markPolicy, layoutList); 1237 | }) 1238 | .style('fill', function (d) { 1239 | return 'purple' 1240 | }); 1241 | break; 1242 | 1243 | case "rect": 1244 | var marks = currentGroup.append('rect') 1245 | .attr('x', function (d) { 1246 | return 0; 1247 | }) 1248 | .attr('y', function (d) { 1249 | return 0; 1250 | }) 1251 | .attr('width', function (d) { 1252 | return d.visualspace.width; 1253 | }) 1254 | .attr('height', function (d) { 1255 | return d.visualspace.height; 1256 | }) 1257 | .style('fill', function (d) { 1258 | return 'purple' 1259 | });; 1260 | break; 1261 | default: 1262 | var marks = currentGroup.append('circle') 1263 | .attr('cx', function (d) { 1264 | return d.visualspace.width / 2; 1265 | }) 1266 | .attr('cy', function (d) { 1267 | return d.visualspace.height / 2; 1268 | }) 1269 | .attr('r', function (d) { 1270 | return calcRadius(d, container, markPolicy, layoutList); 1271 | }) 1272 | .style('fill', function (d) { 1273 | return 'purple' 1274 | }); 1275 | break; 1276 | 1277 | 1278 | } 1279 | 1280 | setMarksColor(marks, container, markPolicy, layoutList); 1281 | 1282 | } 1283 | 1284 | function setMarksColor(marks, rootContainer, markPolicy, layoutList) { 1285 | var leafContainersArr = buildLeafContainersArr(rootContainer, layoutList.head); 1286 | var color; 1287 | color = d3.scaleOrdinal(d3.schemeCategory10); 1288 | if (markPolicy.color.type === 'categorical') { 1289 | 1290 | } else { 1291 | console.log('TODO'); 1292 | } 1293 | if (markPolicy.color.key === 'survived_text') { 1294 | color("YES"); 1295 | color("NO"); 1296 | } 1297 | marks.style('fill', function (d) { 1298 | return color(d.contents[0][markPolicy.color.key]); 1299 | }); 1300 | } 1301 | 1302 | function calcRadius(leafContainer, rootContainer, markPolicy, layoutList) { 1303 | 1304 | var radius; 1305 | if (markPolicy.size.isShared) { 1306 | radius = calcRadiusShared(leafContainer, rootContainer, markPolicy, layoutList); 1307 | } else { 1308 | radius = calcRadiusIsolated(leafContainer, markPolicy); 1309 | } 1310 | return radius; 1311 | } 1312 | 1313 | function calcRadiusIsolated(leafContainer, markPolicy) { 1314 | 1315 | var width = leafContainer.visualspace.width; 1316 | var height = leafContainer.visualspace.height; 1317 | 1318 | if (markPolicy.size.type === 'max') { 1319 | return width > height ? height / 2.0 : width / 2.0; 1320 | } 1321 | } 1322 | 1323 | function calcRadiusShared(leafContainer, rootContainer, markPolicy, layoutList) { 1324 | 1325 | var radius; 1326 | var leafContainersArr = buildLeafContainersArr(rootContainer, layoutList.head); 1327 | 1328 | return d3.min(leafContainersArr, function (d) { 1329 | return calcRadiusIsolated(d, markPolicy); 1330 | }); 1331 | } 1332 | 1333 | function buildLeafContainersArr(container, layout) { 1334 | 1335 | if (layout.child !== 'EndOfLayout') { 1336 | 1337 | var leafs = []; 1338 | container.contents.forEach(function (c) { 1339 | var newLeaves = buildLeafContainersArr(c, layout.child); 1340 | 1341 | newLeaves.forEach(function (d) { 1342 | leafs.push(d); 1343 | }); 1344 | }); 1345 | return leafs; 1346 | 1347 | } else { 1348 | return container.contents; 1349 | } 1350 | } 1351 | 1352 | // Public API here 1353 | return { 1354 | UnitChart: UnitChart 1355 | }; 1356 | }); 1357 | -------------------------------------------------------------------------------- /app/styles/main.css: -------------------------------------------------------------------------------- 1 | .browsehappy { 2 | margin: 0.2em 0; 3 | background: #ccc; 4 | color: #000; 5 | padding: 0.2em 0; 6 | } 7 | 8 | body { 9 | padding: 0; 10 | } 11 | 12 | /* Everything but the jumbotron gets side spacing for mobile first views */ 13 | .header, 14 | .marketing, 15 | .footer { 16 | padding-left: 15px; 17 | padding-right: 15px; 18 | } 19 | 20 | /* Custom page header */ 21 | .header { 22 | border-bottom: 1px solid #e5e5e5; 23 | margin-bottom: 10px; 24 | } 25 | /* Make the masthead heading the same height as the navigation */ 26 | .header h3 { 27 | margin-top: 0; 28 | margin-bottom: 0; 29 | line-height: 40px; 30 | padding-bottom: 19px; 31 | } 32 | 33 | /* Custom page footer */ 34 | .footer { 35 | padding-top: 19px; 36 | color: #777; 37 | border-top: 1px solid #e5e5e5; 38 | } 39 | 40 | .container-narrow > hr { 41 | margin: 30px 0; 42 | } 43 | 44 | /* Main marketing message and sign up button */ 45 | .jumbotron { 46 | text-align: center; 47 | border-bottom: 1px solid #e5e5e5; 48 | } 49 | .jumbotron .btn { 50 | font-size: 21px; 51 | padding: 14px 24px; 52 | } 53 | 54 | /* Supporting marketing content */ 55 | .marketing { 56 | margin: 40px 0; 57 | } 58 | .marketing p + h4 { 59 | margin-top: 28px; 60 | } 61 | 62 | /* Responsive: Portrait tablets and up */ 63 | @media screen and (min-width: 768px) { 64 | .container { 65 | max-width: 730px; 66 | } 67 | 68 | /* Remove the padding we set earlier */ 69 | .header, 70 | .marketing, 71 | .footer { 72 | padding-left: 0; 73 | padding-right: 0; 74 | } 75 | /* Space out the masthead */ 76 | .header { 77 | margin-bottom: 30px; 78 | } 79 | /* Remove the bottom border on the jumbotron for visual effect */ 80 | .jumbotron { 81 | border-bottom: 0; 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /app/views/enum.html: -------------------------------------------------------------------------------- 1 |

Enumeration

Select variables you want to enumerate 2 | 3 |
4 |
5 | 8 | 9 | 10 |
11 | 12 |
13 |

14 | Numer of enumeration:

15 |
16 | -------------------------------------------------------------------------------- /app/views/example.html: -------------------------------------------------------------------------------- 1 | 2 |

Unit Column Chart

Layout1 class fillX
3 | Layout2 id packXY
4 | 5 | By setting the size.isShared for second pack layout, we can create absolute version and relative percentage version.
6 | JSON for Left 7 | JSON for Middle 8 | JSON for Right 9 | 10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | 19 |
20 | And you can create horizontal unit column chart. In this case Layout1 is fillY and Layout2 is packxy ,direction=BTLR. 21 |
22 | JSON for chart 23 | 24 |
25 | 26 |

Hierarchical Sharing

Layout1 class fillX
27 | Layout2 gender fillY
28 | Layout3 id packXY
29 | These sharing settings are hierarchical meaning that each level can have its own sharing configuration on/off and these affect to what extent the domain is shared. 30 |
31 | JSON for Top Left (Layout2: True, Layout3: True ) 32 |
33 | JSON for Top Right (Layout2: True, Layout3: False ) 34 |
35 | JSON for Bottom Left (Layout2: False, Layout3: True) 36 |
37 | JSON for Bottom Right (Layout2: False, Layout3: False) 38 |
39 | 40 | 41 |
42 |
43 |
44 |
45 |
46 |
47 | 48 |
49 |
50 |
51 |
52 |
53 |
54 | 55 |

Maxfill aspect_ratio

Layout1 age PackXY
56 | Layout2 class fillX
57 | Layout3 packXY
58 | 59 | The square aspect_ratio can lead to the empty space. To resolve this, 'maxfill' aspect ratio try to find the an optimal aspect ratio that is close to square while removing empty space. 60 |
61 | JSON for Top (Layout3: aspect_ratio:square) 62 |
63 | JSON for middle (Layout3: aspect_ratio:maxfill ) 64 |
65 | JSON for Bottom (Layout3: aspect_ratio:maxfill isShared is true for Layout2 and Layout3) 66 |
67 | 68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 | 77 |

Size by function

Layout1 class fillX
78 | Layout2 fillY
79 | 80 | "size": { "type": ""sum", "key": "fare"", "isShared": true }, 81 |
82 | 83 | Size can be function of the contents. In top left, size is uniform for layout2. In top right, size is a function of sum of fares. In both, case size is not shared 84 |
These setting can be combined with "isShared" flag. In bottom left, size is uniform and shared, and in bottom right, size is function of sum of fares and is shared. You can use the following syntax. Here the type can be sum, count, or uniform. 85 | If it is sum, it can have additional "key" parameter which will determine the variables for sum. 86 |
87 | "size": { "type": ""sum", "key": "fare", "isShared": true }, 88 |
89 | 90 | JSON for Top Left (Layout2: {"size": {"type":"uniform", "isShared":false}} ) 91 |
92 | JSON for Top Right (Layout2: {"size": {"type":"sum", "key":"fare", "isShared":false}} ) 93 |
94 | JSON for Bottom Left (Layout2: {"size": {"type":"uniform", "isShared":true}} ) 95 |
96 | JSON for Bottom Right (Layout2: {"size": {"type":"sum", "key":"fare", "isShared":true}} ) 97 |
98 | 99 | 100 |
101 |
102 |
103 |
104 |
105 |
106 | 107 |
108 |
109 |
110 |
111 |
112 |
113 | 114 |

Violin Plot

115 |


Layout1 class fillX
116 |

Layout2 fillY size uniform, isShared:true
117 |

Layout3 fillX size count, isShared:true
118 |

Layout4 maxfil size uniform, isShared:false
119 | 120 |

JSON for Unit Violin chart 121 |
122 | 123 |

124 |

Squarified Bar Chart

125 |


Layout1 class fillX
126 |

Layout2 fillX size uniform, isShared:true
127 |

Layout3 fillY size Sum of Fares, isShared:true
128 |

Layout4 maxfil size Sum of Fares, isShared:false
129 | 130 |

JSON for Squarified Bar chart 131 |
132 | 133 |

134 | 135 |

Unit Fluctuation Chart

136 |

Layout1 gender fillY
137 |

Layout2 class fillX size uniform, isShared:true
138 |

Layout3 passthrough size count, isShared:true
139 |

Layout4 maxfil size uniform, isShared:false
140 | 141 | JSON for Unit Fluctuation chart 142 |
143 |

144 | 145 |

Mosaic Plot

146 |

Layout1 class fillY, size:count
147 |

Layout2 survived fillX size:count, isShared:false
148 |

Layout3 sex fillY size count, isShared:false
149 |

Layout4 maxfill size uniform, isShared:false
150 | 151 | JSON for Mosaic plot 152 |
153 | 154 |

155 | -------------------------------------------------------------------------------- /app/views/live.html: -------------------------------------------------------------------------------- 1 |

2 | Edit json and press update button 3 |

4 | 5 |
6 | 7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | -------------------------------------------------------------------------------- /app/views/main.html: -------------------------------------------------------------------------------- 1 |
2 |

Unit Visualization Grammar

3 |

4 | I'm Yeoman
5 | Atom: Unit Visualization Grammar 6 |

7 |
8 | 9 |
10 |

Examples

11 |

Examples of Atom Grammar

12 | 13 |

Live Editor

14 |

Here you can change json specification in editor and see its effect

15 | 16 |

Enumerator

17 |

Calculate the number of enumeration given dataset

18 |
19 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "unit", 3 | "version": "0.0.0", 4 | "dependencies": { 5 | "angular": "^1.4.0", 6 | "bootstrap": "^3.2.0", 7 | "angular-animate": "^1.4.0", 8 | "angular-cookies": "^1.4.0", 9 | "angular-resource": "^1.4.0", 10 | "angular-route": "^1.4.0", 11 | "angular-sanitize": "^1.4.0", 12 | "angular-touch": "^1.4.0", 13 | "d3": "^4.2.2", 14 | "jsoneditor": "^5.5.7" 15 | }, 16 | "devDependencies": { 17 | "angular-mocks": "^1.4.0" 18 | }, 19 | "appPath": "app", 20 | "moduleName": "unitApp", 21 | "overrides": { 22 | "bootstrap": { 23 | "main": [ 24 | "less/bootstrap.less", 25 | "dist/css/bootstrap.css", 26 | "dist/js/bootstrap.js" 27 | ] 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "unit", 3 | "private": true, 4 | "devDependencies": { 5 | "autoprefixer-core": "^5.2.1", 6 | "grunt": "^0.4.5", 7 | "grunt-angular-templates": "^0.5.7", 8 | "grunt-build-control": "^0.7.1", 9 | "grunt-concurrent": "^1.0.0", 10 | "grunt-contrib-clean": "^0.6.0", 11 | "grunt-contrib-concat": "^0.5.0", 12 | "grunt-contrib-connect": "^0.9.0", 13 | "grunt-contrib-copy": "^0.7.0", 14 | "grunt-contrib-cssmin": "^0.12.0", 15 | "grunt-contrib-htmlmin": "^0.4.0", 16 | "grunt-contrib-imagemin": "^1.0.0", 17 | "grunt-contrib-jshint": "^0.11.0", 18 | "grunt-contrib-uglify": "^0.7.0", 19 | "grunt-contrib-watch": "^0.6.1", 20 | "grunt-filerev": "^2.1.2", 21 | "grunt-gh-pages": "^2.0.0", 22 | "grunt-google-cdn": "^0.4.3", 23 | "grunt-jscs": "^1.8.0", 24 | "grunt-newer": "^1.1.0", 25 | "grunt-ng-annotate": "^0.9.2", 26 | "grunt-postcss": "^0.5.5", 27 | "grunt-svgmin": "^2.0.0", 28 | "grunt-usemin": "^3.0.0", 29 | "grunt-wiredep": "^2.0.0", 30 | "jasmine-core": "^2.4.1", 31 | "jit-grunt": "^0.9.1", 32 | "jshint-stylish": "^1.0.0", 33 | "karma": "^1.2.0", 34 | "karma-jasmine": "^1.0.2", 35 | "karma-phantomjs-launcher": "^1.0.1", 36 | "phantomjs-prebuilt": "^2.1.12", 37 | "time-grunt": "^1.0.0" 38 | }, 39 | "engines": { 40 | "node": ">=0.10.0" 41 | }, 42 | "scripts": { 43 | "test": "karma start test/karma.conf.js" 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /python/.ipynb_checkpoints/data script-checkpoint.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [], 3 | "metadata": {}, 4 | "nbformat": 4, 5 | "nbformat_minor": 0 6 | } 7 | -------------------------------------------------------------------------------- /python/data script.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "Let's make arbitrary dataset. \n", 8 | "\n", 9 | "Number of Sedan is 2,000 and SUV is 1,000. \n", 10 | "Among sedans, 200 has mechanical and among SUV, 300 has mechanical issue. " 11 | ] 12 | }, 13 | { 14 | "cell_type": "code", 15 | "execution_count": 1, 16 | "metadata": { 17 | "collapsed": true 18 | }, 19 | "outputs": [], 20 | "source": [ 21 | "numSedan = 2000\n", 22 | "numSedanMechanical = 200\n", 23 | "numSUV = 1000\n", 24 | "numSUVMechanical = 300" 25 | ] 26 | }, 27 | { 28 | "cell_type": "code", 29 | "execution_count": null, 30 | "metadata": { 31 | "collapsed": true 32 | }, 33 | "outputs": [], 34 | "source": [] 35 | } 36 | ], 37 | "metadata": { 38 | "kernelspec": { 39 | "display_name": "Python 2", 40 | "language": "python", 41 | "name": "python2" 42 | }, 43 | "language_info": { 44 | "codemirror_mode": { 45 | "name": "ipython", 46 | "version": 2 47 | }, 48 | "file_extension": ".py", 49 | "mimetype": "text/x-python", 50 | "name": "python", 51 | "nbconvert_exporter": "python", 52 | "pygments_lexer": "ipython2", 53 | "version": "2.7.12" 54 | } 55 | }, 56 | "nbformat": 4, 57 | "nbformat_minor": 0 58 | } 59 | -------------------------------------------------------------------------------- /python/untitled.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intuinno/unit/186ed809d4a7bce0c1aba99da5de4d997e2d3fbe/python/untitled.txt -------------------------------------------------------------------------------- /test/.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "bitwise": true, 3 | "browser": true, 4 | "curly": true, 5 | "eqeqeq": true, 6 | "esnext": true, 7 | "jasmine": true, 8 | "latedef": true, 9 | "noarg": true, 10 | "node": true, 11 | "strict": true, 12 | "undef": true, 13 | "unused": true, 14 | "globals": { 15 | "angular": false, 16 | "inject": false 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /test/karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration 2 | // Generated on 2016-08-23 3 | 4 | module.exports = function(config) { 5 | 'use strict'; 6 | 7 | config.set({ 8 | // enable / disable watching file and executing tests whenever any file changes 9 | autoWatch: true, 10 | 11 | // base path, that will be used to resolve files and exclude 12 | basePath: '../', 13 | 14 | // testing framework to use (jasmine/mocha/qunit/...) 15 | // as well as any additional frameworks (requirejs/chai/sinon/...) 16 | frameworks: [ 17 | 'jasmine' 18 | ], 19 | 20 | // list of files / patterns to load in the browser 21 | files: [ 22 | // bower:js 23 | 'bower_components/jquery/dist/jquery.js', 24 | 'bower_components/angular/angular.js', 25 | 'bower_components/bootstrap/dist/js/bootstrap.js', 26 | 'bower_components/angular-animate/angular-animate.js', 27 | 'bower_components/angular-cookies/angular-cookies.js', 28 | 'bower_components/angular-resource/angular-resource.js', 29 | 'bower_components/angular-route/angular-route.js', 30 | 'bower_components/angular-sanitize/angular-sanitize.js', 31 | 'bower_components/angular-touch/angular-touch.js', 32 | 'bower_components/d3/d3.js', 33 | 'bower_components/jsoneditor/dist/jsoneditor.min.js', 34 | 'bower_components/angular-mocks/angular-mocks.js', 35 | // endbower 36 | 'app/scripts/**/*.js', 37 | 'test/mock/**/*.js', 38 | 'test/spec/**/*.js' 39 | ], 40 | 41 | // list of files / patterns to exclude 42 | exclude: [ 43 | ], 44 | 45 | // web server port 46 | port: 8080, 47 | 48 | // Start these browsers, currently available: 49 | // - Chrome 50 | // - ChromeCanary 51 | // - Firefox 52 | // - Opera 53 | // - Safari (only Mac) 54 | // - PhantomJS 55 | // - IE (only Windows) 56 | browsers: [ 57 | 'PhantomJS' 58 | ], 59 | 60 | // Which plugins to enable 61 | plugins: [ 62 | 'karma-phantomjs-launcher', 63 | 'karma-jasmine' 64 | ], 65 | 66 | // Continuous Integration mode 67 | // if true, it capture browsers, run tests and exit 68 | singleRun: false, 69 | 70 | colors: true, 71 | 72 | // level of logging 73 | // possible values: LOG_DISABLE || LOG_ERROR || LOG_WARN || LOG_INFO || LOG_DEBUG 74 | logLevel: config.LOG_INFO, 75 | 76 | // Uncomment the following lines if you are using grunt's server to run the tests 77 | // proxies: { 78 | // '/': 'http://localhost:9000/' 79 | // }, 80 | // URL root prevent conflicts with the site root 81 | // urlRoot: '_karma_' 82 | }); 83 | }; 84 | -------------------------------------------------------------------------------- /test/spec/controllers/about.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('Controller: AboutCtrl', function () { 4 | 5 | // load the controller's module 6 | beforeEach(module('unitApp')); 7 | 8 | var AboutCtrl, 9 | scope; 10 | 11 | // Initialize the controller and a mock scope 12 | beforeEach(inject(function ($controller, $rootScope) { 13 | scope = $rootScope.$new(); 14 | AboutCtrl = $controller('AboutCtrl', { 15 | $scope: scope 16 | // place here mocked dependencies 17 | }); 18 | })); 19 | 20 | it('should attach a list of awesomeThings to the scope', function () { 21 | expect(AboutCtrl.awesomeThings.length).toBe(3); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /test/spec/controllers/enum.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('Controller: EnumCtrl', function () { 4 | 5 | // load the controller's module 6 | beforeEach(module('unitApp')); 7 | 8 | var EnumCtrl, 9 | scope; 10 | 11 | // Initialize the controller and a mock scope 12 | beforeEach(inject(function ($controller, $rootScope) { 13 | scope = $rootScope.$new(); 14 | EnumCtrl = $controller('EnumCtrl', { 15 | $scope: scope 16 | // place here mocked dependencies 17 | }); 18 | })); 19 | 20 | it('should attach a list of awesomeThings to the scope', function () { 21 | expect(EnumCtrl.awesomeThings.length).toBe(3); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /test/spec/controllers/example.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('Controller: ExampleCtrl', function () { 4 | 5 | // load the controller's module 6 | beforeEach(module('unitApp')); 7 | 8 | var ExampleCtrl, 9 | scope; 10 | 11 | // Initialize the controller and a mock scope 12 | beforeEach(inject(function ($controller, $rootScope) { 13 | scope = $rootScope.$new(); 14 | ExampleCtrl = $controller('ExampleCtrl', { 15 | $scope: scope 16 | // place here mocked dependencies 17 | }); 18 | })); 19 | 20 | it('should attach a list of awesomeThings to the scope', function () { 21 | expect(ExampleCtrl.awesomeThings.length).toBe(3); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /test/spec/controllers/live.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('Controller: LiveCtrl', function () { 4 | 5 | // load the controller's module 6 | beforeEach(module('unitApp')); 7 | 8 | var LiveCtrl, 9 | scope; 10 | 11 | // Initialize the controller and a mock scope 12 | beforeEach(inject(function ($controller, $rootScope) { 13 | scope = $rootScope.$new(); 14 | LiveCtrl = $controller('LiveCtrl', { 15 | $scope: scope 16 | // place here mocked dependencies 17 | }); 18 | })); 19 | 20 | it('should attach a list of awesomeThings to the scope', function () { 21 | expect(LiveCtrl.awesomeThings.length).toBe(3); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /test/spec/controllers/main.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('Controller: MainCtrl', function () { 4 | 5 | // load the controller's module 6 | beforeEach(module('unitApp')); 7 | 8 | var MainCtrl, 9 | scope; 10 | 11 | // Initialize the controller and a mock scope 12 | beforeEach(inject(function ($controller, $rootScope) { 13 | scope = $rootScope.$new(); 14 | MainCtrl = $controller('MainCtrl', { 15 | $scope: scope 16 | // place here mocked dependencies 17 | }); 18 | })); 19 | 20 | it('should attach a list of awesomeThings to the scope', function () { 21 | expect(MainCtrl.awesomeThings.length).toBe(3); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /test/spec/services/unitchart.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('Service: UnitChart', function () { 4 | 5 | // load the service's module 6 | beforeEach(module('unitApp')); 7 | 8 | // instantiate service 9 | var UnitChart; 10 | beforeEach(inject(function (_UnitChart_) { 11 | UnitChart = _UnitChart_; 12 | })); 13 | 14 | it('should do something', function () { 15 | expect(!!UnitChart).toBe(true); 16 | }); 17 | 18 | }); 19 | --------------------------------------------------------------------------------