├── .nojekyll ├── libraries ├── frameworks │ └── bootstrap │ │ ├── js │ │ ├── main.js │ │ ├── plugins.js │ │ └── vendor │ │ │ ├── modernizr-2.6.1-respond-1.1.0.min.js │ │ │ └── bootstrap.min.js │ │ ├── robots.txt │ │ ├── layouts │ │ ├── slide.html │ │ ├── hero.html │ │ ├── special.html │ │ ├── hero2.html │ │ ├── div.html │ │ ├── scripts.html │ │ └── deck.html │ │ ├── ico │ │ ├── apple-touch-icon.png │ │ ├── apple-touch-icon-precomposed.png │ │ ├── apple-touch-icon-57x57-precomposed.png │ │ ├── apple-touch-icon-72x72-precomposed.png │ │ ├── apple-touch-icon-114x114-precomposed.png │ │ └── apple-touch-icon-144x144-precomposed.png │ │ ├── img │ │ ├── glyphicons-halflings.png │ │ └── glyphicons-halflings-white.png │ │ ├── humans.txt │ │ ├── css │ │ ├── main.css │ │ └── bootstrap-responsive.min.css │ │ ├── partials │ │ ├── footer.html │ │ ├── navbar.html │ │ └── head.html │ │ ├── 404.html │ │ └── index.html ├── widgets │ └── d3_sankey │ │ ├── config.yml │ │ ├── css │ │ └── sankey.css │ │ ├── js │ │ ├── LICENSE-d3.md │ │ └── sankey.js │ │ └── layouts │ │ └── chart.html └── highlighters │ └── prettify │ ├── prettify.html │ ├── css │ ├── twitter-bootstrap.css │ ├── desert.css │ ├── default.css │ ├── sons-of-obsidian.css │ ├── sunburst.css │ ├── hemisu-light.css │ └── tomorrow-night-bright.css │ └── js │ └── lang-r.js ├── holdings.txt ├── example_pimco.png ├── PIMCO Bond Stats.xls ├── figure ├── unnamed-chunk-2.png └── unnamed-chunk-3.png ├── assets └── fig │ ├── unnamed-chunk-3.png │ └── unnamed-chunk-5.png ├── config.yml ├── .gitattributes ├── css └── sankey.css ├── wastedfood.txt ├── example_pimco.R ├── example_rcharts_gallery.R ├── example_hirst_horse.R ├── js ├── LICENSE-d3.md └── sankey.js ├── example_hirst_f1.R ├── example_hirst_f1_2.R ├── example_pimco.Rmd ├── example_pimco.md ├── example_random_network.R ├── .gitignore ├── layouts ├── chart.html └── chart_static_title.html ├── example_build_network_sankey.Rmd ├── example.R ├── example_build_network_sankey.md └── example_build_network_sankey.html /.nojekyll: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /libraries/frameworks/bootstrap/js/main.js: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /libraries/frameworks/bootstrap/robots.txt: -------------------------------------------------------------------------------- 1 | # robotstxt.org/ 2 | 3 | User-agent: * 4 | -------------------------------------------------------------------------------- /holdings.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timelyportfolio/rCharts_d3_sankey/HEAD/holdings.txt -------------------------------------------------------------------------------- /example_pimco.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timelyportfolio/rCharts_d3_sankey/HEAD/example_pimco.png -------------------------------------------------------------------------------- /libraries/frameworks/bootstrap/layouts/slide.html: -------------------------------------------------------------------------------- 1 | {{{ slide.header }}} 2 | {{{ slide.content }}} 3 | -------------------------------------------------------------------------------- /PIMCO Bond Stats.xls: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timelyportfolio/rCharts_d3_sankey/HEAD/PIMCO Bond Stats.xls -------------------------------------------------------------------------------- /figure/unnamed-chunk-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timelyportfolio/rCharts_d3_sankey/HEAD/figure/unnamed-chunk-2.png -------------------------------------------------------------------------------- /figure/unnamed-chunk-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timelyportfolio/rCharts_d3_sankey/HEAD/figure/unnamed-chunk-3.png -------------------------------------------------------------------------------- /assets/fig/unnamed-chunk-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timelyportfolio/rCharts_d3_sankey/HEAD/assets/fig/unnamed-chunk-3.png -------------------------------------------------------------------------------- /assets/fig/unnamed-chunk-5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timelyportfolio/rCharts_d3_sankey/HEAD/assets/fig/unnamed-chunk-5.png -------------------------------------------------------------------------------- /libraries/frameworks/bootstrap/ico/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timelyportfolio/rCharts_d3_sankey/HEAD/libraries/frameworks/bootstrap/ico/apple-touch-icon.png -------------------------------------------------------------------------------- /libraries/frameworks/bootstrap/img/glyphicons-halflings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timelyportfolio/rCharts_d3_sankey/HEAD/libraries/frameworks/bootstrap/img/glyphicons-halflings.png -------------------------------------------------------------------------------- /libraries/frameworks/bootstrap/ico/apple-touch-icon-precomposed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timelyportfolio/rCharts_d3_sankey/HEAD/libraries/frameworks/bootstrap/ico/apple-touch-icon-precomposed.png -------------------------------------------------------------------------------- /libraries/frameworks/bootstrap/img/glyphicons-halflings-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timelyportfolio/rCharts_d3_sankey/HEAD/libraries/frameworks/bootstrap/img/glyphicons-halflings-white.png -------------------------------------------------------------------------------- /libraries/frameworks/bootstrap/layouts/hero.html: -------------------------------------------------------------------------------- 1 |
2 | {{{ header }}} 3 | {{{ content }}} 4 |

{{{ help }}} »

5 |
6 | -------------------------------------------------------------------------------- /libraries/frameworks/bootstrap/ico/apple-touch-icon-57x57-precomposed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timelyportfolio/rCharts_d3_sankey/HEAD/libraries/frameworks/bootstrap/ico/apple-touch-icon-57x57-precomposed.png -------------------------------------------------------------------------------- /libraries/frameworks/bootstrap/ico/apple-touch-icon-72x72-precomposed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timelyportfolio/rCharts_d3_sankey/HEAD/libraries/frameworks/bootstrap/ico/apple-touch-icon-72x72-precomposed.png -------------------------------------------------------------------------------- /libraries/frameworks/bootstrap/ico/apple-touch-icon-114x114-precomposed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timelyportfolio/rCharts_d3_sankey/HEAD/libraries/frameworks/bootstrap/ico/apple-touch-icon-114x114-precomposed.png -------------------------------------------------------------------------------- /libraries/frameworks/bootstrap/ico/apple-touch-icon-144x144-precomposed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timelyportfolio/rCharts_d3_sankey/HEAD/libraries/frameworks/bootstrap/ico/apple-touch-icon-144x144-precomposed.png -------------------------------------------------------------------------------- /libraries/frameworks/bootstrap/layouts/special.html: -------------------------------------------------------------------------------- 1 |
2 | {{{ slide.header }}} 3 |
4 | {{{ slide.content }}} 5 |
6 |
7 | {{{ slide.code.content }}} 8 |
9 |
10 | -------------------------------------------------------------------------------- /libraries/frameworks/bootstrap/humans.txt: -------------------------------------------------------------------------------- 1 | # humanstxt.org/ 2 | # The humans responsible & technology colophon 3 | 4 | # TEAM 5 | 6 | -- -- 7 | 8 | # THANKS 9 | 10 | 11 | 12 | # TECHNOLOGY COLOPHON 13 | 14 | HTML5, CSS3 15 | jQuery, Modernizr 16 | -------------------------------------------------------------------------------- /config.yml: -------------------------------------------------------------------------------- 1 | d3_horizon: 2 | css: [css/sankey.css] 3 | jshead: [js/d3.v3.js,js/sankey.js] 4 | cdn: 5 | css: 6 | - "http://timelyportfolio.github.io/rCharts_d3_sankey/css/sankey.css" 7 | jshead: 8 | - "http://d3js.org/d3.v3.min.js" 9 | - "http://timelyportfolio.github.io/rCharts_d3_sankey/js/sankey.js" 10 | -------------------------------------------------------------------------------- /libraries/frameworks/bootstrap/layouts/hero2.html: -------------------------------------------------------------------------------- 1 |
2 | {{{ header }}} 3 |
4 |
5 | {{{ content }}} 6 |
7 |
8 | {{{ video }}} 9 |
10 |
11 |

{{{ help }}} »

12 |
13 | -------------------------------------------------------------------------------- /libraries/widgets/d3_sankey/config.yml: -------------------------------------------------------------------------------- 1 | d3_horizon: 2 | css: [css/sankey.css] 3 | jshead: [js/d3.v3.js,js/sankey.js] 4 | cdn: 5 | css: 6 | - "http://timelyportfolio.github.io/rCharts_d3_sankey/css/sankey.css" 7 | jshead: 8 | - "http://d3js.org/d3.v3.min.js" 9 | - "http://timelyportfolio.github.io/rCharts_d3_sankey/js/sankey.js" 10 | -------------------------------------------------------------------------------- /libraries/frameworks/bootstrap/css/main.css: -------------------------------------------------------------------------------- 1 | 2 | 3 | /* ========================================================================== 4 | Author's custom styles 5 | ========================================================================== */ 6 | 7 | /*.container { 8 | width: 940px; 9 | }*/ 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /libraries/frameworks/bootstrap/partials/footer.html: -------------------------------------------------------------------------------- 1 |

Styled using Bootstrap. Hosted on GitHub. Icons from Font-Awesome. Web fonts from Google. Generated by Slidify

2 | -------------------------------------------------------------------------------- /libraries/frameworks/bootstrap/layouts/div.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | {{{ first }}} 4 |

View details »

5 |
6 |
7 | {{{ second }}} 8 |

View details »

9 |
10 |
11 | {{{ third }}} 12 |

View details »

