├── style.css ├── reports ├── .gitignore ├── sankey-project-outcome │ ├── project-out-come.gif │ ├── index.html │ ├── jquery.csv.min.js │ ├── sankey.js │ └── sketch.js └── sankey │ ├── index.html │ ├── jquery.csv.min.js │ ├── sankey.js │ └── sketch.js ├── src └── .gitignore ├── .gitignore ├── bower_components ├── angular │ ├── index.js │ ├── angular.min.js.gzip │ ├── bower.json │ ├── angular-csp.css │ ├── .bower.json │ ├── package.json │ ├── LICENSE.md │ └── README.md ├── angular-nvd3 │ ├── index.js │ ├── bower.json │ ├── LICENSE │ ├── .bower.json │ ├── package.json │ ├── Gruntfile.js │ ├── README.md │ └── dist │ │ └── angular-nvd3.min.js ├── nvd3 │ ├── meteor │ │ └── export.js │ ├── bower.json │ ├── package.js │ ├── .bower.json │ └── build │ │ ├── nv.d3.min.css.map │ │ ├── nv.d3.min.css │ │ └── nv.d3.css └── d3 │ ├── bower.json │ ├── .bower.json │ ├── README.md │ └── LICENSE ├── datasciheader.png ├── SentimentAnalysis.jpg ├── halin ├── images │ └── project info.png └── 1.1 Project Preprocessing.ipynb ├── index.html ├── clean.py ├── README.md ├── scatter.js ├── sfhomelesstweets.csv ├── sfHomelessData.js └── notebooks └── load_data_example.ipynb /style.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /reports/.gitignore: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/.gitignore: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .ipynb_checkpoints/ 2 | *.pyc 3 | .DS_Store 4 | *~ 5 | __pycache__ 6 | 7 | -------------------------------------------------------------------------------- /bower_components/angular/index.js: -------------------------------------------------------------------------------- 1 | require('./angular'); 2 | module.exports = angular; 3 | -------------------------------------------------------------------------------- /bower_components/angular-nvd3/index.js: -------------------------------------------------------------------------------- 1 | require('./dist/angular-nvd3'); 2 | module.exports = 'nvd3'; -------------------------------------------------------------------------------- /datasciheader.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sfbrigade/datasci-sf-homeless-project/HEAD/datasciheader.png -------------------------------------------------------------------------------- /SentimentAnalysis.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sfbrigade/datasci-sf-homeless-project/HEAD/SentimentAnalysis.jpg -------------------------------------------------------------------------------- /halin/images/project info.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sfbrigade/datasci-sf-homeless-project/HEAD/halin/images/project info.png -------------------------------------------------------------------------------- /bower_components/angular/angular.min.js.gzip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sfbrigade/datasci-sf-homeless-project/HEAD/bower_components/angular/angular.min.js.gzip -------------------------------------------------------------------------------- /reports/sankey-project-outcome/project-out-come.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sfbrigade/datasci-sf-homeless-project/HEAD/reports/sankey-project-outcome/project-out-come.gif -------------------------------------------------------------------------------- /bower_components/nvd3/meteor/export.js: -------------------------------------------------------------------------------- 1 | /*global nv:true*/ // Meteor creates a file-scope global for exporting. This comment prevents a potential JSHint warning. 2 | nv = window.nv; 3 | delete window.nv; 4 | 5 | -------------------------------------------------------------------------------- /bower_components/angular/bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular", 3 | "version": "1.5.7", 4 | "license": "MIT", 5 | "main": "./angular.js", 6 | "ignore": [], 7 | "dependencies": { 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /bower_components/d3/bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "d3", 3 | "description": "A JavaScript visualization library for HTML and SVG.", 4 | "main": "d3.js", 5 | "license": "BSD-3-Clause", 6 | "ignore": [] 7 | } 8 | -------------------------------------------------------------------------------- /bower_components/angular/angular-csp.css: -------------------------------------------------------------------------------- 1 | /* Include this file in your html if you are using the CSP mode. */ 2 | 3 | @charset "UTF-8"; 4 | 5 | [ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], 6 | .ng-cloak, .x-ng-cloak, 7 | .ng-hide:not(.ng-hide-animate) { 8 | display: none !important; 9 | } 10 | 11 | ng\:form { 12 | display: block; 13 | } 14 | 15 | .ng-animate-shim { 16 | visibility:hidden; 17 | } 18 | 19 | .ng-anchor { 20 | position:absolute; 21 | } 22 | -------------------------------------------------------------------------------- /bower_components/angular/.bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular", 3 | "version": "1.5.7", 4 | "license": "MIT", 5 | "main": "./angular.js", 6 | "ignore": [], 7 | "dependencies": {}, 8 | "homepage": "https://github.com/angular/bower-angular", 9 | "_release": "1.5.7", 10 | "_resolution": { 11 | "type": "version", 12 | "tag": "v1.5.7", 13 | "commit": "8b7bc41468112797f501b2f6502a2be5c6a1bf5f" 14 | }, 15 | "_source": "https://github.com/angular/bower-angular.git", 16 | "_target": "^1.x", 17 | "_originalSource": "angular" 18 | } -------------------------------------------------------------------------------- /bower_components/d3/.bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "d3", 3 | "description": "A JavaScript visualization library for HTML and SVG.", 4 | "main": "d3.js", 5 | "license": "BSD-3-Clause", 6 | "ignore": [], 7 | "homepage": "https://github.com/mbostock-bower/d3-bower", 8 | "version": "3.5.17", 9 | "_release": "3.5.17", 10 | "_resolution": { 11 | "type": "version", 12 | "tag": "v3.5.17", 13 | "commit": "abe0262a205c9f3755c3a757de4dfd1d49f34b24" 14 | }, 15 | "_source": "https://github.com/mbostock-bower/d3-bower.git", 16 | "_target": "^3.3.13", 17 | "_originalSource": "d3" 18 | } -------------------------------------------------------------------------------- /bower_components/angular/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular", 3 | "version": "1.5.7", 4 | "description": "HTML enhanced for web apps", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "https://github.com/angular/angular.js.git" 12 | }, 13 | "keywords": [ 14 | "angular", 15 | "framework", 16 | "browser", 17 | "client-side" 18 | ], 19 | "author": "Angular Core Team ", 20 | "license": "MIT", 21 | "bugs": { 22 | "url": "https://github.com/angular/angular.js/issues" 23 | }, 24 | "homepage": "http://angularjs.org" 25 | } 26 | -------------------------------------------------------------------------------- /bower_components/nvd3/bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nvd3", 3 | "homepage": "http://www.nvd3.org", 4 | "authors": [ 5 | "Bob Monteverde", 6 | "Tyler Wolf", 7 | "Robin Hu", 8 | "Frank Shao", 9 | "liquidpele" 10 | ], 11 | "description": "Re-usable charts and chart components for d3.", 12 | "main": [ 13 | "build/nv.d3.js", 14 | "build/nv.d3.css" 15 | ], 16 | "keywords": [ 17 | "d3", 18 | "visualization", 19 | "svg", 20 | "charts" 21 | ], 22 | "license": "Apache-2.0", 23 | "dependencies": { 24 | "d3": "^3.4.4" 25 | }, 26 | "ignore": [ 27 | "**/.*", 28 | "node_modules", 29 | "bower_components", 30 | "test", 31 | "src", 32 | "examples", 33 | "GruntFile.js", 34 | "*.html", 35 | "*.log", 36 | "*.xml", 37 | "*.json", 38 | "*.md" 39 | ] 40 | } 41 | -------------------------------------------------------------------------------- /bower_components/d3/README.md: -------------------------------------------------------------------------------- 1 | # Data-Driven Documents 2 | 3 | 4 | 5 | **D3.js** is a JavaScript library for manipulating documents based on data. **D3** helps you bring data to life using HTML, SVG, and CSS. **D3** emphasizes web standards and combines powerful visualization components with a data-driven approach to DOM manipulation, giving you the full capabilities of modern browsers without tying yourself to a proprietary framework. 6 | 7 | Want to learn more? [See the wiki.](https://github.com/mbostock/d3/wiki) 8 | 9 | For examples, [see the gallery](https://github.com/mbostock/d3/wiki/Gallery) and [mbostock’s bl.ocks](http://bl.ocks.org/mbostock). 10 | 11 | ## Good News, Everyone! 12 | 13 | The next major release of D3, 4.0, is coming! See the [4.0 development branch](https://github.com/mbostock/d3/tree/4) and read the [new API reference](https://github.com/mbostock/d3/blob/4/README.md) to get ready. 14 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Sentiment analysis of tweets about homelessness in San Francisco 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /bower_components/nvd3/package.js: -------------------------------------------------------------------------------- 1 | // Package metadata for Meteor.js full stack web framework 2 | // This file is defined in Meteor documentation at http://docs.meteor.com/#/full/packagejs 3 | // and used by Meteor https://www.meteor.com/ and its package repository Atmosphere https://atmospherejs.com 4 | 5 | Package.describe({ 6 | "name": 'nvd3:nvd3', 7 | summary: 'Nvd3.org charts.', 8 | version: '1.8.4', 9 | git: "https://github.com/novus/nvd3.git" 10 | }); 11 | Package.on_use(function (api) { 12 | api.versionsFrom("METEOR@1.0"); 13 | api.use('d3js:d3@3.5.5', 'client'); 14 | api.add_files('build/nv.d3.js', 'client'); 15 | api.add_files('build/nv.d3.css', 'client'); 16 | api.add_files('meteor/export.js', 'client'); 17 | api.export("nv"); 18 | }); 19 | Package.onTest(function(api) { 20 | api.use(['tinytest', 'test-helpers']); 21 | api.use('d3js:d3', 'client'); 22 | api.addFiles(['build/nv.d3.js', 'meteor/export.js'], "client"); 23 | api.addFiles('test/tinytest/nv-is-defined-test.js', "client"); 24 | }); 25 | -------------------------------------------------------------------------------- /bower_components/angular-nvd3/bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-nvd3", 3 | "version": "1.0.6-dev", 4 | "description": "An AngularJS directive for NVD3.js reusable charting library (based on D3.js)", 5 | "main": [ 6 | "dist/angular-nvd3.js" 7 | ], 8 | "license": "MIT", 9 | "keywords": [ 10 | "d3", 11 | "nvd3", 12 | "angular", 13 | "angular-nvd3", 14 | "directives", 15 | "visualization", 16 | "charts", 17 | "svg" 18 | ], 19 | "authors": [ 20 | "Konstantin Skipor" 21 | ], 22 | "homepage": "http://krispo.github.io/angular-nvd3", 23 | "repository": { 24 | "type": "git", 25 | "url": "https://github.com/krispo/angular-nvd3.git" 26 | }, 27 | "dependencies": { 28 | "angular": "^1.x", 29 | "d3": "^3.3.13", 30 | "nvd3": "^1.7.1" 31 | }, 32 | "ignore": [ 33 | "**/.*", 34 | "node_modules", 35 | "bower_components", 36 | "src", 37 | "test", 38 | "tests", 39 | "lib", 40 | "examples" 41 | ] 42 | } 43 | -------------------------------------------------------------------------------- /bower_components/nvd3/.bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nvd3", 3 | "homepage": "http://www.nvd3.org", 4 | "authors": [ 5 | "Bob Monteverde", 6 | "Tyler Wolf", 7 | "Robin Hu", 8 | "Frank Shao", 9 | "liquidpele" 10 | ], 11 | "description": "Re-usable charts and chart components for d3.", 12 | "main": [ 13 | "build/nv.d3.js", 14 | "build/nv.d3.css" 15 | ], 16 | "keywords": [ 17 | "d3", 18 | "visualization", 19 | "svg", 20 | "charts" 21 | ], 22 | "license": "Apache-2.0", 23 | "dependencies": { 24 | "d3": "^3.4.4" 25 | }, 26 | "ignore": [ 27 | "**/.*", 28 | "node_modules", 29 | "bower_components", 30 | "test", 31 | "src", 32 | "examples", 33 | "GruntFile.js", 34 | "*.html", 35 | "*.log", 36 | "*.xml", 37 | "*.json", 38 | "*.md" 39 | ], 40 | "version": "1.8.4", 41 | "_release": "1.8.4", 42 | "_resolution": { 43 | "type": "version", 44 | "tag": "v1.8.4", 45 | "commit": "011ac4a3b874cc674e2014999e6c931dc055caee" 46 | }, 47 | "_source": "https://github.com/novus/nvd3.git", 48 | "_target": "^1.7.1", 49 | "_originalSource": "nvd3" 50 | } -------------------------------------------------------------------------------- /bower_components/angular-nvd3/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | Copyright (c) 2014 Konstantin Skipor 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | and associated documentation files (the "Software"), to deal in the Software without restriction, 6 | including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, 8 | subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 11 | 12 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT 13 | LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 14 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 15 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE 16 | OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /bower_components/angular/LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Angular 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /bower_components/angular-nvd3/.bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-nvd3", 3 | "version": "1.0.7", 4 | "description": "An AngularJS directive for NVD3.js reusable charting library (based on D3.js)", 5 | "main": [ 6 | "dist/angular-nvd3.js" 7 | ], 8 | "license": "MIT", 9 | "keywords": [ 10 | "d3", 11 | "nvd3", 12 | "angular", 13 | "angular-nvd3", 14 | "directives", 15 | "visualization", 16 | "charts", 17 | "svg" 18 | ], 19 | "authors": [ 20 | "Konstantin Skipor" 21 | ], 22 | "homepage": "http://krispo.github.io/angular-nvd3", 23 | "repository": { 24 | "type": "git", 25 | "url": "https://github.com/krispo/angular-nvd3.git" 26 | }, 27 | "dependencies": { 28 | "angular": "^1.x", 29 | "d3": "^3.3.13", 30 | "nvd3": "^1.7.1" 31 | }, 32 | "ignore": [ 33 | "**/.*", 34 | "node_modules", 35 | "bower_components", 36 | "src", 37 | "test", 38 | "tests", 39 | "lib", 40 | "examples" 41 | ], 42 | "_release": "1.0.7", 43 | "_resolution": { 44 | "type": "version", 45 | "tag": "v1.0.7", 46 | "commit": "33b1ff72f8dd60faa446df11b9564a31ab08a640" 47 | }, 48 | "_source": "https://github.com/krispo/angular-nvd3.git", 49 | "_target": "^1.0.7", 50 | "_originalSource": "angular-nvd3", 51 | "_direct": true 52 | } -------------------------------------------------------------------------------- /bower_components/angular-nvd3/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "AngularJS-nvD3", 3 | "name": "angular-nvd3", 4 | "version": "1.0.7", 5 | "description": "An AngularJS directive for NVD3.js reusable charting library", 6 | "homepage": "http://krispo.github.io/angular-nvd3", 7 | "repository": { 8 | "type": "git", 9 | "url": "https://github.com/krispo/angular-nvd3.git" 10 | }, 11 | "main": "index.js", 12 | "keywords": [ 13 | "angular", 14 | "nvd3", 15 | "d3", 16 | "directive", 17 | "visualization", 18 | "charts", 19 | "svg" 20 | ], 21 | "bugs": { 22 | "url": "https://github.com/krispo/angular-nvd3/issues" 23 | }, 24 | "license": "MIT", 25 | "author": { 26 | "name": "Konstantin Skipor" 27 | }, 28 | "dependencies": { 29 | "angular": "^1.x", 30 | "d3": "^3.3", 31 | "nvd3": "^1.7.1" 32 | }, 33 | "devDependencies": { 34 | "angular-mocks": "^1.x", 35 | "grunt": "^0.4.4", 36 | "grunt-cli": "^0.1.13", 37 | "grunt-contrib-concat": "^0.4.0", 38 | "grunt-contrib-jshint": "^0.10.0", 39 | "grunt-contrib-uglify": "^0.4.0", 40 | "grunt-contrib-watch": "^0.6.1", 41 | "jasmine-core": "^2.4.1", 42 | "karma": "~0.12", 43 | "karma-chrome-launcher": "^0.2.2", 44 | "karma-coverage": "^0.5.5", 45 | "karma-jasmine": "^0.3.8" 46 | }, 47 | "scripts": { 48 | "test": "karma start test/karma.conf.js", 49 | "test-single-run": "karma start test/karma.conf.js --single-run" 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /bower_components/d3/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2010-2016, Michael Bostock 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | * The name Michael Bostock may not be used to endorse or promote products 15 | derived from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | DISCLAIMED. IN NO EVENT SHALL MICHAEL BOSTOCK BE LIABLE FOR ANY DIRECT, 21 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 22 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 24 | OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 25 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 26 | EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | -------------------------------------------------------------------------------- /bower_components/angular-nvd3/Gruntfile.js: -------------------------------------------------------------------------------- 1 | /* global module */ 2 | 3 | module.exports = function(grunt){ 4 | 5 | 'use strict'; 6 | 7 | grunt.initConfig({ 8 | 9 | pkg: grunt.file.readJSON('package.json'), 10 | 11 | concat: { 12 | options: { 13 | banner: 14 | '/**************************************************************************\n' + 15 | '* <%= pkg.title || pkg.name %>, ' + 16 | 'v<%= pkg.version %>; ' + 17 | '<%= pkg.license %>\n' + 18 | '<%= pkg.homepage ? "* " + pkg.homepage + "\\n" : "" %>' + 19 | '**************************************************************************/\n', 20 | stripBanners: true 21 | }, 22 | 23 | dist: { 24 | src: ['src/*.js'], 25 | dest: 'dist/<%= pkg.name %>.js' 26 | } 27 | }, 28 | 29 | uglify: { 30 | options: { 31 | mangle: false 32 | }, 33 | min: { 34 | files: { 35 | 'dist/<%= pkg.name %>.min.js': ['dist/<%= pkg.name %>.js'] 36 | } 37 | } 38 | }, 39 | 40 | jshint: { 41 | options: { 42 | jshintrc: true 43 | }, 44 | afterconcat: ['dist/<%= pkg.name %>.js'], 45 | files: ['Gruntfile.js', 'src/**/*.js', 'test/**/*.js'] 46 | }, 47 | 48 | watch: { 49 | files: ['<%= jshint.files %>'], 50 | tasks: ['jshint'] 51 | } 52 | }); 53 | 54 | grunt.loadNpmTasks('grunt-contrib-concat'); 55 | grunt.loadNpmTasks('grunt-contrib-uglify'); 56 | grunt.loadNpmTasks('grunt-contrib-jshint'); 57 | grunt.loadNpmTasks('grunt-contrib-watch'); 58 | 59 | grunt.registerTask('default', ['concat', 'jshint', 'uglify']); 60 | }; -------------------------------------------------------------------------------- /reports/sankey/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | SF Homeless Project 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 53 | 54 | 55 |
56 |
SF Homeless Project
57 |
58 | Code for America Project  Created by Qianqian Ye Folk me on Github 59 |
60 | 61 | -------------------------------------------------------------------------------- /reports/sankey-project-outcome/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | SF Homeless Project 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 53 | 54 | 55 |
56 |
SF Homeless Project
57 |
58 | Code for America Project  Created by Qianqian Ye Folk me on Github 59 |
60 | 61 | -------------------------------------------------------------------------------- /bower_components/angular/README.md: -------------------------------------------------------------------------------- 1 | # packaged angular 2 | 3 | This repo is for distribution on `npm` and `bower`. The source for this module is in the 4 | [main AngularJS repo](https://github.com/angular/angular.js). 5 | Please file issues and pull requests against that repo. 6 | 7 | ## Install 8 | 9 | You can install this package either with `npm` or with `bower`. 10 | 11 | ### npm 12 | 13 | ```shell 14 | npm install angular 15 | ``` 16 | 17 | Then add a ` 21 | ``` 22 | 23 | Or `require('angular')` from your code. 24 | 25 | ### bower 26 | 27 | ```shell 28 | bower install angular 29 | ``` 30 | 31 | Then add a ` 35 | ``` 36 | 37 | ## Documentation 38 | 39 | Documentation is available on the 40 | [AngularJS docs site](http://docs.angularjs.org/). 41 | 42 | ## License 43 | 44 | The MIT License 45 | 46 | Copyright (c) 2010-2015 Google, Inc. http://angularjs.org 47 | 48 | Permission is hereby granted, free of charge, to any person obtaining a copy 49 | of this software and associated documentation files (the "Software"), to deal 50 | in the Software without restriction, including without limitation the rights 51 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 52 | copies of the Software, and to permit persons to whom the Software is 53 | furnished to do so, subject to the following conditions: 54 | 55 | The above copyright notice and this permission notice shall be included in 56 | all copies or substantial portions of the Software. 57 | 58 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 59 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 60 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 61 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 62 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 63 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 64 | THE SOFTWARE. 65 | -------------------------------------------------------------------------------- /clean.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | df = pd.read_csv('sfhomeless.csv') 3 | 4 | from textblob import TextBlob 5 | df['polarity'] = df.apply(lambda x: TextBlob(x['Text']).sentiment.polarity, axis=1) 6 | df['subjectivity'] = df.apply(lambda x: TextBlob(x['Text']).sentiment.subjectivity, axis=1) 7 | 8 | from dateutil.parser import parse 9 | df['DateCreated'] = df.apply(lambda x: parse(x['DateCreated']), axis=1) 10 | df.sort_values(by=['DateCreated'], inplace=True) 11 | 12 | from difflib import SequenceMatcher 13 | def similar(a, b): 14 | return SequenceMatcher(None, a, b).ratio() 15 | 16 | from sets import Set 17 | cleaned_data = [] 18 | visited = Set() 19 | for i in range(df.shape[0]): 20 | if i not in visited: 21 | cleaned_data.append({ 22 | 'DateCreated': df.iloc[i].DateCreated 23 | , 'polarity': df.iloc[i].polarity 24 | , 'subjectivity': df.iloc[i].subjectivity 25 | , 'count': 0 26 | , 'text': df.iloc[i].Text.replace("'","").replace('"',"").replace('\n', ' ').replace('\r', '') 27 | }) 28 | for j in range(i + 1, df.shape[0]): 29 | if j not in visited and similar(df.iloc[i].Text, df.iloc[j].Text) > 0.8: 30 | visited.add(j) 31 | cleaned_data.append({ 32 | 'DateCreated': df.iloc[j].DateCreated 33 | , 'polarity': df.iloc[j].polarity 34 | , 'subjectivity': df.iloc[j].subjectivity 35 | , 'count': cleaned_data[-1]['count'] + 1 36 | , 'text': df.iloc[i].Text.replace("'","").replace('"',"").replace('\n', ' ').replace('\r', '') 37 | }) 38 | 39 | output_file = open('sfHomelessData.js', 'w') 40 | output_file.write('var sfHomelessData = [\n') 41 | 42 | for i in range(len(cleaned_data)): 43 | new_date = cleaned_data[i]['DateCreated'] 44 | new_line = ('\t[new Date(' + str(new_date.year) 45 | + ', ' + str(new_date.month) + ', ' + str(new_date.day) 46 | + ', ' + str(new_date.hour) 47 | + ', ' + str(new_date.minute) 48 | + ', ' + str(new_date.second) + ').getTime()' 49 | + ', ' + str(cleaned_data[i]['polarity']) 50 | + ', ' + str(cleaned_data[i]['subjectivity']) 51 | + ', ' + str(cleaned_data[i]['count']) 52 | + ', "' + str(cleaned_data[i]['text']) + '"],\n') 53 | output_file.write(new_line) 54 | 55 | output_file.write(']') 56 | output_file.close 57 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![](datasciheader.png) 2 | # CTA-NorCal Homeless Program Outcomes Analysis 3 | 4 | ## HMIS Analytics 5 | 6 | Members of the [Data Science Working Group](https://github.com/sfbrigade/data-science-wg) at Code for San Francisco have been charged with answering the [Community Technology Alliance’s](https://ctagroup.org/) prompt about homelessness programs. 7 | 8 | ## Prompt 9 | What variables best predict whether an individual is categorized as ‘in permanent housing’ as an outcome, by population segment: 10 | - Veterans 11 | - Chronically Homeless 12 | - Continuously Homeless 13 | - Has Disabling Condition 14 | - Domestic Violence Victim 15 | - Male/Female 16 | - Latino/Non-Latino 17 | 18 | ## Data 19 | Data is in [HMIS format](https://www.hudexchange.info/programs/hmis/), a data standard defined by the US Department of Housing and Urban Development 20 | 21 | ## Results 22 | View the [HMIS Data Science Study Presentation](https://docs.google.com/presentation/d/1VqjvqFESZXEjwaNqLywOfcIeyVFPAKO_So9wIdsvWgs/edit?usp=sharing) for a summary of our findings 23 | 24 | ## Featured Notebooks 25 | - [Load and clean the data](https://github.com/sfbrigade/datasci-sf-homeless-project/blob/master/notebooks/load_data_example_v2.ipynb) 26 | - [Explore the data](https://github.com/sfbrigade/datasci-sf-homeless-project/blob/master/notebooks/2016-10-19_mvm_exploration.ipynb) 27 | - [Feature engineering to prepare input variables](https://github.com/sfbrigade/datasci-sf-homeless-project/blob/master/notebooks/2016-12-05_mvm_one_hot_encode.ipynb) 28 | - [Make outcome predictions with logistic regression model](https://github.com/warmlogic/datasci-sf-homeless-project/blob/master/notebooks/2017-01-22_mvm_permanent_housing_predictions.ipynb) 29 | 30 | ## Setup 31 | 32 | Install Jupyter Notebook; this is most easily done by installing Anaconda: https://www.continuum.io/downloads 33 | 34 | Install seaborn. To do this in a new conda environment: 35 | ```conda create --name datasci seaborn``` 36 | 37 | To deactivate/activate the environment: 38 | ```source deactivate datasci``` 39 | ```source activate datasci``` 40 | 41 | ## Get Started 42 | 43 | 1. Fork this repository and clone it locally. 44 | 2. Locate the dataset (pinned in #datasci-homeless on Slack). 45 | 3. Run ```jupyter notebook``` 46 | 4. Navigate to notebooks/load_data_example_v2.ipynb to start exploring the data. 47 | 48 | Additional information on completed and open items can be found in the pinned documents in #datasci-homeless. 49 | -------------------------------------------------------------------------------- /scatter.js: -------------------------------------------------------------------------------- 1 | var app = angular.module('SFHomelessnessApp', ['nvd3']); 2 | 3 | app.controller('MainCtrl', function($scope) { 4 | $scope.options = { 5 | chart: { 6 | type: 'scatterChart', 7 | height: 450, 8 | color: ['#00e3e5', '#29d500', '#c67800', '#bf0000'], 9 | scatter: { 10 | onlyCircles: false 11 | }, 12 | showDistX: true, 13 | showDistY: true, 14 | useInteractiveGuideline: false, 15 | interactive: true, 16 | tooltips: true, 17 | tooltip: { 18 | contentGenerator: function(d) { 19 | return '

Subjectivity index: ' + d.point.subjectivity + ' ('+ d.series[0].key + ')

' + 20 | '

Times RTed: ' + d.point.size + '

' + 21 | '

Sentiment polarity: ' + d.series[0].value + '

' + 22 | '

Tweeted text: ' + d.point.text + '

'; 23 | } 24 | }, 25 | tooltipContent: function(key){ 26 | return '

holla

' + '

' + key + '