13 |
14 |
15 | -------------------------------------------------------------------------------- /libraries/highlighters/prettify/prettify.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | *.sln merge=union 7 | *.csproj merge=union 8 | *.vbproj merge=union 9 | *.fsproj merge=union 10 | *.dbproj merge=union 11 | 12 | # Standard to msysgit 13 | *.doc diff=astextplain 14 | *.DOC diff=astextplain 15 | *.docx diff=astextplain 16 | *.DOCX diff=astextplain 17 | *.dot diff=astextplain 18 | *.DOT diff=astextplain 19 | *.pdf diff=astextplain 20 | *.PDF diff=astextplain 21 | *.rtf diff=astextplain 22 | *.RTF diff=astextplain 23 | -------------------------------------------------------------------------------- /css/sankey.css: -------------------------------------------------------------------------------- 1 | /* 2 | not sure original author 3 | believe I copied/pasted from 4 | http://www.d3noob.org/2013/02/sankey-diagrams-description-of-d3js-code.html 5 | but have to think original source was Mike Bostock 6 | http://bost.ocks.org/mike/sankey/ 7 | */ 8 | 9 | .node rect { 10 | cursor: move; 11 | fill-opacity: .9; 12 | shape-rendering: crispEdges; 13 | } 14 | 15 | .node text { 16 | pointer-events: none; 17 | text-shadow: 0 1px 0 #fff; 18 | } 19 | 20 | .link { 21 | fill: none; 22 | stroke: #000; 23 | stroke-opacity: .2; 24 | } 25 | 26 | .link:hover { 27 | stroke-opacity: .5; 28 | } 29 | 30 | svg { 31 | font: 10px sans-serif; 32 | } -------------------------------------------------------------------------------- /libraries/widgets/d3_sankey/css/sankey.css: -------------------------------------------------------------------------------- 1 | /* 2 | not sure original author 3 | believe I copied/pasted from 4 | http://www.d3noob.org/2013/02/sankey-diagrams-description-of-d3js-code.html 5 | but have to think original source was Mike Bostock 6 | http://bost.ocks.org/mike/sankey/ 7 | */ 8 | 9 | .node rect { 10 | cursor: move; 11 | fill-opacity: .9; 12 | shape-rendering: crispEdges; 13 | } 14 | 15 | .node text { 16 | pointer-events: none; 17 | text-shadow: 0 1px 0 #fff; 18 | } 19 | 20 | .link { 21 | fill: none; 22 | stroke: #000; 23 | stroke-opacity: .2; 24 | } 25 | 26 | .link:hover { 27 | stroke-opacity: .5; 28 | } 29 | 30 | svg { 31 | font: 10px sans-serif; 32 | } -------------------------------------------------------------------------------- /wastedfood.txt: -------------------------------------------------------------------------------- 1 | https://sustainability.water.ca.gov/documents/18/3331370/Food+Waste+and+Energy.pdf 2 | Wasted Food, Wasted Energy: The Embedded Energy in Food Waste in the United States 3 | by Amanda D. Cuellar and Micahel E. Webber 4 | 5 | foodcategory agriculture transportation foodhandling foodprocessing energylost2004 6 | grains 71.4 185 426 155 838 268 7 | vegetables 53.5 407 935 178 1580 381 8 | fruit 26.9 270 619 122 1040 234 9 | dairy 234 273 627 229 1360 436 10 | meatpoultryfish 778 284 652 238 1950 312 11 | eggs 97.1 32.0 73 27 229 72.0 12 | drybeanspeaslentils 8.89 6.5 15 5 35.6 5.67 13 | treenutspeanuts 0.33 9.8 23 8 40.9 6.50 14 | caloric sweeteners 0 137 314 115 566 173 15 | fatsoils 0 85.4 196 72 353 118 16 | -------------------------------------------------------------------------------- /libraries/frameworks/bootstrap/js/plugins.js: -------------------------------------------------------------------------------- 1 | // Avoid `console` errors in browsers that lack a console. 2 | if (!(window.console && console.log)) { 3 | (function() { 4 | var noop = function() {}; 5 | var methods = ['assert', 'clear', 'count', 'debug', 'dir', 'dirxml', 'error', 'exception', 'group', 'groupCollapsed', 'groupEnd', 'info', 'log', 'markTimeline', 'profile', 'profileEnd', 'markTimeline', 'table', 'time', 'timeEnd', 'timeStamp', 'trace', 'warn']; 6 | var length = methods.length; 7 | var console = window.console = {}; 8 | while (length--) { 9 | console[methods[length]] = noop; 10 | } 11 | }()); 12 | } 13 | 14 | // Place any jQuery/helper plugins in here. 15 | -------------------------------------------------------------------------------- /libraries/frameworks/bootstrap/layouts/scripts.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 13 | -------------------------------------------------------------------------------- /libraries/highlighters/prettify/css/twitter-bootstrap.css: -------------------------------------------------------------------------------- 1 | .com { color: #93a1a1; } 2 | .lit { color: #195f91; } 3 | .pun, .opn, .clo { color: #93a1a1; } 4 | .fun { color: #dc322f; } 5 | .str, .atv { color: #D14; } 6 | .kwd, .linenums .tag { color: #1e347b; } 7 | .typ, .atn, .dec, .var { color: teal; } 8 | .pln { color: #48484c; } 9 | 10 | .prettyprint { 11 | padding: 8px; 12 | background-color: #f7f7f9; 13 | border: 1px solid #e1e1e8; 14 | } 15 | .prettyprint.linenums { 16 | -webkit-box-shadow: inset 40px 0 0 #fbfbfc, inset 41px 0 0 #ececf0; 17 | -moz-box-shadow: inset 40px 0 0 #fbfbfc, inset 41px 0 0 #ececf0; 18 | box-shadow: inset 40px 0 0 #fbfbfc, inset 41px 0 0 #ececf0; 19 | } 20 | 21 | /* Specify class=linenums on a pre to get line numbering */ 22 | ol.linenums { 23 | margin: 0 0 0 33px; /* IE indents via margin-left */ 24 | } 25 | ol.linenums li { 26 | padding-left: 12px; 27 | color: #bebec5; 28 | line-height: 18px; 29 | text-shadow: 0 1px 0 #fff; 30 | } -------------------------------------------------------------------------------- /libraries/frameworks/bootstrap/partials/navbar.html: -------------------------------------------------------------------------------- 1 | 26 | 27 | -------------------------------------------------------------------------------- /example_pimco.R: -------------------------------------------------------------------------------- 1 | #sankey of PIMCO All Asset All Authority holdings 2 | #data source http://investments.pimco.com/ShareholderCommunications/External%20Documents/PIMCO%20Bond%20Stats.xls 3 | 4 | require(rCharts) 5 | 6 | #originally read the data from clipboard of Excel copy 7 | #for those interested here is how to do it 8 | #read.delim(file = "clipboard") 9 | 10 | holdings = read.delim("http://timelyportfolio.github.io/rCharts_d3_sankey/holdings.txt", skip = 3, header = FALSE, stringsAsFactors = FALSE) 11 | colnames(holdings) <- c("source","target","value") 12 | 13 | #get rid of holdings with 0 weight or since copy/paste from Excel - 14 | holdings <- holdings[-which(holdings$value == "-"),] 15 | holdings$value <- as.numeric(holdings$value) 16 | 17 | #now we finally have the data in the form we need 18 | sankeyPlot <- rCharts$new() 19 | sankeyPlot$setLib('http://timelyportfolio.github.io/rCharts_d3_sankey') 20 | 21 | sankeyPlot$set( 22 | data = holdings, 23 | nodeWidth = 15, 24 | nodePadding = 10, 25 | layout = 32, 26 | width = 750, 27 | height = 500, 28 | labelFormat = ".1%" 29 | ) 30 | 31 | sankeyPlot -------------------------------------------------------------------------------- /example_rcharts_gallery.R: -------------------------------------------------------------------------------- 1 | require(rCharts) 2 | require(plyr) 3 | 4 | gallery <- read.csv( 5 | "https://docs.google.com/spreadsheet/pub?key=0AovoNzJt5GetdEhQVDgyYXpJMnZ2M2J2YmtvX0I5Snc&output=csv", 6 | stringsAsFactors = FALSE 7 | ) 8 | 9 | gallery.use <- gallery[,c("technology","visualizationType","documentType","author")] 10 | colnames(gallery.use) <- rep("column",4) 11 | 12 | gallery.edge <- rbind( 13 | gallery.use[,1:2], 14 | gallery.use[,2:3], 15 | gallery.use[,3:4], 16 | deparse.level=1 17 | ) 18 | 19 | colnames(gallery.edge) <- c("source","target") 20 | 21 | gallery.edge <- ddply(gallery.edge,~source+target,nrow) 22 | 23 | colnames(gallery.edge) <- c("source","target","value") 24 | 25 | #verify that no source = target 26 | #or will get stuck in infinite loop 27 | gallery.edge[which(gallery.edge[,1]==gallery.edge[,2]),] 28 | 29 | 30 | 31 | gallery.edge$source <- as.character(gallery.edge$source) 32 | gallery.edge$target <- as.character(gallery.edge$target) 33 | sankeyPlot2 <- rCharts$new() 34 | sankeyPlot2$setLib('http://timelyportfolio.github.io/rCharts_d3_sankey/') 35 | sankeyPlot2$set( 36 | data = gallery.edge, 37 | nodeWidth = 15, 38 | nodePadding = 10, 39 | layout = 32, 40 | width = 960, 41 | height = 500 42 | ) 43 | sankeyPlot2 -------------------------------------------------------------------------------- /libraries/frameworks/bootstrap/layouts/deck.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | {{> head }} 8 | {{{ page.assets.css }}} 9 | {{{ page.assets.jshead }}} 10 | 11 | 12 | 20 | 21 | 22 |
23 | {{{ page.content }}} 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 | {{{ page.assets.js }}} 32 | {{> javascripts }} 33 | 34 | -------------------------------------------------------------------------------- /example_hirst_horse.R: -------------------------------------------------------------------------------- 1 | #http://schoolofdata.org/2013/02/20/made-to-measure-reshaping-horsemeat-importexport-data-to-fit-a-sankey-diagram/ 2 | require(reshape) 3 | horseexportsEU <- read.delim( 4 | "https://dl.dropbox.com/u/1156404/horseexportsEU.txt" 5 | ) 6 | #Get a "long" edge list from the 2d data table 7 | x=melt(horseexportsEU,id='COUNTRY') 8 | 9 | # When is what looks like a number to us not a number? 10 | #Turn the numbers into numbers by removing the comma, then casting to an integer 11 | x$value2=as.integer(as.character(gsub(",", "", x$value, fixed = TRUE) )) 12 | 13 | #More tidying... 14 | #1) If we have an NA (null/empty) value, make it -1 15 | x$value2[ is.na(x$value2) ] = -1 16 | #2) Column names with countries that originally contained spaces uses dots in place of spaces. Undo that. 17 | x$variable=gsub(".", " ", x$variable, fixed = TRUE) 18 | 19 | #I want to export a subset of the data 20 | xt=subset(x,value2>0,select=c('COUNTRY','variable','value2')) 21 | #name columns as what is expected by plugin 22 | colnames(xt) <- c("target","source","value") 23 | #need to make names in source and target different to prevent infinite loop 24 | xt$source <- paste0(xt$source,"[export]") 25 | 26 | 27 | sankeyPlot <- rCharts$new() 28 | sankeyPlot$setLib('.') 29 | sankeyPlot$setTemplate(script = "layouts/chart.html") 30 | 31 | sankeyPlot$set( 32 | data = xt, 33 | nodeWidth = 15, 34 | nodePadding = 10, 35 | layout = 32, 36 | width = 700, 37 | height = 400 38 | ) 39 | 40 | sankeyPlot 41 | -------------------------------------------------------------------------------- /js/LICENSE-d3.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013, 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 | -------------------------------------------------------------------------------- /libraries/widgets/d3_sankey/js/LICENSE-d3.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013, 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 | -------------------------------------------------------------------------------- /libraries/frameworks/bootstrap/partials/head.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | {{ page.title }} 4 | 5 | 6 | 7 | 13 | {{# page.cdn }} 14 | 16 | {{/ page.cdn }} 17 | {{^ page.cdn }} 18 | 19 | 20 | {{/ page.cdn }} 21 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /libraries/highlighters/prettify/css/desert.css: -------------------------------------------------------------------------------- 1 | /* desert scheme ported from vim to google prettify */ 2 | pre { display: block; background-color: #333 } 3 | pre .nocode { background-color: none; color: #000 } 4 | pre .str { color: #ffa0a0 } /* string - pink */ 5 | pre .kwd { color: #f0e68c; font-weight: bold } 6 | pre .com { color: #87ceeb } /* comment - skyblue */ 7 | pre .typ { color: #98fb98 } /* type - lightgreen */ 8 | pre .lit { color: #cd5c5c } /* literal - darkred */ 9 | pre .pun { color: #fff } /* punctuation */ 10 | pre .pln { color: #fff } /* plaintext */ 11 | pre .tag { color: #f0e68c; font-weight: bold } /* html/xml tag - lightyellow */ 12 | pre .atn { color: #bdb76b; font-weight: bold } /* attribute name - khaki */ 13 | pre .atv { color: #ffa0a0 } /* attribute value - pink */ 14 | pre .dec { color: #98fb98 } /* decimal - lightgreen */ 15 | 16 | /* Specify class=linenums on a pre to get line numbering */ 17 | ol.linenums { margin-top: 0; margin-bottom: 0; color: #AEAEAE } /* IE indents via margin-left */ 18 | li.L0,li.L1,li.L2,li.L3,li.L5,li.L6,li.L7,li.L8 { list-style-type: none } 19 | /* Alternate shading for lines */ 20 | li.L1,li.L3,li.L5,li.L7,li.L9 { } 21 | 22 | @media print { 23 | pre { background-color: none } 24 | pre .str, code .str { color: #060 } 25 | pre .kwd, code .kwd { color: #006; font-weight: bold } 26 | pre .com, code .com { color: #600; font-style: italic } 27 | pre .typ, code .typ { color: #404; font-weight: bold } 28 | pre .lit, code .lit { color: #044 } 29 | pre .pun, code .pun { color: #440 } 30 | pre .pln, code .pln { color: #000 } 31 | pre .tag, code .tag { color: #006; font-weight: bold } 32 | pre .atn, code .atn { color: #404 } 33 | pre .atv, code .atv { color: #060 } 34 | } 35 | -------------------------------------------------------------------------------- /libraries/highlighters/prettify/css/default.css: -------------------------------------------------------------------------------- 1 | /* Pretty printing styles. Used with prettify.js. */ 2 | 3 | /* SPAN elements with the classes below are added by prettyprint. */ 4 | .pln { color: #000 } /* plain text */ 5 | 6 | @media screen { 7 | .str { color: #080 } /* string content */ 8 | .kwd { color: #008 } /* a keyword */ 9 | .com { color: #800 } /* a comment */ 10 | .typ { color: #606 } /* a type name */ 11 | .lit { color: #066 } /* a literal value */ 12 | /* punctuation, lisp open bracket, lisp close bracket */ 13 | .pun, .opn, .clo { color: #660 } 14 | .tag { color: #008 } /* a markup tag name */ 15 | .atn { color: #606 } /* a markup attribute name */ 16 | .atv { color: #080 } /* a markup attribute value */ 17 | .dec, .var { color: #606 } /* a declaration; a variable name */ 18 | .fun { color: red } /* a function name */ 19 | } 20 | 21 | /* Use higher contrast and text-weight for printable form. */ 22 | @media print, projection { 23 | .str { color: #060 } 24 | .kwd { color: #006; font-weight: bold } 25 | .com { color: #600; font-style: italic } 26 | .typ { color: #404; font-weight: bold } 27 | .lit { color: #044 } 28 | .pun, .opn, .clo { color: #440 } 29 | .tag { color: #006; font-weight: bold } 30 | .atn { color: #404 } 31 | .atv { color: #060 } 32 | } 33 | 34 | /* Put a border around prettyprinted code snippets. */ 35 | pre.prettyprint { padding: 2px; border: 1px solid #888 } 36 | 37 | /* Specify class=linenums on a pre to get line numbering */ 38 | ol.linenums { margin-top: 0; margin-bottom: 0 } /* IE indents via margin-left */ 39 | li.L0, 40 | li.L1, 41 | li.L2, 42 | li.L3, 43 | li.L5, 44 | li.L6, 45 | li.L7, 46 | li.L8 { list-style-type: none } 47 | /* Alternate shading for lines */ 48 | li.L1, 49 | li.L3, 50 | li.L5, 51 | li.L7, 52 | li.L9 { background: #eee } 53 | -------------------------------------------------------------------------------- /example_hirst_f1.R: -------------------------------------------------------------------------------- 1 | #another one from Tony Hirst 2 | #post at http://blog.ouseful.info/2012/05/24/f1-championship-points-as-a-d3-js-powered-sankey-diagram/ 3 | #data at https://views.scraperwiki.com/run/ergast_championship_nodelist/? 4 | #get source from original example 5 | #this is a JSON, so will need to translate 6 | 7 | require(rCharts) 8 | 9 | #expect most data to come straight from R 10 | #in form of source, target, value 11 | 12 | links <- matrix(unlist( 13 | rjson::fromJSON( 14 | file = "https://views.scraperwiki.com/run/ergast_championship_nodelist/?" 15 | )$links 16 | ),ncol = 3, byrow = TRUE) 17 | 18 | nodes <- unlist( 19 | rjson::fromJSON( 20 | file = "https://views.scraperwiki.com/run/ergast_championship_nodelist/?" 21 | )$nodes 22 | ) 23 | 24 | #nodes are 2 columns but in vector form 25 | #just get the name and ignore id 26 | nodes <- nodes[seq(1,length(nodes),by=2)] 27 | 28 | #convert to data.frame so souce and target can be character and value numeric 29 | links <- data.frame(links) 30 | colnames(links) <- c("source", "target", "value") 31 | links$source <- sapply(links$source, FUN = function(x) {return(as.character(nodes[x+1]))}) #x+1 since js starts at 0 32 | links$target <- sapply(links$target, FUN = function(x) {return(nodes[x+1])}) #x+1 since js starts at 0 33 | 34 | 35 | #now we finally have the data in the form we need 36 | sankeyPlot <- rCharts$new() 37 | #can grab from web if available 38 | sankeyPlot$setLib('http://timelyportfolio.github.io/rCharts_d3_sankey') 39 | #eliminate this since rCharts will auto look for chart.html 40 | #sankeyPlot$setTemplate(script = "layouts/chart.html") 41 | 42 | sankeyPlot$set( 43 | data = links, 44 | nodeWidth = 15, 45 | nodePadding = 10, 46 | layout = 32, 47 | width = 700, 48 | height = 400, 49 | units = "points" 50 | ) 51 | 52 | sankeyPlot 53 | -------------------------------------------------------------------------------- /example_hirst_f1_2.R: -------------------------------------------------------------------------------- 1 | #another one from Tony Hirst 2 | #post at http://blog.ouseful.info/2012/05/24/f1-championship-points-as-a-d3-js-powered-sankey-diagram/ 3 | #data at https://views.scraperwiki.com/run/ergast_championship_nodelist/? 4 | #get source from original example 5 | #this is a JSON, so will need to translate 6 | 7 | require(rCharts) 8 | 9 | #expect most data to come straight from R 10 | #in form of source, target, value 11 | 12 | links <- matrix(unlist( 13 | rjson::fromJSON( 14 | file = "https://views.scraperwiki.com/run/ergast_championship_nodelist/?" 15 | )$links 16 | ),ncol = 3, byrow = TRUE) 17 | 18 | nodes <- unlist( 19 | rjson::fromJSON( 20 | file = "https://views.scraperwiki.com/run/ergast_championship_nodelist/?" 21 | )$nodes 22 | ) 23 | 24 | #nodes are 2 columns but in vector form 25 | #just get the name and ignore id 26 | nodes <- nodes[seq(1,length(nodes),by=2)] 27 | 28 | #convert to data.frame so souce and target can be character and value numeric 29 | links <- data.frame(links) 30 | colnames(links) <- c("source", "target", "value") 31 | links$source <- sapply(links$source, FUN = function(x) {return(as.character(nodes[x+1]))}) #x+1 since js starts at 0 32 | links$target <- sapply(links$target, FUN = function(x) {return(nodes[x+1])}) #x+1 since js starts at 0 33 | 34 | 35 | #now we finally have the data in the form we need 36 | sankeyPlot <- rCharts$new() 37 | #can grab from web if available 38 | sankeyPlot$setLib('http://timelyportfolio.github.io/rCharts_d3_sankey') 39 | #explicitly specify this since chart.html is default 40 | sankeyPlot$setTemplate(script = "layouts/chart_static_title.html") 41 | sankeyPlot$set( 42 | data = links, 43 | nodeWidth = 15, 44 | nodePadding = 10, 45 | layout = 32, 46 | width = 700, 47 | height = 400, 48 | units = "points", 49 | margin = list(right = 20, left = 20, bottom = 50, top = 20) 50 | ) 51 | sankeyPlot 52 | -------------------------------------------------------------------------------- /example_pimco.Rmd: -------------------------------------------------------------------------------- 1 | ```{r results = "asis"} 2 | #sankey of PIMCO All Asset All Authority holdings 3 | #data source http://investments.pimco.com/ShareholderCommunications/External%20Documents/PIMCO%20Bond%20Stats.xls 4 | 5 | require(rCharts) 6 | 7 | #originally read the data from clipboard of Excel copy 8 | #for those interested here is how to do it 9 | #read.delim(file = "clipboard") 10 | 11 | require(rCharts) 12 | 13 | #originally read the data from clipboard of Excel copy 14 | #for those interested here is how to do it 15 | #read.delim(file = "clipboard") 16 | 17 | holdings = read.delim("http://timelyportfolio.github.io/rCharts_d3_sankey/holdings.txt", skip = 3, header = FALSE, stringsAsFactors = FALSE) 18 | colnames(holdings) <- c("source","target","value") 19 | 20 | #get rid of holdings with 0 weight or since copy/paste from Excel - 21 | holdings <- holdings[-which(holdings$value == "-"),] 22 | holdings$value <- as.numeric(holdings$value) 23 | 24 | #now we finally have the data in the form we need 25 | sankeyPlot <- rCharts$new() 26 | sankeyPlot$setLib('http://timelyportfolio.github.io/rCharts_d3_sankey') 27 | 28 | sankeyPlot$set( 29 | data = holdings, 30 | nodeWidth = 15, 31 | nodePadding = 10, 32 | layout = 32, 33 | width = 750, 34 | height = 500, 35 | labelFormat = ".1%" 36 | ) 37 | 38 | sankeyPlot 39 | ``` 40 | ```{r fig.width = 20, fig.heigth = 15} 41 | require(igraph) 42 | require(RColorBrewer) 43 | g <- graph.data.frame(holdings) 44 | V(g)$color = brewer.pal("PuBuGn", n=9)[as.numeric(factor(holdings$source))] 45 | plot(g, vertex.color = V(g)$color) 46 | ``` 47 | 48 | ```{r} 49 | #get holdings ready for a bar chart 50 | 51 | holdings.bar <- holdings[-which(holdings$source=="All Asset All Authority"),] 52 | holdings.bar$source <- factor(holdings.bar$source) 53 | holdings.bar$target <- factor(holdings.bar$target, levels = holdings.bar$target, ordered = TRUE) 54 | require(ggplot2) 55 | 56 | ggplot(data=holdings.bar, aes(x=target, y=value, fill=source)) + geom_bar(stat="identity", position=position_dodge()) + coord_flip() 57 | 58 | ``` -------------------------------------------------------------------------------- /libraries/highlighters/prettify/css/sons-of-obsidian.css: -------------------------------------------------------------------------------- 1 | /* 2 | * Derived from einaros's Sons of Obsidian theme at 3 | * http://studiostyl.es/schemes/son-of-obsidian by 4 | * Alex Ford of CodeTunnel: 5 | * http://CodeTunnel.com/blog/post/71/google-code-prettify-obsidian-theme 6 | */ 7 | 8 | .str 9 | { 10 | color: #EC7600; 11 | } 12 | .kwd 13 | { 14 | color: #93C763; 15 | } 16 | .com 17 | { 18 | color: #66747B; 19 | } 20 | .typ 21 | { 22 | color: #678CB1; 23 | } 24 | .lit 25 | { 26 | color: #FACD22; 27 | } 28 | .pun 29 | { 30 | color: #F1F2F3; 31 | } 32 | .pln 33 | { 34 | color: #F1F2F3; 35 | } 36 | .tag 37 | { 38 | color: #8AC763; 39 | } 40 | .atn 41 | { 42 | color: #E0E2E4; 43 | } 44 | .atv 45 | { 46 | color: #EC7600; 47 | } 48 | .dec 49 | { 50 | color: purple; 51 | } 52 | pre.prettyprint 53 | { 54 | border: 0px solid #888; 55 | } 56 | ol.linenums 57 | { 58 | margin-top: 0; 59 | margin-bottom: 0; 60 | } 61 | .prettyprint { 62 | background: #000; 63 | } 64 | li.L0, li.L1, li.L2, li.L3, li.L4, li.L5, li.L6, li.L7, li.L8, li.L9 65 | { 66 | color: #555; 67 | } 68 | li.L1, li.L3, li.L5, li.L7, li.L9 { 69 | background: #111; 70 | } 71 | @media print 72 | { 73 | .str 74 | { 75 | color: #060; 76 | } 77 | .kwd 78 | { 79 | color: #006; 80 | font-weight: bold; 81 | } 82 | .com 83 | { 84 | color: #600; 85 | font-style: italic; 86 | } 87 | .typ 88 | { 89 | color: #404; 90 | font-weight: bold; 91 | } 92 | .lit 93 | { 94 | color: #044; 95 | } 96 | .pun 97 | { 98 | color: #440; 99 | } 100 | .pln 101 | { 102 | color: #000; 103 | } 104 | .tag 105 | { 106 | color: #006; 107 | font-weight: bold; 108 | } 109 | .atn 110 | { 111 | color: #404; 112 | } 113 | .atv 114 | { 115 | color: #060; 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /libraries/highlighters/prettify/css/sunburst.css: -------------------------------------------------------------------------------- 1 | /* Pretty printing styles. Used with prettify.js. */ 2 | /* Vim sunburst theme by David Leibovic */ 3 | 4 | pre .str, code .str { color: #65B042; } /* string - green */ 5 | pre .kwd, code .kwd { color: #E28964; } /* keyword - dark pink */ 6 | pre .com, code .com { color: #AEAEAE; font-style: italic; } /* comment - gray */ 7 | pre .typ, code .typ { color: #89bdff; } /* type - light blue */ 8 | pre .lit, code .lit { color: #3387CC; } /* literal - blue */ 9 | pre .pun, code .pun { color: #fff; } /* punctuation - white */ 10 | pre .pln, code .pln { color: #fff; } /* plaintext - white */ 11 | pre .tag, code .tag { color: #89bdff; } /* html/xml tag - light blue */ 12 | pre .atn, code .atn { color: #bdb76b; } /* html/xml attribute name - khaki */ 13 | pre .atv, code .atv { color: #65B042; } /* html/xml attribute value - green */ 14 | pre .dec, code .dec { color: #3387CC; } /* decimal - blue */ 15 | 16 | pre.prettyprint, code.prettyprint { 17 |  background-color: #000; 18 |  -moz-border-radius: 8px; 19 |  -webkit-border-radius: 8px; 20 |  -o-border-radius: 8px; 21 |  -ms-border-radius: 8px; 22 |  -khtml-border-radius: 8px; 23 |  border-radius: 8px; 24 | } 25 | 26 | pre.prettyprint { 27 |  width: 95%; 28 |  margin: 1em auto; 29 |  padding: 1em; 30 |  white-space: pre-wrap; 31 | } 32 | 33 | 34 | /* Specify class=linenums on a pre to get line numbering */ 35 | ol.linenums { margin-top: 0; margin-bottom: 0; color: #AEAEAE; } /* IE indents via margin-left */ 36 | li.L0,li.L1,li.L2,li.L3,li.L5,li.L6,li.L7,li.L8 { list-style-type: none } 37 | /* Alternate shading for lines */ 38 | li.L1,li.L3,li.L5,li.L7,li.L9 { } 39 | 40 | @media print { 41 | pre .str, code .str { color: #060; } 42 | pre .kwd, code .kwd { color: #006; font-weight: bold; } 43 | pre .com, code .com { color: #600; font-style: italic; } 44 | pre .typ, code .typ { color: #404; font-weight: bold; } 45 | pre .lit, code .lit { color: #044; } 46 | pre .pun, code .pun { color: #440; } 47 | pre .pln, code .pln { color: #000; } 48 | pre .tag, code .tag { color: #006; font-weight: bold; } 49 | pre .atn, code .atn { color: #404; } 50 | pre .atv, code .atv { color: #060; } 51 | } 52 | -------------------------------------------------------------------------------- /example_pimco.md: -------------------------------------------------------------------------------- 1 | 2 | ```r 3 | # sankey of PIMCO All Asset All Authority holdings data source 4 | # http://investments.pimco.com/ShareholderCommunications/External%20Documents/PIMCO%20Bond%20Stats.xls 5 | 6 | require(rCharts) 7 | ``` 8 | 9 | ``` 10 | ## Loading required package: rCharts 11 | ``` 12 | 13 | ```r 14 | 15 | # originally read the data from clipboard of Excel copy for those 16 | # interested here is how to do it read.delim(file = 'clipboard') 17 | 18 | holdings = read.delim("holdings.txt", skip = 3, header = FALSE, stringsAsFactors = FALSE) 19 | colnames(holdings) <- c("source", "target", "value") 20 | 21 | # get rid of holdings with 0 weight or since copy/paste from Excel - 22 | holdings <- holdings[-which(holdings$value == "-"), ] 23 | holdings$value <- as.numeric(holdings$value) 24 | 25 | # now we finally have the data in the form we need 26 | sankeyPlot <- rCharts$new() 27 | sankeyPlot$setLib(".") 28 | sankeyPlot$setTemplate(script = "layouts/chart.html") 29 | 30 | sankeyPlot$set(data = holdings, nodeWidth = 15, nodePadding = 10, layout = 32, 31 | width = 750, height = 500, labelFormat = ".1%") 32 | 33 | sankeyPlot 34 | ``` 35 | 36 | 37 | ```r 38 | require(igraph) 39 | ``` 40 | 41 | ``` 42 | ## Loading required package: igraph 43 | ``` 44 | 45 | ```r 46 | require(RColorBrewer) 47 | ``` 48 | 49 | ``` 50 | ## Loading required package: RColorBrewer 51 | ``` 52 | 53 | ```r 54 | g <- graph.data.frame(holdings) 55 | V(g)$color = brewer.pal("PuBuGn", n = 9)[as.numeric(factor(holdings$source))] 56 | ``` 57 | 58 | ``` 59 | ## Warning: number of items to replace is not a multiple of replacement 60 | ## length 61 | ``` 62 | 63 | ```r 64 | plot(g, vertex.color = V(g)$color) 65 | ``` 66 | 67 | ![plot of chunk unnamed-chunk-2](figure/unnamed-chunk-2.png) 68 | 69 | 70 | 71 | ```r 72 | # get holdings ready for a bar chart 73 | 74 | holdings.bar <- holdings[-which(holdings$source == "All Asset All Authority"), 75 | ] 76 | holdings.bar$source <- factor(holdings.bar$source) 77 | holdings.bar$target <- factor(holdings.bar$target, levels = holdings.bar$target, 78 | ordered = TRUE) 79 | require(ggplot2) 80 | ``` 81 | 82 | ``` 83 | ## Loading required package: ggplot2 84 | ``` 85 | 86 | ```r 87 | 88 | ggplot(data = holdings.bar, aes(x = target, y = value, fill = source)) + geom_bar(stat = "identity", 89 | position = position_dodge()) + coord_flip() 90 | ``` 91 | 92 | ![plot of chunk unnamed-chunk-3](figure/unnamed-chunk-3.png) 93 | 94 | -------------------------------------------------------------------------------- /libraries/highlighters/prettify/js/lang-r.js: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2012 Jeffrey B. Arnold 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | 16 | /** 17 | * @fileoverview 18 | * Registers a language handler for S, S-plus, and R source code. 19 | * 20 | * 21 | * To use, include prettify.js and this file in your HTML page. 22 | * Then put your code in an HTML tag like 23 | *
 code 
24 | * 25 | * Language definition from 26 | * http://cran.r-project.org/doc/manuals/R-lang.html. 27 | * Many of the regexes are shared with the pygments SLexer, 28 | * http://pygments.org/. 29 | * 30 | * @author jeffrey.arnold@gmail.com 31 | */ 32 | PR['registerLangHandler']( 33 | PR['createSimpleLexer']( 34 | [ 35 | [PR['PR_PLAIN'], /^[\t\n\r \xA0]+/, null, '\t\n\r \xA0'], 36 | [PR['PR_STRING'], /^\"(?:[^\"\\]|\\[\s\S])*(?:\"|$)/, null, '"'], 37 | [PR['PR_STRING'], /^\'(?:[^\'\\]|\\[\s\S])*(?:\'|$)/, null, "'"] 38 | ], 39 | [ 40 | [PR['PR_COMMENT'], /^#.*/], 41 | [PR['PR_KEYWORD'], /^(?:if|else|for|while|repeat|in|next|break|return|switch|function)(?![A-Za-z0-9_.])/], 42 | // hex numbes 43 | [PR['PR_LITERAL'], /^0[xX][a-fA-F0-9]+([pP][0-9]+)?[Li]?/], 44 | // Decimal numbers 45 | [PR['PR_LITERAL'], /^[+-]?([0-9]+(\.[0-9]+)?|\.[0-9]+)([eE][+-]?[0-9]+)?[Li]?/], 46 | // builtin symbols 47 | [PR['PR_LITERAL'], /^(?:NULL|NA(?:_(?:integer|real|complex|character)_)?|Inf|TRUE|FALSE|NaN|\.\.(?:\.|[0-9]+))(?![A-Za-z0-9_.])/], 48 | // assignment, operators, and parens, etc. 49 | [PR['PR_PUNCTUATION'], /^(?:<>?|-|==|<=|>=|<|>|&&?|!=|\|\|?|\*|\+|\^|\/|!|%.*?%|=|~|\$|@|:{1,3}|[\[\](){};,?])/], 50 | // valid variable names 51 | [PR['PR_PLAIN'], /^(?:[A-Za-z]+[A-Za-z0-9_.]*|\.[a-zA-Z_][0-9a-zA-Z\._]*)(?![A-Za-z0-9_.])/], 52 | // string backtick 53 | [PR['PR_STRING'], /^`.+`/] 54 | ]), 55 | ['r', 's', 'R', 'S', 'Splus']); 56 | -------------------------------------------------------------------------------- /libraries/highlighters/prettify/css/hemisu-light.css: -------------------------------------------------------------------------------- 1 | /* Hemisu Light */ 2 | /* Original theme - http://noahfrederick.com/vim-color-scheme-hemisu/ */ 3 | /* Pretty printing styles. Used with prettify.js. */ 4 | /* SPAN elements with the classes below are added by prettyprint. */ 5 | /* plain text */ 6 | .pln { 7 | color: #111111; } 8 | 9 | @media screen { 10 | /* string content */ 11 | .str { 12 | color: #739200; } 13 | 14 | /* a keyword */ 15 | .kwd { 16 | color: #739200; } 17 | 18 | /* a comment */ 19 | .com { 20 | color: #999999; } 21 | 22 | /* a type name */ 23 | .typ { 24 | color: #ff0055; } 25 | 26 | /* a literal value */ 27 | .lit { 28 | color: #538192; } 29 | 30 | /* punctuation */ 31 | .pun { 32 | color: #111111; } 33 | 34 | /* lisp open bracket */ 35 | .opn { 36 | color: #111111; } 37 | 38 | /* lisp close bracket */ 39 | .clo { 40 | color: #111111; } 41 | 42 | /* a markup tag name */ 43 | .tag { 44 | color: #111111; } 45 | 46 | /* a markup attribute name */ 47 | .atn { 48 | color: #739200; } 49 | 50 | /* a markup attribute value */ 51 | .atv { 52 | color: #ff0055; } 53 | 54 | /* a declaration */ 55 | .dec { 56 | color: #111111; } 57 | 58 | /* a variable name */ 59 | .var { 60 | color: #111111; } 61 | 62 | /* a function name */ 63 | .fun { 64 | color: #538192; } } 65 | /* Use higher contrast and text-weight for printable form. */ 66 | @media print, projection { 67 | .str { 68 | color: #060; } 69 | 70 | .kwd { 71 | color: #006; 72 | font-weight: bold; } 73 | 74 | .com { 75 | color: #600; 76 | font-style: italic; } 77 | 78 | .typ { 79 | color: #404; 80 | font-weight: bold; } 81 | 82 | .lit { 83 | color: #044; } 84 | 85 | .pun, .opn, .clo { 86 | color: #440; } 87 | 88 | .tag { 89 | color: #006; 90 | font-weight: bold; } 91 | 92 | .atn { 93 | color: #404; } 94 | 95 | .atv { 96 | color: #060; } } 97 | /* Style */ 98 | pre.prettyprint { 99 | background: white; 100 | font-family: Menlo, Monaco, Consolas, monospace; 101 | /* font-size: 12px;*/ 102 | line-height: 1.5; 103 | border: 1px solid #ccc; 104 | padding: 10px; 105 | } 106 | 107 | /* Specify class=linenums on a pre to get line numbering */ 108 | ol.linenums { 109 | margin-top: 0; 110 | margin-bottom: 0; } 111 | 112 | /* IE indents via margin-left */ 113 | li.L0, 114 | li.L1, 115 | li.L2, 116 | li.L3, 117 | li.L4, 118 | li.L5, 119 | li.L6, 120 | li.L7, 121 | li.L8, 122 | li.L9 { 123 | /* */ } 124 | 125 | /* Alternate shading for lines */ 126 | li.L1, 127 | li.L3, 128 | li.L5, 129 | li.L7, 130 | li.L9 { 131 | /* */ } -------------------------------------------------------------------------------- /libraries/highlighters/prettify/css/tomorrow-night-bright.css: -------------------------------------------------------------------------------- 1 | /* Tomorrow Night Blue Theme */ 2 | /* Original theme - https://github.com/chriskempson/tomorrow-theme */ 3 | /* Pretty printing styles. Used with prettify.js. */ 4 | /* SPAN elements with the classes below are added by prettyprint. */ 5 | /* plain text */ 6 | .pln { 7 | color: #eaeaea; } 8 | 9 | @media screen { 10 | /* string content */ 11 | .str { 12 | color: #b9ca4a; } 13 | 14 | /* a keyword */ 15 | .kwd { 16 | color: #c397d8; } 17 | 18 | /* a comment */ 19 | .com { 20 | color: #969896; } 21 | 22 | /* a type name */ 23 | .typ { 24 | color: #7aa6da; } 25 | 26 | /* a literal value */ 27 | .lit { 28 | color: #e78c45; } 29 | 30 | /* punctuation */ 31 | .pun { 32 | color: #eaeaea; } 33 | 34 | /* lisp open bracket */ 35 | .opn { 36 | color: #eaeaea; } 37 | 38 | /* lisp close bracket */ 39 | .clo { 40 | color: #eaeaea; } 41 | 42 | /* a markup tag name */ 43 | .tag { 44 | color: #d54e53; } 45 | 46 | /* a markup attribute name */ 47 | .atn { 48 | color: #e78c45; } 49 | 50 | /* a markup attribute value */ 51 | .atv { 52 | color: #70c0b1; } 53 | 54 | /* a declaration */ 55 | .dec { 56 | color: #e78c45; } 57 | 58 | /* a variable name */ 59 | .var { 60 | color: #d54e53; } 61 | 62 | /* a function name */ 63 | .fun { 64 | color: #7aa6da; } } 65 | /* Use higher contrast and text-weight for printable form. */ 66 | @media print, projection { 67 | .str { 68 | color: #060; } 69 | 70 | .kwd { 71 | color: #006; 72 | font-weight: bold; } 73 | 74 | .com { 75 | color: #600; 76 | font-style: italic; } 77 | 78 | .typ { 79 | color: #404; 80 | font-weight: bold; } 81 | 82 | .lit { 83 | color: #044; } 84 | 85 | .pun, .opn, .clo { 86 | color: #440; } 87 | 88 | .tag { 89 | color: #006; 90 | font-weight: bold; } 91 | 92 | .atn { 93 | color: #404; } 94 | 95 | .atv { 96 | color: #060; } } 97 | /* Style */ 98 | pre.prettyprint { 99 | background: black; 100 | font-family: Menlo, Monaco, Consolas, monospace; 101 | font-size: 12px; 102 | line-height: 1.5; 103 | border: 1px solid #ccc; 104 | padding: 10px; } 105 | 106 | /* Specify class=linenums on a pre to get line numbering */ 107 | ol.linenums { 108 | margin-top: 0; 109 | margin-bottom: 0; } 110 | 111 | /* IE indents via margin-left */ 112 | li.L0, 113 | li.L1, 114 | li.L2, 115 | li.L3, 116 | li.L4, 117 | li.L5, 118 | li.L6, 119 | li.L7, 120 | li.L8, 121 | li.L9 { 122 | /* */ } 123 | 124 | /* Alternate shading for lines */ 125 | li.L1, 126 | li.L3, 127 | li.L5, 128 | li.L7, 129 | li.L9 { 130 | /* */ } -------------------------------------------------------------------------------- /example_random_network.R: -------------------------------------------------------------------------------- 1 | #walk through the steps of creating a tree network for a sankey 2 | #and assigning random weights to the base vertices(out degree = 1) 3 | #and then summing so each edge weight is properly defined 4 | #great exercise to learn the construction of a sankey 5 | #and the conditions for a network to be drawn properly by sankey 6 | 7 | #then plot our network with the rCharts implementation of d3.js sankey plugin 8 | 9 | require(igraph) 10 | require(rCharts) 11 | 12 | 13 | g2 <- graph.tree(40,children=4) 14 | #to construct a sankey the weight of each vertex should be the sum 15 | #of its outgoing edges 16 | #I believe the first step in creating a network that satisfies this condition 17 | #is define a vertex weight for all vertexes with out degree = 0 18 | #but first let's define 0 for all 19 | V(g2)$weight = 0 20 | #now for all vertexes with out degree = 0 21 | V(g2)[degree(g2,mode="out")==0]$weight <- runif(n=length(V(g2)[degree(g2,mode="out")==0]),min=0,max=100) 22 | #the lowest level of the heirarchy is defined with a random weight 23 | #with the lowest level defined we should now be able to sum the vertex weights 24 | #to define the edge weight 25 | #E(g2)$weight = 0.1 #define all weights small to visually see as we build sankey 26 | E(g2)[to(V(g2)$weight>0)]$weight <- V(g2)[V(g2)$weight>0]$weight 27 | #and to find the neighbors to the 0 out degree vertex 28 | #we could do V(g2)[nei(degree(g2,mode="out")==0)] 29 | #we have everything we need to build the rest by summing 30 | #these edge weights if there are edges still undefined 31 | #so set up a loop to run until all edges have a defined weight 32 | while(max(is.na(E(g2)$weight))) { 33 | #get.data.frame gives us from, to, and weight 34 | #we will get this to make an easier reference later 35 | df <- get.data.frame(g2) 36 | #now go through each edge and find the sum of all its subedges 37 | #we need to check to make sure out degree of its "to" vertex is not 0 38 | #or we will get 0 since there are no edges for vertex with out degree 0 39 | for (i in 1:nrow(df)) { 40 | x = df[i,] 41 | #sum only those with out degree > 0 or sum will be 0 42 | if(max(df$from==x$to)) { 43 | E(g2)[from(x$from) & to(x$to)]$weight = sum(E(g2)[from(x$to)]$weight) 44 | } 45 | } 46 | } 47 | 48 | 49 | #just a quick check on the adjacency 50 | get.adjacency(g2,sparse = FALSE,attr="weight") 51 | 52 | 53 | 54 | 55 | #E(g2)$weight <- runif(length(E(g2))) 56 | edgelistWeight <- get.data.frame(g2) 57 | colnames(edgelistWeight) <- c("source","target","value") 58 | edgelistWeight$source <- as.character(edgelistWeight$source) 59 | edgelistWeight$target <- as.character(edgelistWeight$target) 60 | 61 | sankeyPlot2 <- rCharts$new() 62 | sankeyPlot2$setLib('.') 63 | sankeyPlot2$setTemplate(script = "layouts/chart.html") 64 | 65 | sankeyPlot2$set( 66 | data = edgelistWeight, 67 | nodeWidth = 15, 68 | nodePadding = 10, 69 | layout = 32, 70 | width = 960, 71 | height = 500 72 | ) 73 | 74 | sankeyPlot2 75 | 76 | 77 | #now for fun, let's plot the network with igraph 78 | plot(g2) -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ################# 2 | ## Eclipse 3 | ################# 4 | 5 | *.pydevproject 6 | .project 7 | .metadata 8 | bin/ 9 | tmp/ 10 | *.tmp 11 | *.bak 12 | *.swp 13 | *~.nib 14 | local.properties 15 | .classpath 16 | .settings/ 17 | .loadpath 18 | 19 | # External tool builders 20 | .externalToolBuilders/ 21 | 22 | # Locally stored "Eclipse launch configurations" 23 | *.launch 24 | 25 | # CDT-specific 26 | .cproject 27 | 28 | # PDT-specific 29 | .buildpath 30 | 31 | 32 | ################# 33 | ## Visual Studio 34 | ################# 35 | 36 | ## Ignore Visual Studio temporary files, build results, and 37 | ## files generated by popular Visual Studio add-ons. 38 | 39 | # User-specific files 40 | *.suo 41 | *.user 42 | *.sln.docstates 43 | 44 | # Build results 45 | 46 | [Dd]ebug/ 47 | [Rr]elease/ 48 | x64/ 49 | build/ 50 | [Bb]in/ 51 | [Oo]bj/ 52 | 53 | # MSTest test Results 54 | [Tt]est[Rr]esult*/ 55 | [Bb]uild[Ll]og.* 56 | 57 | *_i.c 58 | *_p.c 59 | *.ilk 60 | *.meta 61 | *.obj 62 | *.pch 63 | *.pdb 64 | *.pgc 65 | *.pgd 66 | *.rsp 67 | *.sbr 68 | *.tlb 69 | *.tli 70 | *.tlh 71 | *.tmp 72 | *.tmp_proj 73 | *.log 74 | *.vspscc 75 | *.vssscc 76 | .builds 77 | *.pidb 78 | *.log 79 | *.scc 80 | 81 | # Visual C++ cache files 82 | ipch/ 83 | *.aps 84 | *.ncb 85 | *.opensdf 86 | *.sdf 87 | *.cachefile 88 | 89 | # Visual Studio profiler 90 | *.psess 91 | *.vsp 92 | *.vspx 93 | 94 | # Guidance Automation Toolkit 95 | *.gpState 96 | 97 | # ReSharper is a .NET coding add-in 98 | _ReSharper*/ 99 | *.[Rr]e[Ss]harper 100 | 101 | # TeamCity is a build add-in 102 | _TeamCity* 103 | 104 | # DotCover is a Code Coverage Tool 105 | *.dotCover 106 | 107 | # NCrunch 108 | *.ncrunch* 109 | .*crunch*.local.xml 110 | 111 | # Installshield output folder 112 | [Ee]xpress/ 113 | 114 | # DocProject is a documentation generator add-in 115 | DocProject/buildhelp/ 116 | DocProject/Help/*.HxT 117 | DocProject/Help/*.HxC 118 | DocProject/Help/*.hhc 119 | DocProject/Help/*.hhk 120 | DocProject/Help/*.hhp 121 | DocProject/Help/Html2 122 | DocProject/Help/html 123 | 124 | # Click-Once directory 125 | publish/ 126 | 127 | # Publish Web Output 128 | *.Publish.xml 129 | *.pubxml 130 | 131 | # NuGet Packages Directory 132 | ## TODO: If you have NuGet Package Restore enabled, uncomment the next line 133 | #packages/ 134 | 135 | # Windows Azure Build Output 136 | csx 137 | *.build.csdef 138 | 139 | # Windows Store app package directory 140 | AppPackages/ 141 | 142 | # Others 143 | sql/ 144 | *.Cache 145 | ClientBin/ 146 | [Ss]tyle[Cc]op.* 147 | ~$* 148 | *~ 149 | *.dbmdl 150 | *.[Pp]ublish.xml 151 | *.pfx 152 | *.publishsettings 153 | 154 | # RIA/Silverlight projects 155 | Generated_Code/ 156 | 157 | # Backup & report files from converting an old project file to a newer 158 | # Visual Studio version. Backup files are not needed, because we have git ;-) 159 | _UpgradeReport_Files/ 160 | Backup*/ 161 | UpgradeLog*.XML 162 | UpgradeLog*.htm 163 | 164 | # SQL Server files 165 | App_Data/*.mdf 166 | App_Data/*.ldf 167 | 168 | ############# 169 | ## Windows detritus 170 | ############# 171 | 172 | # Windows image file caches 173 | Thumbs.db 174 | ehthumbs.db 175 | 176 | # Folder config file 177 | Desktop.ini 178 | 179 | # Recycle Bin used on file shares 180 | $RECYCLE.BIN/ 181 | 182 | # Mac crap 183 | .DS_Store 184 | 185 | 186 | ############# 187 | ## Python 188 | ############# 189 | 190 | *.py[co] 191 | 192 | # Packages 193 | *.egg 194 | *.egg-info 195 | dist/ 196 | build/ 197 | eggs/ 198 | parts/ 199 | var/ 200 | sdist/ 201 | develop-eggs/ 202 | .installed.cfg 203 | 204 | # Installer logs 205 | pip-log.txt 206 | 207 | # Unit test / coverage reports 208 | .coverage 209 | .tox 210 | 211 | #Translations 212 | *.mo 213 | 214 | #Mr Developer 215 | .mr.developer.cfg 216 | -------------------------------------------------------------------------------- /layouts/chart.html: -------------------------------------------------------------------------------- 1 | 5 | 6 | 123 | -------------------------------------------------------------------------------- /libraries/widgets/d3_sankey/layouts/chart.html: -------------------------------------------------------------------------------- 1 | 5 | 6 | 123 | -------------------------------------------------------------------------------- /layouts/chart_static_title.html: -------------------------------------------------------------------------------- 1 | 5 | 6 | 126 | -------------------------------------------------------------------------------- /libraries/frameworks/bootstrap/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Page Not Found :( 6 | 141 | 142 | 143 |
144 |