'; 27 | }, 28 | duration: 350, 29 | xAxis: { 30 | axisLabel: 'Datetime', 31 | tickFormat: function(date){ 32 | return d3.time.format('%H:%M:%S')(new Date(date)); 33 | } 34 | }, 35 | yAxis: { 36 | axisLabel: 'Sentiment Polarity', 37 | tickFormat: function(d){ 38 | return d3.format('.02f')(d); 39 | }, 40 | axisLabelDistance: -5 41 | }, 42 | zoom: { 43 | //NOTE: All attributes below are optional 44 | enabled: false, 45 | scaleExtent: [1, 10], 46 | useFixedDomain: false, 47 | useNiceScale: false, 48 | horizontalOff: false, 49 | verticalOff: false, 50 | unzoomEventType: 'dblclick.zoom' 51 | } 52 | } 53 | }; 54 | 55 | $scope.data = getData(); 56 | 57 | function getData(){ 58 | data = [0.25, 0.5, 0.75, 1.0].map(function(cutoff, idx){ 59 | return { 60 | key: ["Highly Objective", "Slightly Objective", "Slightly Subjective", "Highly Subjective"][idx], 61 | values: sfHomelessData.filter(function(d){ 62 | return (d[2] < cutoff) && (d[2] >= cutoff - 0.25) 63 | }).map(function(d){ 64 | return { 65 | x: d[0] 66 | , y: d[1] 67 | , size: d[3] 68 | , shape: 'circle' 69 | , subjectivity: d[2] 70 | , text: d[4] 71 | } 72 | }) 73 | } 74 | }) 75 | return data; 76 | } 77 | }); 78 | -------------------------------------------------------------------------------- /bower_components/nvd3/build/nv.d3.min.css.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["build/nv.d3.css"],"names":[],"mappings":"AAqBA,oBAfA,oBAgBI,KAAM,KAmXN,gBAAiB,WAhFrB,kBA+DA,uBAnWA,oBAfA,oBAmYI,gBAAiB,WAmErB,UAAW,UAJX,mBAvcA,eAsbA,uBA8BA,uCACI,eAAgB,KA+DpB,WA7QA,aAoRI,QAAS,MAST,sBAAuB,KAEvB,mBAAoB,KAtiBxB,eAEI,QAAS,EAuCb,2BA4JA,0DACI,QAAS,EAjMb,oBAEI,OAAQ,KACR,eAAgB,IAIpB,2BACI,eAAgB,IAGpB,gCACI,eAAgB,EAGpB,oBAEI,OAAQ,QAIZ,0BACI,0BACA,eAAgB,IAGpB,mCACI,YAAa,IAGjB,sCACA,uCACA,uCACI,YAAa,OAOjB,oBACI,aAAc,IAEd,WAAY,aAAa,MAAM,OAC/B,gBAAiB,aAAa,MAAM,OACpC,mBAAoB,aAAa,MAAM,OAG3C,0BACI,aAAc,EAGlB,2BACI,KAAM,QAGV,oBACI,KAAM,YAGV,2BACI,KAAM,cAKV,sCAFA,mCACA,6CAEI,eAAgB,EAEhB,WAAY,aAAa,MAAM,OAC/B,gBAAiB,aAAa,MAAM,OACpC,mBAAoB,aAAa,MAAM,OAK3C,8CACA,4CAHA,yCACA,mDAGI,aAAc,EAGlB,sCACA,6CACI,YAAa,IACb,KAAM,cACN,OAAQ,YAIZ,yBACE,aAAc,GAGhB,+BAIA,6BAHE,aAAc,EAOhB,6BACE,OAAQ,KAGV,uBACE,aAAc,MAGhB,gBAAkB,KAAM,KAAK,WAC7B,4BAA8B,aAAc,GAC5C,kCAAoC,aAAc,EAClD,2BAA6B,OAAQ,KAAM,aAAc,IACzD,mCAAqC,OAAQ,KAAM,KAAM,KAAM,aAAc,MAC7E,+BAAiC,OAAQ,KAAM,aAAc,MAC7D,8BAAgC,OAAQ,KAAM,aAAc,KAC5D,gCAAkC,KAAM,KACxC,gCAAkC,KAAM,KACxC,gCAAkC,KAAM,KACxC,0BAA4B,UAAW,KAAM,YAAa,IAC1D,6BAA+B,KAAM,KAGrC,0BACI,KAAM,QACN,aAAc,GAElB,gCACI,aAAc,GAGlB,2CACI,aAAc,IAGlB,iDACI,aAAc,IAGlB,yDACI,OAAQ,QACR,KAAM,QAGV,yDACI,OAAQ,QACR,KAAM,QAGV,wDACI,WAAY,aAAa,MAAM,OAAQ,eAAe,MAAM,OAC5D,gBAAiB,aAAa,MAAM,OAAQ,eAAe,MAAM,OACjE,mBAAoB,aAAa,MAAM,OAAQ,eAAe,MAAM,OAIxE,uCACI,OAAQ,KAIZ,eACE,OAAQ,KACR,aAAc,MAEhB,eACE,OAAQ,KACR,eAAgB,GAElB,oBACE,aAAc,EAOhB,4BACI,aAAa,EACb,aAAa,EAGjB,8BACI,aAAa,EACb,aAAa,EAGjB,qDACI,aAAa,EACb,eAAe,EAQnB,kCACI,aAAc,IAGlB,wCACI,aAAc,EAElB,8BACI,KAAM,KAGV,8BACI,OAAQ,KAGZ,oDACI,aAAc,EACd,eAAgB,EAGpB,sDACI,aAAc,aACd,eAAgB,aAIpB,6CACI,WAAY,aAAa,MAAM,OAAQ,eAAe,MAAM,OAC5D,gBAAiB,aAAa,MAAM,OAAQ,eAAe,MAAM,OACjE,mBAAoB,aAAa,MAAM,OAAQ,eAAe,MAAM,OAKxE,iCADA,4CAEI,aAAc,IACd,aAAc,cACd,eAAgB,cAIpB,2BACI,OAAQ,KACR,eAAgB,EAChB,KAAM,KACN,aAAc,EAKlB,oBACI,OAAQ,UAUZ,aAEI,oBAAqB,KAErB,gBAAiB,KACjB,iBAAkB,KAClB,YAAa,KAEb,MAAM,KACN,OAAO,KAMX,0BAA2B,2BACvB,gBAAiB,EAAE,IAAI,KAAK,eAC5B,mBAAoB,EAAE,IAAI,KAAK,eAC/B,WAAY,EAAE,IAAI,KAAK,eAEvB,sBAAuB,IACvB,mBAAoB,IACpB,cAAe,IAInB,WACI,KAAM,IAAO,KAAK,MAGtB,aACI,KAAM,IAAK,KAAK,MAGpB,qBACI,KAAM,KACN,aAAc,EAGlB,gBACI,UAAW,KACX,YAAa,IAQjB,kBACI,aAAc,KAIlB,uBACI,KAAM,KACN,OAAQ,KAQZ,4BACI,OAAQ,QAGZ,qCACI,aAAc,EAIlB,wBACI,aAAc,YAGlB,+BACI,OAAQ,KACR,aAAc,GACd,KAAM,KACN,aAAc,GAOlB,aACE,WACE,aAAc,EACd,aAAc,GAIlB,oCACI,aAAc,IAGlB,0CACI,aAAc,IAGlB,6CACI,OAAQ,QAGZ,6CACI,OAAQ,QAIZ,uBACI,KAAM,KACN,OAAQ,KACR,eAAgB,GAIpB,uBACI,KAAM,KACN,eAAgB,GAGpB,4CAEI,KAAM,KACN,aAAc,GACd,OAAQ,KACR,gBAAiB,WAGrB,qCACI,aAAc,EACjB,aAAc,IAIf,8BACE,KAAM,KACN,OAAQ,KACR,aAAc,EACd,eAAgB,EAChB,iBAAkB,EAAG,EAUvB,2BACI,UAAW,KACX,KAAM,qBAGV,4BACI,OAAQ,KACR,aAAc,EAGlB,kBAhBI,WAAY,aAAa,MAAM,OAAQ,aAAa,MAAM,OAAQ,eAAe,MAAM,OACvF,gBAAiB,aAAa,MAAM,OAAQ,aAAa,MAAM,OAAQ,eAAe,MAAM,OAC5F,mBAAoB,aAAa,MAAM,OAAQ,aAAa,MAAM,OAAQ,eAAe,MAAM,OAe/F,OAAQ,KACR,aAAc,IACd,eAAgB,EAIhB,aAAc,GAElB,yBACI,aAAc,EAKlB,4BACI,aAAc,EACd,eAAgB,EAIpB,iCACI,aAAc,KACd,eAAgB,GAGpB,kCACI,aAAc,EAWlB,wBACI,KAAM,KAOV,2CACI,OAAQ,KACR,aAAc,MAGlB,uBACA,yBACI,eAAgB,IA4LpB,+BAvIA,WAwII,eAAe,KA1LnB,oBACI,aAAc,EACd,eAAgB,EAGpB,kCACA,kCACI,aAAc,EACd,UAAW,KACX,YAAa,IAGjB,kCACI,OAAQ,KAGZ,oCACI,OAAQ,QACR,KAAM,QAGV,oCACI,OAAQ,QACR,KAAM,QAGV,wCACI,YAAa,IACb,UAAW,MAsEf,cAsCA,wBACI,YAAa,IA1GjB,kCACI,aAAc,GACd,eAAgB,EAChB,WAAY,aAAa,MAAM,OAAQ,eAAe,MAAM,OAC5D,gBAAiB,aAAa,MAAM,OAAQ,eAAe,MAAM,OACjE,mBAAoB,aAAa,MAAM,OAAQ,eAAe,MAAM,OAGxE,wCACI,aAAc,GAIlB,0CACI,eAAgB,EAChB,aAAc,EAIlB,WACI,SAAU,SAEV,MAAO,cACP,QAAS,IAET,QAAS,MAGT,YAAa,MACb,UAAW,KACX,WAAY,KAGZ,YAAa,OAGb,oBAAqB,KAErB,iBAAkB,KAClB,gBAAiB,KACjB,YAAa,KAIb,WAAY,qBACZ,OAAQ,IAAI,MAAM,eAClB,cAAe,IAqBnB,cAgBA,aACI,OAAQ,EAER,WAAY,OAlChB,4BAA6B,6BACzB,WAAY,QAAQ,KAAK,OACzB,gBAAiB,QAAQ,KAAK,OAC9B,mBAAoB,QAAQ,KAAK,OAEjC,iBAAkB,MAClB,sBAAuB,MACvB,yBAA0B,MAG9B,uBACA,uBACI,QAAS,IAGb,cAEI,QAAS,IAAI,KACb,YAAa,KAEb,iBAAkB,sBAClB,MAAO,cAGP,cAAe,IAAI,MAAM,QAEzB,sBAAuB,IAAI,IAAI,EAAE,EACjC,mBAAoB,IAAI,IAAI,EAAE,EAC9B,cAAe,IAAI,IAAI,EAAE,EAG7B,aAEI,QAAS,IAAI,KAIjB,gBACI,QAAS,aACT,OAAQ,IAAI,EAGhB,iBACI,OAAQ,IACR,eAAe,EAInB,oBACI,QAAS,IAAI,IAAI,IAAI,EACrB,eAAgB,OAMpB,8BACI,YAAa,IAEjB,0BACI,WAAY,MACZ,YAAa,IAGjB,4BACI,MAAO,QAGX,iCACI,QAAS,IAAI,IAAI,IAAI,EACrB,oBAAqB,MACrB,oBAAqB,IACrB,iBAAkB,MAClB,iBAAkB,IAGtB,2CAGI,eAAgB,OAIhB,MAAO,KACP,OAAQ,KACR,OAAQ,IAAI,MAAM,KAGtB,mBACI,QAAS,IACT,WAAY,OAGhB,2BACI,eAAgB,KAChB,QAAS,KAUb,wBACI,OAAQ"} -------------------------------------------------------------------------------- /reports/sankey/jquery.csv.min.js: -------------------------------------------------------------------------------- 1 | RegExp.escape=function(a){return a.replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&")},function(a){"use strict";var b;b="undefined"!=typeof jQuery&&jQuery?jQuery:{},b.csv={defaults:{separator:",",delimiter:'"',headers:!0},hooks:{castToScalar:function(a){var b=/\./;if(isNaN(a))return a;if(b.test(a))return parseFloat(a);var c=parseInt(a);return isNaN(c)?null:c}},parsers:{parse:function(b,c){function d(){if(j=0,k="",c.start&&c.state.rowNum=c.end&&(l=!0),c.state.rowNum++,c.state.colNum=1}function e(){if(c.onParseValue===a)i.push(k);else{var b=c.onParseValue(k,c.state);b!==!1&&i.push(b)}k="",j=0,c.state.colNum++}var f=c.separator,g=c.delimiter;c.state.rowNum||(c.state.rowNum=1),c.state.colNum||(c.state.colNum=1);var h=[],i=[],j=0,k="",l=!1,m=RegExp.escape(f),n=RegExp.escape(g),o=/(D|S|\r\n|\n|\r|[^DS\r\n]+)/,p=o.source;return p=p.replace(/S/g,m),p=p.replace(/D/g,n),o=new RegExp(p,"gm"),b.replace(o,function(a){if(!l)switch(j){case 0:if(a===f){k+="",e();break}if(a===g){j=1;break}if(/^(\r\n|\n|\r)$/.test(a)){e(),d();break}k+=a,j=3;break;case 1:if(a===g){j=2;break}k+=a,j=1;break;case 2:if(a===g){k+=a,j=1;break}if(a===f){e();break}if(/^(\r\n|\n|\r)$/.test(a)){e(),d();break}throw new Error("CSVDataError: Illegal State [Row:"+c.state.rowNum+"][Col:"+c.state.colNum+"]");case 3:if(a===f){e();break}if(/^(\r\n|\n|\r)$/.test(a)){e(),d();break}if(a===g)throw new Error("CSVDataError: Illegal Quote [Row:"+c.state.rowNum+"][Col:"+c.state.colNum+"]");throw new Error("CSVDataError: Illegal Data [Row:"+c.state.rowNum+"][Col:"+c.state.colNum+"]");default:throw new Error("CSVDataError: Unknown State [Row:"+c.state.rowNum+"][Col:"+c.state.colNum+"]")}}),0!==i.length&&(e(),d()),h},splitLines:function(b,c){function d(){if(h=0,c.start&&c.state.rowNum=c.end&&(j=!0),c.state.rowNum++}var e=c.separator,f=c.delimiter;c.state.rowNum||(c.state.rowNum=1);var g=[],h=0,i="",j=!1,k=RegExp.escape(e),l=RegExp.escape(f),m=/(D|S|\n|\r|[^DS\r\n]+)/,n=m.source;return n=n.replace(/S/g,k),n=n.replace(/D/g,l),m=new RegExp(n,"gm"),b.replace(m,function(a){if(!j)switch(h){case 0:if(a===e){i+=a,h=0;break}if(a===f){i+=a,h=1;break}if("\n"===a){d();break}if(/^\r$/.test(a))break;i+=a,h=3;break;case 1:if(a===f){i+=a,h=2;break}i+=a,h=1;break;case 2:var b=i.substr(i.length-1);if(a===f&&b===f){i+=a,h=1;break}if(a===e){i+=a,h=0;break}if("\n"===a){d();break}if("\r"===a)break;throw new Error("CSVDataError: Illegal state [Row:"+c.state.rowNum+"]");case 3:if(a===e){i+=a,h=0;break}if("\n"===a){d();break}if("\r"===a)break;if(a===f)throw new Error("CSVDataError: Illegal quote [Row:"+c.state.rowNum+"]");throw new Error("CSVDataError: Illegal state [Row:"+c.state.rowNum+"]");default:throw new Error("CSVDataError: Unknown state [Row:"+c.state.rowNum+"]")}}),""!==i&&d(),g},parseEntry:function(b,c){function d(){if(c.onParseValue===a)g.push(i);else{var b=c.onParseValue(i,c.state);b!==!1&&g.push(b)}i="",h=0,c.state.colNum++}var e=c.separator,f=c.delimiter;c.state.rowNum||(c.state.rowNum=1),c.state.colNum||(c.state.colNum=1);var g=[],h=0,i="";if(!c.match){var j=RegExp.escape(e),k=RegExp.escape(f),l=/(D|S|\n|\r|[^DS\r\n]+)/,m=l.source;m=m.replace(/S/g,j),m=m.replace(/D/g,k),c.match=new RegExp(m,"gm")}return b.replace(c.match,function(a){switch(h){case 0:if(a===e){i+="",d();break}if(a===f){h=1;break}if("\n"===a||"\r"===a)break;i+=a,h=3;break;case 1:if(a===f){h=2;break}i+=a,h=1;break;case 2:if(a===f){i+=a,h=1;break}if(a===e){d();break}if("\n"===a||"\r"===a)break;throw new Error("CSVDataError: Illegal State [Row:"+c.state.rowNum+"][Col:"+c.state.colNum+"]");case 3:if(a===e){d();break}if("\n"===a||"\r"===a)break;if(a===f)throw new Error("CSVDataError: Illegal Quote [Row:"+c.state.rowNum+"][Col:"+c.state.colNum+"]");throw new Error("CSVDataError: Illegal Data [Row:"+c.state.rowNum+"][Col:"+c.state.colNum+"]");default:throw new Error("CSVDataError: Unknown State [Row:"+c.state.rowNum+"][Col:"+c.state.colNum+"]")}}),d(),g}},helpers:{collectPropertyNames:function(a){var b,c,d=[];for(b in a)for(c in a[b])a[b].hasOwnProperty(c)&&d.indexOf(c)<0&&"function"!=typeof a[b][c]&&d.push(c);return d}},toArray:function(c,d,e){d=d!==a?d:{};var f={};f.callback=e!==a&&"function"==typeof e?e:!1,f.separator="separator"in d?d.separator:b.csv.defaults.separator,f.delimiter="delimiter"in d?d.delimiter:b.csv.defaults.delimiter;var g=d.state!==a?d.state:{};d={delimiter:f.delimiter,separator:f.separator,onParseEntry:d.onParseEntry,onParseValue:d.onParseValue,state:g};var h=b.csv.parsers.parseEntry(c,d);return f.callback?void f.callback("",h):h},toArrays:function(c,d,e){d=d!==a?d:{};var f={};f.callback=e!==a&&"function"==typeof e?e:!1,f.separator="separator"in d?d.separator:b.csv.defaults.separator,f.delimiter="delimiter"in d?d.delimiter:b.csv.defaults.delimiter;var g=[];return d={delimiter:f.delimiter,separator:f.separator,onPreParse:d.onPreParse,onParseEntry:d.onParseEntry,onParseValue:d.onParseValue,onPostParse:d.onPostParse,start:d.start,end:d.end,state:{rowNum:1,colNum:1}},d.onPreParse!==a&&d.onPreParse(c,d.state),g=b.csv.parsers.parse(c,d),d.onPostParse!==a&&d.onPostParse(g,d.state),f.callback?void f.callback("",g):g},toObjects:function(c,d,e){d=d!==a?d:{};var f={};f.callback=e!==a&&"function"==typeof e?e:!1,f.separator="separator"in d?d.separator:b.csv.defaults.separator,f.delimiter="delimiter"in d?d.delimiter:b.csv.defaults.delimiter,f.headers="headers"in d?d.headers:b.csv.defaults.headers,d.start="start"in d?d.start:1,f.headers&&d.start++,d.end&&f.headers&&d.end++;var g=[],h=[];d={delimiter:f.delimiter,separator:f.separator,onPreParse:d.onPreParse,onParseEntry:d.onParseEntry,onParseValue:d.onParseValue,onPostParse:d.onPostParse,start:d.start,end:d.end,state:{rowNum:1,colNum:1},match:!1,transform:d.transform};var i={delimiter:f.delimiter,separator:f.separator,start:1,end:1,state:{rowNum:1,colNum:1}};d.onPreParse!==a&&d.onPreParse(c,d.state);var j=b.csv.parsers.splitLines(c,i),k=b.csv.toArray(j[0],d);g=b.csv.parsers.splitLines(c,d),d.state.colNum=1,d.state.rowNum=k?2:1;for(var l=0,m=g.length;m>l;l++){for(var n=b.csv.toArray(g[l],d),o={},p=0;p-1&&(l=l.replace(f.delimiter,f.delimiter+f.delimiter));var m="\n|\r|S|D";m=m.replace("S",f.separator),m=m.replace("D",f.delimiter),l.search(m)>-1&&(l=f.delimiter+l+f.delimiter),h.push(l)}k+=h.join(f.separator)+"\r\n"}return f.callback?void f.callback("",k):k},fromObjects:function(c,d,e){d=d!==a?d:{};var f={};if(f.callback=e!==a&&"function"==typeof e?e:!1,f.separator="separator"in d?d.separator:b.csv.defaults.separator,f.delimiter="delimiter"in d?d.delimiter:b.csv.defaults.delimiter,f.headers="headers"in d?d.headers:b.csv.defaults.headers,f.sortOrder="sortOrder"in d?d.sortOrder:"declare",f.manualOrder="manualOrder"in d?d.manualOrder:[],f.transform=d.transform,"string"==typeof f.manualOrder&&(f.manualOrder=b.csv.toArray(f.manualOrder,f)),f.transform!==a){var g=c;c=[];var h;for(h=0;h0){var j,k=[].concat(f.manualOrder);for(j=0;j=c.end&&(l=!0),c.state.rowNum++,c.state.colNum=1}function e(){if(c.onParseValue===a)i.push(k);else{var b=c.onParseValue(k,c.state);b!==!1&&i.push(b)}k="",j=0,c.state.colNum++}var f=c.separator,g=c.delimiter;c.state.rowNum||(c.state.rowNum=1),c.state.colNum||(c.state.colNum=1);var h=[],i=[],j=0,k="",l=!1,m=RegExp.escape(f),n=RegExp.escape(g),o=/(D|S|\r\n|\n|\r|[^DS\r\n]+)/,p=o.source;return p=p.replace(/S/g,m),p=p.replace(/D/g,n),o=new RegExp(p,"gm"),b.replace(o,function(a){if(!l)switch(j){case 0:if(a===f){k+="",e();break}if(a===g){j=1;break}if(/^(\r\n|\n|\r)$/.test(a)){e(),d();break}k+=a,j=3;break;case 1:if(a===g){j=2;break}k+=a,j=1;break;case 2:if(a===g){k+=a,j=1;break}if(a===f){e();break}if(/^(\r\n|\n|\r)$/.test(a)){e(),d();break}throw new Error("CSVDataError: Illegal State [Row:"+c.state.rowNum+"][Col:"+c.state.colNum+"]");case 3:if(a===f){e();break}if(/^(\r\n|\n|\r)$/.test(a)){e(),d();break}if(a===g)throw new Error("CSVDataError: Illegal Quote [Row:"+c.state.rowNum+"][Col:"+c.state.colNum+"]");throw new Error("CSVDataError: Illegal Data [Row:"+c.state.rowNum+"][Col:"+c.state.colNum+"]");default:throw new Error("CSVDataError: Unknown State [Row:"+c.state.rowNum+"][Col:"+c.state.colNum+"]")}}),0!==i.length&&(e(),d()),h},splitLines:function(b,c){function d(){if(h=0,c.start&&c.state.rowNum=c.end&&(j=!0),c.state.rowNum++}var e=c.separator,f=c.delimiter;c.state.rowNum||(c.state.rowNum=1);var g=[],h=0,i="",j=!1,k=RegExp.escape(e),l=RegExp.escape(f),m=/(D|S|\n|\r|[^DS\r\n]+)/,n=m.source;return n=n.replace(/S/g,k),n=n.replace(/D/g,l),m=new RegExp(n,"gm"),b.replace(m,function(a){if(!j)switch(h){case 0:if(a===e){i+=a,h=0;break}if(a===f){i+=a,h=1;break}if("\n"===a){d();break}if(/^\r$/.test(a))break;i+=a,h=3;break;case 1:if(a===f){i+=a,h=2;break}i+=a,h=1;break;case 2:var b=i.substr(i.length-1);if(a===f&&b===f){i+=a,h=1;break}if(a===e){i+=a,h=0;break}if("\n"===a){d();break}if("\r"===a)break;throw new Error("CSVDataError: Illegal state [Row:"+c.state.rowNum+"]");case 3:if(a===e){i+=a,h=0;break}if("\n"===a){d();break}if("\r"===a)break;if(a===f)throw new Error("CSVDataError: Illegal quote [Row:"+c.state.rowNum+"]");throw new Error("CSVDataError: Illegal state [Row:"+c.state.rowNum+"]");default:throw new Error("CSVDataError: Unknown state [Row:"+c.state.rowNum+"]")}}),""!==i&&d(),g},parseEntry:function(b,c){function d(){if(c.onParseValue===a)g.push(i);else{var b=c.onParseValue(i,c.state);b!==!1&&g.push(b)}i="",h=0,c.state.colNum++}var e=c.separator,f=c.delimiter;c.state.rowNum||(c.state.rowNum=1),c.state.colNum||(c.state.colNum=1);var g=[],h=0,i="";if(!c.match){var j=RegExp.escape(e),k=RegExp.escape(f),l=/(D|S|\n|\r|[^DS\r\n]+)/,m=l.source;m=m.replace(/S/g,j),m=m.replace(/D/g,k),c.match=new RegExp(m,"gm")}return b.replace(c.match,function(a){switch(h){case 0:if(a===e){i+="",d();break}if(a===f){h=1;break}if("\n"===a||"\r"===a)break;i+=a,h=3;break;case 1:if(a===f){h=2;break}i+=a,h=1;break;case 2:if(a===f){i+=a,h=1;break}if(a===e){d();break}if("\n"===a||"\r"===a)break;throw new Error("CSVDataError: Illegal State [Row:"+c.state.rowNum+"][Col:"+c.state.colNum+"]");case 3:if(a===e){d();break}if("\n"===a||"\r"===a)break;if(a===f)throw new Error("CSVDataError: Illegal Quote [Row:"+c.state.rowNum+"][Col:"+c.state.colNum+"]");throw new Error("CSVDataError: Illegal Data [Row:"+c.state.rowNum+"][Col:"+c.state.colNum+"]");default:throw new Error("CSVDataError: Unknown State [Row:"+c.state.rowNum+"][Col:"+c.state.colNum+"]")}}),d(),g}},helpers:{collectPropertyNames:function(a){var b,c,d=[];for(b in a)for(c in a[b])a[b].hasOwnProperty(c)&&d.indexOf(c)<0&&"function"!=typeof a[b][c]&&d.push(c);return d}},toArray:function(c,d,e){d=d!==a?d:{};var f={};f.callback=e!==a&&"function"==typeof e?e:!1,f.separator="separator"in d?d.separator:b.csv.defaults.separator,f.delimiter="delimiter"in d?d.delimiter:b.csv.defaults.delimiter;var g=d.state!==a?d.state:{};d={delimiter:f.delimiter,separator:f.separator,onParseEntry:d.onParseEntry,onParseValue:d.onParseValue,state:g};var h=b.csv.parsers.parseEntry(c,d);return f.callback?void f.callback("",h):h},toArrays:function(c,d,e){d=d!==a?d:{};var f={};f.callback=e!==a&&"function"==typeof e?e:!1,f.separator="separator"in d?d.separator:b.csv.defaults.separator,f.delimiter="delimiter"in d?d.delimiter:b.csv.defaults.delimiter;var g=[];return d={delimiter:f.delimiter,separator:f.separator,onPreParse:d.onPreParse,onParseEntry:d.onParseEntry,onParseValue:d.onParseValue,onPostParse:d.onPostParse,start:d.start,end:d.end,state:{rowNum:1,colNum:1}},d.onPreParse!==a&&d.onPreParse(c,d.state),g=b.csv.parsers.parse(c,d),d.onPostParse!==a&&d.onPostParse(g,d.state),f.callback?void f.callback("",g):g},toObjects:function(c,d,e){d=d!==a?d:{};var f={};f.callback=e!==a&&"function"==typeof e?e:!1,f.separator="separator"in d?d.separator:b.csv.defaults.separator,f.delimiter="delimiter"in d?d.delimiter:b.csv.defaults.delimiter,f.headers="headers"in d?d.headers:b.csv.defaults.headers,d.start="start"in d?d.start:1,f.headers&&d.start++,d.end&&f.headers&&d.end++;var g=[],h=[];d={delimiter:f.delimiter,separator:f.separator,onPreParse:d.onPreParse,onParseEntry:d.onParseEntry,onParseValue:d.onParseValue,onPostParse:d.onPostParse,start:d.start,end:d.end,state:{rowNum:1,colNum:1},match:!1,transform:d.transform};var i={delimiter:f.delimiter,separator:f.separator,start:1,end:1,state:{rowNum:1,colNum:1}};d.onPreParse!==a&&d.onPreParse(c,d.state);var j=b.csv.parsers.splitLines(c,i),k=b.csv.toArray(j[0],d);g=b.csv.parsers.splitLines(c,d),d.state.colNum=1,d.state.rowNum=k?2:1;for(var l=0,m=g.length;m>l;l++){for(var n=b.csv.toArray(g[l],d),o={},p=0;p-1&&(l=l.replace(f.delimiter,f.delimiter+f.delimiter));var m="\n|\r|S|D";m=m.replace("S",f.separator),m=m.replace("D",f.delimiter),l.search(m)>-1&&(l=f.delimiter+l+f.delimiter),h.push(l)}k+=h.join(f.separator)+"\r\n"}return f.callback?void f.callback("",k):k},fromObjects:function(c,d,e){d=d!==a?d:{};var f={};if(f.callback=e!==a&&"function"==typeof e?e:!1,f.separator="separator"in d?d.separator:b.csv.defaults.separator,f.delimiter="delimiter"in d?d.delimiter:b.csv.defaults.delimiter,f.headers="headers"in d?d.headers:b.csv.defaults.headers,f.sortOrder="sortOrder"in d?d.sortOrder:"declare",f.manualOrder="manualOrder"in d?d.manualOrder:[],f.transform=d.transform,"string"==typeof f.manualOrder&&(f.manualOrder=b.csv.toArray(f.manualOrder,f)),f.transform!==a){var g=c;c=[];var h;for(h=0;h0){var j,k=[].concat(f.manualOrder);for(j=0;j` section of your main html: 31 | ```html 32 | 33 | 34 | 35 | 36 | 37 | 38 | ``` 39 | 40 | ##### npm 41 | 42 | $ npm install angular-nvd3 43 | 44 | ##### download 45 | 46 | If you don't use bower or npm, you can manually download and unpack directive with the latest version ([zip](https://github.com/krispo/angular-nvd3/archive/v1.0.7.zip), [tar.gz](https://github.com/krispo/angular-nvd3/archive/v1.0.7.tar.gz)). 47 | 48 | ### Basic usage 49 | 50 | Inject `nvd3` directive into angular module, set up some chart options and push some data to the controller: 51 | ```javascript 52 | angular.module('myApp', ['nvd3']) 53 | .controller('myCtrl', function('$scope'){ 54 | $scope.options = { /* JSON data */ }; 55 | $scope.data = { /* JSON data */ } 56 | }) 57 | ``` 58 | 59 | and in html again you can use it like: 60 | ```html 61 |
62 |
63 | 64 |
65 |
66 | ``` 67 | 68 | The chart would be displayed on the page. 69 | 70 | ### Example 71 | 72 | Let's create a simple **Discrete Bar Chart**. 73 | 74 | Configure options: 75 | ```javascript 76 | $scope.options = { 77 | chart: { 78 | type: 'discreteBarChart', 79 | height: 450, 80 | margin : { 81 | top: 20, 82 | right: 20, 83 | bottom: 60, 84 | left: 55 85 | }, 86 | x: function(d){ return d.label; }, 87 | y: function(d){ return d.value; }, 88 | showValues: true, 89 | valueFormat: function(d){ 90 | return d3.format(',.4f')(d); 91 | }, 92 | transitionDuration: 500, 93 | xAxis: { 94 | axisLabel: 'X Axis' 95 | }, 96 | yAxis: { 97 | axisLabel: 'Y Axis', 98 | axisLabelDistance: 30 99 | } 100 | } 101 | }; 102 | ``` 103 | 104 | Push some data: 105 | ```javascript 106 | $scope.data = [{ 107 | key: "Cumulative Return", 108 | values: [ 109 | { "label" : "A" , "value" : -29.765957771107 }, 110 | { "label" : "B" , "value" : 0 }, 111 | { "label" : "C" , "value" : 32.807804682612 }, 112 | { "label" : "D" , "value" : 196.45946739256 }, 113 | { "label" : "E" , "value" : 0.19434030906893 }, 114 | { "label" : "F" , "value" : -98.079782601442 }, 115 | { "label" : "G" , "value" : -13.925743130903 }, 116 | { "label" : "H" , "value" : -5.1387322875705 } 117 | ] 118 | }]; 119 | ``` 120 | 121 | See the [result](http://krispo.github.io/angular-nvd3/#/discreteBarChart). 122 | 123 | Read more [docs](http://krispo.github.io/angular-nvd3/#/quickstart). 124 | 125 | ### Contribute 126 | 127 | Test it using command: 128 | 129 | $npm test 130 | 131 | Then build using [grunt](http://gruntjs.com/) (*node.js must be installed*): 132 | 133 | $grunt 134 | 135 | ## Release Notes 136 | 137 | ### [1.0.7](https://github.com/krispo/angular-nvd3/releases/tag/v1.0.7) 138 | * added `debounceImmediate` flag 139 | * added compatibility with nvd3 1.8.3 140 | 141 | ### 1.0.6 142 | * merged with nvd3 1.8.2 143 | * fixed travis 144 | * fixed npm package dependencies 145 | * fixed tests 146 | * added `zoomend` event 147 | 148 | ### 1.0.5 (nvd3 v1.8.1) 149 | * fixed `index.js` 150 | * fixed `onReady` attribute 151 | * added `getElement` api method 152 | 153 | ### 1.0.4 154 | * `deepWatchData = true` by default 155 | * deleted `autorefresh`, `deepWatchConfig` configs 156 | * added `deepWatchDataDepth = 2` config to specify watch depth level for data: 0 - by reference (cheap), 1 - by collection item (the middle), 2 - by value (expensive) 157 | * added `onReady` attribute 158 | * added `updateWithTimeout`, `refreshWithTimeout` methods to `api` 159 | * fixed bugs 160 | 161 | ### 1.0.3 162 | * Fixed width and height issues for IE: [#16](https://github.com/krispo/angular-nvd3/issues/16), [#158](https://github.com/krispo/angular-nvd3/issues/158), [#200](https://github.com/krispo/angular-nvd3/issues/200), [#226](https://github.com/krispo/angular-nvd3/issues/226). 163 | * Fixed tooltip issue [#172](https://github.com/krispo/angular-nvd3/issues/172) 164 | * Set `refreshDataOnly = true` by default 165 | * Added `zoom & pan` functionality 166 | * Fixed tooltip content, subtitle and many other issues... 167 | 168 | ### 1.0.2 169 | * Fixed `tooltip` [#222](https://github.com/krispo/angular-nvd3/pull/222) for interactive guideline. 170 | * Set `deepWatchData` to `false` by default 171 | * Added `deepWatchOptions` and `deepWatchConfig` properties 172 | 173 | ### 1.0.1 174 | * Add support for `Candlestick Chart`, `OHLC Chart`, `Sunburst Chart`, `Pox Plot Chart` 175 | 176 | ### 1.0.0-rc.2 177 | * Add support of nvd3 1.8.1 178 | * Fix [issue](https://github.com/krispo/angular-nvd3/issues/100) with `stacked` parameter 179 | 180 | ### 1.0.0-rc 181 | * Rename `utils` module to avoid conflicts 182 | * Fix nvd3 version reference in bower.json 183 | * Remove usage of reserved word `class` 184 | * Fix multiple resize event listeners which were causing null pointer exceptions 185 | * Change bower.json's main property to use regular instead of minified file 186 | 187 | ### 1.0.0-beta (nvd3 v1.7.1) 188 | Under developing in **master** (1.x) branch 189 | 190 | -- 191 | 192 | > If you use the old nvd3 version (v1.1.15-beta), I recommend you to use an updated assembly (`nv.d3.js` and `nv.d3.css`, you can find it in the `lib` directory of this project) with some fixes rather than the last one installed via bower. 193 | 194 | ### [0.1.1 (stable for nvd3 v1.1.15-beta)](https://github.com/krispo/angular-nvd3/releases/tag/v0.1.1) 195 | Under developing in **0.x** branch 196 | 197 | ### 0.1.0 198 | * added update method to global api, [pull request](https://github.com/krispo/angular-nvd3/pull/27) 199 | * fixed bug for `multiChart` 200 | * added getScope method to global api. (give an access to internal directive scope, for example, we can get chart object like: `$scope.api.getScope().chart`) 201 | * fixed multiple chart rendering under initializing (fixed multiple callback calls) 202 | 203 | ### 0.0.9 204 | ... 205 | 206 | ## License 207 | Licensed under the terms of the [MIT License](https://github.com/krispo/angular-nvd3/blob/master/LICENSE) 208 | -------------------------------------------------------------------------------- /reports/sankey/sankey.js: -------------------------------------------------------------------------------- 1 | d3.sankey = function() { 2 | var sankey = {}, 3 | nodeWidth = 24, 4 | nodePadding = 8, 5 | size = [1, 1], 6 | nodes = [], 7 | links = []; 8 | 9 | sankey.nodeWidth = function(_) { 10 | if (!arguments.length) return nodeWidth; 11 | nodeWidth = +_; 12 | return sankey; 13 | }; 14 | 15 | sankey.nodePadding = function(_) { 16 | if (!arguments.length) return nodePadding; 17 | nodePadding = +_; 18 | return sankey; 19 | }; 20 | 21 | sankey.nodes = function(_) { 22 | if (!arguments.length) return nodes; 23 | nodes = _; 24 | return sankey; 25 | }; 26 | 27 | sankey.links = function(_) { 28 | if (!arguments.length) return links; 29 | links = _; 30 | return sankey; 31 | }; 32 | 33 | sankey.size = function(_) { 34 | if (!arguments.length) return size; 35 | size = _; 36 | return sankey; 37 | }; 38 | 39 | sankey.layout = function(iterations) { 40 | computeNodeLinks(); 41 | computeNodeValues(); 42 | computeNodeBreadths(); 43 | computeNodeDepths(iterations); 44 | computeLinkDepths(); 45 | return sankey; 46 | }; 47 | 48 | sankey.relayout = function() { 49 | computeLinkDepths(); 50 | return sankey; 51 | }; 52 | 53 | sankey.link = function() { 54 | var curvature = .5; 55 | 56 | function link(d) { 57 | var x0 = d.source.x + d.source.dx, 58 | x1 = d.target.x, 59 | xi = d3.interpolateNumber(x0, x1), 60 | x2 = xi(curvature), 61 | x3 = xi(1 - curvature), 62 | y0 = d.source.y + d.sy + d.dy / 2, 63 | y1 = d.target.y + d.ty + d.dy / 2; 64 | return "M" + x0 + "," + y0 65 | + "C" + x2 + "," + y0 66 | + " " + x3 + "," + y1 67 | + " " + x1 + "," + y1; 68 | } 69 | 70 | link.curvature = function(_) { 71 | if (!arguments.length) return curvature; 72 | curvature = +_; 73 | return link; 74 | }; 75 | 76 | return link; 77 | }; 78 | 79 | // Populate the sourceLinks and targetLinks for each node. 80 | // Also, if the source and target are not objects, assume they are indices. 81 | function computeNodeLinks() { 82 | nodes.forEach(function(node) { 83 | node.sourceLinks = []; 84 | node.targetLinks = []; 85 | }); 86 | links.forEach(function(link) { 87 | var source = link.source, 88 | target = link.target; 89 | if (typeof source === "number") source = link.source = nodes[link.source]; 90 | if (typeof target === "number") target = link.target = nodes[link.target]; 91 | source.sourceLinks.push(link); 92 | target.targetLinks.push(link); 93 | }); 94 | } 95 | 96 | // Compute the value (size) of each node by summing the associated links. 97 | function computeNodeValues() { 98 | nodes.forEach(function(node) { 99 | node.value = Math.max( 100 | d3.sum(node.sourceLinks, value), 101 | d3.sum(node.targetLinks, value) 102 | ); 103 | }); 104 | } 105 | 106 | // Iteratively assign the breadth (x-position) for each node. 107 | // Nodes are assigned the maximum breadth of incoming neighbors plus one; 108 | // nodes with no incoming links are assigned breadth zero, while 109 | // nodes with no outgoing links are assigned the maximum breadth. 110 | function computeNodeBreadths() { 111 | var remainingNodes = nodes, 112 | nextNodes, 113 | x = 0; 114 | 115 | while (remainingNodes.length) { 116 | nextNodes = []; 117 | remainingNodes.forEach(function(node) { 118 | node.x = x; 119 | node.dx = nodeWidth; 120 | node.sourceLinks.forEach(function(link) { 121 | if (nextNodes.indexOf(link.target) < 0) { 122 | nextNodes.push(link.target); 123 | } 124 | }); 125 | }); 126 | remainingNodes = nextNodes; 127 | ++x; 128 | } 129 | 130 | // 131 | moveSinksRight(x); 132 | scaleNodeBreadths((size[0] - nodeWidth) / (x - 1)); 133 | } 134 | 135 | function moveSourcesRight() { 136 | nodes.forEach(function(node) { 137 | if (!node.targetLinks.length) { 138 | node.x = d3.min(node.sourceLinks, function(d) { return d.target.x; }) - 1; 139 | } 140 | }); 141 | } 142 | 143 | function moveSinksRight(x) { 144 | nodes.forEach(function(node) { 145 | if (!node.sourceLinks.length) { 146 | node.x = x - 1; 147 | } 148 | }); 149 | } 150 | 151 | function scaleNodeBreadths(kx) { 152 | nodes.forEach(function(node) { 153 | node.x *= kx; 154 | }); 155 | } 156 | 157 | function computeNodeDepths(iterations) { 158 | var nodesByBreadth = d3.nest() 159 | .key(function(d) { return d.x; }) 160 | .sortKeys(d3.ascending) 161 | .entries(nodes) 162 | .map(function(d) { return d.values; }); 163 | 164 | // 165 | initializeNodeDepth(); 166 | resolveCollisions(); 167 | for (var alpha = 1; iterations > 0; --iterations) { 168 | relaxRightToLeft(alpha *= .99); 169 | resolveCollisions(); 170 | relaxLeftToRight(alpha); 171 | resolveCollisions(); 172 | } 173 | 174 | function initializeNodeDepth() { 175 | var ky = d3.min(nodesByBreadth, function(nodes) { 176 | return (size[1] - (nodes.length - 1) * nodePadding) / d3.sum(nodes, value); 177 | }); 178 | 179 | nodesByBreadth.forEach(function(nodes) { 180 | nodes.forEach(function(node, i) { 181 | node.y = i; 182 | node.dy = node.value * ky; 183 | }); 184 | }); 185 | 186 | links.forEach(function(link) { 187 | link.dy = link.value * ky; 188 | }); 189 | } 190 | 191 | function relaxLeftToRight(alpha) { 192 | nodesByBreadth.forEach(function(nodes, breadth) { 193 | nodes.forEach(function(node) { 194 | if (node.targetLinks.length) { 195 | var y = d3.sum(node.targetLinks, weightedSource) / d3.sum(node.targetLinks, value); 196 | node.y += (y - center(node)) * alpha; 197 | } 198 | }); 199 | }); 200 | 201 | function weightedSource(link) { 202 | return center(link.source) * link.value; 203 | } 204 | } 205 | 206 | function relaxRightToLeft(alpha) { 207 | nodesByBreadth.slice().reverse().forEach(function(nodes) { 208 | nodes.forEach(function(node) { 209 | if (node.sourceLinks.length) { 210 | var y = d3.sum(node.sourceLinks, weightedTarget) / d3.sum(node.sourceLinks, value); 211 | node.y += (y - center(node)) * alpha; 212 | } 213 | }); 214 | }); 215 | 216 | function weightedTarget(link) { 217 | return center(link.target) * link.value; 218 | } 219 | } 220 | 221 | function resolveCollisions() { 222 | nodesByBreadth.forEach(function(nodes) { 223 | var node, 224 | dy, 225 | y0 = 0, 226 | n = nodes.length, 227 | i; 228 | 229 | // Push any overlapping nodes down. 230 | nodes.sort(ascendingDepth); 231 | for (i = 0; i < n; ++i) { 232 | node = nodes[i]; 233 | dy = y0 - node.y; 234 | if (dy > 0) node.y += dy; 235 | y0 = node.y + node.dy + nodePadding; 236 | } 237 | 238 | // If the bottommost node goes outside the bounds, push it back up. 239 | dy = y0 - nodePadding - size[1]; 240 | if (dy > 0) { 241 | y0 = node.y -= dy; 242 | 243 | // Push any overlapping nodes back up. 244 | for (i = n - 2; i >= 0; --i) { 245 | node = nodes[i]; 246 | dy = node.y + node.dy + nodePadding - y0; 247 | if (dy > 0) node.y -= dy; 248 | y0 = node.y; 249 | } 250 | } 251 | }); 252 | } 253 | 254 | function ascendingDepth(a, b) { 255 | return a.y - b.y; 256 | } 257 | } 258 | 259 | function computeLinkDepths() { 260 | nodes.forEach(function(node) { 261 | node.sourceLinks.sort(ascendingTargetDepth); 262 | node.targetLinks.sort(ascendingSourceDepth); 263 | }); 264 | nodes.forEach(function(node) { 265 | var sy = 0, ty = 0; 266 | node.sourceLinks.forEach(function(link) { 267 | link.sy = sy; 268 | sy += link.dy; 269 | }); 270 | node.targetLinks.forEach(function(link) { 271 | link.ty = ty; 272 | ty += link.dy; 273 | }); 274 | }); 275 | 276 | function ascendingSourceDepth(a, b) { 277 | return a.source.y - b.source.y; 278 | } 279 | 280 | function ascendingTargetDepth(a, b) { 281 | return a.target.y - b.target.y; 282 | } 283 | } 284 | 285 | function center(node) { 286 | return node.y + node.dy / 2; 287 | } 288 | 289 | function value(link) { 290 | return link.value; 291 | } 292 | 293 | return sankey; 294 | }; 295 | -------------------------------------------------------------------------------- /reports/sankey-project-outcome/sankey.js: -------------------------------------------------------------------------------- 1 | d3.sankey = function() { 2 | var sankey = {}, 3 | nodeWidth = 24, 4 | nodePadding = 8, 5 | size = [1, 1], 6 | nodes = [], 7 | links = []; 8 | 9 | sankey.nodeWidth = function(_) { 10 | if (!arguments.length) return nodeWidth; 11 | nodeWidth = +_; 12 | return sankey; 13 | }; 14 | 15 | sankey.nodePadding = function(_) { 16 | if (!arguments.length) return nodePadding; 17 | nodePadding = +_; 18 | return sankey; 19 | }; 20 | 21 | sankey.nodes = function(_) { 22 | if (!arguments.length) return nodes; 23 | nodes = _; 24 | return sankey; 25 | }; 26 | 27 | sankey.links = function(_) { 28 | if (!arguments.length) return links; 29 | links = _; 30 | return sankey; 31 | }; 32 | 33 | sankey.size = function(_) { 34 | if (!arguments.length) return size; 35 | size = _; 36 | return sankey; 37 | }; 38 | 39 | sankey.layout = function(iterations) { 40 | computeNodeLinks(); 41 | computeNodeValues(); 42 | computeNodeBreadths(); 43 | computeNodeDepths(iterations); 44 | computeLinkDepths(); 45 | return sankey; 46 | }; 47 | 48 | sankey.relayout = function() { 49 | computeLinkDepths(); 50 | return sankey; 51 | }; 52 | 53 | sankey.link = function() { 54 | var curvature = .5; 55 | 56 | function link(d) { 57 | var x0 = d.source.x + d.source.dx, 58 | x1 = d.target.x, 59 | xi = d3.interpolateNumber(x0, x1), 60 | x2 = xi(curvature), 61 | x3 = xi(1 - curvature), 62 | y0 = d.source.y + d.sy + d.dy / 2, 63 | y1 = d.target.y + d.ty + d.dy / 2; 64 | return "M" + x0 + "," + y0 65 | + "C" + x2 + "," + y0 66 | + " " + x3 + "," + y1 67 | + " " + x1 + "," + y1; 68 | } 69 | 70 | link.curvature = function(_) { 71 | if (!arguments.length) return curvature; 72 | curvature = +_; 73 | return link; 74 | }; 75 | 76 | return link; 77 | }; 78 | 79 | // Populate the sourceLinks and targetLinks for each node. 80 | // Also, if the source and target are not objects, assume they are indices. 81 | function computeNodeLinks() { 82 | nodes.forEach(function(node) { 83 | node.sourceLinks = []; 84 | node.targetLinks = []; 85 | }); 86 | links.forEach(function(link) { 87 | var source = link.source, 88 | target = link.target; 89 | if (typeof source === "number") source = link.source = nodes[link.source]; 90 | if (typeof target === "number") target = link.target = nodes[link.target]; 91 | source.sourceLinks.push(link); 92 | target.targetLinks.push(link); 93 | }); 94 | } 95 | 96 | // Compute the value (size) of each node by summing the associated links. 97 | function computeNodeValues() { 98 | nodes.forEach(function(node) { 99 | node.value = Math.max( 100 | d3.sum(node.sourceLinks, value), 101 | d3.sum(node.targetLinks, value) 102 | ); 103 | }); 104 | } 105 | 106 | // Iteratively assign the breadth (x-position) for each node. 107 | // Nodes are assigned the maximum breadth of incoming neighbors plus one; 108 | // nodes with no incoming links are assigned breadth zero, while 109 | // nodes with no outgoing links are assigned the maximum breadth. 110 | function computeNodeBreadths() { 111 | var remainingNodes = nodes, 112 | nextNodes, 113 | x = 0; 114 | 115 | while (remainingNodes.length) { 116 | nextNodes = []; 117 | remainingNodes.forEach(function(node) { 118 | node.x = x; 119 | node.dx = nodeWidth; 120 | node.sourceLinks.forEach(function(link) { 121 | if (nextNodes.indexOf(link.target) < 0) { 122 | nextNodes.push(link.target); 123 | } 124 | }); 125 | }); 126 | remainingNodes = nextNodes; 127 | ++x; 128 | } 129 | 130 | // 131 | moveSinksRight(x); 132 | scaleNodeBreadths((size[0] - nodeWidth) / (x - 1)); 133 | } 134 | 135 | function moveSourcesRight() { 136 | nodes.forEach(function(node) { 137 | if (!node.targetLinks.length) { 138 | node.x = d3.min(node.sourceLinks, function(d) { return d.target.x; }) - 1; 139 | } 140 | }); 141 | } 142 | 143 | function moveSinksRight(x) { 144 | nodes.forEach(function(node) { 145 | if (!node.sourceLinks.length) { 146 | node.x = x - 1; 147 | } 148 | }); 149 | } 150 | 151 | function scaleNodeBreadths(kx) { 152 | nodes.forEach(function(node) { 153 | node.x *= kx; 154 | }); 155 | } 156 | 157 | function computeNodeDepths(iterations) { 158 | var nodesByBreadth = d3.nest() 159 | .key(function(d) { return d.x; }) 160 | .sortKeys(d3.ascending) 161 | .entries(nodes) 162 | .map(function(d) { return d.values; }); 163 | 164 | // 165 | initializeNodeDepth(); 166 | resolveCollisions(); 167 | for (var alpha = 1; iterations > 0; --iterations) { 168 | relaxRightToLeft(alpha *= .99); 169 | resolveCollisions(); 170 | relaxLeftToRight(alpha); 171 | resolveCollisions(); 172 | } 173 | 174 | function initializeNodeDepth() { 175 | var ky = d3.min(nodesByBreadth, function(nodes) { 176 | return (size[1] - (nodes.length - 1) * nodePadding) / d3.sum(nodes, value); 177 | }); 178 | 179 | nodesByBreadth.forEach(function(nodes) { 180 | nodes.forEach(function(node, i) { 181 | node.y = i; 182 | node.dy = node.value * ky; 183 | }); 184 | }); 185 | 186 | links.forEach(function(link) { 187 | link.dy = link.value * ky; 188 | }); 189 | } 190 | 191 | function relaxLeftToRight(alpha) { 192 | nodesByBreadth.forEach(function(nodes, breadth) { 193 | nodes.forEach(function(node) { 194 | if (node.targetLinks.length) { 195 | var y = d3.sum(node.targetLinks, weightedSource) / d3.sum(node.targetLinks, value); 196 | node.y += (y - center(node)) * alpha; 197 | } 198 | }); 199 | }); 200 | 201 | function weightedSource(link) { 202 | return center(link.source) * link.value; 203 | } 204 | } 205 | 206 | function relaxRightToLeft(alpha) { 207 | nodesByBreadth.slice().reverse().forEach(function(nodes) { 208 | nodes.forEach(function(node) { 209 | if (node.sourceLinks.length) { 210 | var y = d3.sum(node.sourceLinks, weightedTarget) / d3.sum(node.sourceLinks, value); 211 | node.y += (y - center(node)) * alpha; 212 | } 213 | }); 214 | }); 215 | 216 | function weightedTarget(link) { 217 | return center(link.target) * link.value; 218 | } 219 | } 220 | 221 | function resolveCollisions() { 222 | nodesByBreadth.forEach(function(nodes) { 223 | var node, 224 | dy, 225 | y0 = 0, 226 | n = nodes.length, 227 | i; 228 | 229 | // Push any overlapping nodes down. 230 | nodes.sort(ascendingDepth); 231 | for (i = 0; i < n; ++i) { 232 | node = nodes[i]; 233 | dy = y0 - node.y; 234 | if (dy > 0) node.y += dy; 235 | y0 = node.y + node.dy + nodePadding; 236 | } 237 | 238 | // If the bottommost node goes outside the bounds, push it back up. 239 | dy = y0 - nodePadding - size[1]; 240 | if (dy > 0) { 241 | y0 = node.y -= dy; 242 | 243 | // Push any overlapping nodes back up. 244 | for (i = n - 2; i >= 0; --i) { 245 | node = nodes[i]; 246 | dy = node.y + node.dy + nodePadding - y0; 247 | if (dy > 0) node.y -= dy; 248 | y0 = node.y; 249 | } 250 | } 251 | }); 252 | } 253 | 254 | function ascendingDepth(a, b) { 255 | return a.y - b.y; 256 | } 257 | } 258 | 259 | function computeLinkDepths() { 260 | nodes.forEach(function(node) { 261 | node.sourceLinks.sort(ascendingTargetDepth); 262 | node.targetLinks.sort(ascendingSourceDepth); 263 | }); 264 | nodes.forEach(function(node) { 265 | var sy = 0, ty = 0; 266 | node.sourceLinks.forEach(function(link) { 267 | link.sy = sy; 268 | sy += link.dy; 269 | }); 270 | node.targetLinks.forEach(function(link) { 271 | link.ty = ty; 272 | ty += link.dy; 273 | }); 274 | }); 275 | 276 | function ascendingSourceDepth(a, b) { 277 | return a.source.y - b.source.y; 278 | } 279 | 280 | function ascendingTargetDepth(a, b) { 281 | return a.target.y - b.target.y; 282 | } 283 | } 284 | 285 | function center(node) { 286 | return node.y + node.dy / 2; 287 | } 288 | 289 | function value(link) { 290 | return link.value; 291 | } 292 | 293 | return sankey; 294 | }; 295 | -------------------------------------------------------------------------------- /bower_components/nvd3/build/nv.d3.min.css: -------------------------------------------------------------------------------- 1 | .nvd3 .nv-axis line,.nvd3 .nv-axis path{fill:none;shape-rendering:crispEdges}.nv-brush .extent,.nvd3 .background path,.nvd3 .nv-axis line,.nvd3 .nv-axis path{shape-rendering:crispEdges}.nv-distx,.nv-disty,.nv-noninteractive,.nvd3 .nv-axis,.nvd3.nv-pie .nv-label,.nvd3.nv-sparklineplus g.nv-hoverValue{pointer-events:none}.nvtooltip,svg.nvd3-svg{display:block;-webkit-touch-callout:none;-khtml-user-select:none}.nvd3 .nv-axis{opacity:1}.nvd3 .nv-axis.nv-disabled,.nvd3 .nv-controlsWrap .nv-legend .nv-check-box .nv-check{opacity:0}.nvd3 .nv-axis path{stroke:#000;stroke-opacity:.75}.nvd3 .nv-axis path.domain{stroke-opacity:.75}.nvd3 .nv-axis.nv-x path.domain{stroke-opacity:0}.nvd3 .nv-axis line{stroke:#e5e5e5}.nvd3 .nv-axis .zero line, .nvd3 .nv-axis line.zero{stroke-opacity:.75}.nvd3 .nv-axis .nv-axisMaxMin text{font-weight:700}.nvd3 .x .nv-axis .nv-axisMaxMin text,.nvd3 .x2 .nv-axis .nv-axisMaxMin text,.nvd3 .x3 .nv-axis .nv-axisMaxMin text{text-anchor:middle}.nvd3 .nv-bars rect{fill-opacity:.75;transition:fill-opacity 250ms linear;-moz-transition:fill-opacity 250ms linear;-webkit-transition:fill-opacity 250ms linear}.nvd3 .nv-bars rect.hover{fill-opacity:1}.nvd3 .nv-bars .hover rect{fill:#add8e6}.nvd3 .nv-bars text{fill:transparent}.nvd3 .nv-bars .hover text{fill:rgba(0,0,0,1)}.nvd3 .nv-discretebar .nv-groups rect,.nvd3 .nv-multibar .nv-groups rect,.nvd3 .nv-multibarHorizontal .nv-groups rect{stroke-opacity:0;transition:fill-opacity 250ms linear;-moz-transition:fill-opacity 250ms linear;-webkit-transition:fill-opacity 250ms linear}.nvd3 .nv-candlestickBar .nv-ticks rect:hover,.nvd3 .nv-discretebar .nv-groups rect:hover,.nvd3 .nv-multibar .nv-groups rect:hover,.nvd3 .nv-multibarHorizontal .nv-groups rect:hover{fill-opacity:1}.nvd3 .nv-discretebar .nv-groups text,.nvd3 .nv-multibarHorizontal .nv-groups text{font-weight:700;fill:rgba(0,0,0,1);stroke:transparent}.nvd3 .nv-boxplot circle{fill-opacity:.5}.nvd3 .nv-boxplot circle:hover,.nvd3 .nv-boxplot rect:hover{fill-opacity:1}.nvd3 line.nv-boxplot-median{stroke:#000}.nv-boxplot-tick:hover{stroke-width:2.5px}.nvd3.nv-bullet{font:10px sans-serif}.nvd3.nv-bullet .nv-measure{fill-opacity:.8}.nvd3.nv-bullet .nv-measure:hover{fill-opacity:1}.nvd3.nv-bullet .nv-marker{stroke:#000;stroke-width:2px}.nvd3.nv-bullet .nv-markerTriangle{stroke:#000;fill:#fff;stroke-width:1.5px}.nvd3.nv-bullet .nv-markerLine{stroke:#000;stroke-width:1.5px}.nvd3.nv-bullet .nv-tick line{stroke:#666;stroke-width:.5px}.nvd3.nv-bullet .nv-range.nv-s0{fill:#eee}.nvd3.nv-bullet .nv-range.nv-s1{fill:#ddd}.nvd3.nv-bullet .nv-range.nv-s2{fill:#ccc}.nvd3.nv-bullet .nv-title{font-size:14px;font-weight:700}.nvd3.nv-bullet .nv-subtitle{fill:#999}.nvd3.nv-bullet .nv-range{fill:#bababa;fill-opacity:.4}.nvd3.nv-bullet .nv-range:hover{fill-opacity:.7}.nvd3.nv-candlestickBar .nv-ticks .nv-tick{stroke-width:1px}.nvd3.nv-candlestickBar .nv-ticks .nv-tick.hover{stroke-width:2px}.nvd3.nv-candlestickBar .nv-ticks .nv-tick.positive rect{stroke:#2ca02c;fill:#2ca02c}.nvd3.nv-candlestickBar .nv-ticks .nv-tick.negative rect{stroke:#d62728;fill:#d62728}.with-transitions .nv-candlestickBar .nv-ticks .nv-tick{transition:stroke-width 250ms linear,stroke-opacity 250ms linear;-moz-transition:stroke-width 250ms linear,stroke-opacity 250ms linear;-webkit-transition:stroke-width 250ms linear,stroke-opacity 250ms linear}.nvd3.nv-candlestickBar .nv-ticks line{stroke:#333}.nv-force-node{stroke:#fff;stroke-width:1.5px}.nv-force-link{stroke:#999;stroke-opacity:.6}.nv-force-node text{stroke-width:0}.nvd3 .nv-check-box .nv-box{fill-opacity:0;stroke-width:2}.nvd3 .nv-check-box .nv-check{fill-opacity:0;stroke-width:4}.nvd3 .nv-series.nv-disabled .nv-check-box .nv-check{fill-opacity:0;stroke-opacity:0}.nvd3.nv-linePlusBar .nv-bar rect{fill-opacity:.75}.nvd3.nv-linePlusBar .nv-bar rect:hover{fill-opacity:1}.nvd3 .nv-groups path.nv-line{fill:none}.nvd3 .nv-groups path.nv-area{stroke:none}.nvd3.nv-line .nvd3.nv-scatter .nv-groups .nv-point{fill-opacity:0;stroke-opacity:0}.nvd3.nv-scatter.nv-single-point .nv-groups .nv-point{fill-opacity:.5!important;stroke-opacity:.5!important}.with-transitions .nvd3 .nv-groups .nv-point{transition:stroke-width 250ms linear,stroke-opacity 250ms linear;-moz-transition:stroke-width 250ms linear,stroke-opacity 250ms linear;-webkit-transition:stroke-width 250ms linear,stroke-opacity 250ms linear}.nvd3 .nv-groups .nv-point.hover,.nvd3.nv-scatter .nv-groups .nv-point.hover{stroke-width:7px;fill-opacity:.95!important;stroke-opacity:.95!important}.nvd3 .nv-point-paths path{stroke:#aaa;stroke-opacity:0;fill:#eee;fill-opacity:0}.nvd3 .nv-indexLine{cursor:ew-resize}svg.nvd3-svg{-webkit-user-select:none;-ms-user-select:none;-moz-user-select:none;user-select:none;width:100%;height:100%}.nvtooltip.with-3d-shadow,.with-3d-shadow .nvtooltip{-moz-box-shadow:0 5px 10px rgba(0,0,0,.2);-webkit-box-shadow:0 5px 10px rgba(0,0,0,.2);box-shadow:0 5px 10px rgba(0,0,0,.2);-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px}.nvd3 text{font:400 12px Arial}.nvd3 .title{font:700 14px Arial}.nvd3 .nv-background{fill:#fff;fill-opacity:0}.nvd3.nv-noData{font-size:18px;font-weight:700}.nv-brush .extent{fill-opacity:.125}.nv-brush .resize path{fill:#eee;stroke:#666}.nvd3 .nv-legend .nv-series{cursor:pointer}.nvd3 .nv-legend .nv-disabled circle{fill-opacity:0}.nvd3 .nv-brush .extent{fill-opacity:0!important}.nvd3 .nv-brushBackground rect{stroke:#000;stroke-width:.4;fill:#fff;fill-opacity:.7}@media print{.nvd3 text{stroke-width:0;fill-opacity:1}}.nvd3.nv-ohlcBar .nv-ticks .nv-tick{stroke-width:1px}.nvd3.nv-ohlcBar .nv-ticks .nv-tick.hover{stroke-width:2px}.nvd3.nv-ohlcBar .nv-ticks .nv-tick.positive{stroke:#2ca02c}.nvd3.nv-ohlcBar .nv-ticks .nv-tick.negative{stroke:#d62728}.nvd3 .background path{fill:none;stroke:#EEE;stroke-opacity:.4}.nvd3 .foreground path{fill:none;stroke-opacity:.7}.nvd3 .nv-parallelCoordinates-brush .extent{fill:#fff;fill-opacity:.6;stroke:gray;shape-rendering:crispEdges}.nvd3 .nv-parallelCoordinates .hover{fill-opacity:1;stroke-width:3px}.nvd3 .missingValuesline line{fill:none;stroke:#000;stroke-width:1;stroke-opacity:1;stroke-dasharray:5,5}.nvd3.nv-pie .nv-pie-title{font-size:24px;fill:rgba(19,196,249,.59)}.nvd3.nv-pie .nv-slice text{stroke:#000;stroke-width:0}.nvd3.nv-pie path{transition:fill-opacity 250ms linear,stroke-width 250ms linear,stroke-opacity 250ms linear;-moz-transition:fill-opacity 250ms linear,stroke-width 250ms linear,stroke-opacity 250ms linear;-webkit-transition:fill-opacity 250ms linear,stroke-width 250ms linear,stroke-opacity 250ms linear;stroke:#fff;stroke-width:1px;stroke-opacity:1;fill-opacity:.7}.nvd3.nv-pie .hover path{fill-opacity:1}.nvd3.nv-pie .nv-label rect{fill-opacity:0;stroke-opacity:0}.nvd3 .nv-groups .nv-point.hover{stroke-width:20px;stroke-opacity:.5}.nvd3 .nv-scatter .nv-point.hover{fill-opacity:1}.nvd3.nv-sparkline path{fill:none}.nvd3.nv-sparklineplus .nv-hoverValue line{stroke:#333;stroke-width:1.5px}.nvd3.nv-sparklineplus,.nvd3.nv-sparklineplus g{pointer-events:all}.nvd3 .nv-interactiveGuideLine,.nvtooltip{pointer-events:none}.nvd3 .nv-hoverArea{fill-opacity:0;stroke-opacity:0}.nvd3.nv-sparklineplus .nv-xValue,.nvd3.nv-sparklineplus .nv-yValue{stroke-width:0;font-size:.9em;font-weight:400}.nvd3.nv-sparklineplus .nv-yValue{stroke:#f66}.nvd3.nv-sparklineplus .nv-maxValue{stroke:#2ca02c;fill:#2ca02c}.nvd3.nv-sparklineplus .nv-minValue{stroke:#d62728;fill:#d62728}.nvd3.nv-sparklineplus .nv-currentValue{font-weight:700;font-size:1.1em}.nvtooltip h3,.nvtooltip table td.key{font-weight:400}.nvd3.nv-stackedarea path.nv-area{fill-opacity:.7;stroke-opacity:0;transition:fill-opacity 250ms linear,stroke-opacity 250ms linear;-moz-transition:fill-opacity 250ms linear,stroke-opacity 250ms linear;-webkit-transition:fill-opacity 250ms linear,stroke-opacity 250ms linear}.nvd3.nv-stackedarea path.nv-area.hover{fill-opacity:.9}.nvd3.nv-stackedarea .nv-groups .nv-point{stroke-opacity:0;fill-opacity:0}.nvtooltip{position:absolute;color:rgba(0,0,0,1);padding:1px;z-index:10000;font-family:Arial;font-size:13px;text-align:left;white-space:nowrap;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background:rgba(255,255,255,.8);border:1px solid rgba(0,0,0,.5);border-radius:4px}.nvtooltip h3,.nvtooltip p{margin:0;text-align:center}.nvtooltip.with-transitions,.with-transitions .nvtooltip{transition:opacity 50ms linear;-moz-transition:opacity 50ms linear;-webkit-transition:opacity 50ms linear;transition-delay:200ms;-moz-transition-delay:200ms;-webkit-transition-delay:200ms}.nvtooltip.x-nvtooltip,.nvtooltip.y-nvtooltip{padding:8px}.nvtooltip h3{padding:4px 14px;line-height:18px;background-color:rgba(247,247,247,.75);color:rgba(0,0,0,1);border-bottom:1px solid #ebebeb;-webkit-border-radius:5px 5px 0 0;-moz-border-radius:5px 5px 0 0;border-radius:5px 5px 0 0}.nvtooltip p{padding:5px 14px}.nvtooltip span{display:inline-block;margin:2px 0}.nvtooltip table{margin:6px;border-spacing:0}.nvtooltip table td{padding:2px 9px 2px 0;vertical-align:middle}.nvtooltip table td.key.total{font-weight:700}.nvtooltip table td.value{text-align:right;font-weight:700}.nvtooltip table td.percent{color:#a9a9a9}.nvtooltip table tr.highlight td{padding:1px 9px 1px 0;border-bottom-style:solid;border-bottom-width:1px;border-top-style:solid;border-top-width:1px}.nvtooltip table td.legend-color-guide div{vertical-align:middle;width:12px;height:12px;border:1px solid #999}.nvtooltip .footer{padding:3px;text-align:center}.nvtooltip-pending-removal{pointer-events:none;display:none}.nvd3 line.nv-guideline{stroke:#ccc} 2 | /*# sourceMappingURL=nv.d3.min.css.map */ -------------------------------------------------------------------------------- /reports/sankey/sketch.js: -------------------------------------------------------------------------------- 1 | 2 | google.charts.load("current", {packages:["sankey"]}); 3 | google.charts.setOnLoadCallback(drawChart); 4 | 5 | function uniq(a) { 6 | var seen = {}; 7 | return a.filter(function(item) { 8 | return seen.hasOwnProperty(item) ? false : (seen[item] = true); 9 | }); 10 | } 11 | 12 | function drawChart() { 13 | $.get("SFHomeless_individ_features_strings_parsed.csv", function(csvString) { 14 | // transform the CSV string into a 2-dimensional array 15 | var arrayData = $.csv.toArrays(csvString, {onParseValue: $.csv.hooks.castToScalar}); 16 | // console.log(arrayData); 17 | var data = new google.visualization.DataTable(); 18 | 19 | var allRaces = []; 20 | var allEthnicity = []; 21 | var allGenders = []; 22 | var allVeteran = []; 23 | var allChronic = []; 24 | var allViolence = []; 25 | var allAge = []; 26 | 27 | for (var i = 1; i < arrayData.length; i++) { //loop of all data in the array 28 | 29 | allRaces.push(arrayData[i][10]); 30 | allEthnicity.push(arrayData[i][7]); 31 | allGenders.push(arrayData[i][1]); 32 | allVeteran.push(arrayData[i][11]); 33 | allChronic.push(arrayData[i][3]); 34 | allViolence.push(arrayData[i][9]); 35 | allAge.push(arrayData[i][6]); 36 | 37 | } 38 | 39 | allRaces = uniq(allRaces); 40 | allEthnicity = uniq(allEthnicity); 41 | allGenders = uniq(allGenders); 42 | allVeteran = uniq(allVeteran); 43 | allChronic = uniq(allChronic); 44 | allViolence = uniq(allViolence); 45 | allAge = uniq(allAge); 46 | 47 | 48 | console.log(allRaces); 49 | console.log(allEthnicity); 50 | console.log(allGenders); 51 | console.log(allVeteran); 52 | console.log(allChronic); 53 | console.log(allViolence); 54 | console.log(allAge); 55 | 56 | 57 | var FinalDataArray = []; // only need one big array to store everything 58 | 59 | // -----------1. Race to Ethnicity-----------// 60 | 61 | for (var raceindex = 0; raceindex < allRaces.length; raceindex++) { 62 | for (var ethnicityindex = 0; ethnicityindex < allEthnicity.length; ethnicityindex++) { 63 | var nowCount = 0; 64 | var nowRace = allRaces[raceindex]; 65 | var nowEthnicity = allEthnicity[ethnicityindex]; 66 | for (var dataIndex = 0; dataIndex < arrayData.length; dataIndex++) { 67 | if(arrayData[dataIndex][10] == nowRace && arrayData[dataIndex][7] == nowEthnicity){ 68 | nowCount++; 69 | } 70 | } 71 | var miniArray_local = []; 72 | miniArray_local.push(nowRace); 73 | miniArray_local.push(nowEthnicity); 74 | miniArray_local.push(nowCount); 75 | // console.log(miniArray_local); 76 | FinalDataArray.push(miniArray_local); 77 | } 78 | } 79 | 80 | // //-----------2. Ethnicity to Gender-----------// 81 | 82 | for (var ethnicityindex = 0; ethnicityindex < allEthnicity.length; ethnicityindex++) { 83 | for (var genderindex = 0; genderindex < allGenders.length; genderindex++) { 84 | var nowCount = 0; 85 | var nowEthnicity = allEthnicity[ethnicityindex]; 86 | var nowGender = allGenders[genderindex]; 87 | for (var dataIndex = 0; dataIndex < arrayData.length; dataIndex++) { 88 | if(arrayData[dataIndex][7] == nowEthnicity && arrayData[dataIndex][1] == nowGender ){ 89 | nowCount++; 90 | } 91 | } 92 | var miniArray_local = []; 93 | miniArray_local.push(nowEthnicity); 94 | miniArray_local.push(nowGender); 95 | miniArray_local.push(nowCount); 96 | // console.log(miniArray_local); 97 | FinalDataArray.push(miniArray_local); 98 | } 99 | } 100 | 101 | //-----------3. Gender to Veteran-----------// 102 | 103 | for (var genderindex = 0; genderindex < allGenders.length; genderindex++) { // choose an armed to look for 104 | for (var veteranindex = 0; veteranindex < allVeteran.length; veteranindex++) { // choose a classification to look for 105 | var nowCount = 0; // start counting with no values 106 | var nowGender = allGenders[genderindex];// our chosen gender for this loop 107 | var nowVeteran = allVeteran[veteranindex]; // our chosen veteran for this loop 108 | for (var dataIndex = 0; dataIndex < arrayData.length; dataIndex++) { //loop of all data in the array looking for the above race and gender 109 | if(arrayData[dataIndex][1] == nowGender && arrayData[dataIndex][11] == nowVeteran ){ // if this data object matches our chosen gender and race 110 | nowCount++; //add one value to our item count 111 | } 112 | } 113 | var miniArray_local = []; 114 | miniArray_local.push(nowGender); 115 | miniArray_local.push(nowVeteran); 116 | miniArray_local.push(nowCount); 117 | // console.log(miniArray_local); 118 | FinalDataArray.push(miniArray_local); 119 | } 120 | } 121 | 122 | //-----------4. Veteran to Chronic-----------// 123 | for (var veteranindex = 0; veteranindex < allVeteran.length; veteranindex++) { 124 | for (var chronicindex = 0; chronicindex < allChronic.length; chronicindex++) { 125 | var nowCount = 0; 126 | var nowVeteran = allVeteran[veteranindex]; 127 | var nowchronic = allChronic[chronicindex]; 128 | for (var dataIndex = 0; dataIndex < arrayData.length; dataIndex++) { 129 | if(arrayData[dataIndex][11] == nowVeteran && arrayData[dataIndex][3] == nowchronic ){ 130 | nowCount++; 131 | } 132 | } 133 | var miniArray_local = []; 134 | miniArray_local.push(nowVeteran); 135 | miniArray_local.push(nowchronic); 136 | miniArray_local.push(nowCount); 137 | // console.log(miniArray_local); 138 | FinalDataArray.push(miniArray_local); 139 | } 140 | } 141 | 142 | //-----------5. Chronic to Violence-----------// 143 | for (var chronicindex = 0; chronicindex < allChronic.length; chronicindex++) { 144 | for (var violenceindex = 0; violenceindex < allViolence.length; violenceindex++) { 145 | var nowCount = 0; 146 | var nowchronic = allChronic[chronicindex]; 147 | var nowViolence = allViolence[violenceindex]; 148 | for (var dataIndex = 0; dataIndex < arrayData.length; dataIndex++) { 149 | 150 | if(arrayData[dataIndex][3] == nowchronic && arrayData[dataIndex][9] == nowViolence ){ 151 | nowCount++; 152 | } 153 | } 154 | var miniArray_local = []; 155 | // console.log('in all the data we found this:'); 156 | miniArray_local.push(nowchronic); 157 | miniArray_local.push(nowViolence); 158 | miniArray_local.push(nowCount); 159 | // console.log(miniArray_local); 160 | FinalDataArray.push(miniArray_local); 161 | } 162 | } 163 | 164 | 165 | //-----------6. Violence to Age-----------// 166 | for (var violenceindex = 0; violenceindex < allViolence.length; violenceindex++) { 167 | for (var ageindex = -1; ageindex <= 102; ageindex+=5) { 168 | var nowCount = 0; 169 | var nowViolence = allViolence[violenceindex]; 170 | var nowAge = ageindex; 171 | for (var dataIndex = 0; dataIndex < arrayData.length; dataIndex++) { 172 | 173 | var inDataAge = arrayData[dataIndex][6]; 174 | 175 | if(arrayData[dataIndex][9] == nowViolence && inDataAge > nowAge && inDataAge <= nowAge+5 ){ 176 | nowCount++; 177 | } 178 | } 179 | var miniArray_local = []; 180 | miniArray_local.push(nowViolence); 181 | miniArray_local.push((nowAge+1) +'-'+(nowAge+5)); 182 | miniArray_local.push(nowCount); 183 | FinalDataArray.push(miniArray_local); 184 | } 185 | } 186 | 187 | // console.log('IN THE END we found this:'); 188 | // console.log(FinalDataArray); 189 | 190 | data.addColumn('string', 'From'); 191 | data.addColumn('string', 'To'); 192 | data.addColumn('number', 'Ammt'); 193 | data.addRows(FinalDataArray); 194 | 195 | 196 | //-----------for style----------// 197 | 198 | var colors = ['#a6cee3', '#b2df8a', '#fb9a99', '#fdbf6f','#cab2d6', '#ffff99', '#1f78b4', '#33a02c']; 199 | 200 | var options = { 201 | sankey: { 202 | // iterations: 0, //If set iterations to 0, and the diagram should draw according to the input order of the data. 203 | 204 | node: { 205 | colors: colors, 206 | labelPadding: 15, 207 | label: { color: '#dddddd', 208 | fontSize: 12, } 209 | 210 | }, 211 | link: { 212 | colorMode: 'gradient', 213 | colors: colors 214 | } 215 | } 216 | }; 217 | 218 | // Instantiate and draw our chart, passing in some options. 219 | var chart = new google.visualization.Sankey(document.getElementById('sankey_multiple')); 220 | chart.draw(data, options); 221 | 222 | 223 | }); 224 | } -------------------------------------------------------------------------------- /bower_components/angular-nvd3/dist/angular-nvd3.min.js: -------------------------------------------------------------------------------- 1 | !function(){"use strict";angular.module("nvd3",[]).directive("nvd3",["nvd3Utils",function(nvd3Utils){return{restrict:"AE",scope:{data:"=",options:"=",api:"=?",events:"=?",config:"=?",onReady:"&?"},link:function(scope,element,attrs){function configure(chart,options,chartType){chart&&options&&angular.forEach(chart,function(value,key){"_"===key[0]||("dispatch"===key?(void 0!==options[key]&&null!==options[key]||scope._config.extended&&(options[key]={}),configureEvents(value,options[key])):"tooltip"===key?(void 0!==options[key]&&null!==options[key]||scope._config.extended&&(options[key]={}),configure(chart[key],options[key],chartType)):"contentGenerator"===key?options[key]&&chart[key](options[key]):-1===["axis","clearHighlights","defined","highlightPoint","nvPointerEventsClass","options","rangeBand","rangeBands","scatter","open","close","node"].indexOf(key)&&(void 0===options[key]||null===options[key]?scope._config.extended&&(options[key]=value()):chart[key](options[key])))})}function configureEvents(dispatch,options){dispatch&&options&&angular.forEach(dispatch,function(value,key){void 0===options[key]||null===options[key]?scope._config.extended&&(options[key]=value.on):dispatch.on(key+"._",options[key])})}function configureWrapper(name){var _=nvd3Utils.deepExtend(defaultWrapper(name),scope.options[name]||{});scope._config.extended&&(scope.options[name]=_);var wrapElement=angular.element("
").html(_.html||"").addClass(name).addClass(_.className).removeAttr("style").css(_.css);_.html||wrapElement.text(_.text),_.enable&&("title"===name?element.prepend(wrapElement):"subtitle"===name?angular.element(element[0].querySelector(".title")).after(wrapElement):"caption"===name&&element.append(wrapElement))}function configureStyles(){var _=nvd3Utils.deepExtend(defaultStyles(),scope.options.styles||{});scope._config.extended&&(scope.options.styles=_),angular.forEach(_.classes,function(value,key){value?element.addClass(key):element.removeClass(key)}),element.removeAttr("style").css(_.css)}function defaultWrapper(_){switch(_){case"title":return{enable:!1,text:"Write Your Title",className:"h4",css:{width:scope.options.chart.width+"px",textAlign:"center"}};case"subtitle":return{enable:!1,text:"Write Your Subtitle",css:{width:scope.options.chart.width+"px",textAlign:"center"}};case"caption":return{enable:!1,text:"Figure 1. Write Your Caption text.",css:{width:scope.options.chart.width+"px",textAlign:"center"}}}}function defaultStyles(){return{classes:{"with-3d-shadow":!0,"with-transitions":!0,gallery:!1},css:{}}}function dataWatchFn(newData,oldData){newData!==oldData&&(scope._config.disabled||(scope._config.refreshDataOnly?scope.api.update():scope.api.refresh()))}var defaultConfig={extended:!1,visible:!0,disabled:!1,refreshDataOnly:!0,deepWatchOptions:!0,deepWatchData:!0,deepWatchDataDepth:2,debounce:10,debounceImmediate:!0};scope.isReady=!1,scope._config=angular.extend(defaultConfig,scope.config),scope.api={refresh:function(){scope.api.updateWithOptions(scope.options),scope.isReady=!0},refreshWithTimeout:function(t){setTimeout(function(){scope.api.refresh()},t)},update:function(){scope.chart&&scope.svg?scope.svg.datum(scope.data).call(scope.chart):scope.api.refresh()},updateWithTimeout:function(t){setTimeout(function(){scope.api.update()},t)},updateWithOptions:function(options){scope.api.clearElement(),angular.isDefined(options)!==!1&&scope._config.visible&&(scope.chart=nv.models[options.chart.type](),scope.chart.id=Math.random().toString(36).substr(2,15),angular.forEach(scope.chart,function(value,key){"_"===key[0]||["clearHighlights","highlightPoint","id","options","resizeHandler","state","open","close","tooltipContent"].indexOf(key)>=0||("dispatch"===key?(void 0!==options.chart[key]&&null!==options.chart[key]||scope._config.extended&&(options.chart[key]={}),configureEvents(scope.chart[key],options.chart[key])):["bars","bars1","bars2","boxplot","bullet","controls","discretebar","distX","distY","interactiveLayer","legend","lines","lines1","lines2","multibar","pie","scatter","scatters1","scatters2","sparkline","stack1","stack2","sunburst","tooltip","x2Axis","xAxis","y1Axis","y2Axis","y3Axis","y4Axis","yAxis","yAxis1","yAxis2"].indexOf(key)>=0||"stacked"===key&&"stackedAreaChart"===options.chart.type?(void 0!==options.chart[key]&&null!==options.chart[key]||scope._config.extended&&(options.chart[key]={}),configure(scope.chart[key],options.chart[key],options.chart.type)):"focusHeight"===key&&"lineChart"===options.chart.type||"focusHeight"===key&&"lineWithFocusChart"===options.chart.type||("xTickFormat"!==key&&"yTickFormat"!==key||"lineWithFocusChart"!==options.chart.type)&&("tooltips"===key&&"boxPlotChart"===options.chart.type||("tooltipXContent"!==key&&"tooltipYContent"!==key||"scatterChart"!==options.chart.type)&&("x"!==key&&"y"!==key||"forceDirectedGraph"!==options.chart.type)&&(void 0===options.chart[key]||null===options.chart[key]?scope._config.extended&&("barColor"===key?options.chart[key]=value()():options.chart[key]=value()):scope.chart[key](options.chart[key]))))}),"sunburstChart"===options.chart.type?scope.api.updateWithData(angular.copy(scope.data)):scope.api.updateWithData(scope.data),(options.title||scope._config.extended)&&configureWrapper("title"),(options.subtitle||scope._config.extended)&&configureWrapper("subtitle"),(options.caption||scope._config.extended)&&configureWrapper("caption"),(options.styles||scope._config.extended)&&configureStyles(),nv.addGraph(function(){return scope.chart?(scope.chart.resizeHandler&&scope.chart.resizeHandler.clear(),scope.chart.resizeHandler=nv.utils.windowResize(function(){scope.chart&&scope.chart.update&&scope.chart.update()}),void 0!==options.chart.zoom&&["scatterChart","lineChart","candlestickBarChart","cumulativeLineChart","historicalBarChart","ohlcBarChart","stackedAreaChart"].indexOf(options.chart.type)>-1&&nvd3Utils.zoom(scope,options),scope.chart):void 0},options.chart.callback))},updateWithData:function(data){if(data){d3.select(element[0]).select("svg").remove();var h,w;scope.svg=d3.select(element[0]).append("svg"),(h=scope.options.chart.height)&&(isNaN(+h)||(h+="px"),scope.svg.attr("height",h).style({height:h})),(w=scope.options.chart.width)?(isNaN(+w)||(w+="px"),scope.svg.attr("width",w).style({width:w})):scope.svg.attr("width","100%").style({width:"100%"}),scope.svg.datum(data).call(scope.chart)}},clearElement:function(){if(element.find(".title").remove(),element.find(".subtitle").remove(),element.find(".caption").remove(),element.empty(),scope.chart&&scope.chart.tooltip&&scope.chart.tooltip.id&&d3.select("#"+scope.chart.tooltip.id()).remove(),nv.graphs&&scope.chart)for(var i=nv.graphs.length-1;i>=0;i--)nv.graphs[i]&&nv.graphs[i].id===scope.chart.id&&nv.graphs.splice(i,1);nv.tooltip&&nv.tooltip.cleanup&&nv.tooltip.cleanup(),scope.chart&&scope.chart.resizeHandler&&scope.chart.resizeHandler.clear(),scope.chart=null},getScope:function(){return scope},getElement:function(){return element}},scope._config.deepWatchOptions&&scope.$watch("options",nvd3Utils.debounce(function(newOptions){scope._config.disabled||scope.api.refresh()},scope._config.debounce,scope._config.debounceImmediate),!0),scope._config.deepWatchData&&(1===scope._config.deepWatchDataDepth?scope.$watchCollection("data",dataWatchFn):scope.$watch("data",dataWatchFn,2===scope._config.deepWatchDataDepth)),scope.$watch("config",function(newConfig,oldConfig){newConfig!==oldConfig&&(scope._config=angular.extend(defaultConfig,newConfig),scope.api.refresh())},!0),scope._config.deepWatchOptions||scope._config.deepWatchData||scope.api.refresh(),angular.forEach(scope.events,function(eventHandler,event){scope.$on(event,function(e,args){return eventHandler(e,scope,args)})}),element.on("$destroy",function(){scope.api.clearElement()}),scope.$watch("isReady",function(isReady){isReady&&scope.onReady&&"function"==typeof scope.onReady()&&scope.onReady()(scope,element)})}}}]).factory("nvd3Utils",function(){return{debounce:function(func,wait,immediate){var timeout;return function(){var context=this,args=arguments,later=function(){timeout=null,immediate||func.apply(context,args)},callNow=immediate&&!timeout;clearTimeout(timeout),timeout=setTimeout(later,wait),callNow&&func.apply(context,args)}},deepExtend:function(dst){var me=this;return angular.forEach(arguments,function(obj){obj!==dst&&angular.forEach(obj,function(value,key){dst[key]&&dst[key].constructor&&dst[key].constructor===Object?me.deepExtend(dst[key],value):dst[key]=value})}),dst},zoom:function(scope,options){var zoom=options.chart.zoom,enabled="undefined"==typeof zoom.enabled||null===zoom.enabled?!0:zoom.enabled;if(enabled){var fixDomain,d3zoom,zoomed,unzoomed,zoomend,xScale=scope.chart.xAxis.scale(),yScale=scope.chart.yAxis.scale(),xDomain=scope.chart.xDomain||xScale.domain,yDomain=scope.chart.yDomain||yScale.domain,x_boundary=xScale.domain().slice(),y_boundary=yScale.domain().slice(),scale=zoom.scale||1,translate=zoom.translate||[0,0],scaleExtent=zoom.scaleExtent||[1,10],useFixedDomain=zoom.useFixedDomain||!1,useNiceScale=zoom.useNiceScale||!1,horizontalOff=zoom.horizontalOff||!1,verticalOff=zoom.verticalOff||!1,unzoomEventType=zoom.unzoomEventType||"dblclick.zoom";useNiceScale&&(xScale.nice(),yScale.nice()),fixDomain=function(domain,boundary){return domain[0]=Math.min(Math.max(domain[0],boundary[0]),boundary[1]-boundary[1]/scaleExtent[1]),domain[1]=Math.max(boundary[0]+boundary[1]/scaleExtent[1],Math.min(domain[1],boundary[1])),domain},zoomed=function(){if(void 0!==zoom.zoomed){var domains=zoom.zoomed(xScale.domain(),yScale.domain());horizontalOff||xDomain([domains.x1,domains.x2]),verticalOff||yDomain([domains.y1,domains.y2])}else horizontalOff||xDomain(useFixedDomain?fixDomain(xScale.domain(),x_boundary):xScale.domain()),verticalOff||yDomain(useFixedDomain?fixDomain(yScale.domain(),y_boundary):yScale.domain());scope.chart.update()},unzoomed=function(){if(void 0!==zoom.unzoomed){var domains=zoom.unzoomed(xScale.domain(),yScale.domain());horizontalOff||xDomain([domains.x1,domains.x2]),verticalOff||yDomain([domains.y1,domains.y2])}else horizontalOff||xDomain(x_boundary),verticalOff||yDomain(y_boundary);d3zoom.scale(scale).translate(translate),scope.chart.update()},zoomend=function(){void 0!==zoom.zoomend&&zoom.zoomend()},d3zoom=d3.behavior.zoom().x(xScale).y(yScale).scaleExtent(scaleExtent).on("zoom",zoomed).on("zoomend",zoomend),scope.svg.call(d3zoom),d3zoom.scale(scale).translate(translate).event(scope.svg),"none"!==unzoomEventType&&scope.svg.on(unzoomEventType,unzoomed)}}}})}(); -------------------------------------------------------------------------------- /reports/sankey-project-outcome/sketch.js: -------------------------------------------------------------------------------- 1 | 2 | google.charts.load("current", {packages:["sankey"]}); 3 | google.charts.setOnLoadCallback(drawChart); 4 | 5 | function uniq(a) { 6 | var seen = {}; 7 | return a.filter(function(item) { 8 | return seen.hasOwnProperty(item) ? false : (seen[item] = true); 9 | }); 10 | } 11 | 12 | function drawChart() { 13 | // $.get("SFHomeless_individ_features_strings_parsed.csv", function(csvString) { 14 | $.get("homeless_3_projects_outcome_parsed-1207.csv", function(csvString) { 15 | // transform the CSV string into a 2-dimensional array 16 | var arrayData = $.csv.toArrays(csvString, {onParseValue: $.csv.hooks.castToScalar}); 17 | console.log(arrayData); 18 | var data = new google.visualization.DataTable(); 19 | 20 | var allRaces = []; 21 | var allEthnicity = []; 22 | var allGenders = []; 23 | var allVeteran = []; 24 | var allAge = []; 25 | var allStatus = []; 26 | var allProject1 = []; 27 | var allProject2 = []; 28 | var allProject3 = []; 29 | var allPermanentHousing = []; 30 | 31 | for (var i = 1; i < arrayData.length; i++) { //loop of all data in the array 32 | 33 | allRaces.push(arrayData[i][1]); 34 | allEthnicity.push(arrayData[i][2]); 35 | allGenders.push(arrayData[i][3]); 36 | allVeteran.push(arrayData[i][4]); 37 | allAge.push(arrayData[i][6]); 38 | allStatus.push(arrayData[i][8]); 39 | allProject1.push(arrayData[i][9]); 40 | allProject2.push(arrayData[i][10]); 41 | allProject3.push(arrayData[i][11]); 42 | allPermanentHousing.push(arrayData[i][12]); 43 | } 44 | 45 | allRaces = uniq(allRaces); 46 | allEthnicity = uniq(allEthnicity); 47 | allGenders = uniq(allGenders); 48 | allVeteran = uniq(allVeteran); 49 | allAge = uniq(allAge); 50 | allStatus = uniq(allStatus); 51 | allProject1 = uniq(allProject1); 52 | allProject2 = uniq(allProject2); 53 | allProject3 = uniq(allProject3); 54 | allPermanentHousing = uniq(allPermanentHousing); 55 | 56 | console.log(allRaces); 57 | console.log(allEthnicity); 58 | console.log(allGenders); 59 | console.log(allVeteran); 60 | console.log(allAge); 61 | console.log(allStatus); 62 | console.log(allProject1); 63 | console.log(allProject2); 64 | console.log(allProject3); 65 | console.log(allPermanentHousing); 66 | 67 | 68 | var FinalDataArray = []; // only need one big array to store everything 69 | 70 | // //-----------1. Gender to Veteran-----------// 71 | 72 | for (var genderindex = 0; genderindex < allGenders.length; genderindex++) { // choose an armed to look for 73 | for (var veteranindex = 0; veteranindex < allVeteran.length; veteranindex++) { // choose a classification to look for 74 | var nowCount = 0; // start counting with no values 75 | var nowGender = allGenders[genderindex];// our chosen gender for this loop 76 | var nowVeteran = allVeteran[veteranindex]; // our chosen veteran for this loop 77 | for (var dataIndex = 0; dataIndex < arrayData.length; dataIndex++) { //loop of all data in the array looking for the above race and gender 78 | if(arrayData[dataIndex][3] == nowGender && arrayData[dataIndex][4] == nowVeteran ){ // if this data object matches our chosen gender and race 79 | nowCount++; //add one value to our item count 80 | } 81 | } 82 | var miniArray_local = []; 83 | miniArray_local.push(nowGender); 84 | miniArray_local.push(nowVeteran); 85 | miniArray_local.push(nowCount); 86 | // console.log(miniArray_local); 87 | FinalDataArray.push(miniArray_local); 88 | } 89 | } 90 | 91 | // //-----------2. Veteran to Race-----------// 92 | for (var veteranindex = 0; veteranindex < allVeteran.length; veteranindex++) { 93 | for (raceindex = 0; raceindex < allRaces.length; raceindex++) { 94 | var nowCount = 0; // start counting with no values 95 | var nowVeteran = allVeteran[veteranindex]; 96 | var nowRace = allRaces[raceindex]; 97 | for (var dataIndex = 0; dataIndex < arrayData.length; dataIndex++) { 98 | if(arrayData[dataIndex][4] == nowVeteran && arrayData[dataIndex][1] == nowRace ){ 99 | nowCount++; //add one value to our item count 100 | } 101 | } 102 | var miniArray_local = []; 103 | miniArray_local.push(nowVeteran); 104 | miniArray_local.push(nowRace); 105 | miniArray_local.push(nowCount); 106 | // console.log(miniArray_local); 107 | FinalDataArray.push(miniArray_local); 108 | } 109 | } 110 | // -----------3. Race to Ethnicity-----------// 111 | 112 | for (var raceindex = 0; raceindex < allRaces.length; raceindex++) { 113 | for (var ethnicityindex = 0; ethnicityindex < allEthnicity.length; ethnicityindex++) { 114 | var nowCount = 0; 115 | var nowRace = allRaces[raceindex]; 116 | var nowEthnicity = allEthnicity[ethnicityindex]; 117 | for (var dataIndex = 0; dataIndex < arrayData.length; dataIndex++) { 118 | if(arrayData[dataIndex][1] == nowRace && arrayData[dataIndex][2] == nowEthnicity){ 119 | nowCount++; 120 | } 121 | } 122 | var miniArray_local = []; 123 | miniArray_local.push(nowRace); 124 | miniArray_local.push(nowEthnicity); 125 | miniArray_local.push(nowCount); 126 | // console.log(miniArray_local); 127 | FinalDataArray.push(miniArray_local); 128 | } 129 | } 130 | 131 | // //-----------4. Ethnicity to Status-----------// 132 | 133 | for (var ethnicityindex = 0; ethnicityindex < allEthnicity.length; ethnicityindex++) { 134 | for (var statusindex = 0; statusindex < allStatus.length; statusindex++) { 135 | var nowCount = 0; 136 | var nowEthnicity = allEthnicity[ethnicityindex]; 137 | var nowStatus = allStatus[statusindex]; 138 | for (var dataIndex = 0; dataIndex < arrayData.length; dataIndex++) { 139 | if(arrayData[dataIndex][2] == nowEthnicity && arrayData[dataIndex][8] == nowStatus ){ 140 | nowCount++; 141 | } 142 | } 143 | var miniArray_local = []; 144 | miniArray_local.push(nowEthnicity); 145 | miniArray_local.push(nowStatus); 146 | miniArray_local.push(nowCount); 147 | // console.log(miniArray_local); 148 | FinalDataArray.push(miniArray_local); 149 | } 150 | } 151 | 152 | 153 | 154 | 155 | // //-----------5. Status to Project 1-----------// 156 | for (var statusindex = 0; statusindex < allStatus.length; statusindex++) { 157 | for (var project1index = 0; project1index < allProject1.length; project1index++) { 158 | var nowCount = 0; // start counting with no values 159 | var nowStatus = allStatus[statusindex]; 160 | var nowProject1 = allProject1[project1index]; 161 | for (var dataIndex = 0; dataIndex < arrayData.length; dataIndex++) { 162 | if(arrayData[dataIndex][8] == nowStatus && arrayData[dataIndex][9] == nowProject1 ){ 163 | nowCount++; //add one value to our item count 164 | } 165 | } 166 | var miniArray_local = []; 167 | miniArray_local.push(nowStatus); 168 | miniArray_local.push(nowProject1); 169 | miniArray_local.push(nowCount); 170 | // console.log(miniArray_local); 171 | FinalDataArray.push(miniArray_local); 172 | } 173 | } 174 | 175 | // //-----------6. Project 1 to Project 2-----------// 176 | for (var project1index = 0; project1index < allProject1.length; project1index++) { 177 | for (var project2index = 0; project2index < allProject2.length; project2index++) { 178 | var nowCount = 0; // start counting with no values 179 | var nowProject1 = allProject1[project1index]; 180 | var nowProject2 = allProject2[project2index]; 181 | for (var dataIndex = 0; dataIndex < arrayData.length; dataIndex++) { 182 | if(arrayData[dataIndex][9] == nowProject1 && arrayData[dataIndex][10] == nowProject2 ){ 183 | nowCount++; //add one value to our item count 184 | } 185 | } 186 | var miniArray_local = []; 187 | miniArray_local.push(nowProject1); 188 | miniArray_local.push(nowProject2); 189 | miniArray_local.push(nowCount); 190 | // console.log(miniArray_local); 191 | FinalDataArray.push(miniArray_local); 192 | } 193 | } 194 | // //-----------7. Project 2 to Project 3-----------// 195 | for (var project2index = 0; project2index < allProject2.length; project2index++) { 196 | for (var project3index = 0; project3index < allProject3.length; project3index++) { 197 | var nowCount = 0; // start counting with no values 198 | var nowProject2 = allProject2[project2index]; 199 | var nowProject3 = allProject3[project3index]; 200 | for (var dataIndex = 0; dataIndex < arrayData.length; dataIndex++) { 201 | if(arrayData[dataIndex][10] == nowProject2 && arrayData[dataIndex][11] == nowProject3 ){ 202 | nowCount++; //add one value to our item count 203 | } 204 | } 205 | var miniArray_local = []; 206 | miniArray_local.push(nowProject2); 207 | miniArray_local.push(nowProject3); 208 | miniArray_local.push(nowCount); 209 | // console.log(miniArray_local); 210 | FinalDataArray.push(miniArray_local); 211 | } 212 | } 213 | 214 | // //-----------8. Project 3 to Permanent Housing-----------// 215 | for (var project3index = 0; project3index < allProject3.length; project3index++) { 216 | for (var PermanentHousingindex = 0; PermanentHousingindex < allPermanentHousing.length; PermanentHousingindex++) { 217 | var nowCount = 0; // start counting with no values 218 | var nowProject3 = allProject3[project3index]; 219 | var nowPermanentHousing = allPermanentHousing[PermanentHousingindex]; 220 | 221 | for (var dataIndex = 0; dataIndex < arrayData.length; dataIndex++) { 222 | if(arrayData[dataIndex][11] == nowProject3 && arrayData[dataIndex][12] == nowPermanentHousing ){ 223 | nowCount++; //add one value to our item count 224 | } 225 | } 226 | var miniArray_local = []; 227 | miniArray_local.push(nowProject3); 228 | miniArray_local.push(nowPermanentHousing); 229 | miniArray_local.push(nowCount); 230 | // console.log(miniArray_local); 231 | FinalDataArray.push(miniArray_local); 232 | } 233 | } 234 | // // console.log('IN THE END we found this:'); 235 | // // console.log(FinalDataArray); 236 | 237 | data.addColumn('string', 'From'); 238 | data.addColumn('string', 'To'); 239 | data.addColumn('number', 'Ammt'); 240 | data.addRows(FinalDataArray); 241 | 242 | 243 | //-----------for style----------// 244 | 245 | var colors = ['#a6cee3', '#b2df8a', '#fb9a99', '#fdbf6f','#cab2d6', '#ffff99', '#1f78b4', '#33a02c']; 246 | 247 | var options = { 248 | sankey: { 249 | // iterations: 0, //If set iterations to 0, and the diagram should draw according to the input order of the data. 250 | 251 | node: { 252 | // width: 2, 253 | nodePadding: 29, 254 | colors: colors, 255 | labelPadding: 1, 256 | label: { color: '#dddddd', 257 | fontSize: 10, 258 | } 259 | 260 | }, 261 | link: { 262 | colorMode: 'gradient', 263 | colors: colors 264 | } 265 | } 266 | }; 267 | 268 | // Instantiate and draw our chart, passing in some options. 269 | var chart = new google.visualization.Sankey(document.getElementById('sankey_multiple')); 270 | chart.draw(data, options); 271 | 272 | 273 | }); 274 | } -------------------------------------------------------------------------------- /halin/1.1 Project Preprocessing.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": { 6 | "run_control": { 7 | "breakpoint": false 8 | } 9 | }, 10 | "source": [ 11 | "# Analyzing enrollment and projects" 12 | ] 13 | }, 14 | { 15 | "cell_type": "markdown", 16 | "metadata": { 17 | "run_control": { 18 | "breakpoint": false 19 | } 20 | }, 21 | "source": [ 22 | "So, let's first group projects together into \"super-types\" and then remove certain projects we're not interested in. From there, we can categorize each one of the rows in enrollment (people) based on their project super-type. From there, let's check how often people come back" 23 | ] 24 | }, 25 | { 26 | "cell_type": "markdown", 27 | "metadata": { 28 | "run_control": { 29 | "breakpoint": false 30 | } 31 | }, 32 | "source": [ 33 | "# First off, Project Preprocessing" 34 | ] 35 | }, 36 | { 37 | "cell_type": "code", 38 | "execution_count": 1, 39 | "metadata": { 40 | "collapsed": true, 41 | "run_control": { 42 | "breakpoint": false 43 | } 44 | }, 45 | "outputs": [], 46 | "source": [ 47 | "import numpy as np\n", 48 | "import pandas as pd" 49 | ] 50 | }, 51 | { 52 | "cell_type": "code", 53 | "execution_count": 2, 54 | "metadata": { 55 | "collapsed": true, 56 | "run_control": { 57 | "breakpoint": false 58 | } 59 | }, 60 | "outputs": [], 61 | "source": [ 62 | "project = pd.read_csv(\"data/raw/Project.csv\")" 63 | ] 64 | }, 65 | { 66 | "cell_type": "code", 67 | "execution_count": 3, 68 | "metadata": { 69 | "collapsed": true 70 | }, 71 | "outputs": [], 72 | "source": [ 73 | "project[\"Project Type Code\"].value_counts(dropna=False)\n", 74 | "\n", 75 | "toss_out = {\"Other (HUD)\", \"Services Only (HUD)\", \"Street Outreach (HUD)\", \"RETIRED (HUD)\"} # And NaN value\n", 76 | "ext_funding = {\"Homelessness Prevention (HUD)\"}\n", 77 | "temp_housing = {\"Transitional housing (HUD)\"}\n", 78 | "nightly_housing = {\"Emergency Shelter (HUD)\"}\n", 79 | "long_stay = {\"PH - Permanent Supportive Housing (disability required for entry) (HUD)\", \"PH - Rapid Re-Housing (HUD)\"}" 80 | ] 81 | }, 82 | { 83 | "cell_type": "markdown", 84 | "metadata": { 85 | "run_control": { 86 | "breakpoint": false 87 | } 88 | }, 89 | "source": [ 90 | "## Toss out unnecessary data" 91 | ] 92 | }, 93 | { 94 | "cell_type": "code", 95 | "execution_count": 4, 96 | "metadata": { 97 | "collapsed": true, 98 | "run_control": { 99 | "breakpoint": false 100 | } 101 | }, 102 | "outputs": [], 103 | "source": [ 104 | "in_toss_out = project.apply(lambda row: row[\"Project Type Code\"] in toss_out, axis=1)\n", 105 | "filtered_project = project[~in_toss_out]" 106 | ] 107 | }, 108 | { 109 | "cell_type": "code", 110 | "execution_count": 5, 111 | "metadata": { 112 | "collapsed": true, 113 | "run_control": { 114 | "breakpoint": false 115 | } 116 | }, 117 | "outputs": [], 118 | "source": [ 119 | "filtered_project = filtered_project.loc[filtered_project[\"Project Type Code\"].dropna().index, :]" 120 | ] 121 | }, 122 | { 123 | "cell_type": "code", 124 | "execution_count": 6, 125 | "metadata": { 126 | "collapsed": true, 127 | "run_control": { 128 | "breakpoint": false 129 | } 130 | }, 131 | "outputs": [], 132 | "source": [ 133 | "assert all(type(project_type) is str for project_type in filtered_project[\"Project Type Code\"])" 134 | ] 135 | }, 136 | { 137 | "cell_type": "markdown", 138 | "metadata": { 139 | "run_control": { 140 | "breakpoint": false 141 | } 142 | }, 143 | "source": [ 144 | "## Examine data" 145 | ] 146 | }, 147 | { 148 | "cell_type": "code", 149 | "execution_count": 7, 150 | "metadata": { 151 | "run_control": { 152 | "breakpoint": false 153 | } 154 | }, 155 | "outputs": [ 156 | { 157 | "data": { 158 | "text/plain": [ 159 | "Homelessness Prevention (HUD) 36\n", 160 | "PH - Permanent Supportive Housing (disability required for entry) (HUD) 35\n", 161 | "PH - Rapid Re-Housing (HUD) 32\n", 162 | "Emergency Shelter (HUD) 27\n", 163 | "Transitional housing (HUD) 25\n", 164 | "Name: Project Type Code, dtype: int64" 165 | ] 166 | }, 167 | "execution_count": 7, 168 | "metadata": {}, 169 | "output_type": "execute_result" 170 | } 171 | ], 172 | "source": [ 173 | "filtered_project[\"Project Type Code\"].value_counts()" 174 | ] 175 | }, 176 | { 177 | "cell_type": "markdown", 178 | "metadata": { 179 | "run_control": { 180 | "breakpoint": false 181 | } 182 | }, 183 | "source": [ 184 | "# Create the \"super projects\"" 185 | ] 186 | }, 187 | { 188 | "cell_type": "code", 189 | "execution_count": 8, 190 | "metadata": { 191 | "collapsed": true, 192 | "run_control": { 193 | "breakpoint": false 194 | } 195 | }, 196 | "outputs": [], 197 | "source": [ 198 | "assert ext_funding\n", 199 | "assert temp_housing\n", 200 | "assert long_stay" 201 | ] 202 | }, 203 | { 204 | "cell_type": "code", 205 | "execution_count": 9, 206 | "metadata": { 207 | "collapsed": true, 208 | "run_control": { 209 | "breakpoint": false 210 | } 211 | }, 212 | "outputs": [], 213 | "source": [ 214 | "def assign_super_project(row):\n", 215 | " code = row[\"Project Type Code\"]\n", 216 | " if code in ext_funding: return \"External Funding\"\n", 217 | " if code in temp_housing: return \"Temporary Housing\"\n", 218 | " if code in long_stay: return \"Long Stay\"\n", 219 | " if code in nightly_housing: return \"Nightly Housing\"\n", 220 | " raise ValueError(\"Project Type was not accounted for\")" 221 | ] 222 | }, 223 | { 224 | "cell_type": "code", 225 | "execution_count": 10, 226 | "metadata": { 227 | "collapsed": true, 228 | "run_control": { 229 | "breakpoint": false 230 | } 231 | }, 232 | "outputs": [], 233 | "source": [ 234 | "super_projects = filtered_project.apply(assign_super_project, axis=1)" 235 | ] 236 | }, 237 | { 238 | "cell_type": "code", 239 | "execution_count": 11, 240 | "metadata": { 241 | "collapsed": true, 242 | "run_control": { 243 | "breakpoint": false 244 | } 245 | }, 246 | "outputs": [], 247 | "source": [ 248 | "filtered_project[\"Super Project\"] = super_projects" 249 | ] 250 | }, 251 | { 252 | "cell_type": "code", 253 | "execution_count": 12, 254 | "metadata": { 255 | "run_control": { 256 | "breakpoint": false 257 | } 258 | }, 259 | "outputs": [ 260 | { 261 | "data": { 262 | "text/html": [ 263 | "
\n", 264 | "\n", 265 | " \n", 266 | " \n", 267 | " \n", 268 | " \n", 269 | " \n", 270 | " \n", 271 | " \n", 272 | " \n", 273 | " \n", 274 | " \n", 275 | " \n", 276 | " \n", 277 | " \n", 278 | " \n", 279 | " \n", 280 | " \n", 281 | " \n", 282 | " \n", 283 | " \n", 284 | " \n", 285 | " \n", 286 | " \n", 287 | " \n", 288 | " \n", 289 | " \n", 290 | " \n", 291 | " \n", 292 | " \n", 293 | " \n", 294 | " \n", 295 | " \n", 296 | " \n", 297 | " \n", 298 | " \n", 299 | " \n", 300 | " \n", 301 | " \n", 302 | " \n", 303 | " \n", 304 | " \n", 305 | " \n", 306 | " \n", 307 | " \n", 308 | " \n", 309 | " \n", 310 | " \n", 311 | " \n", 312 | " \n", 313 | " \n", 314 | " \n", 315 | " \n", 316 | " \n", 317 | " \n", 318 | " \n", 319 | " \n", 320 | " \n", 321 | " \n", 322 | " \n", 323 | " \n", 324 | " \n", 325 | " \n", 326 | " \n", 327 | " \n", 328 | " \n", 329 | " \n", 330 | " \n", 331 | " \n", 332 | " \n", 333 | " \n", 334 | " \n", 335 | " \n", 336 | " \n", 337 | " \n", 338 | " \n", 339 | " \n", 340 | " \n", 341 | " \n", 342 | " \n", 343 | " \n", 344 | " \n", 345 | " \n", 346 | " \n", 347 | " \n", 348 | " \n", 349 | " \n", 350 | " \n", 351 | " \n", 352 | " \n", 353 | " \n", 354 | " \n", 355 | " \n", 356 | " \n", 357 | " \n", 358 | " \n", 359 | "
Project NameProject IDOrganization NameCoC CodeProject Type CodeMethod for Tracking ES UtilizationAddress CityAddress Postal CodeFunderGrant Start DateGrant End DateSuper Project
0MOSBE CHS - Elm House2142MOSBE Community Human Services (CHS)CA-506Transitional housing (HUD)NaNNaN93942NaNNaNNaNTemporary Housing
1MOSBE CHS - Elm House2142MOSBE Community Human Services (CHS)CA-506Transitional housing (HUD)NaNNaN93955NaNNaNNaNTemporary Housing
2MOSBE CHS - RHY - BCP ES3417MOSBE Community Human Services (CHS)CA-506Emergency Shelter (HUD)NaNMonterey93942NaNNaNNaNNightly Housing
3MOSBE CHS - RHY - BCP ES3417MOSBE Community Human Services (CHS)CA-506Emergency Shelter (HUD)NaNSeaside93955NaNNaNNaNNightly Housing
4MOSBE CHS - RHY - BCP - HP3418MOSBE Community Human Services (CHS)CA-506Homelessness Prevention (HUD)NaNMonterey93942NaNNaNNaNExternal Funding
\n", 360 | "
" 361 | ], 362 | "text/plain": [ 363 | " Project Name Project ID \\\n", 364 | "0 MOSBE CHS - Elm House 2142 \n", 365 | "1 MOSBE CHS - Elm House 2142 \n", 366 | "2 MOSBE CHS - RHY - BCP ES 3417 \n", 367 | "3 MOSBE CHS - RHY - BCP ES 3417 \n", 368 | "4 MOSBE CHS - RHY - BCP - HP 3418 \n", 369 | "\n", 370 | " Organization Name CoC Code \\\n", 371 | "0 MOSBE Community Human Services (CHS) CA-506 \n", 372 | "1 MOSBE Community Human Services (CHS) CA-506 \n", 373 | "2 MOSBE Community Human Services (CHS) CA-506 \n", 374 | "3 MOSBE Community Human Services (CHS) CA-506 \n", 375 | "4 MOSBE Community Human Services (CHS) CA-506 \n", 376 | "\n", 377 | " Project Type Code Method for Tracking ES Utilization \\\n", 378 | "0 Transitional housing (HUD) NaN \n", 379 | "1 Transitional housing (HUD) NaN \n", 380 | "2 Emergency Shelter (HUD) NaN \n", 381 | "3 Emergency Shelter (HUD) NaN \n", 382 | "4 Homelessness Prevention (HUD) NaN \n", 383 | "\n", 384 | " Address City Address Postal Code Funder Grant Start Date Grant End Date \\\n", 385 | "0 NaN 93942 NaN NaN NaN \n", 386 | "1 NaN 93955 NaN NaN NaN \n", 387 | "2 Monterey 93942 NaN NaN NaN \n", 388 | "3 Seaside 93955 NaN NaN NaN \n", 389 | "4 Monterey 93942 NaN NaN NaN \n", 390 | "\n", 391 | " Super Project \n", 392 | "0 Temporary Housing \n", 393 | "1 Temporary Housing \n", 394 | "2 Nightly Housing \n", 395 | "3 Nightly Housing \n", 396 | "4 External Funding " 397 | ] 398 | }, 399 | "execution_count": 12, 400 | "metadata": {}, 401 | "output_type": "execute_result" 402 | } 403 | ], 404 | "source": [ 405 | "filtered_project.head()" 406 | ] 407 | }, 408 | { 409 | "cell_type": "code", 410 | "execution_count": 13, 411 | "metadata": { 412 | "collapsed": true, 413 | "run_control": { 414 | "breakpoint": false 415 | } 416 | }, 417 | "outputs": [], 418 | "source": [ 419 | "filtered_project.to_csv(\"data/preprocessed/projects.csv\", sep=\",\")" 420 | ] 421 | }, 422 | { 423 | "cell_type": "code", 424 | "execution_count": null, 425 | "metadata": { 426 | "collapsed": true, 427 | "run_control": { 428 | "breakpoint": false 429 | } 430 | }, 431 | "outputs": [], 432 | "source": [] 433 | } 434 | ], 435 | "metadata": { 436 | "kernelspec": { 437 | "display_name": "Python 2", 438 | "language": "python", 439 | "name": "python2" 440 | }, 441 | "language_info": { 442 | "codemirror_mode": { 443 | "name": "ipython", 444 | "version": 2 445 | }, 446 | "file_extension": ".py", 447 | "mimetype": "text/x-python", 448 | "name": "python", 449 | "nbconvert_exporter": "python", 450 | "pygments_lexer": "ipython2", 451 | "version": "2.7.13" 452 | } 453 | }, 454 | "nbformat": 4, 455 | "nbformat_minor": 2 456 | } 457 | -------------------------------------------------------------------------------- /sfhomelesstweets.csv: -------------------------------------------------------------------------------- 1 | ,Text,DateCreated 2 | 0,How mental illness factors into San Francisco's homeless population https://t.co/7Dj7dspuRb,Thu Jun 30 05:30:08 +0000 2016 3 | 1,RT @invisiblepeople: T.J. has been homeless in San Francisco for the last three years. https://t.co/3QZHQyY291 #SFHomelessProject,Thu Jun 30 05:28:05 +0000 2016 4 | 2,"RT @MidniteMission: ""From homeless in San Francisco to a job in the tech industry."" 5 | 6 | Founded in 1914, The Midnight Mission offers... https:",Thu Jun 30 05:25:35 +0000 2016 7 | 3,We can learn from kids and their empathy for San Francisco's homeless - SF Gate https://t.co/v1CfvCxr0e,Thu Jun 30 05:23:35 +0000 2016 8 | 4,"RT @BuzzFeedNews: Can you make it through the night as one of the more than 6,500 homeless people in San Francisco? #SFHomelessProject http",Thu Jun 30 05:22:13 +0000 2016 9 | 5,"RT @CNNMoney: Media unites to highlight San Francisco homeless crisis 10 | https://t.co/v3bdipLRXc https://t.co/BtsQL5rqSy",Thu Jun 30 05:19:30 +0000 2016 11 | 6,RT @KathyStocker: From homeless in San Francisco to a job in the tech industry https://t.co/fvK1zMyiXY #SFHomelessProject,Thu Jun 30 05:17:55 +0000 2016 12 | 7,"RT @MidniteMission: ""From homeless in San Francisco to a job in the tech industry."" 13 | 14 | Founded in 1914, The Midnight Mission offers... https:",Thu Jun 30 05:13:30 +0000 2016 15 | 8,L'emergenza #homeless a #SanFrancisco: How many people live on San Francisco streets? https://t.co/ZxSjFZ5vzz #SFHomelessProject,Thu Jun 30 05:13:25 +0000 2016 16 | 9,"RT @CNNMoney: Media unites to highlight San Francisco homeless crisis 17 | https://t.co/v3bdipLRXc https://t.co/BtsQL5rqSy",Thu Jun 30 05:12:54 +0000 2016 18 | 10,Media unites to highlight San Francisco homeless crisis https://t.co/GbPuss3AkB,Thu Jun 30 05:12:50 +0000 2016 19 | 11,"RT @BuzzFeedNews: Can you make it through the night as one of the more than 6,500 homeless people in San Francisco? #SFHomelessProject http",Thu Jun 30 05:11:03 +0000 2016 20 | 12,Media unites to highlight San Francisco homeless crisis June 29 - CNNMoney https://t.co/1h9Gkgi7Ue,Thu Jun 30 05:08:47 +0000 2016 21 | 13,RT @CityLab: San Francisco homelessness looks just like it did 20 years ago https://t.co/FluLs97Q1b #cityreads #SFHomelessProject https://t,Thu Jun 30 05:05:47 +0000 2016 22 | 14,RT @KQEDnews: A #homeless protest in 1983 San Francisco. What's changed in the Bay? https://t.co/YDvmpaWmnF #SFHomelessProject https://t.co,Thu Jun 30 05:04:56 +0000 2016 23 | 15,"FinancialDocCMJ: CNNMoney: Media unites to highlight San Francisco homeless crisis 24 | https://t.co/rhsSXfpJ7D https://t.co/EzYPsgOboG",Thu Jun 30 05:04:18 +0000 2016 25 | 16,RT @MLNow: Property of San Francisco homeless routinely disappeared by city https://t.co/uV4T1nhQsA https://t.co/YzkKqczwF6,Thu Jun 30 05:02:29 +0000 2016 26 | 17,RT @EugeneKan: This is a worthwhile initiative: The Running Club for the Homeless @backonmyfeet heads to San Francisco. https://t.co/kp5drR,Thu Jun 30 05:02:25 +0000 2016 27 | 18,"RT @CNNMoney: Media unites to highlight San Francisco homeless crisis 28 | https://t.co/v3bdipLRXc https://t.co/BtsQL5rqSy",Thu Jun 30 05:01:09 +0000 2016 29 | 19,RT @invisiblepeople: #SFHomelessProject Shane's story is a very candid interview on the connection between incarceration and homelessness h,Thu Jun 30 05:00:55 +0000 2016 30 | 20,RT @invisiblepeople: #SFHomelessProject Shane's story is a very candid interview on the connection between incarceration and homelessness h,Thu Jun 30 05:00:52 +0000 2016 31 | 21,San Francisco media plan week of coverage on homeless crisis - Business .. Related Articles: https://t.co/6zh7PjrCgW,Thu Jun 30 05:00:42 +0000 2016 32 | 22,"RT @CNNMoney: Media unites to highlight San Francisco homeless crisis 33 | https://t.co/v3bdipLRXc https://t.co/BtsQL5rqSy",Thu Jun 30 05:00:39 +0000 2016 34 | 23,"RT @CNNMoney: Media unites to highlight San Francisco homeless crisis 35 | https://t.co/v3bdipLRXc https://t.co/BtsQL5rqSy",Thu Jun 30 05:00:32 +0000 2016 36 | 24,#SFHomelessProject Shane's story is a very candid interview on the connection between incarceration and homelessness https://t.co/i7xtWEuEwg,Thu Jun 30 05:00:28 +0000 2016 37 | 25,#SFHomelessProject Shane's story is a very candid interview on the connection between incarceration and homelessness https://t.co/O4JMYxMZPK,Thu Jun 30 05:00:28 +0000 2016 38 | 26,"RT @CNNMoney: Media unites to highlight San Francisco homeless crisis 39 | https://t.co/v3bdipLRXc https://t.co/BtsQL5rqSy",Thu Jun 30 04:59:49 +0000 2016 40 | 27,RT @bayareahomeless: A portrait gallery of homeless and low-income chefs in training. https://t.co/upmGHNAJR7 #SFHomelessProject https://t.,Thu Jun 30 04:58:39 +0000 2016 41 | 28,"RT @CNNMoney: Media unites to highlight San Francisco homeless crisis 42 | https://t.co/v3bdipLRXc https://t.co/BtsQL5rqSy",Thu Jun 30 04:58:21 +0000 2016 43 | 29,"RT @CNNMoney: Media unites to highlight San Francisco homeless crisis 44 | https://t.co/v3bdipLRXc https://t.co/BtsQL5rqSy",Thu Jun 30 04:57:42 +0000 2016 45 | 30,"RT @CNNMoney: Media unites to highlight San Francisco homeless crisis 46 | https://t.co/v3bdipLRXc https://t.co/BtsQL5rqSy",Thu Jun 30 04:57:40 +0000 2016 47 | 31,"RT @CNNMoney: Media unites to highlight San Francisco homeless crisis 48 | https://t.co/v3bdipLRXc https://t.co/BtsQL5rqSy",Thu Jun 30 04:57:34 +0000 2016 49 | 32,"RT @CNNMoney: Media unites to highlight San Francisco homeless crisis 50 | https://t.co/v3bdipLRXc https://t.co/BtsQL5rqSy",Thu Jun 30 04:56:57 +0000 2016 51 | 33,Woman who's been homeless since age 6 finds housing in San Francisco - KGO-TV https://t.co/bB3TzX05Uh https://t.co/F9sErkrIST,Thu Jun 30 04:56:17 +0000 2016 52 | 34,Woman who's been homeless since age 6 finds housing in San Francisco - KGO-TV https://t.co/bB3TzX05Uh,Thu Jun 30 04:56:08 +0000 2016 53 | 35,RT @KQEDnews: A #homeless protest in 1983 San Francisco. What's changed in the Bay? https://t.co/YDvmpaWmnF #SFHomelessProject https://t.co,Thu Jun 30 04:53:52 +0000 2016 54 | 36,"RT @CNNMoney: Media unites to highlight San Francisco homeless crisis 55 | https://t.co/v3bdipLRXc https://t.co/BtsQL5rqSy",Thu Jun 30 04:53:25 +0000 2016 56 | 37,"@quonky ""Is that homeless man wearing a white magicians cape after Labor Day? Ha! Only San Francisco!"" How close am I?",Thu Jun 30 04:52:29 +0000 2016 57 | 38,We can learn from kids and their empathy for San Francisco's homeless - SF Gate https://t.co/di0UpZXJG6,Thu Jun 30 04:52:09 +0000 2016 58 | 39,RT @Gizmodo: How should San Francisco help its homeless population? Bay Area journalists weigh in https://t.co/SXwQjmlQKC https://t.co/eUhd,Thu Jun 30 04:51:56 +0000 2016 59 | 40,RT @MLNow: Despite widespread sweeps Public Works only stored property of 23 homless people in 6 months https://t.co/aVntPBtfQp https://t.c,Thu Jun 30 04:50:52 +0000 2016 60 | 41,"RT @CNNMoney: Media unites to highlight San Francisco homeless crisis 61 | https://t.co/v3bdipLRXc https://t.co/BtsQL5rqSy",Thu Jun 30 04:50:45 +0000 2016 62 | 42,"RT @CNNMoney: Media unites to highlight San Francisco homeless crisis 63 | https://t.co/v3bdipLRXc https://t.co/BtsQL5rqSy",Thu Jun 30 04:50:15 +0000 2016 64 | 43,RT @invisiblepeople: #SFHomelessProject Dawns sign reads PREGNANT & STRESSED!! as she sits begging for change in San Francisco https://t,Thu Jun 30 04:50:14 +0000 2016 65 | 44,"RT @CNNMoney: Media unites to highlight San Francisco homeless crisis 66 | https://t.co/v3bdipLRXc https://t.co/BtsQL5rqSy",Thu Jun 30 04:50:10 +0000 2016 67 | 45,RT @SFGate: Lava Mae delivers SF's homeless population much needed showers https://t.co/eWyDwJ2B9w #SFHomelessProject https://t.co/IsnuYiTD,Thu Jun 30 04:49:51 +0000 2016 68 | 46,"RT @CNNMoney: Media unites to highlight San Francisco homeless crisis 69 | https://t.co/v3bdipLRXc https://t.co/BtsQL5rqSy",Thu Jun 30 04:49:35 +0000 2016 70 | 47,"RT @CNNMoney: Media unites to highlight San Francisco homeless crisis 71 | https://t.co/v3bdipLRXc https://t.co/BtsQL5rqSy",Thu Jun 30 04:49:34 +0000 2016 72 | 48,San Francisco photographer captures homeless pregnant women in beautiful portraits: submitted by /u/... https://t.co/wiXB1VYsyp,Thu Jun 30 04:49:05 +0000 2016 73 | 49,"Media unites to highlight San Francisco homeless crisis 74 | https://t.co/RhvF3TMMhF https://t.co/B8kuRYTkKo via CNNMoney",Thu Jun 30 04:48:48 +0000 2016 75 | 50,A homeless moms answer: leave San Francisco https://t.co/wkLW0jwGoR,Thu Jun 30 04:48:42 +0000 2016 76 | 51,"RT @CNNMoney: Media unites to highlight San Francisco homeless crisis 77 | https://t.co/v3bdipLRXc https://t.co/BtsQL5rqSy",Thu Jun 30 04:48:30 +0000 2016 78 | 52,"RT @CNNMoney: Media unites to highlight San Francisco homeless crisis 79 | https://t.co/v3bdipLRXc https://t.co/BtsQL5rqSy",Thu Jun 30 04:48:15 +0000 2016 80 | 53,Media unites to highlight San Francisco homeless crisis https://t.co/Pfgx2Di2xz via @CNNMoney,Thu Jun 30 04:47:32 +0000 2016 81 | 54,"RT @CNNMoney: Media unites to highlight San Francisco homeless crisis 82 | https://t.co/v3bdipLRXc https://t.co/BtsQL5rqSy",Thu Jun 30 04:47:13 +0000 2016 83 | 55,"RT @CNNMoney: Media unites to highlight San Francisco homeless crisis 84 | https://t.co/v3bdipLRXc https://t.co/BtsQL5rqSy",Thu Jun 30 04:46:47 +0000 2016 85 | 56,"RT @CNNMoney: Media unites to highlight San Francisco homeless crisis 86 | https://t.co/v3bdipLRXc https://t.co/BtsQL5rqSy",Thu Jun 30 04:46:37 +0000 2016 87 | 57,"CNNMoney: Media unites to highlight San Francisco homeless crisis 88 | https://t.co/Iz5ewchNOq https://t.co/TPaK71UTSY",Thu Jun 30 04:46:26 +0000 2016 89 | 58,RT @KQEDnews: A #homeless protest in 1983 San Francisco. What's changed in the Bay? https://t.co/YDvmpaWmnF #SFHomelessProject https://t.co,Thu Jun 30 04:46:09 +0000 2016 90 | 59,This is a worthwhile initiative: The Running Club for the Homeless @backonmyfeet heads to San Francisco. https://t.co/kp5drRwKst,Thu Jun 30 04:45:30 +0000 2016 91 | 60,"#XRIM #MONEY : CNNMoney : Media unites to highlight San Francisco homeless crisis 92 | https://t.co/2QHqEWYUiD) https://t.co/cpvJ5sCn0t",Thu Jun 30 04:44:47 +0000 2016 93 | 61,San Francisco photographer captures homeless pregnant women in beautiful portraits - SF Gate https://t.co/T52Ooa013i,Thu Jun 30 04:44:47 +0000 2016 94 | 62,RT @invisiblepeople: #SFHomelessProject Dawns sign reads PREGNANT & STRESSED!! as she sits begging for change in San Francisco https://t,Thu Jun 30 04:44:16 +0000 2016 95 | 63,"RT @CNNMoney: Media unites to highlight San Francisco homeless crisis 96 | https://t.co/v3bdipLRXc https://t.co/BtsQL5rqSy",Thu Jun 30 04:44:03 +0000 2016 97 | 64,"CNNMoney: Media unites to highlight San Francisco homeless crisis 98 | https://t.co/vGlFHx9cHQ https://t.co/kRu9qWYB4m",Thu Jun 30 04:43:53 +0000 2016 99 | 65,"RT @CNNMoney: Media unites to highlight San Francisco homeless crisis 100 | https://t.co/v3bdipLRXc https://t.co/BtsQL5rqSy",Thu Jun 30 04:43:34 +0000 2016 101 | 66,"Media unites to highlight San Francisco homeless crisis https://t.co/b3uEmwGw63 https://t.co/sn02Q1bnji 102 | For more... https://t.co/1aurDOIpH5",Thu Jun 30 04:43:31 +0000 2016 103 | 67,"RT @CNNMoney: Media unites to highlight San Francisco homeless crisis 104 | https://t.co/v3bdipLRXc https://t.co/BtsQL5rqSy",Thu Jun 30 04:43:27 +0000 2016 105 | 68,"RT @CNNMoney: Media unites to highlight San Francisco homeless crisis 106 | https://t.co/v3bdipLRXc https://t.co/BtsQL5rqSy",Thu Jun 30 04:40:15 +0000 2016 107 | 69,"RT @CNNMoney: Media unites to highlight San Francisco homeless crisis 108 | https://t.co/v3bdipLRXc https://t.co/BtsQL5rqSy",Thu Jun 30 04:38:57 +0000 2016 109 | 70,"RT @CNNMoney: Media unites to highlight San Francisco homeless crisis 110 | https://t.co/v3bdipLRXc https://t.co/BtsQL5rqSy",Thu Jun 30 04:38:11 +0000 2016 111 | 71,"RT @CNNMoney: Media unites to highlight San Francisco homeless crisis 112 | https://t.co/v3bdipLRXc https://t.co/BtsQL5rqSy",Thu Jun 30 04:37:10 +0000 2016 113 | 72,"Media unites to highlight San Francisco homeless crisis 114 | https://t.co/nft4YdbCVd https://t.co/U2neNUzcuZ",Thu Jun 30 04:37:07 +0000 2016 115 | 73,"@CNNMoney: Media unites to highlight San Francisco homeless crisis 116 | https://t.co/wAQjbPROP5/s/Vbwi https://t.co/PGLULZ3EwM/s/4Tyd 117 | 118 | m.twitt...",Thu Jun 30 04:36:49 +0000 2016 119 | 74,"CNNMoney: Media unites to highlight San Francisco homeless crisis 120 | https://t.co/VWKXdrmh0C https://t.co/PrZ8PkCgo9",Thu Jun 30 04:36:05 +0000 2016 121 | 75,Insecurity In The City Of Food: How San Francisco Feeds Its Homeless https://t.co/oFsNXMt4QR,Thu Jun 30 04:35:52 +0000 2016 122 | 76,"RT @CNNMoney: Media unites to highlight San Francisco homeless crisis 123 | https://t.co/v3bdipLRXc https://t.co/BtsQL5rqSy",Thu Jun 30 04:35:20 +0000 2016 124 | 77,"RT @CNNMoney: Media unites to highlight San Francisco homeless crisis 125 | https://t.co/v3bdipLRXc https://t.co/BtsQL5rqSy",Thu Jun 30 04:35:04 +0000 2016 126 | 78,We can learn from kids and their empathy for San Francisco's homeless - SF Gate https://t.co/nPDyy5RdUl,Thu Jun 30 04:34:05 +0000 2016 127 | 79,"RT @CNNMoney: Media unites to highlight San Francisco homeless crisis 128 | https://t.co/v3bdipLRXc https://t.co/BtsQL5rqSy",Thu Jun 30 04:32:25 +0000 2016 129 | 80,"RT @CNNMoney: Media unites to highlight San Francisco homeless crisis 130 | https://t.co/v3bdipLRXc https://t.co/BtsQL5rqSy",Thu Jun 30 04:31:23 +0000 2016 131 | 81,"Media unites to highlight San Francisco homeless crisis 132 | https://t.co/v3bdipLRXc https://t.co/BtsQL5rqSy",Thu Jun 30 04:31:01 +0000 2016 133 | 82,RT @Gizmodo: How should San Francisco help its homeless population? Bay Area journalists weigh in https://t.co/SXwQjmlQKC https://t.co/eUhd,Thu Jun 30 04:30:58 +0000 2016 134 | 83,RT @bayareahomeless: A portrait gallery of homeless and low-income chefs in training. https://t.co/upmGHNAJR7 #SFHomelessProject https://t.,Thu Jun 30 04:30:21 +0000 2016 135 | 84,A #homeless protest in 1983 San Francisco. What's changed in the Bay? https://t.co/YDvmpaWmnF #SFHomelessProject https://t.co/WfHf3wHrq1,Thu Jun 30 04:30:10 +0000 2016 136 | 85,"San Francisco homelessness Q&A: Frequently asked questions, answers https://t.co/EyAXjOxM79 via @demunderground #homeless",Thu Jun 30 04:28:46 +0000 2016 137 | 86,RT @invisiblepeople: #SFHomelessProject Dawns sign reads PREGNANT & STRESSED!! as she sits begging for change in San Francisco https://t,Thu Jun 30 04:27:22 +0000 2016 138 | 87,Data shows San Francisco has second highest homeless population in Unite.. Related Articles: https://t.co/JfHiIVVfyz,Thu Jun 30 04:24:52 +0000 2016 139 | 88,RT @MLNow: Property of San Francisco homeless routinely disappeared by city https://t.co/uV4T1nhQsA https://t.co/YzkKqczwF6,Thu Jun 30 04:23:56 +0000 2016 140 | 89,RT @bayareahomeless: A portrait gallery of homeless and low-income chefs in training. https://t.co/upmGHNAJR7 #SFHomelessProject https://t.,Thu Jun 30 04:21:58 +0000 2016 141 | 90,RT @bayareahomeless: Homeless But at Home in San Francisco https://t.co/tIUvIc3YFw #SFHomelessProject https://t.co/j70eyCmglY,Thu Jun 30 04:20:38 +0000 2016 142 | 91,RT @KathyStocker: From homeless in San Francisco to a job in the tech industry https://t.co/fvK1zMyiXY #SFHomelessProject,Thu Jun 30 04:20:24 +0000 2016 143 | 92,RT @bayareahomeless: A portrait gallery of homeless and low-income chefs in training. https://t.co/upmGHNAJR7 #SFHomelessProject https://t.,Thu Jun 30 04:19:36 +0000 2016 144 | 93,RT @invisiblepeople: #SFHomelessProject Dawns sign reads PREGNANT & STRESSED!! as she sits begging for change in San Francisco https://t,Thu Jun 30 04:19:25 +0000 2016 145 | 94,What role should media coverage play in Portland's homeless crisis? https://t.co/e5w5ZOmai2 https://t.co/xdZ09X1kKW,Thu Jun 30 04:19:12 +0000 2016 146 | 95,Kudos to these tech companies helping! https://t.co/fvK1zMyiXY,Thu Jun 30 04:18:49 +0000 2016 147 | 96,RT @samueldodge: These are our family members we're leaving them out on the street to suffer and that's not alright! https://t.co/mq3QIsBdL,Thu Jun 30 04:16:42 +0000 2016 148 | 97,From homeless in San Francisco to a job in the tech industry https://t.co/fvK1zMyiXY #SFHomelessProject,Thu Jun 30 04:14:30 +0000 2016 149 | 98,RT @Gizmodo: How should San Francisco help its homeless population? Bay Area journalists weigh in https://t.co/SXwQjmlQKC https://t.co/eUhd,Thu Jun 30 04:13:35 +0000 2016 150 | 99,RT @bayareahomeless: A portrait gallery of homeless and low-income chefs in training. https://t.co/upmGHNAJR7 #SFHomelessProject https://t.,Thu Jun 30 04:12:23 +0000 2016 151 | -------------------------------------------------------------------------------- /bower_components/nvd3/build/nv.d3.css: -------------------------------------------------------------------------------- 1 | /* nvd3 version 1.8.4 (https://github.com/novus/nvd3) 2016-07-03 */ 2 | .nvd3 .nv-axis { 3 | pointer-events:none; 4 | opacity: 1; 5 | } 6 | 7 | .nvd3 .nv-axis path { 8 | fill: none; 9 | stroke: #000; 10 | stroke-opacity: .75; 11 | shape-rendering: crispEdges; 12 | } 13 | 14 | .nvd3 .nv-axis path.domain { 15 | stroke-opacity: .75; 16 | } 17 | 18 | .nvd3 .nv-axis.nv-x path.domain { 19 | stroke-opacity: 0; 20 | } 21 | 22 | .nvd3 .nv-axis line { 23 | fill: none; 24 | stroke: #e5e5e5; 25 | shape-rendering: crispEdges; 26 | } 27 | 28 | .nvd3 .nv-axis .zero line, 29 | /*this selector may not be necessary*/ .nvd3 .nv-axis line.zero { 30 | stroke-opacity: .75; 31 | } 32 | 33 | .nvd3 .nv-axis .nv-axisMaxMin text { 34 | font-weight: bold; 35 | } 36 | 37 | .nvd3 .x .nv-axis .nv-axisMaxMin text, 38 | .nvd3 .x2 .nv-axis .nv-axisMaxMin text, 39 | .nvd3 .x3 .nv-axis .nv-axisMaxMin text { 40 | text-anchor: middle 41 | } 42 | 43 | .nvd3 .nv-axis.nv-disabled { 44 | opacity: 0; 45 | } 46 | 47 | .nvd3 .nv-bars rect { 48 | fill-opacity: .75; 49 | 50 | transition: fill-opacity 250ms linear; 51 | -moz-transition: fill-opacity 250ms linear; 52 | -webkit-transition: fill-opacity 250ms linear; 53 | } 54 | 55 | .nvd3 .nv-bars rect.hover { 56 | fill-opacity: 1; 57 | } 58 | 59 | .nvd3 .nv-bars .hover rect { 60 | fill: lightblue; 61 | } 62 | 63 | .nvd3 .nv-bars text { 64 | fill: rgba(0,0,0,0); 65 | } 66 | 67 | .nvd3 .nv-bars .hover text { 68 | fill: rgba(0,0,0,1); 69 | } 70 | 71 | .nvd3 .nv-multibar .nv-groups rect, 72 | .nvd3 .nv-multibarHorizontal .nv-groups rect, 73 | .nvd3 .nv-discretebar .nv-groups rect { 74 | stroke-opacity: 0; 75 | 76 | transition: fill-opacity 250ms linear; 77 | -moz-transition: fill-opacity 250ms linear; 78 | -webkit-transition: fill-opacity 250ms linear; 79 | } 80 | 81 | .nvd3 .nv-multibar .nv-groups rect:hover, 82 | .nvd3 .nv-multibarHorizontal .nv-groups rect:hover, 83 | .nvd3 .nv-candlestickBar .nv-ticks rect:hover, 84 | .nvd3 .nv-discretebar .nv-groups rect:hover { 85 | fill-opacity: 1; 86 | } 87 | 88 | .nvd3 .nv-discretebar .nv-groups text, 89 | .nvd3 .nv-multibarHorizontal .nv-groups text { 90 | font-weight: bold; 91 | fill: rgba(0,0,0,1); 92 | stroke: rgba(0,0,0,0); 93 | } 94 | 95 | /* boxplot CSS */ 96 | .nvd3 .nv-boxplot circle { 97 | fill-opacity: 0.5; 98 | } 99 | 100 | .nvd3 .nv-boxplot circle:hover { 101 | fill-opacity: 1; 102 | } 103 | 104 | .nvd3 .nv-boxplot rect:hover { 105 | fill-opacity: 1; 106 | } 107 | 108 | .nvd3 line.nv-boxplot-median { 109 | stroke: black; 110 | } 111 | 112 | .nv-boxplot-tick:hover { 113 | stroke-width: 2.5px; 114 | } 115 | /* bullet */ 116 | .nvd3.nv-bullet { font: 10px sans-serif; } 117 | .nvd3.nv-bullet .nv-measure { fill-opacity: .8; } 118 | .nvd3.nv-bullet .nv-measure:hover { fill-opacity: 1; } 119 | .nvd3.nv-bullet .nv-marker { stroke: #000; stroke-width: 2px; } 120 | .nvd3.nv-bullet .nv-markerTriangle { stroke: #000; fill: #fff; stroke-width: 1.5px; } 121 | .nvd3.nv-bullet .nv-markerLine { stroke: #000; stroke-width: 1.5px; } 122 | .nvd3.nv-bullet .nv-tick line { stroke: #666; stroke-width: .5px; } 123 | .nvd3.nv-bullet .nv-range.nv-s0 { fill: #eee; } 124 | .nvd3.nv-bullet .nv-range.nv-s1 { fill: #ddd; } 125 | .nvd3.nv-bullet .nv-range.nv-s2 { fill: #ccc; } 126 | .nvd3.nv-bullet .nv-title { font-size: 14px; font-weight: bold; } 127 | .nvd3.nv-bullet .nv-subtitle { fill: #999; } 128 | 129 | 130 | .nvd3.nv-bullet .nv-range { 131 | fill: #bababa; 132 | fill-opacity: .4; 133 | } 134 | .nvd3.nv-bullet .nv-range:hover { 135 | fill-opacity: .7; 136 | } 137 | 138 | .nvd3.nv-candlestickBar .nv-ticks .nv-tick { 139 | stroke-width: 1px; 140 | } 141 | 142 | .nvd3.nv-candlestickBar .nv-ticks .nv-tick.hover { 143 | stroke-width: 2px; 144 | } 145 | 146 | .nvd3.nv-candlestickBar .nv-ticks .nv-tick.positive rect { 147 | stroke: #2ca02c; 148 | fill: #2ca02c; 149 | } 150 | 151 | .nvd3.nv-candlestickBar .nv-ticks .nv-tick.negative rect { 152 | stroke: #d62728; 153 | fill: #d62728; 154 | } 155 | 156 | .with-transitions .nv-candlestickBar .nv-ticks .nv-tick { 157 | transition: stroke-width 250ms linear, stroke-opacity 250ms linear; 158 | -moz-transition: stroke-width 250ms linear, stroke-opacity 250ms linear; 159 | -webkit-transition: stroke-width 250ms linear, stroke-opacity 250ms linear; 160 | 161 | } 162 | 163 | .nvd3.nv-candlestickBar .nv-ticks line { 164 | stroke: #333; 165 | } 166 | 167 | 168 | .nv-force-node { 169 | stroke: #fff; 170 | stroke-width: 1.5px; 171 | } 172 | .nv-force-link { 173 | stroke: #999; 174 | stroke-opacity: .6; 175 | } 176 | .nv-force-node text { 177 | stroke-width: 0px 178 | } 179 | 180 | .nvd3 .nv-legend .nv-disabled rect { 181 | /*fill-opacity: 0;*/ 182 | } 183 | 184 | .nvd3 .nv-check-box .nv-box { 185 | fill-opacity:0; 186 | stroke-width:2; 187 | } 188 | 189 | .nvd3 .nv-check-box .nv-check { 190 | fill-opacity:0; 191 | stroke-width:4; 192 | } 193 | 194 | .nvd3 .nv-series.nv-disabled .nv-check-box .nv-check { 195 | fill-opacity:0; 196 | stroke-opacity:0; 197 | } 198 | 199 | .nvd3 .nv-controlsWrap .nv-legend .nv-check-box .nv-check { 200 | opacity: 0; 201 | } 202 | 203 | /* line plus bar */ 204 | .nvd3.nv-linePlusBar .nv-bar rect { 205 | fill-opacity: .75; 206 | } 207 | 208 | .nvd3.nv-linePlusBar .nv-bar rect:hover { 209 | fill-opacity: 1; 210 | } 211 | .nvd3 .nv-groups path.nv-line { 212 | fill: none; 213 | } 214 | 215 | .nvd3 .nv-groups path.nv-area { 216 | stroke: none; 217 | } 218 | 219 | .nvd3.nv-line .nvd3.nv-scatter .nv-groups .nv-point { 220 | fill-opacity: 0; 221 | stroke-opacity: 0; 222 | } 223 | 224 | .nvd3.nv-scatter.nv-single-point .nv-groups .nv-point { 225 | fill-opacity: .5 !important; 226 | stroke-opacity: .5 !important; 227 | } 228 | 229 | 230 | .with-transitions .nvd3 .nv-groups .nv-point { 231 | transition: stroke-width 250ms linear, stroke-opacity 250ms linear; 232 | -moz-transition: stroke-width 250ms linear, stroke-opacity 250ms linear; 233 | -webkit-transition: stroke-width 250ms linear, stroke-opacity 250ms linear; 234 | 235 | } 236 | 237 | .nvd3.nv-scatter .nv-groups .nv-point.hover, 238 | .nvd3 .nv-groups .nv-point.hover { 239 | stroke-width: 7px; 240 | fill-opacity: .95 !important; 241 | stroke-opacity: .95 !important; 242 | } 243 | 244 | 245 | .nvd3 .nv-point-paths path { 246 | stroke: #aaa; 247 | stroke-opacity: 0; 248 | fill: #eee; 249 | fill-opacity: 0; 250 | } 251 | 252 | 253 | 254 | .nvd3 .nv-indexLine { 255 | cursor: ew-resize; 256 | } 257 | 258 | /******************** 259 | * SVG CSS 260 | */ 261 | 262 | /******************** 263 | Default CSS for an svg element nvd3 used 264 | */ 265 | svg.nvd3-svg { 266 | -webkit-touch-callout: none; 267 | -webkit-user-select: none; 268 | -khtml-user-select: none; 269 | -ms-user-select: none; 270 | -moz-user-select: none; 271 | user-select: none; 272 | display: block; 273 | width:100%; 274 | height:100%; 275 | } 276 | 277 | /******************** 278 | Box shadow and border radius styling 279 | */ 280 | .nvtooltip.with-3d-shadow, .with-3d-shadow .nvtooltip { 281 | -moz-box-shadow: 0 5px 10px rgba(0,0,0,.2); 282 | -webkit-box-shadow: 0 5px 10px rgba(0,0,0,.2); 283 | box-shadow: 0 5px 10px rgba(0,0,0,.2); 284 | 285 | -webkit-border-radius: 5px; 286 | -moz-border-radius: 5px; 287 | border-radius: 5px; 288 | } 289 | 290 | 291 | .nvd3 text { 292 | font: normal 12px Arial; 293 | } 294 | 295 | .nvd3 .title { 296 | font: bold 14px Arial; 297 | } 298 | 299 | .nvd3 .nv-background { 300 | fill: white; 301 | fill-opacity: 0; 302 | } 303 | 304 | .nvd3.nv-noData { 305 | font-size: 18px; 306 | font-weight: bold; 307 | } 308 | 309 | 310 | /********** 311 | * Brush 312 | */ 313 | 314 | .nv-brush .extent { 315 | fill-opacity: .125; 316 | shape-rendering: crispEdges; 317 | } 318 | 319 | .nv-brush .resize path { 320 | fill: #eee; 321 | stroke: #666; 322 | } 323 | 324 | 325 | /********** 326 | * Legend 327 | */ 328 | 329 | .nvd3 .nv-legend .nv-series { 330 | cursor: pointer; 331 | } 332 | 333 | .nvd3 .nv-legend .nv-disabled circle { 334 | fill-opacity: 0; 335 | } 336 | 337 | /* focus */ 338 | .nvd3 .nv-brush .extent { 339 | fill-opacity: 0 !important; 340 | } 341 | 342 | .nvd3 .nv-brushBackground rect { 343 | stroke: #000; 344 | stroke-width: .4; 345 | fill: #fff; 346 | fill-opacity: .7; 347 | } 348 | 349 | /********** 350 | * Print 351 | */ 352 | 353 | @media print { 354 | .nvd3 text { 355 | stroke-width: 0; 356 | fill-opacity: 1; 357 | } 358 | } 359 | 360 | .nvd3.nv-ohlcBar .nv-ticks .nv-tick { 361 | stroke-width: 1px; 362 | } 363 | 364 | .nvd3.nv-ohlcBar .nv-ticks .nv-tick.hover { 365 | stroke-width: 2px; 366 | } 367 | 368 | .nvd3.nv-ohlcBar .nv-ticks .nv-tick.positive { 369 | stroke: #2ca02c; 370 | } 371 | 372 | .nvd3.nv-ohlcBar .nv-ticks .nv-tick.negative { 373 | stroke: #d62728; 374 | } 375 | 376 | 377 | .nvd3 .background path { 378 | fill: none; 379 | stroke: #EEE; 380 | stroke-opacity: .4; 381 | shape-rendering: crispEdges; 382 | } 383 | 384 | .nvd3 .foreground path { 385 | fill: none; 386 | stroke-opacity: .7; 387 | } 388 | 389 | .nvd3 .nv-parallelCoordinates-brush .extent 390 | { 391 | fill: #fff; 392 | fill-opacity: .6; 393 | stroke: gray; 394 | shape-rendering: crispEdges; 395 | } 396 | 397 | .nvd3 .nv-parallelCoordinates .hover { 398 | fill-opacity: 1; 399 | stroke-width: 3px; 400 | } 401 | 402 | 403 | .nvd3 .missingValuesline line { 404 | fill: none; 405 | stroke: black; 406 | stroke-width: 1; 407 | stroke-opacity: 1; 408 | stroke-dasharray: 5, 5; 409 | } 410 | .nvd3.nv-pie path { 411 | stroke-opacity: 0; 412 | transition: fill-opacity 250ms linear, stroke-width 250ms linear, stroke-opacity 250ms linear; 413 | -moz-transition: fill-opacity 250ms linear, stroke-width 250ms linear, stroke-opacity 250ms linear; 414 | -webkit-transition: fill-opacity 250ms linear, stroke-width 250ms linear, stroke-opacity 250ms linear; 415 | 416 | } 417 | 418 | .nvd3.nv-pie .nv-pie-title { 419 | font-size: 24px; 420 | fill: rgba(19, 196, 249, 0.59); 421 | } 422 | 423 | .nvd3.nv-pie .nv-slice text { 424 | stroke: #000; 425 | stroke-width: 0; 426 | } 427 | 428 | .nvd3.nv-pie path { 429 | stroke: #fff; 430 | stroke-width: 1px; 431 | stroke-opacity: 1; 432 | } 433 | 434 | .nvd3.nv-pie path { 435 | fill-opacity: .7; 436 | } 437 | .nvd3.nv-pie .hover path { 438 | fill-opacity: 1; 439 | } 440 | .nvd3.nv-pie .nv-label { 441 | pointer-events: none; 442 | } 443 | .nvd3.nv-pie .nv-label rect { 444 | fill-opacity: 0; 445 | stroke-opacity: 0; 446 | } 447 | 448 | /* scatter */ 449 | .nvd3 .nv-groups .nv-point.hover { 450 | stroke-width: 20px; 451 | stroke-opacity: .5; 452 | } 453 | 454 | .nvd3 .nv-scatter .nv-point.hover { 455 | fill-opacity: 1; 456 | } 457 | .nv-noninteractive { 458 | pointer-events: none; 459 | } 460 | 461 | .nv-distx, .nv-disty { 462 | pointer-events: none; 463 | } 464 | 465 | /* sparkline */ 466 | .nvd3.nv-sparkline path { 467 | fill: none; 468 | } 469 | 470 | .nvd3.nv-sparklineplus g.nv-hoverValue { 471 | pointer-events: none; 472 | } 473 | 474 | .nvd3.nv-sparklineplus .nv-hoverValue line { 475 | stroke: #333; 476 | stroke-width: 1.5px; 477 | } 478 | 479 | .nvd3.nv-sparklineplus, 480 | .nvd3.nv-sparklineplus g { 481 | pointer-events: all; 482 | } 483 | 484 | .nvd3 .nv-hoverArea { 485 | fill-opacity: 0; 486 | stroke-opacity: 0; 487 | } 488 | 489 | .nvd3.nv-sparklineplus .nv-xValue, 490 | .nvd3.nv-sparklineplus .nv-yValue { 491 | stroke-width: 0; 492 | font-size: .9em; 493 | font-weight: normal; 494 | } 495 | 496 | .nvd3.nv-sparklineplus .nv-yValue { 497 | stroke: #f66; 498 | } 499 | 500 | .nvd3.nv-sparklineplus .nv-maxValue { 501 | stroke: #2ca02c; 502 | fill: #2ca02c; 503 | } 504 | 505 | .nvd3.nv-sparklineplus .nv-minValue { 506 | stroke: #d62728; 507 | fill: #d62728; 508 | } 509 | 510 | .nvd3.nv-sparklineplus .nv-currentValue { 511 | font-weight: bold; 512 | font-size: 1.1em; 513 | } 514 | /* stacked area */ 515 | .nvd3.nv-stackedarea path.nv-area { 516 | fill-opacity: .7; 517 | stroke-opacity: 0; 518 | transition: fill-opacity 250ms linear, stroke-opacity 250ms linear; 519 | -moz-transition: fill-opacity 250ms linear, stroke-opacity 250ms linear; 520 | -webkit-transition: fill-opacity 250ms linear, stroke-opacity 250ms linear; 521 | } 522 | 523 | .nvd3.nv-stackedarea path.nv-area.hover { 524 | fill-opacity: .9; 525 | } 526 | 527 | 528 | .nvd3.nv-stackedarea .nv-groups .nv-point { 529 | stroke-opacity: 0; 530 | fill-opacity: 0; 531 | } 532 | 533 | 534 | .nvtooltip { 535 | position: absolute; 536 | background-color: rgba(255,255,255,1.0); 537 | color: rgba(0,0,0,1.0); 538 | padding: 1px; 539 | border: 1px solid rgba(0,0,0,.2); 540 | z-index: 10000; 541 | display: block; 542 | 543 | font-family: Arial; 544 | font-size: 13px; 545 | text-align: left; 546 | pointer-events: none; 547 | 548 | white-space: nowrap; 549 | 550 | -webkit-touch-callout: none; 551 | -webkit-user-select: none; 552 | -khtml-user-select: none; 553 | -moz-user-select: none; 554 | -ms-user-select: none; 555 | user-select: none; 556 | } 557 | 558 | .nvtooltip { 559 | background: rgba(255,255,255, 0.8); 560 | border: 1px solid rgba(0,0,0,0.5); 561 | border-radius: 4px; 562 | } 563 | 564 | /*Give tooltips that old fade in transition by 565 | putting a "with-transitions" class on the container div. 566 | */ 567 | .nvtooltip.with-transitions, .with-transitions .nvtooltip { 568 | transition: opacity 50ms linear; 569 | -moz-transition: opacity 50ms linear; 570 | -webkit-transition: opacity 50ms linear; 571 | 572 | transition-delay: 200ms; 573 | -moz-transition-delay: 200ms; 574 | -webkit-transition-delay: 200ms; 575 | } 576 | 577 | .nvtooltip.x-nvtooltip, 578 | .nvtooltip.y-nvtooltip { 579 | padding: 8px; 580 | } 581 | 582 | .nvtooltip h3 { 583 | margin: 0; 584 | padding: 4px 14px; 585 | line-height: 18px; 586 | font-weight: normal; 587 | background-color: rgba(247,247,247,0.75); 588 | color: rgba(0,0,0,1.0); 589 | text-align: center; 590 | 591 | border-bottom: 1px solid #ebebeb; 592 | 593 | -webkit-border-radius: 5px 5px 0 0; 594 | -moz-border-radius: 5px 5px 0 0; 595 | border-radius: 5px 5px 0 0; 596 | } 597 | 598 | .nvtooltip p { 599 | margin: 0; 600 | padding: 5px 14px; 601 | text-align: center; 602 | } 603 | 604 | .nvtooltip span { 605 | display: inline-block; 606 | margin: 2px 0; 607 | } 608 | 609 | .nvtooltip table { 610 | margin: 6px; 611 | border-spacing:0; 612 | } 613 | 614 | 615 | .nvtooltip table td { 616 | padding: 2px 9px 2px 0; 617 | vertical-align: middle; 618 | } 619 | 620 | .nvtooltip table td.key { 621 | font-weight: normal; 622 | } 623 | .nvtooltip table td.key.total { 624 | font-weight: bold; 625 | } 626 | .nvtooltip table td.value { 627 | text-align: right; 628 | font-weight: bold; 629 | } 630 | 631 | .nvtooltip table td.percent { 632 | color: darkgray; 633 | } 634 | 635 | .nvtooltip table tr.highlight td { 636 | padding: 1px 9px 1px 0; 637 | border-bottom-style: solid; 638 | border-bottom-width: 1px; 639 | border-top-style: solid; 640 | border-top-width: 1px; 641 | } 642 | 643 | .nvtooltip table td.legend-color-guide div { 644 | width: 8px; 645 | height: 8px; 646 | vertical-align: middle; 647 | } 648 | 649 | .nvtooltip table td.legend-color-guide div { 650 | width: 12px; 651 | height: 12px; 652 | border: 1px solid #999; 653 | } 654 | 655 | .nvtooltip .footer { 656 | padding: 3px; 657 | text-align: center; 658 | } 659 | 660 | .nvtooltip-pending-removal { 661 | pointer-events: none; 662 | display: none; 663 | } 664 | 665 | 666 | /**** 667 | Interactive Layer 668 | */ 669 | .nvd3 .nv-interactiveGuideLine { 670 | pointer-events:none; 671 | } 672 | .nvd3 line.nv-guideline { 673 | stroke: #ccc; 674 | } 675 | -------------------------------------------------------------------------------- /sfHomelessData.js: -------------------------------------------------------------------------------- 1 | var sfHomelessData = [ 2 | [new Date(2016, 6, 30, 4, 12, 23).getTime(), 0.0, 0.0, 0, "RT @bayareahomeless: A portrait gallery of homeless and low-income chefs in training. https://t.co/upmGHNAJR7 #SFHomelessProject https://t."], 3 | [new Date(2016, 6, 30, 4, 19, 36).getTime(), 0.0, 0.0, 1, "RT @bayareahomeless: A portrait gallery of homeless and low-income chefs in training. https://t.co/upmGHNAJR7 #SFHomelessProject https://t."], 4 | [new Date(2016, 6, 30, 4, 21, 58).getTime(), 0.0, 0.0, 2, "RT @bayareahomeless: A portrait gallery of homeless and low-income chefs in training. https://t.co/upmGHNAJR7 #SFHomelessProject https://t."], 5 | [new Date(2016, 6, 30, 4, 30, 21).getTime(), 0.0, 0.0, 3, "RT @bayareahomeless: A portrait gallery of homeless and low-income chefs in training. https://t.co/upmGHNAJR7 #SFHomelessProject https://t."], 6 | [new Date(2016, 6, 30, 4, 58, 39).getTime(), 0.0, 0.0, 4, "RT @bayareahomeless: A portrait gallery of homeless and low-income chefs in training. https://t.co/upmGHNAJR7 #SFHomelessProject https://t."], 7 | [new Date(2016, 6, 30, 4, 13, 35).getTime(), 0.0, 0.0, 0, "RT @Gizmodo: How should San Francisco help its homeless population? Bay Area journalists weigh in https://t.co/SXwQjmlQKC https://t.co/eUhd"], 8 | [new Date(2016, 6, 30, 4, 30, 58).getTime(), 0.0, 0.0, 1, "RT @Gizmodo: How should San Francisco help its homeless population? Bay Area journalists weigh in https://t.co/SXwQjmlQKC https://t.co/eUhd"], 9 | [new Date(2016, 6, 30, 4, 51, 56).getTime(), 0.0, 0.0, 2, "RT @Gizmodo: How should San Francisco help its homeless population? Bay Area journalists weigh in https://t.co/SXwQjmlQKC https://t.co/eUhd"], 10 | [new Date(2016, 6, 30, 4, 14, 30).getTime(), 0.0, 0.0, 0, "From homeless in San Francisco to a job in the tech industry https://t.co/fvK1zMyiXY #SFHomelessProject"], 11 | [new Date(2016, 6, 30, 4, 20, 24).getTime(), 0.0, 0.0, 1, "From homeless in San Francisco to a job in the tech industry https://t.co/fvK1zMyiXY #SFHomelessProject"], 12 | [new Date(2016, 6, 30, 5, 17, 55).getTime(), 0.0, 0.0, 2, "From homeless in San Francisco to a job in the tech industry https://t.co/fvK1zMyiXY #SFHomelessProject"], 13 | [new Date(2016, 6, 30, 4, 16, 42).getTime(), 0.0, 0.0, 0, "RT @samueldodge: These are our family members were leaving them out on the street to suffer and thats not alright! https://t.co/mq3QIsBdL"], 14 | [new Date(2016, 6, 30, 4, 18, 49).getTime(), 0.0, 0.0, 0, "Kudos to these tech companies helping! https://t.co/fvK1zMyiXY"], 15 | [new Date(2016, 6, 30, 4, 19, 12).getTime(), 0.0, 0.0, 0, "What role should media coverage play in Portlands homeless crisis? https://t.co/e5w5ZOmai2 https://t.co/xdZ09X1kKW"], 16 | [new Date(2016, 6, 30, 4, 19, 25).getTime(), 0.520833333333, 0.5, 0, "RT @invisiblepeople: #SFHomelessProject Dawns sign reads PREGNANT & STRESSED!! as she sits begging for change in San Francisco https://t"], 17 | [new Date(2016, 6, 30, 4, 27, 22).getTime(), 0.520833333333, 0.5, 1, "RT @invisiblepeople: #SFHomelessProject Dawns sign reads PREGNANT & STRESSED!! as she sits begging for change in San Francisco https://t"], 18 | [new Date(2016, 6, 30, 4, 44, 16).getTime(), 0.520833333333, 0.5, 2, "RT @invisiblepeople: #SFHomelessProject Dawns sign reads PREGNANT & STRESSED!! as she sits begging for change in San Francisco https://t"], 19 | [new Date(2016, 6, 30, 4, 50, 14).getTime(), 0.520833333333, 0.5, 3, "RT @invisiblepeople: #SFHomelessProject Dawns sign reads PREGNANT & STRESSED!! as she sits begging for change in San Francisco https://t"], 20 | [new Date(2016, 6, 30, 4, 20, 38).getTime(), 0.0, 0.0, 0, "RT @bayareahomeless: Homeless But at Home in San Francisco https://t.co/tIUvIc3YFw #SFHomelessProject https://t.co/j70eyCmglY"], 21 | [new Date(2016, 6, 30, 4, 23, 56).getTime(), 0.0, 0.0, 0, "RT @MLNow: Property of San Francisco homeless routinely disappeared by city https://t.co/uV4T1nhQsA https://t.co/YzkKqczwF6"], 22 | [new Date(2016, 6, 30, 5, 2, 29).getTime(), 0.0, 0.0, 1, "RT @MLNow: Property of San Francisco homeless routinely disappeared by city https://t.co/uV4T1nhQsA https://t.co/YzkKqczwF6"], 23 | [new Date(2016, 6, 30, 4, 24, 52).getTime(), 0.0, 0.2, 0, "Data shows San Francisco has second highest homeless population in Unite.. Related Articles: https://t.co/JfHiIVVfyz"], 24 | [new Date(2016, 6, 30, 4, 28, 46).getTime(), 0.1, 0.3, 0, "San Francisco homelessness Q&A: Frequently asked questions, answers https://t.co/EyAXjOxM79 via @demunderground #homeless"], 25 | [new Date(2016, 6, 30, 4, 30, 10).getTime(), 0.0, 0.0, 0, "A #homeless protest in 1983 San Francisco. Whats changed in the Bay? https://t.co/YDvmpaWmnF #SFHomelessProject https://t.co/WfHf3wHrq1"], 26 | [new Date(2016, 6, 30, 4, 46, 9).getTime(), 0.0, 0.0, 1, "A #homeless protest in 1983 San Francisco. Whats changed in the Bay? https://t.co/YDvmpaWmnF #SFHomelessProject https://t.co/WfHf3wHrq1"], 27 | [new Date(2016, 6, 30, 4, 53, 52).getTime(), 0.0, 0.0, 2, "A #homeless protest in 1983 San Francisco. Whats changed in the Bay? https://t.co/YDvmpaWmnF #SFHomelessProject https://t.co/WfHf3wHrq1"], 28 | [new Date(2016, 6, 30, 5, 4, 56).getTime(), 0.0, 0.0, 3, "A #homeless protest in 1983 San Francisco. Whats changed in the Bay? https://t.co/YDvmpaWmnF #SFHomelessProject https://t.co/WfHf3wHrq1"], 29 | [new Date(2016, 6, 30, 4, 31, 1).getTime(), 0.0, 0.0, 0, "Media unites to highlight San Francisco homeless crisis https://t.co/v3bdipLRXc https://t.co/BtsQL5rqSy"], 30 | [new Date(2016, 6, 30, 4, 31, 23).getTime(), 0.0, 0.0, 1, "Media unites to highlight San Francisco homeless crisis https://t.co/v3bdipLRXc https://t.co/BtsQL5rqSy"], 31 | [new Date(2016, 6, 30, 4, 32, 25).getTime(), 0.0, 0.0, 2, "Media unites to highlight San Francisco homeless crisis https://t.co/v3bdipLRXc https://t.co/BtsQL5rqSy"], 32 | [new Date(2016, 6, 30, 4, 35, 4).getTime(), 0.0, 0.0, 3, "Media unites to highlight San Francisco homeless crisis https://t.co/v3bdipLRXc https://t.co/BtsQL5rqSy"], 33 | [new Date(2016, 6, 30, 4, 35, 20).getTime(), 0.0, 0.0, 4, "Media unites to highlight San Francisco homeless crisis https://t.co/v3bdipLRXc https://t.co/BtsQL5rqSy"], 34 | [new Date(2016, 6, 30, 4, 37, 7).getTime(), 0.0, 0.0, 5, "Media unites to highlight San Francisco homeless crisis https://t.co/v3bdipLRXc https://t.co/BtsQL5rqSy"], 35 | [new Date(2016, 6, 30, 4, 37, 10).getTime(), 0.0, 0.0, 6, "Media unites to highlight San Francisco homeless crisis https://t.co/v3bdipLRXc https://t.co/BtsQL5rqSy"], 36 | [new Date(2016, 6, 30, 4, 38, 11).getTime(), 0.0, 0.0, 7, "Media unites to highlight San Francisco homeless crisis https://t.co/v3bdipLRXc https://t.co/BtsQL5rqSy"], 37 | [new Date(2016, 6, 30, 4, 38, 57).getTime(), 0.0, 0.0, 8, "Media unites to highlight San Francisco homeless crisis https://t.co/v3bdipLRXc https://t.co/BtsQL5rqSy"], 38 | [new Date(2016, 6, 30, 4, 40, 15).getTime(), 0.0, 0.0, 9, "Media unites to highlight San Francisco homeless crisis https://t.co/v3bdipLRXc https://t.co/BtsQL5rqSy"], 39 | [new Date(2016, 6, 30, 4, 43, 27).getTime(), 0.0, 0.0, 10, "Media unites to highlight San Francisco homeless crisis https://t.co/v3bdipLRXc https://t.co/BtsQL5rqSy"], 40 | [new Date(2016, 6, 30, 4, 43, 34).getTime(), 0.0, 0.0, 11, "Media unites to highlight San Francisco homeless crisis https://t.co/v3bdipLRXc https://t.co/BtsQL5rqSy"], 41 | [new Date(2016, 6, 30, 4, 44, 3).getTime(), 0.0, 0.0, 12, "Media unites to highlight San Francisco homeless crisis https://t.co/v3bdipLRXc https://t.co/BtsQL5rqSy"], 42 | [new Date(2016, 6, 30, 4, 46, 37).getTime(), 0.0, 0.0, 13, "Media unites to highlight San Francisco homeless crisis https://t.co/v3bdipLRXc https://t.co/BtsQL5rqSy"], 43 | [new Date(2016, 6, 30, 4, 46, 47).getTime(), 0.0, 0.0, 14, "Media unites to highlight San Francisco homeless crisis https://t.co/v3bdipLRXc https://t.co/BtsQL5rqSy"], 44 | [new Date(2016, 6, 30, 4, 47, 13).getTime(), 0.0, 0.0, 15, "Media unites to highlight San Francisco homeless crisis https://t.co/v3bdipLRXc https://t.co/BtsQL5rqSy"], 45 | [new Date(2016, 6, 30, 4, 48, 15).getTime(), 0.0, 0.0, 16, "Media unites to highlight San Francisco homeless crisis https://t.co/v3bdipLRXc https://t.co/BtsQL5rqSy"], 46 | [new Date(2016, 6, 30, 4, 48, 30).getTime(), 0.0, 0.0, 17, "Media unites to highlight San Francisco homeless crisis https://t.co/v3bdipLRXc https://t.co/BtsQL5rqSy"], 47 | [new Date(2016, 6, 30, 4, 49, 34).getTime(), 0.0, 0.0, 18, "Media unites to highlight San Francisco homeless crisis https://t.co/v3bdipLRXc https://t.co/BtsQL5rqSy"], 48 | [new Date(2016, 6, 30, 4, 49, 35).getTime(), 0.0, 0.0, 19, "Media unites to highlight San Francisco homeless crisis https://t.co/v3bdipLRXc https://t.co/BtsQL5rqSy"], 49 | [new Date(2016, 6, 30, 4, 50, 10).getTime(), 0.0, 0.0, 20, "Media unites to highlight San Francisco homeless crisis https://t.co/v3bdipLRXc https://t.co/BtsQL5rqSy"], 50 | [new Date(2016, 6, 30, 4, 50, 15).getTime(), 0.0, 0.0, 21, "Media unites to highlight San Francisco homeless crisis https://t.co/v3bdipLRXc https://t.co/BtsQL5rqSy"], 51 | [new Date(2016, 6, 30, 4, 50, 45).getTime(), 0.0, 0.0, 22, "Media unites to highlight San Francisco homeless crisis https://t.co/v3bdipLRXc https://t.co/BtsQL5rqSy"], 52 | [new Date(2016, 6, 30, 4, 53, 25).getTime(), 0.0, 0.0, 23, "Media unites to highlight San Francisco homeless crisis https://t.co/v3bdipLRXc https://t.co/BtsQL5rqSy"], 53 | [new Date(2016, 6, 30, 4, 56, 57).getTime(), 0.0, 0.0, 24, "Media unites to highlight San Francisco homeless crisis https://t.co/v3bdipLRXc https://t.co/BtsQL5rqSy"], 54 | [new Date(2016, 6, 30, 4, 57, 34).getTime(), 0.0, 0.0, 25, "Media unites to highlight San Francisco homeless crisis https://t.co/v3bdipLRXc https://t.co/BtsQL5rqSy"], 55 | [new Date(2016, 6, 30, 4, 57, 40).getTime(), 0.0, 0.0, 26, "Media unites to highlight San Francisco homeless crisis https://t.co/v3bdipLRXc https://t.co/BtsQL5rqSy"], 56 | [new Date(2016, 6, 30, 4, 57, 42).getTime(), 0.0, 0.0, 27, "Media unites to highlight San Francisco homeless crisis https://t.co/v3bdipLRXc https://t.co/BtsQL5rqSy"], 57 | [new Date(2016, 6, 30, 4, 58, 21).getTime(), 0.0, 0.0, 28, "Media unites to highlight San Francisco homeless crisis https://t.co/v3bdipLRXc https://t.co/BtsQL5rqSy"], 58 | [new Date(2016, 6, 30, 4, 59, 49).getTime(), 0.0, 0.0, 29, "Media unites to highlight San Francisco homeless crisis https://t.co/v3bdipLRXc https://t.co/BtsQL5rqSy"], 59 | [new Date(2016, 6, 30, 5, 0, 32).getTime(), 0.0, 0.0, 30, "Media unites to highlight San Francisco homeless crisis https://t.co/v3bdipLRXc https://t.co/BtsQL5rqSy"], 60 | [new Date(2016, 6, 30, 5, 0, 39).getTime(), 0.0, 0.0, 31, "Media unites to highlight San Francisco homeless crisis https://t.co/v3bdipLRXc https://t.co/BtsQL5rqSy"], 61 | [new Date(2016, 6, 30, 5, 1, 9).getTime(), 0.0, 0.0, 32, "Media unites to highlight San Francisco homeless crisis https://t.co/v3bdipLRXc https://t.co/BtsQL5rqSy"], 62 | [new Date(2016, 6, 30, 5, 12, 54).getTime(), 0.0, 0.0, 33, "Media unites to highlight San Francisco homeless crisis https://t.co/v3bdipLRXc https://t.co/BtsQL5rqSy"], 63 | [new Date(2016, 6, 30, 5, 19, 30).getTime(), 0.0, 0.0, 34, "Media unites to highlight San Francisco homeless crisis https://t.co/v3bdipLRXc https://t.co/BtsQL5rqSy"], 64 | [new Date(2016, 6, 30, 4, 36, 5).getTime(), 0.0, 0.0, 35, "RT @CNNMoney: Media unites to highlight San Francisco homeless crisis https://t.co/v3bdipLRXc https://t.co/BtsQL5rqSy"], 65 | [new Date(2016, 6, 30, 4, 43, 53).getTime(), 0.0, 0.0, 36, "RT @CNNMoney: Media unites to highlight San Francisco homeless crisis https://t.co/v3bdipLRXc https://t.co/BtsQL5rqSy"], 66 | [new Date(2016, 6, 30, 4, 46, 26).getTime(), 0.0, 0.0, 37, "RT @CNNMoney: Media unites to highlight San Francisco homeless crisis https://t.co/v3bdipLRXc https://t.co/BtsQL5rqSy"], 67 | [new Date(2016, 6, 30, 4, 34, 5).getTime(), 0.0, 0.0, 0, "We can learn from kids and their empathy for San Franciscos homeless - SF Gate https://t.co/nPDyy5RdUl"], 68 | [new Date(2016, 6, 30, 4, 52, 9).getTime(), 0.0, 0.0, 1, "We can learn from kids and their empathy for San Franciscos homeless - SF Gate https://t.co/nPDyy5RdUl"], 69 | [new Date(2016, 6, 30, 5, 23, 35).getTime(), 0.0, 0.0, 2, "We can learn from kids and their empathy for San Franciscos homeless - SF Gate https://t.co/nPDyy5RdUl"], 70 | [new Date(2016, 6, 30, 4, 35, 52).getTime(), 0.0, 0.0, 0, "Insecurity In The City Of Food: How San Francisco Feeds Its Homeless https://t.co/oFsNXMt4QR"], 71 | [new Date(2016, 6, 30, 4, 36, 49).getTime(), 0.0, 0.0, 0, "@CNNMoney: Media unites to highlight San Francisco homeless crisis https://t.co/wAQjbPROP5/s/Vbwi https://t.co/PGLULZ3EwM/s/4Tyd m.twitt..."], 72 | [new Date(2016, 6, 30, 4, 43, 31).getTime(), 0.5, 0.5, 0, "Media unites to highlight San Francisco homeless crisis https://t.co/b3uEmwGw63 https://t.co/sn02Q1bnji For more... https://t.co/1aurDOIpH5"], 73 | [new Date(2016, 6, 30, 4, 44, 47).getTime(), 0.0, 0.0, 0, "#XRIM #MONEY : CNNMoney : Media unites to highlight San Francisco homeless crisis https://t.co/2QHqEWYUiD) https://t.co/cpvJ5sCn0t"], 74 | [new Date(2016, 6, 30, 4, 44, 47).getTime(), 0.591666666667, 0.75, 0, "San Francisco photographer captures homeless pregnant women in beautiful portraits - SF Gate https://t.co/T52Ooa013i"], 75 | [new Date(2016, 6, 30, 4, 49, 5).getTime(), 0.591666666667, 0.75, 1, "San Francisco photographer captures homeless pregnant women in beautiful portraits - SF Gate https://t.co/T52Ooa013i"], 76 | [new Date(2016, 6, 30, 4, 45, 30).getTime(), 0.5, 0.5, 0, "This is a worthwhile initiative: The Running Club for the Homeless @backonmyfeet heads to San Francisco. https://t.co/kp5drRwKst"], 77 | [new Date(2016, 6, 30, 5, 2, 25).getTime(), 0.5, 0.5, 1, "This is a worthwhile initiative: The Running Club for the Homeless @backonmyfeet heads to San Francisco. https://t.co/kp5drRwKst"], 78 | [new Date(2016, 6, 30, 4, 47, 32).getTime(), 0.0, 0.0, 0, "Media unites to highlight San Francisco homeless crisis https://t.co/Pfgx2Di2xz via @CNNMoney"], 79 | [new Date(2016, 6, 30, 5, 12, 50).getTime(), 0.0, 0.0, 1, "Media unites to highlight San Francisco homeless crisis https://t.co/Pfgx2Di2xz via @CNNMoney"], 80 | [new Date(2016, 6, 30, 4, 48, 42).getTime(), 0.0, 0.0, 0, "A homeless moms answer: leave San Francisco https://t.co/wkLW0jwGoR"], 81 | [new Date(2016, 6, 30, 4, 48, 48).getTime(), 0.0, 0.0, 0, "Media unites to highlight San Francisco homeless crisis https://t.co/RhvF3TMMhF https://t.co/B8kuRYTkKo via CNNMoney"], 82 | [new Date(2016, 6, 30, 4, 49, 51).getTime(), 0.2, 0.2, 0, "RT @SFGate: Lava Mae delivers SFs homeless population much needed showers https://t.co/eWyDwJ2B9w #SFHomelessProject https://t.co/IsnuYiTD"], 83 | [new Date(2016, 6, 30, 4, 50, 52).getTime(), 0.0, 0.533333333333, 0, "RT @MLNow: Despite widespread sweeps Public Works only stored property of 23 homless people in 6 months https://t.co/aVntPBtfQp https://t.c"], 84 | [new Date(2016, 6, 30, 4, 52, 29).getTime(), 0.0, 0.5, 0, "@quonky Is that homeless man wearing a white magicians cape after Labor Day? Ha! Only San Francisco! How close am I?"], 85 | [new Date(2016, 6, 30, 4, 56, 8).getTime(), 0.0, 0.0, 0, "Woman whos been homeless since age 6 finds housing in San Francisco - KGO-TV https://t.co/bB3TzX05Uh"], 86 | [new Date(2016, 6, 30, 4, 56, 17).getTime(), 0.0, 0.0, 1, "Woman whos been homeless since age 6 finds housing in San Francisco - KGO-TV https://t.co/bB3TzX05Uh"], 87 | [new Date(2016, 6, 30, 5, 0, 28).getTime(), 0.78, 1.0, 0, "#SFHomelessProject Shanes story is a very candid interview on the connection between incarceration and homelessness https://t.co/O4JMYxMZPK"], 88 | [new Date(2016, 6, 30, 5, 0, 28).getTime(), 0.78, 1.0, 1, "#SFHomelessProject Shanes story is a very candid interview on the connection between incarceration and homelessness https://t.co/O4JMYxMZPK"], 89 | [new Date(2016, 6, 30, 5, 0, 52).getTime(), 0.78, 1.0, 2, "#SFHomelessProject Shanes story is a very candid interview on the connection between incarceration and homelessness https://t.co/O4JMYxMZPK"], 90 | [new Date(2016, 6, 30, 5, 0, 55).getTime(), 0.78, 1.0, 3, "#SFHomelessProject Shanes story is a very candid interview on the connection between incarceration and homelessness https://t.co/O4JMYxMZPK"], 91 | [new Date(2016, 6, 30, 5, 0, 42).getTime(), 0.0, 0.4, 0, "San Francisco media plan week of coverage on homeless crisis - Business .. Related Articles: https://t.co/6zh7PjrCgW"], 92 | [new Date(2016, 6, 30, 5, 4, 18).getTime(), 0.0, 0.0, 0, "FinancialDocCMJ: CNNMoney: Media unites to highlight San Francisco homeless crisis https://t.co/rhsSXfpJ7D https://t.co/EzYPsgOboG"], 93 | [new Date(2016, 6, 30, 5, 5, 47).getTime(), 0.0, 0.0, 0, "RT @CityLab: San Francisco homelessness looks just like it did 20 years ago https://t.co/FluLs97Q1b #cityreads #SFHomelessProject https://t"], 94 | [new Date(2016, 6, 30, 5, 8, 47).getTime(), 0.0, 0.0, 0, "Media unites to highlight San Francisco homeless crisis June 29 - CNNMoney https://t.co/1h9Gkgi7Ue"], 95 | [new Date(2016, 6, 30, 5, 11, 3).getTime(), 0.5, 0.5, 0, "RT @BuzzFeedNews: Can you make it through the night as one of the more than 6,500 homeless people in San Francisco? #SFHomelessProject http"], 96 | [new Date(2016, 6, 30, 5, 22, 13).getTime(), 0.5, 0.5, 1, "RT @BuzzFeedNews: Can you make it through the night as one of the more than 6,500 homeless people in San Francisco? #SFHomelessProject http"], 97 | [new Date(2016, 6, 30, 5, 13, 25).getTime(), 0.318181818182, 0.5, 0, "Lemergenza #homeless a #SanFrancisco: How many people live on San Francisco streets? https://t.co/ZxSjFZ5vzz #SFHomelessProject"], 98 | [new Date(2016, 6, 30, 5, 13, 30).getTime(), 0.1, 0.0, 0, "RT @MidniteMission: From homeless in San Francisco to a job in the tech industry. Founded in 1914, The Midnight Mission offers... https:"], 99 | [new Date(2016, 6, 30, 5, 25, 35).getTime(), 0.1, 0.0, 1, "RT @MidniteMission: From homeless in San Francisco to a job in the tech industry. Founded in 1914, The Midnight Mission offers... https:"], 100 | [new Date(2016, 6, 30, 5, 28, 5).getTime(), 0.0, 0.0666666666667, 0, "RT @invisiblepeople: T.J. has been homeless in San Francisco for the last three years. https://t.co/3QZHQyY291 #SFHomelessProject"], 101 | [new Date(2016, 6, 30, 5, 30, 8).getTime(), -0.1, 0.2, 0, "How mental illness factors into San Franciscos homeless population https://t.co/7Dj7dspuRb"], 102 | ] -------------------------------------------------------------------------------- /notebooks/load_data_example.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "The purpose of this notebook is to load the data into two formats:\n", 8 | "\n", 9 | "1. Full dataset (excluding rows with missing data, such as exit dates). This is the dataframe called `df`.\n", 10 | " 1. Each person's information gets combined into one row per project enrollment.\n", 11 | "2. Each person summarized as one row. This is the dataframe called `df_features`.\n", 12 | "\n", 13 | "You can examine how each sheet is loaded using the dataset loading script: `datasci-sf-homeless-project/src/data/dataset.py`\n", 14 | "\n", 15 | "The script assumes you have access to the data via Dropbox, as mentioned in the sfbrigade Slack team #datasci-homeless channel. Everyone has read access, but talk to Matt, Catherine, or Annalie if you want to be added to the shared folder. If you download the data and/or want to keep it somewhere else, just supply each `process_data_*` function with a datadir argument, e.g.:\n", 16 | "\n", 17 | "```python\n", 18 | "df_client = ds.process_data_client(datadir='/path/to/raw/csv/files/')\n", 19 | "```\n", 20 | "\n", 21 | "Notes:\n", 22 | "\n", 23 | "- One person can have multiple rows in `df`.\n", 24 | "- One person can be enrolled in multiple projects at the same time.\n", 25 | "- This notebook does not yet make use of the `Service` or `Bed Inventory` sheets.\n", 26 | "- If you save out the CSV at the end (or have it from Dropbox), you can simply load the dataset with the commands:\n", 27 | "\n", 28 | "```python\n", 29 | "filename = os.path.join(os.getenv('HOME'), 'Dropbox', 'C4SF-datasci-homeless', 'processed', 'homeless_row_per_enrollment.csv')\n", 30 | "df = pd.read_csv(filename, header=0, index_col=0, parse_dates=['Entry Date', 'Exit Date', 'Residential Move In Date'])\n", 31 | "```" 32 | ] 33 | }, 34 | { 35 | "cell_type": "code", 36 | "execution_count": 1, 37 | "metadata": { 38 | "collapsed": true 39 | }, 40 | "outputs": [], 41 | "source": [ 42 | "%matplotlib inline\n", 43 | "%config InlineBackend.figure_format='retina'\n", 44 | "%load_ext autoreload\n", 45 | "# # the \"1\" means: always reload modules marked with \"%aimport\"\n", 46 | "%autoreload 2\n", 47 | "\n", 48 | "from __future__ import absolute_import, division, print_function\n", 49 | "from matplotlib import pyplot as plt\n", 50 | "import seaborn as sns\n", 51 | "import numpy as np\n", 52 | "import pandas as pd\n", 53 | "import os, sys\n", 54 | "# from tqdm import tqdm\n", 55 | "# import warnings\n", 56 | "\n", 57 | "sns.set_context(\"poster\", font_scale=1.3)\n", 58 | "pd.set_option('display.max_columns', 100)\n", 59 | "\n", 60 | "# add the data functions to the path\n", 61 | "src_data_dir = os.path.join(os.getcwd(), os.pardir, 'src/data')\n", 62 | "sys.path.append(src_data_dir)\n", 63 | "\n", 64 | "# functions to load the data\n", 65 | "import dataset as ds" 66 | ] 67 | }, 68 | { 69 | "cell_type": "code", 70 | "execution_count": 2, 71 | "metadata": { 72 | "collapsed": false 73 | }, 74 | "outputs": [], 75 | "source": [ 76 | "# load in and process the data in separate sheets\n", 77 | "\n", 78 | "df_client = ds.process_data_client()\n", 79 | "\n", 80 | "df_enroll = ds.process_data_enrollment()\n", 81 | "# Only keep rows with entry dates starting in 2012\n", 82 | "df_enroll = df_enroll[df_enroll['Entry Date'] >= '2012']\n", 83 | "\n", 84 | "df_disability = ds.process_data_disability()\n", 85 | "\n", 86 | "df_healthins = ds.process_data_healthins()\n", 87 | "\n", 88 | "df_benefit = ds.process_data_benefit()\n", 89 | "\n", 90 | "df_income = ds.process_data_income()\n", 91 | "\n", 92 | "df_project = ds.process_data_project()\n", 93 | "\n", 94 | "df_service = ds.process_data_service()\n", 95 | "\n", 96 | "df_bedinv = ds.process_data_bedinventory()" 97 | ] 98 | }, 99 | { 100 | "cell_type": "code", 101 | "execution_count": 3, 102 | "metadata": { 103 | "collapsed": true 104 | }, 105 | "outputs": [], 106 | "source": [ 107 | "# Join the client information with enrollment information.\n", 108 | "# Inner join because we want to only keep individuals\n", 109 | "# for whom we have both client and enrollment information.\n", 110 | "df = df_client.merge(df_enroll, how='inner', left_index=True, right_index=True)\n", 111 | "\n", 112 | "# just choose the first non-cash benefit; this is too simple!\n", 113 | "# TODO: join on the exact Project ID and Date\n", 114 | "df = df.merge(df_benefit.reset_index().groupby(by=['Personal ID'])[['Non-Cash Benefit']].nth(0),\n", 115 | " how='left', left_index=True, right_index=True)\n", 116 | "\n", 117 | "df['Non-Cash Benefit'] = df['Non-Cash Benefit'].fillna('None')\n", 118 | "\n", 119 | "# add information about their disability status\n", 120 | "df = df.merge(df_disability.reset_index().groupby(by=['Personal ID'])[['Disability Type']].nth(0),\n", 121 | " how='left', left_index=True, right_index=True)\n", 122 | "\n", 123 | "df['Disability Type'] = df['Disability Type'].fillna('None')\n", 124 | "\n", 125 | "# add Project Type Code to DataFrame\n", 126 | "df = df.merge(df_project[['Project Name',\n", 127 | " 'Project Type Code',\n", 128 | " 'Address City',\n", 129 | " 'Address Postal Code',\n", 130 | " ]], left_on='Project ID', right_index=True)\n", 131 | "\n", 132 | "# sort by entry date\n", 133 | "df = df.sort_values('Entry Date')" 134 | ] 135 | }, 136 | { 137 | "cell_type": "code", 138 | "execution_count": 4, 139 | "metadata": { 140 | "collapsed": false 141 | }, 142 | "outputs": [ 143 | { 144 | "name": "stdout", 145 | "output_type": "stream", 146 | "text": [ 147 | "(63324, 32)\n", 148 | "11363\n" 149 | ] 150 | } 151 | ], 152 | "source": [ 153 | "# number of rows in the dataset\n", 154 | "print(df.shape)\n", 155 | "\n", 156 | "# number of people in the dataset\n", 157 | "print(df.index.nunique())" 158 | ] 159 | }, 160 | { 161 | "cell_type": "code", 162 | "execution_count": 5, 163 | "metadata": { 164 | "collapsed": false 165 | }, 166 | "outputs": [], 167 | "source": [ 168 | "# set up to count the number of times a person was in the system\n", 169 | "df['Enrollments'] = 1\n", 170 | "\n", 171 | "# create feature vectors for each person by subselecting or aggregating their enrollments;\n", 172 | "# one row per person\n", 173 | "agg = {\n", 174 | " 'In Permanent Housing': 'last',\n", 175 | " 'Enrollments': 'sum',\n", 176 | " 'Race': 'first',\n", 177 | " 'Ethnicity': 'first',\n", 178 | " 'Gender': 'first',\n", 179 | " 'Veteran Status': 'max',\n", 180 | " 'Client Age at Entry': 'last',\n", 181 | " 'Days Enrolled': 'sum',\n", 182 | " 'Domestic Violence Victim': 'max',\n", 183 | " 'Disability Type': 'last',\n", 184 | " 'Non-Cash Benefit': 'last',\n", 185 | " 'Housing Status @ Project Start': 'last',\n", 186 | " 'Living situation before program entry?': 'last',\n", 187 | " 'Continuously Homeless One Year': 'max',\n", 188 | " 'Chronic Homeless': 'max',\n", 189 | " 'Project Name': 'last',\n", 190 | " 'Project Type Code': 'last',\n", 191 | " }\n", 192 | "df_features = df.reset_index().groupby(by=['Personal ID']).agg(agg)\n", 193 | "\n", 194 | "# remove spaces in the variables \n", 195 | "df_features = df_features.rename(\n", 196 | " columns={\n", 197 | " 'In Permanent Housing': 'in_permanent_housing', \n", 198 | " 'Enrollments': 'enrollments',\n", 199 | " 'Race': 'race',\n", 200 | " 'Ethnicity': 'ethnicity',\n", 201 | " 'Gender': 'gender',\n", 202 | " 'Veteran Status': 'veteran_status',\n", 203 | " 'Client Age at Entry': 'client_age_at_entry',\n", 204 | " 'Days Enrolled': 'days_enrolled',\n", 205 | " 'Domestic Violence Victim': 'domestic_violence_victim',\n", 206 | " 'Disability Type': 'disability_type',\n", 207 | " 'Non-Cash Benefit': 'non_cash_benefit',\n", 208 | " 'Housing Status @ Project Start': 'housing_status_project_start',\n", 209 | " 'Living situation before program entry?': 'living_situation_before_program_entry',\n", 210 | " 'Continuously Homeless One Year': 'continuously_homeless_one_year',\n", 211 | " 'Chronic Homeless': 'chronic_homeless',\n", 212 | " 'Project Name': 'project_name',\n", 213 | " 'Project Type Code': 'project_type_code',\n", 214 | " })\n", 215 | "\n", 216 | "# convert booleans to integers\n", 217 | "cols = [\n", 218 | " 'domestic_violence_victim',\n", 219 | " 'veteran_status',\n", 220 | " 'in_permanent_housing',\n", 221 | " 'continuously_homeless_one_year',\n", 222 | " 'chronic_homeless',\n", 223 | " ]\n", 224 | "for col in cols:\n", 225 | " df_features[col] = df_features[col].astype(int)" 226 | ] 227 | }, 228 | { 229 | "cell_type": "code", 230 | "execution_count": 6, 231 | "metadata": { 232 | "collapsed": false 233 | }, 234 | "outputs": [ 235 | { 236 | "data": { 237 | "text/plain": [ 238 | "(11363, 17)" 239 | ] 240 | }, 241 | "execution_count": 6, 242 | "metadata": {}, 243 | "output_type": "execute_result" 244 | } 245 | ], 246 | "source": [ 247 | "# number of people in the dataset\n", 248 | "df_features.shape" 249 | ] 250 | }, 251 | { 252 | "cell_type": "code", 253 | "execution_count": 7, 254 | "metadata": { 255 | "collapsed": false 256 | }, 257 | "outputs": [ 258 | { 259 | "data": { 260 | "text/html": [ 261 | "
\n", 262 | "\n", 263 | " \n", 264 | " \n", 265 | " \n", 266 | " \n", 267 | " \n", 268 | " \n", 269 | " \n", 270 | " \n", 271 | " \n", 272 | " \n", 273 | " \n", 274 | " \n", 275 | " \n", 276 | " \n", 277 | " \n", 278 | " \n", 279 | " \n", 280 | " \n", 281 | " \n", 282 | " \n", 283 | " \n", 284 | " \n", 285 | " \n", 286 | " \n", 287 | " \n", 288 | " \n", 289 | " \n", 290 | " \n", 291 | " \n", 292 | " \n", 293 | " \n", 294 | " \n", 295 | " \n", 296 | " \n", 297 | " \n", 298 | " \n", 299 | " \n", 300 | " \n", 301 | " \n", 302 | " \n", 303 | " \n", 304 | " \n", 305 | " \n", 306 | " \n", 307 | " \n", 308 | " \n", 309 | " \n", 310 | " \n", 311 | " \n", 312 | " \n", 313 | " \n", 314 | " \n", 315 | " \n", 316 | " \n", 317 | " \n", 318 | " \n", 319 | " \n", 320 | " \n", 321 | " \n", 322 | " \n", 323 | " \n", 324 | " \n", 325 | " \n", 326 | " \n", 327 | " \n", 328 | " \n", 329 | " \n", 330 | " \n", 331 | " \n", 332 | " \n", 333 | " \n", 334 | " \n", 335 | " \n", 336 | " \n", 337 | " \n", 338 | " \n", 339 | " \n", 340 | " \n", 341 | " \n", 342 | " \n", 343 | " \n", 344 | " \n", 345 | " \n", 346 | " \n", 347 | " \n", 348 | " \n", 349 | " \n", 350 | " \n", 351 | " \n", 352 | " \n", 353 | " \n", 354 | " \n", 355 | " \n", 356 | " \n", 357 | " \n", 358 | " \n", 359 | " \n", 360 | " \n", 361 | " \n", 362 | " \n", 363 | " \n", 364 | " \n", 365 | " \n", 366 | " \n", 367 | " \n", 368 | " \n", 369 | " \n", 370 | " \n", 371 | " \n", 372 | " \n", 373 | " \n", 374 | " \n", 375 | " \n", 376 | " \n", 377 | " \n", 378 | " \n", 379 | " \n", 380 | " \n", 381 | " \n", 382 | " \n", 383 | " \n", 384 | " \n", 385 | " \n", 386 | " \n", 387 | " \n", 388 | " \n", 389 | " \n", 390 | " \n", 391 | " \n", 392 | " \n", 393 | " \n", 394 | " \n", 395 | " \n", 396 | " \n", 397 | " \n", 398 | " \n", 399 | " \n", 400 | " \n", 401 | " \n", 402 | " \n", 403 | " \n", 404 | " \n", 405 | " \n", 406 | " \n", 407 | "
chronic_homelessnon_cash_benefitin_permanent_housingproject_type_codeenrollmentscontinuously_homeless_one_yeardisability_typedomestic_violence_victimveteran_statusdays_enrolledraceclient_age_at_entryethnicitygenderproject_nameliving_situation_before_program_entryhousing_status_project_start
Personal ID
1737810Food Stamps0Emergency Shelter20None10147White35Hispanic/LatinoFemaleMOSBE SOP - Natividad ShelterEmergency shelter, including hotel or motel pa...Category 1 - Homeless
1737820None0Emergency Shelter11None10147White10Hispanic/LatinoMaleMOSBE SOP - Natividad ShelterEmergency shelter, including hotel or motel pa...Category 1 - Homeless
1737830None0Emergency Shelter11None10147White12Hispanic/LatinoFemaleMOSBE SOP - Natividad ShelterEmergency shelter, including hotel or motel pa...Category 1 - Homeless
1738030Food Stamps0Emergency Shelter10None1078White32Hispanic/LatinoFemaleMOSBE SOP - Natividad ShelterStaying or living in a friend's room, apartmen...Category 1 - Homeless
1738040None0Emergency Shelter10None0078White11Hispanic/LatinoFemaleMOSBE SOP - Natividad ShelterStaying or living in a friend's room, apartmen...Category 1 - Homeless
\n", 408 | "
" 409 | ], 410 | "text/plain": [ 411 | " chronic_homeless non_cash_benefit in_permanent_housing \\\n", 412 | "Personal ID \n", 413 | "173781 0 Food Stamps 0 \n", 414 | "173782 0 None 0 \n", 415 | "173783 0 None 0 \n", 416 | "173803 0 Food Stamps 0 \n", 417 | "173804 0 None 0 \n", 418 | "\n", 419 | " project_type_code enrollments continuously_homeless_one_year \\\n", 420 | "Personal ID \n", 421 | "173781 Emergency Shelter 2 0 \n", 422 | "173782 Emergency Shelter 1 1 \n", 423 | "173783 Emergency Shelter 1 1 \n", 424 | "173803 Emergency Shelter 1 0 \n", 425 | "173804 Emergency Shelter 1 0 \n", 426 | "\n", 427 | " disability_type domestic_violence_victim veteran_status \\\n", 428 | "Personal ID \n", 429 | "173781 None 1 0 \n", 430 | "173782 None 1 0 \n", 431 | "173783 None 1 0 \n", 432 | "173803 None 1 0 \n", 433 | "173804 None 0 0 \n", 434 | "\n", 435 | " days_enrolled race client_age_at_entry ethnicity \\\n", 436 | "Personal ID \n", 437 | "173781 147 White 35 Hispanic/Latino \n", 438 | "173782 147 White 10 Hispanic/Latino \n", 439 | "173783 147 White 12 Hispanic/Latino \n", 440 | "173803 78 White 32 Hispanic/Latino \n", 441 | "173804 78 White 11 Hispanic/Latino \n", 442 | "\n", 443 | " gender project_name \\\n", 444 | "Personal ID \n", 445 | "173781 Female MOSBE SOP - Natividad Shelter \n", 446 | "173782 Male MOSBE SOP - Natividad Shelter \n", 447 | "173783 Female MOSBE SOP - Natividad Shelter \n", 448 | "173803 Female MOSBE SOP - Natividad Shelter \n", 449 | "173804 Female MOSBE SOP - Natividad Shelter \n", 450 | "\n", 451 | " living_situation_before_program_entry \\\n", 452 | "Personal ID \n", 453 | "173781 Emergency shelter, including hotel or motel pa... \n", 454 | "173782 Emergency shelter, including hotel or motel pa... \n", 455 | "173783 Emergency shelter, including hotel or motel pa... \n", 456 | "173803 Staying or living in a friend's room, apartmen... \n", 457 | "173804 Staying or living in a friend's room, apartmen... \n", 458 | "\n", 459 | " housing_status_project_start \n", 460 | "Personal ID \n", 461 | "173781 Category 1 - Homeless \n", 462 | "173782 Category 1 - Homeless \n", 463 | "173783 Category 1 - Homeless \n", 464 | "173803 Category 1 - Homeless \n", 465 | "173804 Category 1 - Homeless " 466 | ] 467 | }, 468 | "execution_count": 7, 469 | "metadata": {}, 470 | "output_type": "execute_result" 471 | } 472 | ], 473 | "source": [ 474 | "# glance at the data\n", 475 | "df_features.head()" 476 | ] 477 | }, 478 | { 479 | "cell_type": "code", 480 | "execution_count": 8, 481 | "metadata": { 482 | "collapsed": true 483 | }, 484 | "outputs": [], 485 | "source": [ 486 | "# save it for easy loading\n", 487 | "filename = os.path.join(os.getenv('HOME'), 'Dropbox', 'C4SF-datasci-homeless', 'processed', 'homeless_row_per_enrollment.csv')\n", 488 | "df.to_csv(filename)" 489 | ] 490 | }, 491 | { 492 | "cell_type": "code", 493 | "execution_count": null, 494 | "metadata": { 495 | "collapsed": true 496 | }, 497 | "outputs": [], 498 | "source": [] 499 | } 500 | ], 501 | "metadata": { 502 | "kernelspec": { 503 | "display_name": "Python 3", 504 | "language": "python", 505 | "name": "python3" 506 | }, 507 | "language_info": { 508 | "codemirror_mode": { 509 | "name": "ipython", 510 | "version": 3 511 | }, 512 | "file_extension": ".py", 513 | "mimetype": "text/x-python", 514 | "name": "python", 515 | "nbconvert_exporter": "python", 516 | "pygments_lexer": "ipython3", 517 | "version": "3.5.2" 518 | }, 519 | "nav_menu": {}, 520 | "toc": { 521 | "navigate_menu": true, 522 | "number_sections": false, 523 | "sideBar": true, 524 | "threshold": 6, 525 | "toc_cell": false, 526 | "toc_section_display": "block", 527 | "toc_window_display": false 528 | } 529 | }, 530 | "nbformat": 4, 531 | "nbformat_minor": 1 532 | } 533 | --------------------------------------------------------------------------------