Not found :(

145 |

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

146 |

It looks like this was the result of either:

147 |
    148 |
  • a mistyped address
  • 149 |
  • an out-of-date link
  • 150 |
151 | 154 | 155 |
156 | 157 | 158 | -------------------------------------------------------------------------------- /libraries/frameworks/bootstrap/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 29 | 30 | 31 | 32 | 68 | 69 |
70 | 71 | 72 |
73 |

Hello, world!

74 |

This is a template for a simple marketing or informational website. It includes a large callout called the hero unit and three supporting pieces of content. Use it as a starting point to create something more unique.

75 |

Learn more »

76 |
77 | 78 | 79 |
80 |
81 |

Heading

82 |

Donec id elit non mi porta gravida at eget metus. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Etiam porta sem malesuada magna mollis euismod. Donec sed odio dui.

83 |

View details »

84 |
85 |
86 |

Heading

87 |

Donec id elit non mi porta gravida at eget metus. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Etiam porta sem malesuada magna mollis euismod. Donec sed odio dui.

88 |

View details »

89 |
90 |
91 |

Heading

92 |

Donec sed odio dui. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Vestibulum id ligula porta felis euismod semper. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus.

93 |

View details »

94 |
95 |
96 | 97 |
98 | 99 |
100 |

© Company 2012

101 |
102 | 103 |
104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 119 | 120 | 121 | -------------------------------------------------------------------------------- /example_build_network_sankey.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: Sankey from Scratch 3 | author: Timely Portfolio 4 | github: {user: timelyportfolio, repo: rCharts_d3_sankey, branch: "gh-pages"} 5 | framework: bootstrap 6 | mode: selfcontained 7 | highlighter: prettify 8 | hitheme: twitter-bootstrap 9 | widgets: "d3_sankey" 10 | assets: 11 | css: 12 | - "http://fonts.googleapis.com/css?family=Raleway:300" 13 | - "http://fonts.googleapis.com/css?family=Oxygen" 14 | --- 15 | 16 | 38 | 39 | Fork me on GitHub 40 | 41 | ```{r echo=F, warning= F, message=F} 42 | opts_chunk$set( 43 | message = FALSE, 44 | warning = FALSE, 45 | error = FALSE, 46 | tidy = FALSE, 47 | cache = FALSE, 48 | results = 'asis' 49 | ) 50 | ``` 51 | # Sankey from Scratch using `rCharts`, `d3.js`, and `igraph` 52 | 53 | ## Introduction 54 | 55 | This example will walk through the steps of using the `R` package [`igraph`](http://igraph.sourceforge.net/) to create a tree network for a [sankey diagram](http://econ.st/JwNX8s). This is a great exercise to learn some basics of `igraph`, explore the construction of a sankey, and determine the conditions for a network to be drawn properly as a sankey. After all of this, we will plot our network with the [`rCharts`](http://rcharts.io/site) implementation of the [d3.js sankey plugin](https://github.com/d3/d3-plugins/blob/master/sankey/sankey.js). 56 | 57 | 58 | ## Build a Network 59 | Let's first start by loading the `igraph` and `rCharts` packages. Then we will use `graph.tree` to build a tree network with 40 vertices with 4 children. 60 | ```{r} 61 | require(igraph) 62 | require(rCharts) 63 | 64 | g <- graph.tree(40, children = 4) 65 | ``` 66 | For fun, we will assign a weight of 1 `E(g)$weight = 1` for each edge and then draw a Sankey diagram using `rCharts`. Going forward I will try to explain the `R` code through comments in the code block. 67 | 68 | ## Plot Our Sankey to Find a Problem 69 | ```{r} 70 | E(g)$weight = 1 71 | 72 | edgelist <- get.data.frame(g) #this will give us a data frame with from,to,weight 73 | colnames(edgelist) <- c("source","target","value") 74 | #make character rather than numeric for proper functioning 75 | edgelist$source <- as.character(edgelist$source) 76 | edgelist$target <- as.character(edgelist$target) 77 | 78 | sankeyPlot <- rCharts$new() 79 | sankeyPlot$setLib('libraries/widgets/d3_sankey') 80 | sankeyPlot$setTemplate(script = "libraries/widgets/d3_sankey/layouts/chart.html") 81 | 82 | sankeyPlot$set( 83 | data = edgelist, 84 | nodeWidth = 15, 85 | nodePadding = 10, 86 | layout = 32, 87 | width = 960, 88 | height = 500 89 | ) 90 | 91 | sankeyPlot$print(chartId = 'sankey1') 92 | ``` 93 | 94 | Interact with the sankey plot a little, and try to find the problem in our hastily constructed network. Hovering over the vertex 4 will reveal our issue. The edge from 1 to 4 is not as big as the sum of the edges going out from 4. For this to make sense, unless 4 is magically creating something, the sum of the inflow should equal the sum of the outflow. Since 4 has four children each with weight of 1 (outflow = 1 + 1 + 1 + 1 = 4), we would expect the inflow to also be 4. It is only 1 though since we made all our edges' weights = 1 `E(g)$weight = 1`. How then would we build our network with edge weights so that for each vertex, the sum of in equals the sum of out. 95 | 96 | 97 | ## Fix Our Problem For a Beautiful Sankey 98 | I am a network novice, so while the code below works, I am sure there are better ways of accomplishing the desired result. I heavily commented the code, but I will quickly describe the steps. The code starts at the lowest level of the heirarchy, or those vertexes where there is nothing going out (out degree = 0). In our network, these are 11 through 40. With `igraph` we can identify these by `V(g2)[degree(g2,mode="out")==0]`. For these we will assign a weight. Then we will loop through all of the edges summing all of the weights of the out until we have reached the top of the heirarchy. 99 | 100 | ```{r} 101 | g2 <- graph.tree(40, children=4) 102 | #to construct a sankey the weight of each vertex should be the sum 103 | #of its outgoing edges 104 | #I believe the first step in creating a network that satisfies this condition 105 | #is define a vertex weight for all vertexes with out degree = 0 106 | #but first let's define 0 for all 107 | V(g2)$weight = 0 108 | #now for all vertexes with out degree = 0 109 | V(g2)[degree(g2,mode="out")==0]$weight <- runif(n=length(V(g2)[degree(g2,mode="out")==0]),min=0,max=100) 110 | #the lowest level of the heirarchy is defined with a random weight 111 | #with the lowest level defined we should now be able to sum the vertex weights 112 | #to define the edge weight 113 | #E(g2)$weight = 0.1 #define all weights small to visually see as we build sankey 114 | E(g2)[to(V(g2)$weight>0)]$weight <- V(g2)[V(g2)$weight>0]$weight 115 | #and to find the neighbors to the 0 out degree vertex 116 | #we could do V(g2)[nei(degree(g2,mode="out")==0)] 117 | #we have everything we need to build the rest by summing 118 | #these edge weights if there are edges still undefined 119 | #so set up a loop to run until all edges have a defined weight 120 | while(max(is.na(E(g2)$weight))) { 121 | #get.data.frame gives us from, to, and weight 122 | #we will get this to make an easier reference later 123 | df <- get.data.frame(g2) 124 | #now go through each edge and find the sum of all its subedges 125 | #we need to check to make sure out degree of its "to" vertex is not 0 126 | #or we will get 0 since there are no edges for vertex with out degree 0 127 | for (i in 1:nrow(df)) { 128 | x = df[i,] 129 | #sum only those with out degree > 0 or sum will be 0 130 | if(max(df$from==x$to)) { 131 | E(g2)[from(x$from) & to(x$to)]$weight = sum(E(g2)[from(x$to)]$weight) 132 | } 133 | } 134 | } 135 | 136 | edgelistWeight <- get.data.frame(g2) 137 | colnames(edgelistWeight) <- c("source","target","value") 138 | edgelistWeight$source <- as.character(edgelistWeight$source) 139 | edgelistWeight$target <- as.character(edgelistWeight$target) 140 | 141 | sankeyPlot2 <- rCharts$new() 142 | sankeyPlot2$setLib('libraries/widgets/d3_sankey') 143 | sankeyPlot2$setTemplate(script = 'libraries/widgets/d3_sankey/layouts/chart.html') 144 | 145 | sankeyPlot2$set( 146 | data = edgelistWeight, 147 | nodeWidth = 15, 148 | nodePadding = 10, 149 | layout = 32, 150 | width = 960, 151 | height = 500 152 | ) 153 | 154 | sankeyPlot2 155 | ``` 156 | 157 | ## Another Look at Our Network 158 | There are very [good examples](http://rulesofreason.wordpress.com/tag/plot-igraph/) illustrating the use of `igraph` to plot a network. This is not one of these examples. For fun though, let's plot the network with igraph using just the defaults to compare it to our Sankey output from above. 159 | 160 | ```{r} 161 | plot(g2) 162 | ``` 163 | 164 | ## Lots More Sankey 165 | Believe it or not, there is an entire site devoted to sankey diagrams. For all the sankey you can handle, check out http://sankey-diagrams.com. Here are a couple more sankeys generated from `rCharts`: http://rcharts.io/viewer/?6001601#.UeWfuY3VCSo, http://rcharts.io/viewer/?6003605, http://rcharts.io/viewer/?6003575. -------------------------------------------------------------------------------- /example.R: -------------------------------------------------------------------------------- 1 | require(rCharts) 2 | require(rjson) 3 | require(igraph) 4 | 5 | #get source from original example 6 | #this is a JSON, so will need to translate 7 | #this is complicated and unnecessary but feel I need to replicate 8 | #for completeness 9 | 10 | #expect most data to come straight from R 11 | #in form of source, target, value 12 | 13 | links <- matrix(unlist( 14 | rjson::fromJSON( 15 | file = "http://bost.ocks.org/mike/sankey/energy.json" 16 | )$links 17 | ),ncol = 3, byrow = TRUE) 18 | 19 | nodes <- unlist( 20 | rjson::fromJSON( 21 | file = "http://bost.ocks.org/mike/sankey/energy.json" 22 | )$nodes 23 | ) 24 | 25 | #convert to data.frame so souce and target can be character and value numeric 26 | links <- data.frame(links) 27 | colnames(links) <- c("source", "target", "value") 28 | links$source <- sapply(links$source, FUN = function(x) {return(as.character(nodes[x+1]))}) #x+1 since js starts at 0 29 | links$target <- sapply(links$target, FUN = function(x) {return(nodes[x+1])}) #x+1 since js starts at 0 30 | 31 | 32 | #now we finally have the data in the form we need 33 | sankeyPlot <- rCharts$new() 34 | sankeyPlot$setLib('.') 35 | sankeyPlot$setTemplate(script = "layouts/chart.html") 36 | 37 | sankeyPlot$set( 38 | data = links, 39 | nodeWidth = 15, 40 | nodePadding = 10, 41 | layout = 32, 42 | width = 960, 43 | height = 500, 44 | units = "TWh", 45 | title = "Sankey Diagram" 46 | ) 47 | 48 | sankeyPlot 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | data(foodwebs, package = "igraphdata") 71 | data(karate, package = "igraphdata") 72 | data(Koenigsberg, package = "igraphdata") 73 | edgelist <- get.data.frame(foodwebs$ChesLower) 74 | 75 | #simulate a network 76 | g <- graph.tree(26,children=2) 77 | edgelist <- get.data.frame(g) 78 | edgelist$value <- 1 79 | colnames(edgelist) <- c("source","target","value") 80 | edgelist$source <- LETTERS[edgelist$source] 81 | edgelist$target <- LETTERS[edgelist$target] 82 | 83 | sankeyPlot <- rCharts$new() 84 | sankeyPlot$setLib('.') 85 | sankeyPlot$setTemplate(script = "layouts/chart.html") 86 | 87 | sankeyPlot$set( 88 | data = edgelist, 89 | nodeWidth = 15, 90 | nodePadding = 10, 91 | layout = 32, 92 | width = 960, 93 | height = 500 94 | ) 95 | 96 | sankeyPlot 97 | 98 | 99 | g2 <- graph.tree(40,children=4) 100 | #to construct a sankey the weight of each vertex should be the sum 101 | #of its outgoing edges 102 | #I believe the first step in creating a network that satisfies this condition 103 | #is define a vertex weight for all vertexes with out degree = 0 104 | #but first let's define 0 for all 105 | V(g2)$weight = 0 106 | #now for all vertexes with out degree = 0 107 | V(g2)[degree(g2,mode="out")==0]$weight <- runif(n=length(V(g2)[degree(g2,mode="out")==0]),min=0,max=100) 108 | #the lowest level of the heirarchy is defined with a random weight 109 | #with the lowest level defined we should now be able to sum the vertex weights 110 | #to define the edge weight 111 | #E(g2)$weight = 0.1 #define all weights small to visually see as we build sankey 112 | E(g2)[to(V(g2)$weight>0)]$weight <- V(g2)[V(g2)$weight>0]$weight 113 | #and to find the neighbors to the 0 out degree vertex 114 | #we could do V(g2)[nei(degree(g2,mode="out")==0)] 115 | #we have everything we need to build the rest by summing 116 | #these edge weights if there are edges still undefined 117 | #so set up a loop to run until all edges have a defined weight 118 | while(max(is.na(E(g2)$weight))) { 119 | #get.data.frame gives us from, to, and weight 120 | #we will get this to make an easier reference later 121 | df <- get.data.frame(g2) 122 | #now go through each edge and find the sum of all its subedges 123 | #we need to check to make sure out degree of its "to" vertex is not 0 124 | #or we will get 0 since there are no edges for vertex with out degree 0 125 | for (i in 1:nrow(df)) { 126 | x = df[i,] 127 | #sum only those with out degree > 0 or sum will be 0 128 | if(max(df$from==x$to)) { 129 | E(g2)[from(x$from) & to(x$to)]$weight = sum(E(g2)[from(x$to)]$weight) 130 | } 131 | } 132 | } 133 | 134 | 135 | #just a quick check on the adjacency 136 | get.adjacency(g2,sparse = FALSE,attr="weight") 137 | 138 | 139 | 140 | 141 | #E(g2)$weight <- runif(length(E(g2))) 142 | edgelistWeight <- get.data.frame(g2) 143 | colnames(edgelistWeight) <- c("source","target","value") 144 | edgelistWeight$source <- as.character(edgelistWeight$source) 145 | edgelistWeight$target <- as.character(edgelistWeight$target) 146 | 147 | sankeyPlot2 <- rCharts$new() 148 | sankeyPlot2$setLib('.') 149 | sankeyPlot2$setTemplate(script = "layouts/chart.html") 150 | 151 | sankeyPlot2$set( 152 | data = edgelistWeight, 153 | nodeWidth = 15, 154 | nodePadding = 10, 155 | layout = 32, 156 | width = 960, 157 | height = 500 158 | ) 159 | 160 | sankeyPlot2 161 | 162 | 163 | 164 | data(pHWebs, package = "cheddar") 165 | 166 | community <- pHWebs[[1]]$trophic.links 167 | community$value <- 1 168 | colnames(community) <- c("source","target", "value") 169 | community$source <- paste0(community$source,"[resource]") 170 | 171 | sankeyPlot <- rCharts$new() 172 | sankeyPlot$setLib('.') 173 | sankeyPlot$setTemplate(script = "layouts/chart.html") 174 | 175 | sankeyPlot$set( 176 | data = community, 177 | nodeWidth = 15, 178 | nodePadding = 10, 179 | layout = 32, 180 | width = 960, 181 | height = 500 182 | ) 183 | 184 | sankeyPlot 185 | 186 | 187 | 188 | 189 | 190 | data(Millstream, package = "cheddar") 191 | 192 | community <- pHWebs[[1]]$trophic.links 193 | community$value <- 1 194 | colnames(community) <- c("source","target", "value") 195 | community$source <- paste0(community$source,"[resource]") 196 | 197 | sankeyPlot <- rCharts$new() 198 | sankeyPlot$setLib('.') 199 | sankeyPlot$setTemplate(script = "layouts/chart.html") 200 | 201 | sankeyPlot$set( 202 | data = community, 203 | nodeWidth = 15, 204 | nodePadding = 10, 205 | layout = 32, 206 | width = 960, 207 | height = 500 208 | ) 209 | 210 | sankeyPlot 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | ToIgraph <- function(community, weight=NULL) 223 | { 224 | if(is.null(TLPS(community))) 225 | { 226 | stop('The community has no trophic links') 227 | } 228 | else 229 | { 230 | tlps <- TLPS(community, link.properties=weight) 231 | if(!is.null(weight)) 232 | { 233 | tlps$weight <- tlps[,weight] 234 | } 235 | return (graph.data.frame(tlps, 236 | vertices=NPS(community), 237 | directed=TRUE)) 238 | } 239 | } 240 | data(TL84) 241 | # Unweighted network 242 | TL84.ig <- ToIgraph(TL84) 243 | 244 | edgelist <- data.frame(get.edgelist(TL84.ig),stringsAsFactors = FALSE) 245 | edgelist$value <- rep(1,nrow(edgelist)) 246 | colnames(edgelist) <- c("source","target","value") 247 | edgelist$source <- paste0(edgelist$source,"[src]") 248 | 249 | sankeyPlot <- rCharts$new() 250 | sankeyPlot$setLib('.') 251 | sankeyPlot$setTemplate(script = "layouts/chart.html") 252 | 253 | sankeyPlot$set( 254 | data = edgelist, 255 | nodeWidth = 15, 256 | nodePadding = 10, 257 | layout = 32, 258 | width = 960, 259 | height = 500 260 | ) 261 | 262 | sankeyPlot 263 | 264 | 265 | 266 | graph.edgelist(as.matrix(edgelist)[,1:2],directed = TRUE) 267 | g <- graph.edgelist(as.matrix(edgelist)[,1:2],directed = TRUE) 268 | a <- get.adjacency(g) 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | edgelist <- get.data.frame(as.undirected(erdos.renyi.game(n=20,p.or.m=.5,type="gnp",directed=T),mode="collapse")) 277 | edgelist$value <- 1 278 | colnames(edgelist) <- c("source","target","value") 279 | edgelist$source <- paste0(edgelist$source,"[src]") 280 | 281 | sankeyPlot <- rCharts$new() 282 | sankeyPlot$setLib('.') 283 | sankeyPlot$setTemplate(script = "layouts/chart.html") 284 | 285 | sankeyPlot$set( 286 | data = edgelist, 287 | nodeWidth = 15, 288 | nodePadding = 10, 289 | layout = 32, 290 | width = 960, 291 | height = 500 292 | ) 293 | 294 | sankeyPlot -------------------------------------------------------------------------------- /js/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 | nextNodes.push(link.target); 122 | }); 123 | }); 124 | remainingNodes = nextNodes; 125 | ++x; 126 | } 127 | 128 | // 129 | moveSinksRight(x); 130 | scaleNodeBreadths((size[0] - nodeWidth) / (x - 1)); 131 | } 132 | 133 | function moveSourcesRight() { 134 | nodes.forEach(function(node) { 135 | if (!node.targetLinks.length) { 136 | node.x = d3.min(node.sourceLinks, function(d) { return d.target.x; }) - 1; 137 | } 138 | }); 139 | } 140 | 141 | function moveSinksRight(x) { 142 | nodes.forEach(function(node) { 143 | if (!node.sourceLinks.length) { 144 | node.x = x - 1; 145 | } 146 | }); 147 | } 148 | 149 | function scaleNodeBreadths(kx) { 150 | nodes.forEach(function(node) { 151 | node.x *= kx; 152 | }); 153 | } 154 | 155 | function computeNodeDepths(iterations) { 156 | var nodesByBreadth = d3.nest() 157 | .key(function(d) { return d.x; }) 158 | .sortKeys(d3.ascending) 159 | .entries(nodes) 160 | .map(function(d) { return d.values; }); 161 | 162 | // 163 | initializeNodeDepth(); 164 | resolveCollisions(); 165 | for (var alpha = 1; iterations > 0; --iterations) { 166 | relaxRightToLeft(alpha *= .99); 167 | resolveCollisions(); 168 | relaxLeftToRight(alpha); 169 | resolveCollisions(); 170 | } 171 | 172 | function initializeNodeDepth() { 173 | var ky = d3.min(nodesByBreadth, function(nodes) { 174 | return (size[1] - (nodes.length - 1) * nodePadding) / d3.sum(nodes, value); 175 | }); 176 | 177 | nodesByBreadth.forEach(function(nodes) { 178 | nodes.forEach(function(node, i) { 179 | node.y = i; 180 | node.dy = node.value * ky; 181 | }); 182 | }); 183 | 184 | links.forEach(function(link) { 185 | link.dy = link.value * ky; 186 | }); 187 | } 188 | 189 | function relaxLeftToRight(alpha) { 190 | nodesByBreadth.forEach(function(nodes, breadth) { 191 | nodes.forEach(function(node) { 192 | if (node.targetLinks.length) { 193 | var y = d3.sum(node.targetLinks, weightedSource) / d3.sum(node.targetLinks, value); 194 | node.y += (y - center(node)) * alpha; 195 | } 196 | }); 197 | }); 198 | 199 | function weightedSource(link) { 200 | return center(link.source) * link.value; 201 | } 202 | } 203 | 204 | function relaxRightToLeft(alpha) { 205 | nodesByBreadth.slice().reverse().forEach(function(nodes) { 206 | nodes.forEach(function(node) { 207 | if (node.sourceLinks.length) { 208 | var y = d3.sum(node.sourceLinks, weightedTarget) / d3.sum(node.sourceLinks, value); 209 | node.y += (y - center(node)) * alpha; 210 | } 211 | }); 212 | }); 213 | 214 | function weightedTarget(link) { 215 | return center(link.target) * link.value; 216 | } 217 | } 218 | 219 | function resolveCollisions() { 220 | nodesByBreadth.forEach(function(nodes) { 221 | var node, 222 | dy, 223 | y0 = 0, 224 | n = nodes.length, 225 | i; 226 | 227 | // Push any overlapping nodes down. 228 | nodes.sort(ascendingDepth); 229 | for (i = 0; i < n; ++i) { 230 | node = nodes[i]; 231 | dy = y0 - node.y; 232 | if (dy > 0) node.y += dy; 233 | y0 = node.y + node.dy + nodePadding; 234 | } 235 | 236 | // If the bottommost node goes outside the bounds, push it back up. 237 | dy = y0 - nodePadding - size[1]; 238 | if (dy > 0) { 239 | y0 = node.y -= dy; 240 | 241 | // Push any overlapping nodes back up. 242 | for (i = n - 2; i >= 0; --i) { 243 | node = nodes[i]; 244 | dy = node.y + node.dy + nodePadding - y0; 245 | if (dy > 0) node.y -= dy; 246 | y0 = node.y; 247 | } 248 | } 249 | }); 250 | } 251 | 252 | function ascendingDepth(a, b) { 253 | return a.y - b.y; 254 | } 255 | } 256 | 257 | function computeLinkDepths() { 258 | nodes.forEach(function(node) { 259 | node.sourceLinks.sort(ascendingTargetDepth); 260 | node.targetLinks.sort(ascendingSourceDepth); 261 | }); 262 | nodes.forEach(function(node) { 263 | var sy = 0, ty = 0; 264 | node.sourceLinks.forEach(function(link) { 265 | link.sy = sy; 266 | sy += link.dy; 267 | }); 268 | node.targetLinks.forEach(function(link) { 269 | link.ty = ty; 270 | ty += link.dy; 271 | }); 272 | }); 273 | 274 | function ascendingSourceDepth(a, b) { 275 | return a.source.y - b.source.y; 276 | } 277 | 278 | function ascendingTargetDepth(a, b) { 279 | return a.target.y - b.target.y; 280 | } 281 | } 282 | 283 | function center(node) { 284 | return node.y + node.dy / 2; 285 | } 286 | 287 | function value(link) { 288 | return link.value; 289 | } 290 | 291 | return sankey; 292 | }; 293 | -------------------------------------------------------------------------------- /libraries/widgets/d3_sankey/js/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 | nextNodes.push(link.target); 122 | }); 123 | }); 124 | remainingNodes = nextNodes; 125 | ++x; 126 | } 127 | 128 | // 129 | moveSinksRight(x); 130 | scaleNodeBreadths((size[0] - nodeWidth) / (x - 1)); 131 | } 132 | 133 | function moveSourcesRight() { 134 | nodes.forEach(function(node) { 135 | if (!node.targetLinks.length) { 136 | node.x = d3.min(node.sourceLinks, function(d) { return d.target.x; }) - 1; 137 | } 138 | }); 139 | } 140 | 141 | function moveSinksRight(x) { 142 | nodes.forEach(function(node) { 143 | if (!node.sourceLinks.length) { 144 | node.x = x - 1; 145 | } 146 | }); 147 | } 148 | 149 | function scaleNodeBreadths(kx) { 150 | nodes.forEach(function(node) { 151 | node.x *= kx; 152 | }); 153 | } 154 | 155 | function computeNodeDepths(iterations) { 156 | var nodesByBreadth = d3.nest() 157 | .key(function(d) { return d.x; }) 158 | .sortKeys(d3.ascending) 159 | .entries(nodes) 160 | .map(function(d) { return d.values; }); 161 | 162 | // 163 | initializeNodeDepth(); 164 | resolveCollisions(); 165 | for (var alpha = 1; iterations > 0; --iterations) { 166 | relaxRightToLeft(alpha *= .99); 167 | resolveCollisions(); 168 | relaxLeftToRight(alpha); 169 | resolveCollisions(); 170 | } 171 | 172 | function initializeNodeDepth() { 173 | var ky = d3.min(nodesByBreadth, function(nodes) { 174 | return (size[1] - (nodes.length - 1) * nodePadding) / d3.sum(nodes, value); 175 | }); 176 | 177 | nodesByBreadth.forEach(function(nodes) { 178 | nodes.forEach(function(node, i) { 179 | node.y = i; 180 | node.dy = node.value * ky; 181 | }); 182 | }); 183 | 184 | links.forEach(function(link) { 185 | link.dy = link.value * ky; 186 | }); 187 | } 188 | 189 | function relaxLeftToRight(alpha) { 190 | nodesByBreadth.forEach(function(nodes, breadth) { 191 | nodes.forEach(function(node) { 192 | if (node.targetLinks.length) { 193 | var y = d3.sum(node.targetLinks, weightedSource) / d3.sum(node.targetLinks, value); 194 | node.y += (y - center(node)) * alpha; 195 | } 196 | }); 197 | }); 198 | 199 | function weightedSource(link) { 200 | return center(link.source) * link.value; 201 | } 202 | } 203 | 204 | function relaxRightToLeft(alpha) { 205 | nodesByBreadth.slice().reverse().forEach(function(nodes) { 206 | nodes.forEach(function(node) { 207 | if (node.sourceLinks.length) { 208 | var y = d3.sum(node.sourceLinks, weightedTarget) / d3.sum(node.sourceLinks, value); 209 | node.y += (y - center(node)) * alpha; 210 | } 211 | }); 212 | }); 213 | 214 | function weightedTarget(link) { 215 | return center(link.target) * link.value; 216 | } 217 | } 218 | 219 | function resolveCollisions() { 220 | nodesByBreadth.forEach(function(nodes) { 221 | var node, 222 | dy, 223 | y0 = 0, 224 | n = nodes.length, 225 | i; 226 | 227 | // Push any overlapping nodes down. 228 | nodes.sort(ascendingDepth); 229 | for (i = 0; i < n; ++i) { 230 | node = nodes[i]; 231 | dy = y0 - node.y; 232 | if (dy > 0) node.y += dy; 233 | y0 = node.y + node.dy + nodePadding; 234 | } 235 | 236 | // If the bottommost node goes outside the bounds, push it back up. 237 | dy = y0 - nodePadding - size[1]; 238 | if (dy > 0) { 239 | y0 = node.y -= dy; 240 | 241 | // Push any overlapping nodes back up. 242 | for (i = n - 2; i >= 0; --i) { 243 | node = nodes[i]; 244 | dy = node.y + node.dy + nodePadding - y0; 245 | if (dy > 0) node.y -= dy; 246 | y0 = node.y; 247 | } 248 | } 249 | }); 250 | } 251 | 252 | function ascendingDepth(a, b) { 253 | return a.y - b.y; 254 | } 255 | } 256 | 257 | function computeLinkDepths() { 258 | nodes.forEach(function(node) { 259 | node.sourceLinks.sort(ascendingTargetDepth); 260 | node.targetLinks.sort(ascendingSourceDepth); 261 | }); 262 | nodes.forEach(function(node) { 263 | var sy = 0, ty = 0; 264 | node.sourceLinks.forEach(function(link) { 265 | link.sy = sy; 266 | sy += link.dy; 267 | }); 268 | node.targetLinks.forEach(function(link) { 269 | link.ty = ty; 270 | ty += link.dy; 271 | }); 272 | }); 273 | 274 | function ascendingSourceDepth(a, b) { 275 | return a.source.y - b.source.y; 276 | } 277 | 278 | function ascendingTargetDepth(a, b) { 279 | return a.target.y - b.target.y; 280 | } 281 | } 282 | 283 | function center(node) { 284 | return node.y + node.dy / 2; 285 | } 286 | 287 | function value(link) { 288 | return link.value; 289 | } 290 | 291 | return sankey; 292 | }; 293 | -------------------------------------------------------------------------------- /libraries/frameworks/bootstrap/css/bootstrap-responsive.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap Responsive v2.1.1 3 | * 4 | * Copyright 2012 Twitter, Inc 5 | * Licensed under the Apache License v2.0 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Designed and built with all the love in the world @twitter by @mdo and @fat. 9 | */.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;line-height:0;content:""}.clearfix:after{clear:both}.hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.input-block-level{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.hidden{display:none;visibility:hidden}.visible-phone{display:none!important}.visible-tablet{display:none!important}.hidden-desktop{display:none!important}.visible-desktop{display:inherit!important}@media(min-width:768px) and (max-width:979px){.hidden-desktop{display:inherit!important}.visible-desktop{display:none!important}.visible-tablet{display:inherit!important}.hidden-tablet{display:none!important}}@media(max-width:767px){.hidden-desktop{display:inherit!important}.visible-desktop{display:none!important}.visible-phone{display:inherit!important}.hidden-phone{display:none!important}}@media(min-width:1200px){.row{margin-left:-30px;*zoom:1}.row:before,.row:after{display:table;line-height:0;content:""}.row:after{clear:both}[class*="span"]{float:left;min-height:1px;margin-left:30px}.container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:1170px}.span12{width:1170px}.span11{width:1070px}.span10{width:970px}.span9{width:870px}.span8{width:770px}.span7{width:670px}.span6{width:570px}.span5{width:470px}.span4{width:370px}.span3{width:270px}.span2{width:170px}.span1{width:70px}.offset12{margin-left:1230px}.offset11{margin-left:1130px}.offset10{margin-left:1030px}.offset9{margin-left:930px}.offset8{margin-left:830px}.offset7{margin-left:730px}.offset6{margin-left:630px}.offset5{margin-left:530px}.offset4{margin-left:430px}.offset3{margin-left:330px}.offset2{margin-left:230px}.offset1{margin-left:130px}.row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;line-height:0;content:""}.row-fluid:after{clear:both}.row-fluid [class*="span"]{display:block;float:left;width:100%;min-height:30px;margin-left:2.564102564102564%;*margin-left:2.5109110747408616%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="span"]:first-child{margin-left:0}.row-fluid .span12{width:100%;*width:99.94680851063829%}.row-fluid .span11{width:91.45299145299145%;*width:91.39979996362975%}.row-fluid .span10{width:82.90598290598291%;*width:82.8527914166212%}.row-fluid .span9{width:74.35897435897436%;*width:74.30578286961266%}.row-fluid .span8{width:65.81196581196582%;*width:65.75877432260411%}.row-fluid .span7{width:57.26495726495726%;*width:57.21176577559556%}.row-fluid .span6{width:48.717948717948715%;*width:48.664757228587014%}.row-fluid .span5{width:40.17094017094017%;*width:40.11774868157847%}.row-fluid .span4{width:31.623931623931625%;*width:31.570740134569924%}.row-fluid .span3{width:23.076923076923077%;*width:23.023731587561375%}.row-fluid .span2{width:14.52991452991453%;*width:14.476723040552828%}.row-fluid .span1{width:5.982905982905983%;*width:5.929714493544281%}.row-fluid .offset12{margin-left:105.12820512820512%;*margin-left:105.02182214948171%}.row-fluid .offset12:first-child{margin-left:102.56410256410257%;*margin-left:102.45771958537915%}.row-fluid .offset11{margin-left:96.58119658119658%;*margin-left:96.47481360247316%}.row-fluid .offset11:first-child{margin-left:94.01709401709402%;*margin-left:93.91071103837061%}.row-fluid .offset10{margin-left:88.03418803418803%;*margin-left:87.92780505546462%}.row-fluid .offset10:first-child{margin-left:85.47008547008548%;*margin-left:85.36370249136206%}.row-fluid .offset9{margin-left:79.48717948717949%;*margin-left:79.38079650845607%}.row-fluid .offset9:first-child{margin-left:76.92307692307693%;*margin-left:76.81669394435352%}.row-fluid .offset8{margin-left:70.94017094017094%;*margin-left:70.83378796144753%}.row-fluid .offset8:first-child{margin-left:68.37606837606839%;*margin-left:68.26968539734497%}.row-fluid .offset7{margin-left:62.393162393162385%;*margin-left:62.28677941443899%}.row-fluid .offset7:first-child{margin-left:59.82905982905982%;*margin-left:59.72267685033642%}.row-fluid .offset6{margin-left:53.84615384615384%;*margin-left:53.739770867430444%}.row-fluid .offset6:first-child{margin-left:51.28205128205128%;*margin-left:51.175668303327875%}.row-fluid .offset5{margin-left:45.299145299145295%;*margin-left:45.1927623204219%}.row-fluid .offset5:first-child{margin-left:42.73504273504273%;*margin-left:42.62865975631933%}.row-fluid .offset4{margin-left:36.75213675213675%;*margin-left:36.645753773413354%}.row-fluid .offset4:first-child{margin-left:34.18803418803419%;*margin-left:34.081651209310785%}.row-fluid .offset3{margin-left:28.205128205128204%;*margin-left:28.0987452264048%}.row-fluid .offset3:first-child{margin-left:25.641025641025642%;*margin-left:25.53464266230224%}.row-fluid .offset2{margin-left:19.65811965811966%;*margin-left:19.551736679396257%}.row-fluid .offset2:first-child{margin-left:17.094017094017094%;*margin-left:16.98763411529369%}.row-fluid .offset1{margin-left:11.11111111111111%;*margin-left:11.004728132387708%}.row-fluid .offset1:first-child{margin-left:8.547008547008547%;*margin-left:8.440625568285142%}input,textarea,.uneditable-input{margin-left:0}.controls-row [class*="span"]+[class*="span"]{margin-left:30px}input.span12,textarea.span12,.uneditable-input.span12{width:1156px}input.span11,textarea.span11,.uneditable-input.span11{width:1056px}input.span10,textarea.span10,.uneditable-input.span10{width:956px}input.span9,textarea.span9,.uneditable-input.span9{width:856px}input.span8,textarea.span8,.uneditable-input.span8{width:756px}input.span7,textarea.span7,.uneditable-input.span7{width:656px}input.span6,textarea.span6,.uneditable-input.span6{width:556px}input.span5,textarea.span5,.uneditable-input.span5{width:456px}input.span4,textarea.span4,.uneditable-input.span4{width:356px}input.span3,textarea.span3,.uneditable-input.span3{width:256px}input.span2,textarea.span2,.uneditable-input.span2{width:156px}input.span1,textarea.span1,.uneditable-input.span1{width:56px}.thumbnails{margin-left:-30px}.thumbnails>li{margin-left:30px}.row-fluid .thumbnails{margin-left:0}}@media(min-width:768px) and (max-width:979px){.row{margin-left:-20px;*zoom:1}.row:before,.row:after{display:table;line-height:0;content:""}.row:after{clear:both}[class*="span"]{float:left;min-height:1px;margin-left:20px}.container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:724px}.span12{width:724px}.span11{width:662px}.span10{width:600px}.span9{width:538px}.span8{width:476px}.span7{width:414px}.span6{width:352px}.span5{width:290px}.span4{width:228px}.span3{width:166px}.span2{width:104px}.span1{width:42px}.offset12{margin-left:764px}.offset11{margin-left:702px}.offset10{margin-left:640px}.offset9{margin-left:578px}.offset8{margin-left:516px}.offset7{margin-left:454px}.offset6{margin-left:392px}.offset5{margin-left:330px}.offset4{margin-left:268px}.offset3{margin-left:206px}.offset2{margin-left:144px}.offset1{margin-left:82px}.row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;line-height:0;content:""}.row-fluid:after{clear:both}.row-fluid [class*="span"]{display:block;float:left;width:100%;min-height:30px;margin-left:2.7624309392265194%;*margin-left:2.709239449864817%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="span"]:first-child{margin-left:0}.row-fluid .span12{width:100%;*width:99.94680851063829%}.row-fluid .span11{width:91.43646408839778%;*width:91.38327259903608%}.row-fluid .span10{width:82.87292817679558%;*width:82.81973668743387%}.row-fluid .span9{width:74.30939226519337%;*width:74.25620077583166%}.row-fluid .span8{width:65.74585635359117%;*width:65.69266486422946%}.row-fluid .span7{width:57.18232044198895%;*width:57.12912895262725%}.row-fluid .span6{width:48.61878453038674%;*width:48.56559304102504%}.row-fluid .span5{width:40.05524861878453%;*width:40.00205712942283%}.row-fluid .span4{width:31.491712707182323%;*width:31.43852121782062%}.row-fluid .span3{width:22.92817679558011%;*width:22.87498530621841%}.row-fluid .span2{width:14.3646408839779%;*width:14.311449394616199%}.row-fluid .span1{width:5.801104972375691%;*width:5.747913483013988%}.row-fluid .offset12{margin-left:105.52486187845304%;*margin-left:105.41847889972962%}.row-fluid .offset12:first-child{margin-left:102.76243093922652%;*margin-left:102.6560479605031%}.row-fluid .offset11{margin-left:96.96132596685082%;*margin-left:96.8549429881274%}.row-fluid .offset11:first-child{margin-left:94.1988950276243%;*margin-left:94.09251204890089%}.row-fluid .offset10{margin-left:88.39779005524862%;*margin-left:88.2914070765252%}.row-fluid .offset10:first-child{margin-left:85.6353591160221%;*margin-left:85.52897613729868%}.row-fluid .offset9{margin-left:79.8342541436464%;*margin-left:79.72787116492299%}.row-fluid .offset9:first-child{margin-left:77.07182320441989%;*margin-left:76.96544022569647%}.row-fluid .offset8{margin-left:71.2707182320442%;*margin-left:71.16433525332079%}.row-fluid .offset8:first-child{margin-left:68.50828729281768%;*margin-left:68.40190431409427%}.row-fluid .offset7{margin-left:62.70718232044199%;*margin-left:62.600799341718584%}.row-fluid .offset7:first-child{margin-left:59.94475138121547%;*margin-left:59.838368402492065%}.row-fluid .offset6{margin-left:54.14364640883978%;*margin-left:54.037263430116376%}.row-fluid .offset6:first-child{margin-left:51.38121546961326%;*margin-left:51.27483249088986%}.row-fluid .offset5{margin-left:45.58011049723757%;*margin-left:45.47372751851417%}.row-fluid .offset5:first-child{margin-left:42.81767955801105%;*margin-left:42.71129657928765%}.row-fluid .offset4{margin-left:37.01657458563536%;*margin-left:36.91019160691196%}.row-fluid .offset4:first-child{margin-left:34.25414364640884%;*margin-left:34.14776066768544%}.row-fluid .offset3{margin-left:28.45303867403315%;*margin-left:28.346655695309746%}.row-fluid .offset3:first-child{margin-left:25.69060773480663%;*margin-left:25.584224756083227%}.row-fluid .offset2{margin-left:19.88950276243094%;*margin-left:19.783119783707537%}.row-fluid .offset2:first-child{margin-left:17.12707182320442%;*margin-left:17.02068884448102%}.row-fluid .offset1{margin-left:11.32596685082873%;*margin-left:11.219583872105325%}.row-fluid .offset1:first-child{margin-left:8.56353591160221%;*margin-left:8.457152932878806%}input,textarea,.uneditable-input{margin-left:0}.controls-row [class*="span"]+[class*="span"]{margin-left:20px}input.span12,textarea.span12,.uneditable-input.span12{width:710px}input.span11,textarea.span11,.uneditable-input.span11{width:648px}input.span10,textarea.span10,.uneditable-input.span10{width:586px}input.span9,textarea.span9,.uneditable-input.span9{width:524px}input.span8,textarea.span8,.uneditable-input.span8{width:462px}input.span7,textarea.span7,.uneditable-input.span7{width:400px}input.span6,textarea.span6,.uneditable-input.span6{width:338px}input.span5,textarea.span5,.uneditable-input.span5{width:276px}input.span4,textarea.span4,.uneditable-input.span4{width:214px}input.span3,textarea.span3,.uneditable-input.span3{width:152px}input.span2,textarea.span2,.uneditable-input.span2{width:90px}input.span1,textarea.span1,.uneditable-input.span1{width:28px}}@media(max-width:767px){body{padding-right:20px;padding-left:20px}.navbar-fixed-top,.navbar-fixed-bottom,.navbar-static-top{margin-right:-20px;margin-left:-20px}.container-fluid{padding:0}.dl-horizontal dt{float:none;width:auto;clear:none;text-align:left}.dl-horizontal dd{margin-left:0}.container{width:auto}.row-fluid{width:100%}.row,.thumbnails{margin-left:0}.thumbnails>li{float:none;margin-left:0}[class*="span"],.row-fluid [class*="span"]{display:block;float:none;width:100%;margin-left:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.span12,.row-fluid .span12{width:100%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.input-large,.input-xlarge,.input-xxlarge,input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.input-prepend input,.input-append input,.input-prepend input[class*="span"],.input-append input[class*="span"]{display:inline-block;width:auto}.controls-row [class*="span"]+[class*="span"]{margin-left:0}.modal{position:fixed;top:20px;right:20px;left:20px;width:auto;margin:0}.modal.fade.in{top:auto}}@media(max-width:480px){.nav-collapse{-webkit-transform:translate3d(0,0,0)}.page-header h1 small{display:block;line-height:20px}input[type="checkbox"],input[type="radio"]{border:1px solid #ccc}.form-horizontal .control-label{float:none;width:auto;padding-top:0;text-align:left}.form-horizontal .controls{margin-left:0}.form-horizontal .control-list{padding-top:0}.form-horizontal .form-actions{padding-right:10px;padding-left:10px}.modal{top:10px;right:10px;left:10px}.modal-header .close{padding:10px;margin:-10px}.carousel-caption{position:static}}@media(max-width:979px){body{padding-top:0}.navbar-fixed-top,.navbar-fixed-bottom{position:static}.navbar-fixed-top{margin-bottom:20px}.navbar-fixed-bottom{margin-top:20px}.navbar-fixed-top .navbar-inner,.navbar-fixed-bottom .navbar-inner{padding:5px}.navbar .container{width:auto;padding:0}.navbar .brand{padding-right:10px;padding-left:10px;margin:0 0 0 -5px}.nav-collapse{clear:both}.nav-collapse .nav{float:none;margin:0 0 10px}.nav-collapse .nav>li{float:none}.nav-collapse .nav>li>a{margin-bottom:2px}.nav-collapse .nav>.divider-vertical{display:none}.nav-collapse .nav .nav-header{color:#777;text-shadow:none}.nav-collapse .nav>li>a,.nav-collapse .dropdown-menu a{padding:9px 15px;font-weight:bold;color:#777;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.nav-collapse .btn{padding:4px 10px 4px;font-weight:normal;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.nav-collapse .dropdown-menu li+li a{margin-bottom:2px}.nav-collapse .nav>li>a:hover,.nav-collapse .dropdown-menu a:hover{background-color:#f2f2f2}.navbar-inverse .nav-collapse .nav>li>a:hover,.navbar-inverse .nav-collapse .dropdown-menu a:hover{background-color:#111}.nav-collapse.in .btn-group{padding:0;margin-top:5px}.nav-collapse .dropdown-menu{position:static;top:auto;left:auto;display:block;float:none;max-width:none;padding:0;margin:0 15px;background-color:transparent;border:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.nav-collapse .dropdown-menu:before,.nav-collapse .dropdown-menu:after{display:none}.nav-collapse .dropdown-menu .divider{display:none}.nav-collapse .nav>li>.dropdown-menu:before,.nav-collapse .nav>li>.dropdown-menu:after{display:none}.nav-collapse .navbar-form,.nav-collapse .navbar-search{float:none;padding:10px 15px;margin:10px 0;border-top:1px solid #f2f2f2;border-bottom:1px solid #f2f2f2;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1)}.navbar-inverse .nav-collapse .navbar-form,.navbar-inverse .nav-collapse .navbar-search{border-top-color:#111;border-bottom-color:#111}.navbar .nav-collapse .nav.pull-right{float:none;margin-left:0}.nav-collapse,.nav-collapse.collapse{height:0;overflow:hidden}.navbar .btn-navbar{display:block}.navbar-static .navbar-inner{padding-right:10px;padding-left:10px}}@media(min-width:980px){.nav-collapse.collapse{height:auto!important;overflow:visible!important}} 10 | -------------------------------------------------------------------------------- /example_build_network_sankey.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Sankey from Scratch 3 | author: Timely Portfolio 4 | github: {user: timelyportfolio, repo: rCharts_d3_horizon, branch: "gh-pages"} 5 | framework: bootstrap 6 | mode: selfcontained 7 | highlighter: prettify 8 | hitheme: twitter-bootstrap 9 | widgets: "d3_sankey" 10 | assets: 11 | css: 12 | - "http://fonts.googleapis.com/css?family=Raleway:300" 13 | - "http://fonts.googleapis.com/css?family=Oxygen" 14 | --- 15 | 16 | 38 | 39 | Fork me on GitHub 40 | 41 | 42 | 43 | # Sankey from Scratch using `rCharts`, `d3.js`, and `igraph` 44 | 45 | ## Introduction 46 | 47 | This example will walk through the steps of using the `R` package [`igraph`](http://igraph.sourceforge.net/) to create a tree network for a [sankey diagram](http://econ.st/JwNX8s). This is a great exercise to learn some basics of `igraph`, explore the construction of a sankey, and determine the conditions for a network to be drawn properly as a sankey. After all of this, we will plot our network with the [`rCharts`](http://rcharts.io/site) implementation of the [d3.js sankey plugin](https://github.com/d3/d3-plugins/blob/master/sankey/sankey.js). 48 | 49 | 50 | ## Build a Network 51 | Let's first start by loading the `igraph` and `rCharts` packages. Then we will use `graph.tree` to build a tree network with 40 vertices with 4 children. 52 | 53 | ```r 54 | require(igraph) 55 | require(rCharts) 56 | 57 | g <- graph.tree(40, children = 4) 58 | ``` 59 | 60 | For fun, we will assign a weight of 1 `E(g)$weight = 1` for each edge and then draw a Sankey diagram using `rCharts`. Going forward I will try to explain the `R` code through comments in the code block. 61 | 62 | ## Plot Our Sankey to Find a Problem 63 | 64 | ```r 65 | E(g)$weight = 1 66 | 67 | edgelist <- get.data.frame(g) #this will give us a data frame with from,to,weight 68 | colnames(edgelist) <- c("source","target","value") 69 | #make character rather than numeric for proper functioning 70 | edgelist$source <- as.character(edgelist$source) 71 | edgelist$target <- as.character(edgelist$target) 72 | 73 | sankeyPlot <- rCharts$new() 74 | sankeyPlot$setLib('libraries/widgets/d3_sankey') 75 | sankeyPlot$setTemplate(script = "libraries/widgets/d3_sankey/layouts/chart.html") 76 | 77 | sankeyPlot$set( 78 | data = edgelist, 79 | nodeWidth = 15, 80 | nodePadding = 10, 81 | layout = 32, 82 | width = 960, 83 | height = 500 84 | ) 85 | 86 | sankeyPlot$print(chartId = 'sankey1') 87 | ``` 88 | 89 | 90 |
91 | 95 | 96 | 220 | 221 | 222 | Interact with the sankey plot a little, and try to find the problem in our hastily constructed network. Hovering over the vertex 4 will reveal our issue. The edge from 1 to 4 is not as big as the sum of the edges going out from 4. For this to make sense, unless 4 is magically creating something, the sum of the inflow should equal the sum of the outflow. Since 4 has four children each with weight of 1 (outflow = 1 + 1 + 1 + 1 = 4), we would expect the inflow to also be 4. It is only 1 though since we made all our edges' weights = 1 `E(g)$weight = 1`. How then would we build our network with edge weights so that for each vertex, the sum of in equals the sum of out. 223 | 224 | 225 | ## Fix Our Problem For a Beautiful Sankey 226 | I am a network novice, so while the code below works, I am sure there are better ways of accomplishing the desired result. I heavily commented the code, but I will quickly describe the steps. The code starts at the lowest level of the heirarchy, or those vertexes where there is nothing going out (out degree = 0). In our network, these are 11 through 40. With `igraph` we can identify these by `V(g2)[degree(g2,mode="out")==0]`. For these we will assign a weight. Then we will loop through all of the edges summing all of the weights of the out until we have reached the top of the heirarchy. 227 | 228 | 229 | ```r 230 | g2 <- graph.tree(40, children=4) 231 | #to construct a sankey the weight of each vertex should be the sum 232 | #of its outgoing edges 233 | #I believe the first step in creating a network that satisfies this condition 234 | #is define a vertex weight for all vertexes with out degree = 0 235 | #but first let's define 0 for all 236 | V(g2)$weight = 0 237 | #now for all vertexes with out degree = 0 238 | V(g2)[degree(g2,mode="out")==0]$weight <- runif(n=length(V(g2)[degree(g2,mode="out")==0]),min=0,max=100) 239 | #the lowest level of the heirarchy is defined with a random weight 240 | #with the lowest level defined we should now be able to sum the vertex weights 241 | #to define the edge weight 242 | #E(g2)$weight = 0.1 #define all weights small to visually see as we build sankey 243 | E(g2)[to(V(g2)$weight>0)]$weight <- V(g2)[V(g2)$weight>0]$weight 244 | #and to find the neighbors to the 0 out degree vertex 245 | #we could do V(g2)[nei(degree(g2,mode="out")==0)] 246 | #we have everything we need to build the rest by summing 247 | #these edge weights if there are edges still undefined 248 | #so set up a loop to run until all edges have a defined weight 249 | while(max(is.na(E(g2)$weight))) { 250 | #get.data.frame gives us from, to, and weight 251 | #we will get this to make an easier reference later 252 | df <- get.data.frame(g2) 253 | #now go through each edge and find the sum of all its subedges 254 | #we need to check to make sure out degree of its "to" vertex is not 0 255 | #or we will get 0 since there are no edges for vertex with out degree 0 256 | for (i in 1:nrow(df)) { 257 | x = df[i,] 258 | #sum only those with out degree > 0 or sum will be 0 259 | if(max(df$from==x$to)) { 260 | E(g2)[from(x$from) & to(x$to)]$weight = sum(E(g2)[from(x$to)]$weight) 261 | } 262 | } 263 | } 264 | 265 | edgelistWeight <- get.data.frame(g2) 266 | colnames(edgelistWeight) <- c("source","target","value") 267 | edgelistWeight$source <- as.character(edgelistWeight$source) 268 | edgelistWeight$target <- as.character(edgelistWeight$target) 269 | 270 | sankeyPlot2 <- rCharts$new() 271 | sankeyPlot2$setLib('libraries/widgets/d3_sankey') 272 | sankeyPlot2$setTemplate(script = 'libraries/widgets/d3_sankey/layouts/chart.html') 273 | 274 | sankeyPlot2$set( 275 | data = edgelistWeight, 276 | nodeWidth = 15, 277 | nodePadding = 10, 278 | layout = 32, 279 | width = 960, 280 | height = 500 281 | ) 282 | 283 | sankeyPlot2 284 | ``` 285 | 286 | 287 |
288 | 292 | 293 | 417 | 418 | 419 | ## Another Look at Our Network 420 | There are very [good examples](http://rulesofreason.wordpress.com/tag/plot-igraph/) illustrating the use of `igraph` to plot a network. This is not one of these examples. For fun though, let's plot the network with igraph using just the defaults to compare it to our Sankey output from above. 421 | 422 | 423 | ```r 424 | plot(g2) 425 | ``` 426 | 427 | ![plot of chunk unnamed-chunk-5](assets/fig/unnamed-chunk-5.png) 428 | 429 | 430 | ## Lots More Sankey 431 | Believe it or not, there is an entire site devoted to sankey diagrams. For all the sankey you can handle, check out http://sankey-diagrams.com. Here are a couple more sankeys generated from `rCharts`: http://rcharts.io/viewer/?6001601#.UeWfuY3VCSo, http://rcharts.io/viewer/?6003605, http://rcharts.io/viewer/?6003575. 432 | -------------------------------------------------------------------------------- /libraries/frameworks/bootstrap/js/vendor/modernizr-2.6.1-respond-1.1.0.min.js: -------------------------------------------------------------------------------- 1 | /* Modernizr 2.6.1 (Custom Build) | MIT & BSD 2 | * Build: http://modernizr.com/download/#-fontface-backgroundsize-borderimage-borderradius-boxshadow-flexbox-hsla-multiplebgs-opacity-rgba-textshadow-cssanimations-csscolumns-generatedcontent-cssgradients-cssreflections-csstransforms-csstransforms3d-csstransitions-applicationcache-canvas-canvastext-draganddrop-hashchange-history-audio-video-indexeddb-input-inputtypes-localstorage-postmessage-sessionstorage-websockets-websqldatabase-webworkers-geolocation-inlinesvg-smil-svg-svgclippaths-touch-webgl-shiv-mq-cssclasses-addtest-prefixed-teststyles-testprop-testallprops-hasevent-prefixes-domprefixes-load 3 | */ 4 | ;window.Modernizr=function(a,b,c){function D(a){j.cssText=a}function E(a,b){return D(n.join(a+";")+(b||""))}function F(a,b){return typeof a===b}function G(a,b){return!!~(""+a).indexOf(b)}function H(a,b){for(var d in a){var e=a[d];if(!G(e,"-")&&j[e]!==c)return b=="pfx"?e:!0}return!1}function I(a,b,d){for(var e in a){var f=b[a[e]];if(f!==c)return d===!1?a[e]:F(f,"function")?f.bind(d||b):f}return!1}function J(a,b,c){var d=a.charAt(0).toUpperCase()+a.slice(1),e=(a+" "+p.join(d+" ")+d).split(" ");return F(b,"string")||F(b,"undefined")?H(e,b):(e=(a+" "+q.join(d+" ")+d).split(" "),I(e,b,c))}function K(){e.input=function(c){for(var d=0,e=c.length;d',a,""].join(""),k.id=h,(l?k:m).innerHTML+=f,m.appendChild(k),l||(m.style.background="",g.appendChild(m)),i=c(k,a),l?k.parentNode.removeChild(k):m.parentNode.removeChild(m),!!i},z=function(b){var c=a.matchMedia||a.msMatchMedia;if(c)return c(b).matches;var d;return y("@media "+b+" { #"+h+" { position: absolute; } }",function(b){d=(a.getComputedStyle?getComputedStyle(b,null):b.currentStyle)["position"]=="absolute"}),d},A=function(){function d(d,e){e=e||b.createElement(a[d]||"div"),d="on"+d;var f=d in e;return f||(e.setAttribute||(e=b.createElement("div")),e.setAttribute&&e.removeAttribute&&(e.setAttribute(d,""),f=F(e[d],"function"),F(e[d],"undefined")||(e[d]=c),e.removeAttribute(d))),e=null,f}var a={select:"input",change:"input",submit:"form",reset:"form",error:"img",load:"img",abort:"img"};return d}(),B={}.hasOwnProperty,C;!F(B,"undefined")&&!F(B.call,"undefined")?C=function(a,b){return B.call(a,b)}:C=function(a,b){return b in a&&F(a.constructor.prototype[b],"undefined")},Function.prototype.bind||(Function.prototype.bind=function(b){var c=this;if(typeof c!="function")throw new TypeError;var d=w.call(arguments,1),e=function(){if(this instanceof e){var a=function(){};a.prototype=c.prototype;var f=new a,g=c.apply(f,d.concat(w.call(arguments)));return Object(g)===g?g:f}return c.apply(b,d.concat(w.call(arguments)))};return e}),s.flexbox=function(){return J("flexWrap")},s.canvas=function(){var a=b.createElement("canvas");return!!a.getContext&&!!a.getContext("2d")},s.canvastext=function(){return!!e.canvas&&!!F(b.createElement("canvas").getContext("2d").fillText,"function")},s.webgl=function(){return!!a.WebGLRenderingContext},s.touch=function(){var c;return"ontouchstart"in a||a.DocumentTouch&&b instanceof DocumentTouch?c=!0:y(["@media (",n.join("touch-enabled),("),h,")","{#modernizr{top:9px;position:absolute}}"].join(""),function(a){c=a.offsetTop===9}),c},s.geolocation=function(){return"geolocation"in navigator},s.postmessage=function(){return!!a.postMessage},s.websqldatabase=function(){return!!a.openDatabase},s.indexedDB=function(){return!!J("indexedDB",a)},s.hashchange=function(){return A("hashchange",a)&&(b.documentMode===c||b.documentMode>7)},s.history=function(){return!!a.history&&!!history.pushState},s.draganddrop=function(){var a=b.createElement("div");return"draggable"in a||"ondragstart"in a&&"ondrop"in a},s.websockets=function(){return"WebSocket"in a||"MozWebSocket"in a},s.rgba=function(){return D("background-color:rgba(150,255,150,.5)"),G(j.backgroundColor,"rgba")},s.hsla=function(){return D("background-color:hsla(120,40%,100%,.5)"),G(j.backgroundColor,"rgba")||G(j.backgroundColor,"hsla")},s.multiplebgs=function(){return D("background:url(https://),url(https://),red url(https://)"),/(url\s*\(.*?){3}/.test(j.background)},s.backgroundsize=function(){return J("backgroundSize")},s.borderimage=function(){return J("borderImage")},s.borderradius=function(){return J("borderRadius")},s.boxshadow=function(){return J("boxShadow")},s.textshadow=function(){return b.createElement("div").style.textShadow===""},s.opacity=function(){return E("opacity:.55"),/^0.55$/.test(j.opacity)},s.cssanimations=function(){return J("animationName")},s.csscolumns=function(){return J("columnCount")},s.cssgradients=function(){var a="background-image:",b="gradient(linear,left top,right bottom,from(#9f9),to(white));",c="linear-gradient(left top,#9f9, white);";return D((a+"-webkit- ".split(" ").join(b+a)+n.join(c+a)).slice(0,-a.length)),G(j.backgroundImage,"gradient")},s.cssreflections=function(){return J("boxReflect")},s.csstransforms=function(){return!!J("transform")},s.csstransforms3d=function(){var a=!!J("perspective");return a&&"webkitPerspective"in g.style&&y("@media (transform-3d),(-webkit-transform-3d){#modernizr{left:9px;position:absolute;height:3px;}}",function(b,c){a=b.offsetLeft===9&&b.offsetHeight===3}),a},s.csstransitions=function(){return J("transition")},s.fontface=function(){var a;return y('@font-face {font-family:"font";src:url("https://")}',function(c,d){var e=b.getElementById("smodernizr"),f=e.sheet||e.styleSheet,g=f?f.cssRules&&f.cssRules[0]?f.cssRules[0].cssText:f.cssText||"":"";a=/src/i.test(g)&&g.indexOf(d.split(" ")[0])===0}),a},s.generatedcontent=function(){var a;return y(['#modernizr:after{content:"',l,'";visibility:hidden}'].join(""),function(b){a=b.offsetHeight>=1}),a},s.video=function(){var a=b.createElement("video"),c=!1;try{if(c=!!a.canPlayType)c=new Boolean(c),c.ogg=a.canPlayType('video/ogg; codecs="theora"').replace(/^no$/,""),c.h264=a.canPlayType('video/mp4; codecs="avc1.42E01E"').replace(/^no$/,""),c.webm=a.canPlayType('video/webm; codecs="vp8, vorbis"').replace(/^no$/,"")}catch(d){}return c},s.audio=function(){var a=b.createElement("audio"),c=!1;try{if(c=!!a.canPlayType)c=new Boolean(c),c.ogg=a.canPlayType('audio/ogg; codecs="vorbis"').replace(/^no$/,""),c.mp3=a.canPlayType("audio/mpeg;").replace(/^no$/,""),c.wav=a.canPlayType('audio/wav; codecs="1"').replace(/^no$/,""),c.m4a=(a.canPlayType("audio/x-m4a;")||a.canPlayType("audio/aac;")).replace(/^no$/,"")}catch(d){}return c},s.localstorage=function(){try{return localStorage.setItem(h,h),localStorage.removeItem(h),!0}catch(a){return!1}},s.sessionstorage=function(){try{return sessionStorage.setItem(h,h),sessionStorage.removeItem(h),!0}catch(a){return!1}},s.webworkers=function(){return!!a.Worker},s.applicationcache=function(){return!!a.applicationCache},s.svg=function(){return!!b.createElementNS&&!!b.createElementNS(r.svg,"svg").createSVGRect},s.inlinesvg=function(){var a=b.createElement("div");return a.innerHTML="",(a.firstChild&&a.firstChild.namespaceURI)==r.svg},s.smil=function(){return!!b.createElementNS&&/SVGAnimate/.test(m.call(b.createElementNS(r.svg,"animate")))},s.svgclippaths=function(){return!!b.createElementNS&&/SVGClipPath/.test(m.call(b.createElementNS(r.svg,"clipPath")))};for(var L in s)C(s,L)&&(x=L.toLowerCase(),e[x]=s[L](),v.push((e[x]?"":"no-")+x));return e.input||K(),e.addTest=function(a,b){if(typeof a=="object")for(var d in a)C(a,d)&&e.addTest(d,a[d]);else{a=a.toLowerCase();if(e[a]!==c)return e;b=typeof b=="function"?b():b,f&&(g.className+=" "+(b?"":"no-")+a),e[a]=b}return e},D(""),i=k=null,function(a,b){function k(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x",d.insertBefore(c.lastChild,d.firstChild)}function l(){var a=r.elements;return typeof a=="string"?a.split(" "):a}function m(a){var b=i[a[g]];return b||(b={},h++,a[g]=h,i[h]=b),b}function n(a,c,f){c||(c=b);if(j)return c.createElement(a);f||(f=m(c));var g;return f.cache[a]?g=f.cache[a].cloneNode():e.test(a)?g=(f.cache[a]=f.createElem(a)).cloneNode():g=f.createElem(a),g.canHaveChildren&&!d.test(a)?f.frag.appendChild(g):g}function o(a,c){a||(a=b);if(j)return a.createDocumentFragment();c=c||m(a);var d=c.frag.cloneNode(),e=0,f=l(),g=f.length;for(;e",f="hidden"in a,j=a.childNodes.length==1||function(){b.createElement("a");var a=b.createDocumentFragment();return typeof a.cloneNode=="undefined"||typeof a.createDocumentFragment=="undefined"||typeof a.createElement=="undefined"}()}catch(c){f=!0,j=!0}})();var r={elements:c.elements||"abbr article aside audio bdi canvas data datalist details figcaption figure footer header hgroup mark meter nav output progress section summary time video",shivCSS:c.shivCSS!==!1,supportsUnknownElements:j,shivMethods:c.shivMethods!==!1,type:"default",shivDocument:q,createElement:n,createDocumentFragment:o};a.html5=r,q(b)}(this,b),e._version=d,e._prefixes=n,e._domPrefixes=q,e._cssomPrefixes=p,e.mq=z,e.hasEvent=A,e.testProp=function(a){return H([a])},e.testAllProps=J,e.testStyles=y,e.prefixed=function(a,b,c){return b?J(a,b,c):J(a,"pfx")},g.className=g.className.replace(/(^|\s)no-js(\s|$)/,"$1$2")+(f?" js "+v.join(" "):""),e}(this,this.document),function(a,b,c){function d(a){return o.call(a)=="[object Function]"}function e(a){return typeof a=="string"}function f(){}function g(a){return!a||a=="loaded"||a=="complete"||a=="uninitialized"}function h(){var a=p.shift();q=1,a?a.t?m(function(){(a.t=="c"?B.injectCss:B.injectJs)(a.s,0,a.a,a.x,a.e,1)},0):(a(),h()):q=0}function i(a,c,d,e,f,i,j){function k(b){if(!o&&g(l.readyState)&&(u.r=o=1,!q&&h(),l.onload=l.onreadystatechange=null,b)){a!="img"&&m(function(){t.removeChild(l)},50);for(var d in y[c])y[c].hasOwnProperty(d)&&y[c][d].onload()}}var j=j||B.errorTimeout,l={},o=0,r=0,u={t:d,s:c,e:f,a:i,x:j};y[c]===1&&(r=1,y[c]=[],l=b.createElement(a)),a=="object"?l.data=c:(l.src=c,l.type=a),l.width=l.height="0",l.onerror=l.onload=l.onreadystatechange=function(){k.call(this,r)},p.splice(e,0,u),a!="img"&&(r||y[c]===2?(t.insertBefore(l,s?null:n),m(k,j)):y[c].push(l))}function j(a,b,c,d,f){return q=0,b=b||"j",e(a)?i(b=="c"?v:u,a,b,this.i++,c,d,f):(p.splice(this.i++,0,a),p.length==1&&h()),this}function k(){var a=B;return a.loader={load:j,i:0},a}var l=b.documentElement,m=a.setTimeout,n=b.getElementsByTagName("script")[0],o={}.toString,p=[],q=0,r="MozAppearance"in l.style,s=r&&!!b.createRange().compareNode,t=s?l:n.parentNode,l=a.opera&&o.call(a.opera)=="[object Opera]",l=!!b.attachEvent&&!l,u=r?"object":l?"script":"img",v=l?"script":u,w=Array.isArray||function(a){return o.call(a)=="[object Array]"},x=[],y={},z={timeout:function(a,b){return b.length&&(a.timeout=b[0]),a}},A,B;B=function(a){function b(a){var a=a.split("!"),b=x.length,c=a.pop(),d=a.length,c={url:c,origUrl:c,prefixes:a},e,f,g;for(f=0;f #mq-test-1 { width: 42px; }';a.insertBefore(d,b);c=g.offsetWidth==42;a.removeChild(d);return{matches:c,media:h}}})(document); 9 | 10 | /*! Respond.js v1.1.0: min/max-width media query polyfill. (c) Scott Jehl. MIT/GPLv2 Lic. j.mp/respondjs */ 11 | (function(e){e.respond={};respond.update=function(){};respond.mediaQueriesSupported=e.matchMedia&&e.matchMedia("only all").matches;if(respond.mediaQueriesSupported){return}var w=e.document,s=w.documentElement,i=[],k=[],q=[],o={},h=30,f=w.getElementsByTagName("head")[0]||s,g=w.getElementsByTagName("base")[0],b=f.getElementsByTagName("link"),d=[],a=function(){var D=b,y=D.length,B=0,A,z,C,x;for(;B-1,minw:F.match(/\(min\-width:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/)&&parseFloat(RegExp.$1)+(RegExp.$2||""),maxw:F.match(/\(max\-width:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/)&&parseFloat(RegExp.$1)+(RegExp.$2||"")})}}j()},l,r,v=function(){var z,A=w.createElement("div"),x=w.body,y=false;A.style.cssText="position:absolute;font-size:1em;width:1em";if(!x){x=y=w.createElement("body");x.style.background="none"}x.appendChild(A);s.insertBefore(x,s.firstChild);z=A.offsetWidth;if(y){s.removeChild(x)}else{x.removeChild(A)}z=p=parseFloat(z);return z},p,j=function(I){var x="clientWidth",B=s[x],H=w.compatMode==="CSS1Compat"&&B||w.body[x]||B,D={},G=b[b.length-1],z=(new Date()).getTime();if(I&&l&&z-l-1?(p||v()):1)}if(!!J){J=parseFloat(J)*(J.indexOf(y)>-1?(p||v()):1)}if(!K.hasquery||(!A||!L)&&(A||H>=C)&&(L||H<=J)){if(!D[K.media]){D[K.media]=[]}D[K.media].push(k[K.rules])}}for(var E in q){if(q[E]&&q[E].parentNode===f){f.removeChild(q[E])}}for(var E in D){var M=w.createElement("style"),F=D[E].join("\n");M.type="text/css";M.media=E;f.insertBefore(M,G.nextSibling);if(M.styleSheet){M.styleSheet.cssText=F}else{M.appendChild(w.createTextNode(F))}q.push(M)}},n=function(x,z){var y=c();if(!y){return}y.open("GET",x,true);y.onreadystatechange=function(){if(y.readyState!=4||y.status!=200&&y.status!=304){return}z(y.responseText)};if(y.readyState==4){return}y.send(null)},c=(function(){var x=false;try{x=new XMLHttpRequest()}catch(y){x=new ActiveXObject("Microsoft.XMLHTTP")}return function(){return x}})();a();respond.update=a;function t(){j(true)}if(e.addEventListener){e.addEventListener("resize",t,false)}else{if(e.attachEvent){e.attachEvent("onresize",t)}}})(this); -------------------------------------------------------------------------------- /example_build_network_sankey.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Sankey from Scratch 10 | 11 | 12 | 13 | 19 | 20 | 21 | 22 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 48 | 49 | 50 |
51 | 52 | 74 | 75 |

Fork me on GitHub

76 | 77 |

Sankey from Scratch using rCharts, d3.js, and igraph

78 | 79 |

Introduction

80 | 81 |

This example will walk through the steps of using the R package igraph to create a tree network for a sankey diagram. This is a great exercise to learn some basics of igraph, explore the construction of a sankey, and determine the conditions for a network to be drawn properly as a sankey. After all of this, we will plot our network with the rCharts implementation of the d3.js sankey plugin.

82 | 83 |

Build a Network

84 | 85 |

Let's first start by loading the igraph and rCharts packages. Then we will use graph.tree to build a tree network with 40 vertices with 4 children.

86 | 87 |
require(igraph)
 88 | require(rCharts)
 89 | 
 90 | g <- graph.tree(40, children = 4)
 91 | 
92 | 93 |

For fun, we will assign a weight of 1 E(g)$weight = 1 for each edge and then draw a Sankey diagram using rCharts. Going forward I will try to explain the R code through comments in the code block.

94 | 95 |

Plot Our Sankey to Find a Problem

96 | 97 |
E(g)$weight = 1
 98 | 
 99 | edgelist <- get.data.frame(g) #this will give us a data frame with from,to,weight
100 | colnames(edgelist) <- c("source","target","value")
101 | #make character rather than numeric for proper functioning
102 | edgelist$source <- as.character(edgelist$source)
103 | edgelist$target <- as.character(edgelist$target)
104 | 
105 | sankeyPlot <- rCharts$new()
106 | sankeyPlot$setLib('libraries/widgets/d3_sankey')
107 | sankeyPlot$setTemplate(script = "libraries/widgets/d3_sankey/layouts/chart.html")
108 | 
109 | sankeyPlot$set(
110 |   data = edgelist,
111 |   nodeWidth = 15,
112 |   nodePadding = 10,
113 |   layout = 32,
114 |   width = 960,
115 |   height = 500
116 | )
117 | 
118 | sankeyPlot$print(chartId = 'sankey1')
119 | 
120 | 121 |
122 | 123 | 127 | 128 | 254 | 255 |

Interact with the sankey plot a little, and try to find the problem in our hastily constructed network. Hovering over the vertex 4 will reveal our issue. The edge from 1 to 4 is not as big as the sum of the edges going out from 4. For this to make sense, unless 4 is magically creating something, the sum of the inflow should equal the sum of the outflow. Since 4 has four children each with weight of 1 (outflow = 1 + 1 + 1 + 1 = 4), we would expect the inflow to also be 4. It is only 1 though since we made all our edges' weights = 1 E(g)$weight = 1. How then would we build our network with edge weights so that for each vertex, the sum of in equals the sum of out.

256 | 257 |

Fix Our Problem For a Beautiful Sankey

258 | 259 |

I am a network novice, so while the code below works, I am sure there are better ways of accomplishing the desired result. I heavily commented the code, but I will quickly describe the steps. The code starts at the lowest level of the heirarchy, or those vertexes where there is nothing going out (out degree = 0). In our network, these are 11 through 40. With igraph we can identify these by V(g2)[degree(g2,mode="out")==0]. For these we will assign a weight. Then we will loop through all of the edges summing all of the weights of the out until we have reached the top of the heirarchy.

260 | 261 |
g2 <- graph.tree(40, children=4)
262 | #to construct a sankey the weight of each vertex should be the sum
263 | #of its outgoing edges
264 | #I believe the first step in creating a network that satisfies this condition
265 | #is define a vertex weight for all vertexes with out degree = 0
266 | #but first let's define 0 for all
267 | V(g2)$weight = 0
268 | #now for all vertexes with out degree = 0
269 | V(g2)[degree(g2,mode="out")==0]$weight <- runif(n=length(V(g2)[degree(g2,mode="out")==0]),min=0,max=100)
270 | #the lowest level of the heirarchy is defined with a random weight
271 | #with the lowest level defined we should now be able to sum the vertex weights
272 | #to define the edge weight
273 | #E(g2)$weight = 0.1 #define all weights small to visually see as we build sankey
274 | E(g2)[to(V(g2)$weight>0)]$weight <- V(g2)[V(g2)$weight>0]$weight
275 | #and to find the neighbors to the 0 out degree vertex
276 | #we could do V(g2)[nei(degree(g2,mode="out")==0)]
277 | #we have everything we need to build the rest by summing
278 | #these edge weights if there are edges still undefined
279 | #so set up a loop to run until all edges have a defined weight
280 | while(max(is.na(E(g2)$weight))) {
281 |   #get.data.frame gives us from, to, and weight
282 |   #we will get this to make an easier reference later
283 |   df <- get.data.frame(g2)
284 |   #now go through each edge and find the sum of all its subedges
285 |   #we need to check to make sure out degree of its "to" vertex is not 0
286 |   #or we will get 0 since there are no edges for vertex with out degree 0
287 |   for (i in 1:nrow(df)) {
288 |     x = df[i,]
289 |     #sum only those with out degree > 0 or sum will be 0
290 |     if(max(df$from==x$to)) {
291 |       E(g2)[from(x$from) & to(x$to)]$weight = sum(E(g2)[from(x$to)]$weight)
292 |     }
293 |   }
294 | }
295 | 
296 | edgelistWeight <- get.data.frame(g2)
297 | colnames(edgelistWeight) <- c("source","target","value")
298 | edgelistWeight$source <- as.character(edgelistWeight$source)
299 | edgelistWeight$target <- as.character(edgelistWeight$target)
300 | 
301 | sankeyPlot2 <- rCharts$new()
302 | sankeyPlot2$setLib('libraries/widgets/d3_sankey')
303 | sankeyPlot2$setTemplate(script = 'libraries/widgets/d3_sankey/layouts/chart.html')
304 | 
305 | sankeyPlot2$set(
306 |   data = edgelistWeight,
307 |   nodeWidth = 15,
308 |   nodePadding = 10,
309 |   layout = 32,
310 |   width = 960,
311 |   height = 500
312 | )
313 | 
314 | sankeyPlot2
315 | 
316 | 317 |
318 | 319 | 323 | 324 | 450 | 451 |

Another Look at Our Network

452 | 453 |

There are very good examples illustrating the use of igraph to plot a network. This is not one of these examples. For fun though, let's plot the network with igraph using just the defaults to compare it to our Sankey output from above.

454 | 455 |
plot(g2)
456 | 
457 | 458 |

plot of chunk unnamed-chunk-5

459 | 460 |

Lots More Sankey

461 | 462 |

Believe it or not, there is an entire site devoted to sankey diagrams. For all the sankey you can handle, check out http://sankey-diagrams.com. Here are a couple more sankeys generated from rCharts: http://rcharts.io/viewer/?6001601#.UeWfuY3VCSo, http://rcharts.io/viewer/?6003605, http://rcharts.io/viewer/?6003575.

463 | 464 |
465 | 466 | 467 | 468 | 469 | 470 | 471 | 472 | 473 | 474 | 475 | 482 | 483 | -------------------------------------------------------------------------------- /libraries/frameworks/bootstrap/js/vendor/bootstrap.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap.js by @fat & @mdo 3 | * Copyright 2012 Twitter, Inc. 4 | * http://www.apache.org/licenses/LICENSE-2.0.txt 5 | */ 6 | !function(e){e(function(){"use strict";e.support.transition=function(){var e=function(){var e=document.createElement("bootstrap"),t={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"},n;for(n in t)if(e.style[n]!==undefined)return t[n]}();return e&&{end:e}}()})}(window.jQuery),!function(e){"use strict";var t='[data-dismiss="alert"]',n=function(n){e(n).on("click",t,this.close)};n.prototype.close=function(t){function s(){i.trigger("closed").remove()}var n=e(this),r=n.attr("data-target"),i;r||(r=n.attr("href"),r=r&&r.replace(/.*(?=#[^\s]*$)/,"")),i=e(r),t&&t.preventDefault(),i.length||(i=n.hasClass("alert")?n:n.parent()),i.trigger(t=e.Event("close"));if(t.isDefaultPrevented())return;i.removeClass("in"),e.support.transition&&i.hasClass("fade")?i.on(e.support.transition.end,s):s()},e.fn.alert=function(t){return this.each(function(){var r=e(this),i=r.data("alert");i||r.data("alert",i=new n(this)),typeof t=="string"&&i[t].call(r)})},e.fn.alert.Constructor=n,e(function(){e("body").on("click.alert.data-api",t,n.prototype.close)})}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.$element=e(t),this.options=e.extend({},e.fn.button.defaults,n)};t.prototype.setState=function(e){var t="disabled",n=this.$element,r=n.data(),i=n.is("input")?"val":"html";e+="Text",r.resetText||n.data("resetText",n[i]()),n[i](r[e]||this.options[e]),setTimeout(function(){e=="loadingText"?n.addClass(t).attr(t,t):n.removeClass(t).removeAttr(t)},0)},t.prototype.toggle=function(){var e=this.$element.closest('[data-toggle="buttons-radio"]');e&&e.find(".active").removeClass("active"),this.$element.toggleClass("active")},e.fn.button=function(n){return this.each(function(){var r=e(this),i=r.data("button"),s=typeof n=="object"&&n;i||r.data("button",i=new t(this,s)),n=="toggle"?i.toggle():n&&i.setState(n)})},e.fn.button.defaults={loadingText:"loading..."},e.fn.button.Constructor=t,e(function(){e("body").on("click.button.data-api","[data-toggle^=button]",function(t){var n=e(t.target);n.hasClass("btn")||(n=n.closest(".btn")),n.button("toggle")})})}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.$element=e(t),this.options=n,this.options.slide&&this.slide(this.options.slide),this.options.pause=="hover"&&this.$element.on("mouseenter",e.proxy(this.pause,this)).on("mouseleave",e.proxy(this.cycle,this))};t.prototype={cycle:function(t){return t||(this.paused=!1),this.options.interval&&!this.paused&&(this.interval=setInterval(e.proxy(this.next,this),this.options.interval)),this},to:function(t){var n=this.$element.find(".item.active"),r=n.parent().children(),i=r.index(n),s=this;if(t>r.length-1||t<0)return;return this.sliding?this.$element.one("slid",function(){s.to(t)}):i==t?this.pause().cycle():this.slide(t>i?"next":"prev",e(r[t]))},pause:function(t){return t||(this.paused=!0),this.$element.find(".next, .prev").length&&e.support.transition.end&&(this.$element.trigger(e.support.transition.end),this.cycle()),clearInterval(this.interval),this.interval=null,this},next:function(){if(this.sliding)return;return this.slide("next")},prev:function(){if(this.sliding)return;return this.slide("prev")},slide:function(t,n){var r=this.$element.find(".item.active"),i=n||r[t](),s=this.interval,o=t=="next"?"left":"right",u=t=="next"?"first":"last",a=this,f=e.Event("slide",{relatedTarget:i[0]});this.sliding=!0,s&&this.pause(),i=i.length?i:this.$element.find(".item")[u]();if(i.hasClass("active"))return;if(e.support.transition&&this.$element.hasClass("slide")){this.$element.trigger(f);if(f.isDefaultPrevented())return;i.addClass(t),i[0].offsetWidth,r.addClass(o),i.addClass(o),this.$element.one(e.support.transition.end,function(){i.removeClass([t,o].join(" ")).addClass("active"),r.removeClass(["active",o].join(" ")),a.sliding=!1,setTimeout(function(){a.$element.trigger("slid")},0)})}else{this.$element.trigger(f);if(f.isDefaultPrevented())return;r.removeClass("active"),i.addClass("active"),this.sliding=!1,this.$element.trigger("slid")}return s&&this.cycle(),this}},e.fn.carousel=function(n){return this.each(function(){var r=e(this),i=r.data("carousel"),s=e.extend({},e.fn.carousel.defaults,typeof n=="object"&&n),o=typeof n=="string"?n:s.slide;i||r.data("carousel",i=new t(this,s)),typeof n=="number"?i.to(n):o?i[o]():s.interval&&i.cycle()})},e.fn.carousel.defaults={interval:5e3,pause:"hover"},e.fn.carousel.Constructor=t,e(function(){e("body").on("click.carousel.data-api","[data-slide]",function(t){var n=e(this),r,i=e(n.attr("data-target")||(r=n.attr("href"))&&r.replace(/.*(?=#[^\s]+$)/,"")),s=!i.data("modal")&&e.extend({},i.data(),n.data());i.carousel(s),t.preventDefault()})})}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.$element=e(t),this.options=e.extend({},e.fn.collapse.defaults,n),this.options.parent&&(this.$parent=e(this.options.parent)),this.options.toggle&&this.toggle()};t.prototype={constructor:t,dimension:function(){var e=this.$element.hasClass("width");return e?"width":"height"},show:function(){var t,n,r,i;if(this.transitioning)return;t=this.dimension(),n=e.camelCase(["scroll",t].join("-")),r=this.$parent&&this.$parent.find("> .accordion-group > .in");if(r&&r.length){i=r.data("collapse");if(i&&i.transitioning)return;r.collapse("hide"),i||r.data("collapse",null)}this.$element[t](0),this.transition("addClass",e.Event("show"),"shown"),e.support.transition&&this.$element[t](this.$element[0][n])},hide:function(){var t;if(this.transitioning)return;t=this.dimension(),this.reset(this.$element[t]()),this.transition("removeClass",e.Event("hide"),"hidden"),this.$element[t](0)},reset:function(e){var t=this.dimension();return this.$element.removeClass("collapse")[t](e||"auto")[0].offsetWidth,this.$element[e!==null?"addClass":"removeClass"]("collapse"),this},transition:function(t,n,r){var i=this,s=function(){n.type=="show"&&i.reset(),i.transitioning=0,i.$element.trigger(r)};this.$element.trigger(n);if(n.isDefaultPrevented())return;this.transitioning=1,this.$element[t]("in"),e.support.transition&&this.$element.hasClass("collapse")?this.$element.one(e.support.transition.end,s):s()},toggle:function(){this[this.$element.hasClass("in")?"hide":"show"]()}},e.fn.collapse=function(n){return this.each(function(){var r=e(this),i=r.data("collapse"),s=typeof n=="object"&&n;i||r.data("collapse",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.collapse.defaults={toggle:!0},e.fn.collapse.Constructor=t,e(function(){e("body").on("click.collapse.data-api","[data-toggle=collapse]",function(t){var n=e(this),r,i=n.attr("data-target")||t.preventDefault()||(r=n.attr("href"))&&r.replace(/.*(?=#[^\s]+$)/,""),s=e(i).data("collapse")?"toggle":n.data();n[e(i).hasClass("in")?"addClass":"removeClass"]("collapsed"),e(i).collapse(s)})})}(window.jQuery),!function(e){"use strict";function r(){i(e(t)).removeClass("open")}function i(t){var n=t.attr("data-target"),r;return n||(n=t.attr("href"),n=n&&/#/.test(n)&&n.replace(/.*(?=#[^\s]*$)/,"")),r=e(n),r.length||(r=t.parent()),r}var t="[data-toggle=dropdown]",n=function(t){var n=e(t).on("click.dropdown.data-api",this.toggle);e("html").on("click.dropdown.data-api",function(){n.parent().removeClass("open")})};n.prototype={constructor:n,toggle:function(t){var n=e(this),s,o;if(n.is(".disabled, :disabled"))return;return s=i(n),o=s.hasClass("open"),r(),o||(s.toggleClass("open"),n.focus()),!1},keydown:function(t){var n,r,s,o,u,a;if(!/(38|40|27)/.test(t.keyCode))return;n=e(this),t.preventDefault(),t.stopPropagation();if(n.is(".disabled, :disabled"))return;o=i(n),u=o.hasClass("open");if(!u||u&&t.keyCode==27)return n.click();r=e("[role=menu] li:not(.divider) a",o);if(!r.length)return;a=r.index(r.filter(":focus")),t.keyCode==38&&a>0&&a--,t.keyCode==40&&a').appendTo(document.body),this.options.backdrop!="static"&&this.$backdrop.click(e.proxy(this.hide,this)),i&&this.$backdrop[0].offsetWidth,this.$backdrop.addClass("in"),i?this.$backdrop.one(e.support.transition.end,t):t()}else!this.isShown&&this.$backdrop?(this.$backdrop.removeClass("in"),e.support.transition&&this.$element.hasClass("fade")?this.$backdrop.one(e.support.transition.end,e.proxy(this.removeBackdrop,this)):this.removeBackdrop()):t&&t()}},e.fn.modal=function(n){return this.each(function(){var r=e(this),i=r.data("modal"),s=e.extend({},e.fn.modal.defaults,r.data(),typeof n=="object"&&n);i||r.data("modal",i=new t(this,s)),typeof n=="string"?i[n]():s.show&&i.show()})},e.fn.modal.defaults={backdrop:!0,keyboard:!0,show:!0},e.fn.modal.Constructor=t,e(function(){e("body").on("click.modal.data-api",'[data-toggle="modal"]',function(t){var n=e(this),r=n.attr("href"),i=e(n.attr("data-target")||r&&r.replace(/.*(?=#[^\s]+$)/,"")),s=i.data("modal")?"toggle":e.extend({remote:!/#/.test(r)&&r},i.data(),n.data());t.preventDefault(),i.modal(s).one("hide",function(){n.focus()})})})}(window.jQuery),!function(e){"use strict";var t=function(e,t){this.init("tooltip",e,t)};t.prototype={constructor:t,init:function(t,n,r){var i,s;this.type=t,this.$element=e(n),this.options=this.getOptions(r),this.enabled=!0,this.options.trigger=="click"?this.$element.on("click."+this.type,this.options.selector,e.proxy(this.toggle,this)):this.options.trigger!="manual"&&(i=this.options.trigger=="hover"?"mouseenter":"focus",s=this.options.trigger=="hover"?"mouseleave":"blur",this.$element.on(i+"."+this.type,this.options.selector,e.proxy(this.enter,this)),this.$element.on(s+"."+this.type,this.options.selector,e.proxy(this.leave,this))),this.options.selector?this._options=e.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},getOptions:function(t){return t=e.extend({},e.fn[this.type].defaults,t,this.$element.data()),t.delay&&typeof t.delay=="number"&&(t.delay={show:t.delay,hide:t.delay}),t},enter:function(t){var n=e(t.currentTarget)[this.type](this._options).data(this.type);if(!n.options.delay||!n.options.delay.show)return n.show();clearTimeout(this.timeout),n.hoverState="in",this.timeout=setTimeout(function(){n.hoverState=="in"&&n.show()},n.options.delay.show)},leave:function(t){var n=e(t.currentTarget)[this.type](this._options).data(this.type);this.timeout&&clearTimeout(this.timeout);if(!n.options.delay||!n.options.delay.hide)return n.hide();n.hoverState="out",this.timeout=setTimeout(function(){n.hoverState=="out"&&n.hide()},n.options.delay.hide)},show:function(){var e,t,n,r,i,s,o;if(this.hasContent()&&this.enabled){e=this.tip(),this.setContent(),this.options.animation&&e.addClass("fade"),s=typeof this.options.placement=="function"?this.options.placement.call(this,e[0],this.$element[0]):this.options.placement,t=/in/.test(s),e.remove().css({top:0,left:0,display:"block"}).appendTo(t?this.$element:document.body),n=this.getPosition(t),r=e[0].offsetWidth,i=e[0].offsetHeight;switch(t?s.split(" ")[1]:s){case"bottom":o={top:n.top+n.height,left:n.left+n.width/2-r/2};break;case"top":o={top:n.top-i,left:n.left+n.width/2-r/2};break;case"left":o={top:n.top+n.height/2-i/2,left:n.left-r};break;case"right":o={top:n.top+n.height/2-i/2,left:n.left+n.width}}e.css(o).addClass(s).addClass("in")}},setContent:function(){var e=this.tip(),t=this.getTitle();e.find(".tooltip-inner")[this.options.html?"html":"text"](t),e.removeClass("fade in top bottom left right")},hide:function(){function r(){var t=setTimeout(function(){n.off(e.support.transition.end).remove()},500);n.one(e.support.transition.end,function(){clearTimeout(t),n.remove()})}var t=this,n=this.tip();return n.removeClass("in"),e.support.transition&&this.$tip.hasClass("fade")?r():n.remove(),this},fixTitle:function(){var e=this.$element;(e.attr("title")||typeof e.attr("data-original-title")!="string")&&e.attr("data-original-title",e.attr("title")||"").removeAttr("title")},hasContent:function(){return this.getTitle()},getPosition:function(t){return e.extend({},t?{top:0,left:0}:this.$element.offset(),{width:this.$element[0].offsetWidth,height:this.$element[0].offsetHeight})},getTitle:function(){var e,t=this.$element,n=this.options;return e=t.attr("data-original-title")||(typeof n.title=="function"?n.title.call(t[0]):n.title),e},tip:function(){return this.$tip=this.$tip||e(this.options.template)},validate:function(){this.$element[0].parentNode||(this.hide(),this.$element=null,this.options=null)},enable:function(){this.enabled=!0},disable:function(){this.enabled=!1},toggleEnabled:function(){this.enabled=!this.enabled},toggle:function(){this[this.tip().hasClass("in")?"hide":"show"]()},destroy:function(){this.hide().$element.off("."+this.type).removeData(this.type)}},e.fn.tooltip=function(n){return this.each(function(){var r=e(this),i=r.data("tooltip"),s=typeof n=="object"&&n;i||r.data("tooltip",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.tooltip.Constructor=t,e.fn.tooltip.defaults={animation:!0,placement:"top",selector:!1,template:'
',trigger:"hover",title:"",delay:0,html:!0}}(window.jQuery),!function(e){"use strict";var t=function(e,t){this.init("popover",e,t)};t.prototype=e.extend({},e.fn.tooltip.Constructor.prototype,{constructor:t,setContent:function(){var e=this.tip(),t=this.getTitle(),n=this.getContent();e.find(".popover-title")[this.options.html?"html":"text"](t),e.find(".popover-content > *")[this.options.html?"html":"text"](n),e.removeClass("fade top bottom left right in")},hasContent:function(){return this.getTitle()||this.getContent()},getContent:function(){var e,t=this.$element,n=this.options;return e=t.attr("data-content")||(typeof n.content=="function"?n.content.call(t[0]):n.content),e},tip:function(){return this.$tip||(this.$tip=e(this.options.template)),this.$tip},destroy:function(){this.hide().$element.off("."+this.type).removeData(this.type)}}),e.fn.popover=function(n){return this.each(function(){var r=e(this),i=r.data("popover"),s=typeof n=="object"&&n;i||r.data("popover",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.popover.Constructor=t,e.fn.popover.defaults=e.extend({},e.fn.tooltip.defaults,{placement:"right",trigger:"click",content:"",template:'

'})}(window.jQuery),!function(e){"use strict";function t(t,n){var r=e.proxy(this.process,this),i=e(t).is("body")?e(window):e(t),s;this.options=e.extend({},e.fn.scrollspy.defaults,n),this.$scrollElement=i.on("scroll.scroll-spy.data-api",r),this.selector=(this.options.target||(s=e(t).attr("href"))&&s.replace(/.*(?=#[^\s]+$)/,"")||"")+" .nav li > a",this.$body=e("body"),this.refresh(),this.process()}t.prototype={constructor:t,refresh:function(){var t=this,n;this.offsets=e([]),this.targets=e([]),n=this.$body.find(this.selector).map(function(){var t=e(this),n=t.data("target")||t.attr("href"),r=/^#\w/.test(n)&&e(n);return r&&r.length&&[[r.position().top,n]]||null}).sort(function(e,t){return e[0]-t[0]}).each(function(){t.offsets.push(this[0]),t.targets.push(this[1])})},process:function(){var e=this.$scrollElement.scrollTop()+this.options.offset,t=this.$scrollElement[0].scrollHeight||this.$body[0].scrollHeight,n=t-this.$scrollElement.height(),r=this.offsets,i=this.targets,s=this.activeTarget,o;if(e>=n)return s!=(o=i.last()[0])&&this.activate(o);for(o=r.length;o--;)s!=i[o]&&e>=r[o]&&(!r[o+1]||e<=r[o+1])&&this.activate(i[o])},activate:function(t){var n,r;this.activeTarget=t,e(this.selector).parent(".active").removeClass("active"),r=this.selector+'[data-target="'+t+'"],'+this.selector+'[href="'+t+'"]',n=e(r).parent("li").addClass("active"),n.parent(".dropdown-menu").length&&(n=n.closest("li.dropdown").addClass("active")),n.trigger("activate")}},e.fn.scrollspy=function(n){return this.each(function(){var r=e(this),i=r.data("scrollspy"),s=typeof n=="object"&&n;i||r.data("scrollspy",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.scrollspy.Constructor=t,e.fn.scrollspy.defaults={offset:10},e(window).on("load",function(){e('[data-spy="scroll"]').each(function(){var t=e(this);t.scrollspy(t.data())})})}(window.jQuery),!function(e){"use strict";var t=function(t){this.element=e(t)};t.prototype={constructor:t,show:function(){var t=this.element,n=t.closest("ul:not(.dropdown-menu)"),r=t.attr("data-target"),i,s,o;r||(r=t.attr("href"),r=r&&r.replace(/.*(?=#[^\s]*$)/,""));if(t.parent("li").hasClass("active"))return;i=n.find(".active a").last()[0],o=e.Event("show",{relatedTarget:i}),t.trigger(o);if(o.isDefaultPrevented())return;s=e(r),this.activate(t.parent("li"),n),this.activate(s,s.parent(),function(){t.trigger({type:"shown",relatedTarget:i})})},activate:function(t,n,r){function o(){i.removeClass("active").find("> .dropdown-menu > .active").removeClass("active"),t.addClass("active"),s?(t[0].offsetWidth,t.addClass("in")):t.removeClass("fade"),t.parent(".dropdown-menu")&&t.closest("li.dropdown").addClass("active"),r&&r()}var i=n.find("> .active"),s=r&&e.support.transition&&i.hasClass("fade");s?i.one(e.support.transition.end,o):o(),i.removeClass("in")}},e.fn.tab=function(n){return this.each(function(){var r=e(this),i=r.data("tab");i||r.data("tab",i=new t(this)),typeof n=="string"&&i[n]()})},e.fn.tab.Constructor=t,e(function(){e("body").on("click.tab.data-api",'[data-toggle="tab"], [data-toggle="pill"]',function(t){t.preventDefault(),e(this).tab("show")})})}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.$element=e(t),this.options=e.extend({},e.fn.typeahead.defaults,n),this.matcher=this.options.matcher||this.matcher,this.sorter=this.options.sorter||this.sorter,this.highlighter=this.options.highlighter||this.highlighter,this.updater=this.options.updater||this.updater,this.$menu=e(this.options.menu).appendTo("body"),this.source=this.options.source,this.shown=!1,this.listen()};t.prototype={constructor:t,select:function(){var e=this.$menu.find(".active").attr("data-value");return this.$element.val(this.updater(e)).change(),this.hide()},updater:function(e){return e},show:function(){var t=e.extend({},this.$element.offset(),{height:this.$element[0].offsetHeight});return this.$menu.css({top:t.top+t.height,left:t.left}),this.$menu.show(),this.shown=!0,this},hide:function(){return this.$menu.hide(),this.shown=!1,this},lookup:function(t){var n;return this.query=this.$element.val(),!this.query||this.query.length"+t+""})},render:function(t){var n=this;return t=e(t).map(function(t,r){return t=e(n.options.item).attr("data-value",r),t.find("a").html(n.highlighter(r)),t[0]}),t.first().addClass("active"),this.$menu.html(t),this},next:function(t){var n=this.$menu.find(".active").removeClass("active"),r=n.next();r.length||(r=e(this.$menu.find("li")[0])),r.addClass("active")},prev:function(e){var t=this.$menu.find(".active").removeClass("active"),n=t.prev();n.length||(n=this.$menu.find("li").last()),n.addClass("active")},listen:function(){this.$element.on("blur",e.proxy(this.blur,this)).on("keypress",e.proxy(this.keypress,this)).on("keyup",e.proxy(this.keyup,this)),(e.browser.chrome||e.browser.webkit||e.browser.msie)&&this.$element.on("keydown",e.proxy(this.keydown,this)),this.$menu.on("click",e.proxy(this.click,this)).on("mouseenter","li",e.proxy(this.mouseenter,this))},move:function(e){if(!this.shown)return;switch(e.keyCode){case 9:case 13:case 27:e.preventDefault();break;case 38:e.preventDefault(),this.prev();break;case 40:e.preventDefault(),this.next()}e.stopPropagation()},keydown:function(t){this.suppressKeyPressRepeat=!~e.inArray(t.keyCode,[40,38,9,13,27]),this.move(t)},keypress:function(e){if(this.suppressKeyPressRepeat)return;this.move(e)},keyup:function(e){switch(e.keyCode){case 40:case 38:break;case 9:case 13:if(!this.shown)return;this.select();break;case 27:if(!this.shown)return;this.hide();break;default:this.lookup()}e.stopPropagation(),e.preventDefault()},blur:function(e){var t=this;setTimeout(function(){t.hide()},150)},click:function(e){e.stopPropagation(),e.preventDefault(),this.select()},mouseenter:function(t){this.$menu.find(".active").removeClass("active"),e(t.currentTarget).addClass("active")}},e.fn.typeahead=function(n){return this.each(function(){var r=e(this),i=r.data("typeahead"),s=typeof n=="object"&&n;i||r.data("typeahead",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.typeahead.defaults={source:[],items:8,menu:'',item:'
  • ',minLength:1},e.fn.typeahead.Constructor=t,e(function(){e("body").on("focus.typeahead.data-api",'[data-provide="typeahead"]',function(t){var n=e(this);if(n.data("typeahead"))return;t.preventDefault(),n.typeahead(n.data())})})}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.options=e.extend({},e.fn.affix.defaults,n),this.$window=e(window).on("scroll.affix.data-api",e.proxy(this.checkPosition,this)),this.$element=e(t),this.checkPosition()};t.prototype.checkPosition=function(){if(!this.$element.is(":visible"))return;var t=e(document).height(),n=this.$window.scrollTop(),r=this.$element.offset(),i=this.options.offset,s=i.bottom,o=i.top,u="affix affix-top affix-bottom",a;typeof i!="object"&&(s=o=i),typeof o=="function"&&(o=i.top()),typeof s=="function"&&(s=i.bottom()),a=this.unpin!=null&&n+this.unpin<=r.top?!1:s!=null&&r.top+this.$element.height()>=t-s?"bottom":o!=null&&n<=o?"top":!1;if(this.affixed===a)return;this.affixed=a,this.unpin=a=="bottom"?r.top-n:null,this.$element.removeClass(u).addClass("affix"+(a?"-"+a:""))},e.fn.affix=function(n){return this.each(function(){var r=e(this),i=r.data("affix"),s=typeof n=="object"&&n;i||r.data("affix",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.affix.Constructor=t,e.fn.affix.defaults={offset:0},e(window).on("load",function(){e('[data-spy="affix"]').each(function(){var t=e(this),n=t.data();n.offset=n.offset||{},n.offsetBottom&&(n.offset.bottom=n.offsetBottom),n.offsetTop&&(n.offset.top=n.offsetTop),t.affix(n)})})}(window.jQuery); --------------------------------------------------------------------------------