├── .github
├── dependabot.yml
└── workflows
│ ├── ci.yml
│ └── pages.yml
├── Gemfile
├── known-methods.md
├── .gitignore
├── standard-library
├── svg.md
├── indices.md
├── bipartite.md
├── graphml.md
├── index.md
├── canvas.md
├── assertions.md
├── components.md
├── layout-noverlap.md
├── simple-path.md
├── layout-force.md
├── traversal.md
├── gexf.md
├── dag.md
├── layout-forceatlas2.md
├── cores.md
├── communities-louvain.md
├── shortest-path.md
├── operators.md
├── utils.md
├── layout.md
├── generators.md
└── metrics.md
├── _config.yml
├── _local_config.yml
├── _libs.json
├── implementing-graphology.md
├── utilities.md
├── properties.md
├── Gemfile.lock
├── serialization.md
├── instantiation.md
├── performance-tips.md
├── index.md
├── events.md
├── read.md
├── design-choices.md
└── mutation.md
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 | - package-ecosystem: bundler
4 | directory: /
5 | schedule:
6 | interval: daily
7 | allow:
8 | - dependency-type: direct
9 |
--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | source 'https://rubygems.org'
2 |
3 | gem "jekyll", "~> 4.3.4" # installed by `gem jekyll`
4 | # gem "webrick" # required when using Ruby >= 3 and Jekyll <= 4.2.2
5 |
6 | gem "just-the-docs", "0.10.0" # pinned to the current release
7 | # gem "just-the-docs" # always download the latest release
8 |
--------------------------------------------------------------------------------
/known-methods.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: Known methods
4 | nav_order: 14
5 | menu_toc:
6 | - "#.toJSON"
7 | - "#.inspect"
8 | ---
9 |
10 | # Known methods
11 |
12 | ## #.toJSON
13 |
14 | Alias of the [`#.export`](#export) method used by JavaScript to serialize the `Graph` instance when using `JSON.stringify`.
15 |
16 | ```js
17 | JSON.stringify(graph);
18 | ```
19 |
20 | ## #.inspect
21 |
22 | Used by node.js to pretty print the object when using `console.log`.
23 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Not sure what a .gitignore is?
2 | # See: https://git-scm.com/docs/gitignore
3 |
4 | # These are directly copied from Jekyll's first-party docs on `.gitignore` files:
5 | # https://jekyllrb.com/tutorials/using-jekyll-with-bundler/#commit-to-source-control
6 |
7 | # Ignore the default location of the built site, and caches and metadata generated by Jekyll
8 | _site/
9 | .sass-cache/
10 | .jekyll-cache/
11 | .jekyll-metadata
12 |
13 | # Ignore folders generated by Bundler
14 | .bundle/
15 | vendor/
16 |
--------------------------------------------------------------------------------
/standard-library/svg.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: svg
4 | nav_order: 19
5 | parent: Standard library
6 | aux_links:
7 | "Library directory": "https://github.com/graphology/graphology/tree/master/src/svg"
8 |
9 | ---
10 |
11 | # Graphology SVG
12 |
13 | SVG rendering routines for [`graphology`](..).
14 |
15 | ## Installation
16 |
17 | ```
18 | npm install graphology-svg
19 | ```
20 |
21 | ## Usage
22 |
23 | ```js
24 | var render = require('graphology-svg');
25 |
26 | render(graph, './graph.svg', () => console.log('Done!'));
27 | render(graph, './graph.svg', settings, () => console.log('Done!'));
28 | ```
29 |
30 |
--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 |
3 | on:
4 | push:
5 | branches: ["master"]
6 | pull_request:
7 |
8 | jobs:
9 | # Build job
10 | build:
11 | runs-on: ubuntu-latest
12 | steps:
13 | - name: Checkout
14 | uses: actions/checkout@v4
15 | - name: Setup Ruby
16 | uses: ruby/setup-ruby@v1
17 | with:
18 | ruby-version: '3.3' # Not needed with a .ruby-version file
19 | bundler-cache: true # runs 'bundle install' and caches installed gems automatically
20 | cache-version: 0 # Increment this number if you need to re-download cached gems
21 | - name: Build with Jekyll
22 | run: bundle exec jekyll build
23 |
--------------------------------------------------------------------------------
/_config.yml:
--------------------------------------------------------------------------------
1 | title: Graphology
2 | theme: just-the-docs
3 | color_scheme: 'light'
4 | search_enabled: true
5 | aux_links:
6 | GitHub Repository: https://github.com/graphology/graphology
7 | aux_links_new_tab: false
8 |
9 | # Footer last edited timestamp
10 | last_edit_timestamp: true # show or hide edit time - page must have `last_modified_date` defined in the frontmatter
11 | last_edit_time_format: "%b %e %Y at %I:%M %p" # uses ruby's time format: https://ruby-doc.org/stdlib-2.7.0/libdoc/time/rdoc/Time.html
12 |
13 | # Footer "Edit this page on GitHub" link text
14 | gh_edit_link: true # show or hide edit this page link
15 | gh_edit_link_text: "Edit this page on GitHub."
16 | gh_edit_repository: "https://github.com/graphology/graphology.github.io" # the github URL for your repo
17 | gh_edit_branch: "main" # the branch that your docs is served from
18 | # gh_edit_source: docs # the source that your files originate from
19 | gh_edit_view_mode: "edit" # "tree" or "edit" if you want the user to jump into the editor immediate
20 |
--------------------------------------------------------------------------------
/_local_config.yml:
--------------------------------------------------------------------------------
1 | title: Graphology
2 | theme: just-the-docs
3 | color_scheme: 'light'
4 | search_enabled: true
5 | aux_links:
6 | GitHub Repository: https://github.com/graphology/graphology
7 | aux_links_new_tab: false
8 |
9 | # Footer last edited timestamp
10 | last_edit_timestamp: true # show or hide edit time - page must have `last_modified_date` defined in the frontmatter
11 | last_edit_time_format: "%b %e %Y at %I:%M %p" # uses ruby's time format: https://ruby-doc.org/stdlib-2.7.0/libdoc/time/rdoc/Time.html
12 |
13 | # Footer "Edit this page on GitHub" link text
14 | gh_edit_link: true # show or hide edit this page link
15 | gh_edit_link_text: "Edit this page on GitHub."
16 | gh_edit_repository: "https://github.com/graphology/graphology.github.io" # the github URL for your repo
17 | gh_edit_branch: "main" # the branch that your docs is served from
18 | # gh_edit_source: docs # the source that your files originate from
19 | gh_edit_view_mode: "edit" # "tree" or "edit" if you want the user to jump into the editor immediate
20 |
--------------------------------------------------------------------------------
/standard-library/indices.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: indices
4 | nav_order: 10
5 | parent: Standard library
6 | aux_links:
7 | "Library directory": "https://github.com/graphology/graphology/tree/master/src/indices"
8 | "Changelog": "https://github.com/graphology/graphology/tree/master/src/indices/CHANGELOG.md"
9 | ---
10 |
11 | # Graphology Indices
12 |
13 | Miscellaneous indices to be used with [`graphology`](..).
14 |
15 | ## Installation
16 |
17 | ```
18 | npm install graphology-indices
19 | ```
20 |
21 | ## Contents
22 |
23 | This library contains multiple low-level indexation structures used to optimize graph computations in other `graphology` libraries. This library is not meant to be used as such and this is why it is not thoroughly documented.
24 |
25 | For now, here are the exposed indices:
26 |
27 | - An unweighted and weighted neighborhood index used to speed up computations requiring many successive BSTs in a graph.
28 | - A directed and undirected index used to track an evolving community structure when running the Louvain community detection algorithm.
29 | - An indexed view of a graph's connected components sorted by order.
30 | - A specialized stack/set that can be used to perform memory-efficient DFS traversals.
31 | - A specialized queue/set that can be used to perform memory-efficient BFS traversals.
32 |
33 |
--------------------------------------------------------------------------------
/standard-library/bipartite.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: bipartite
4 | nav_order: 1
5 | parent: Standard library
6 | aux_links:
7 | "Library directory": "https://github.com/graphology/graphology/tree/master/src/bipartite"
8 | "Changelog": "https://github.com/graphology/graphology/tree/master/src/bipartite/CHANGELOG.md"
9 | ---
10 |
11 | # Graphology Bipartite
12 |
13 | Functions related to bipartite graphs and to be used with [`graphology`](..).
14 |
15 | ## Installation
16 |
17 | ```
18 | npm install graphology-bipartite
19 | ```
20 |
21 | ## Usage
22 |
23 | - [isBypartiteBy](#isbypartiteby)
24 |
25 | ### isBypartiteBy
26 |
27 | Returns whether the given graph is bipartite according to the given partition scheme.
28 |
29 | ```js
30 | import {isBypartiteBy} from 'graphology-bipartite';
31 | // Alternatively, to load only the relevant code:
32 | import isBypartiteBy from 'graphology-bipartite/is-bipartite-by';
33 |
34 | // Wrt some node attribute:
35 | isBipartiteBy(graph, 'category');
36 |
37 | // Using some getter function:
38 | isBipartiteBy(graph, (node, attr) => externalIndex[node].category);
39 | ```
40 |
41 | _Arguments_
42 |
43 | - **graph** _Graph_: target graph.
44 | - **getNodePartition** _string\|function_: node attribute name or getter function taking a node entry (node, attributes) and returning this node's partition.
45 |
46 |
--------------------------------------------------------------------------------
/_libs.json:
--------------------------------------------------------------------------------
1 | {
2 | "assertions": "Miscellaneous assertions (same nodes, same edges etc.).",
3 | "bipartite": "Bipartite graph helper functions (coloring, projection etc.).",
4 | "canvas": "Canvas rendering routines for graphs.",
5 | "communities-louvain": "Louvain method for community detection.",
6 | "components": "Connected components (strong, weak etc.).",
7 | "dag": "Functions related to directed acyclic graphs (cycle detection, topological sorting etc.).",
8 | "cores": "Various utilities related to k-cores.",
9 | "generators": "Graph generators (random graphs, complete graphs etc.).",
10 | "gexf": "Parsers & writers for the GEXF file format.",
11 | "graphml": "Parsers & writers for the GRAPHML file format.",
12 | "indices": "Various specialized graph indices (neighborhood, louvain etc.)",
13 | "layout": "Basic graph layouts (random, circle etc.).",
14 | "layout-force": "Basic force layout algorithm.",
15 | "layout-forceatlas2": "ForceAtlas2 layout algorithm.",
16 | "layout-noverlap": "Noverlap anti-collision layout algorithm.",
17 | "metrics": "Modularity, density, centrality etc.",
18 | "operators": "Graph unary, binary & cast operators (reverse, union, intersection, conversion etc.)",
19 | "shortest-path": "Shortest path functions (Dijkstra, A\\* etc.)",
20 | "simple-path": "Simple path related functions (e.g. all paths between source & target)",
21 | "svg": "SVG export for graphs.",
22 | "traversal": "Traversal functions (DFS, BFS, etc.)",
23 | "utils": "Miscellaneous utils used by most of the other modules."
24 | }
25 |
--------------------------------------------------------------------------------
/standard-library/graphml.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: graphml
4 | nav_order: 9
5 | parent: Standard library
6 | aux_links:
7 | "Library directory": "https://github.com/graphology/graphology/tree/master/src/graphml"
8 |
9 | ---
10 |
11 | # Graphology GRAPHML Utilities
12 |
13 | GRAPHML parser & writer for [`graphology`](..).
14 |
15 | For more information about the GRAPHML file format, you can head [there](http://graphml.graphdrawing.org/).
16 |
17 | ## Installation
18 |
19 | ```
20 | npm install graphology-graphml
21 | ```
22 |
23 | ## Usage
24 |
25 | - [Parser](#parser)
26 |
27 | ### Parser
28 |
29 | The parser must be passed a `graphology` constructor and is able to read either a string, or an `XMLDocument` instance.
30 |
31 | ```js
32 | var Graph = require('graphology');
33 |
34 | // Node
35 | var graphml = require('graphology-graphml');
36 | // Browser
37 | var graphml = require('graphology-graphml/browser');
38 |
39 | // Reading a string
40 | var graph = graphml.parse(Graph, string);
41 |
42 | // Reading a dom document
43 | var graph = graphml.parse(Graph, xmlDocument);
44 |
45 | // Passing options
46 | var graph = graphml.parse(Graph, string, {addMissingNodes: true});
47 | ```
48 |
49 | _Arguments_
50 |
51 | - **constructor** _GraphClass_: graphology constructor to use.
52 | - **source** _string\|Document_: source data to parse.
53 | - **options** ?object: parsing options:
54 | - **addMissingNodes** ?boolean false: whether to add missing nodes referenced in the file's edges.
55 |
56 |
--------------------------------------------------------------------------------
/implementing-graphology.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: Implementing graphology
4 | nav_order: 15
5 | ---
6 |
7 | # Implementing graphology
8 |
9 | Although the `graphology` npm package proposes its reference implementation, `graphology`is actually only a specification for a JavaScript/TypeScript `Graph` that anyone remains free to implement however they like.
10 |
11 | What's more, any custom implementation of `graphology` remains completely able to use all of the [standard library](./standard-library) and type declarations, without any additional complications.
12 |
13 | Graphs are complex structures and, while we designed the reference implementation to handle most common cases with good performance, there is no silver bullet and one will always be able to implement the present specifications in a more performant fashion for very specific use cases.
14 |
15 | If you wish to implement `graphology` on your own and want to be sure you are doing it correctly, know that it is possible to test your own implementation against the lib's unit tests.
16 |
17 | ## Running the unit tests
18 |
19 | First, you need to install `graphology` and `mocha` from npm:
20 |
21 | ```
22 | npm install --save-dev graphology mocha
23 | ```
24 |
25 | Then you need to create a file that will be run by `mocha`:
26 |
27 | ```js
28 | // test.js
29 | import specs from 'graphology/specs';
30 | import Graph from 'my-custom-graphology-implementation';
31 |
32 | module.exports = specs(Graph, Graph);
33 | ```
34 |
35 | *Arguments*
36 |
37 | * **class** function: the Graph class of your implementation.
38 | * **implementation** object: an object containing the rest of the implementation (alternative constructors, errors). Note that most of the time, or at least if you export your implementation through CommonJS, the `class` and `implementation` arguments will be the same.
39 |
40 | Then, run the tests using `mocha`:
41 |
42 | ```
43 | mocha -u exports test.js
44 | ```
45 |
--------------------------------------------------------------------------------
/.github/workflows/pages.yml:
--------------------------------------------------------------------------------
1 | # This workflow uses actions that are not certified by GitHub.
2 | # They are provided by a third-party and are governed by
3 | # separate terms of service, privacy policy, and support
4 | # documentation.
5 |
6 | # Sample workflow for building and deploying a Jekyll site to GitHub Pages
7 | name: Deploy Jekyll site to Pages
8 |
9 | on:
10 | push:
11 | branches: ["master"]
12 |
13 | # Allows you to run this workflow manually from the Actions tab
14 | workflow_dispatch:
15 |
16 | # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
17 | permissions:
18 | contents: read
19 | pages: write
20 | id-token: write
21 |
22 | # Allow one concurrent deployment
23 | concurrency:
24 | group: "pages"
25 | cancel-in-progress: true
26 |
27 | jobs:
28 | # Build job
29 | build:
30 | runs-on: ubuntu-latest
31 | steps:
32 | - name: Checkout
33 | uses: actions/checkout@v4
34 | - name: Setup Ruby
35 | uses: ruby/setup-ruby@v1
36 | with:
37 | ruby-version: '3.3' # Not needed with a .ruby-version file
38 | bundler-cache: true # runs 'bundle install' and caches installed gems automatically
39 | cache-version: 0 # Increment this number if you need to re-download cached gems
40 | - name: Setup Pages
41 | id: pages
42 | uses: actions/configure-pages@v5
43 | - name: Build with Jekyll
44 | # Outputs to the './_site' directory by default
45 | run: bundle exec jekyll build --baseurl "${{ steps.pages.outputs.base_path }}"
46 | env:
47 | JEKYLL_ENV: production
48 | - name: Upload artifact
49 | # Automatically uploads an artifact from the './_site' directory by default
50 | uses: actions/upload-pages-artifact@v3
51 |
52 | # Deployment job
53 | deploy:
54 | environment:
55 | name: github-pages
56 | url: ${{ steps.deployment.outputs.page_url }}
57 | runs-on: ubuntu-latest
58 | needs: build
59 | steps:
60 | - name: Deploy to GitHub Pages
61 | id: deployment
62 | uses: actions/deploy-pages@v4
63 |
--------------------------------------------------------------------------------
/utilities.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: Utilities
4 | nav_order: 13
5 | menu_toc:
6 | - "#.copy"
7 | - "#.nullCopy"
8 | - "#.emptyCopy"
9 | ---
10 |
11 | # Utilities
12 |
13 | ## #.copy
14 |
15 | Returns a copy of the current instance.
16 |
17 | *Example*
18 |
19 | ```js
20 | graph.mergeEdgeWithKey('T->E', 'Thomas', 'Eric', {type: 'KNOWS'});
21 |
22 | const newGraph = graph.copy();
23 | newGraph.hasNode('Eric');
24 | >>> true
25 | newGraph.order
26 | >>> 2
27 | newGraph.size
28 | >>> 1
29 | graph.type === newGraph.type
30 | >>> true
31 | ```
32 |
33 | *Arguments*
34 |
35 | * **options** [object]: options to merge to create a slightly different graph. Note that those options will be validated to ensure that created graph is an "upgrade" and so no information can be lost. For instance, a mixed graph can be created from a directed one, but the reverse is not true.
36 |
37 | ## #.nullCopy
38 |
39 | Returns a null copy, i.e. a copy of the graph without nodes nor edges, of the current instance while retaining the type & the options of the graph.
40 |
41 | *Example*
42 |
43 | ```js
44 | graph.mergeEdgeWithKey('T->E', 'Thomas', 'Eric', {type: 'KNOWS'});
45 |
46 | const newGraph = graph.nullCopy();
47 | newGraph.hasNode('Eric');
48 | >>> false
49 | newGraph.order
50 | >>> 0
51 | newGraph.size
52 | >>> 0
53 | graph.type === newGraph.type
54 | >>> true
55 | ```
56 |
57 | *Arguments*
58 |
59 | * **options** [object]: options to merge to create a graph with different characteristics.
60 |
61 | ## #.emptyCopy
62 |
63 | Returns an empty copy, i.e. a copy of the graph containing only nodes, of the current instance while retaining the type & the options of the graph.
64 |
65 | This is useful to functions needing to return subgraphs or near identical copies of a graph such as reversed graph or graph converted to another type altogether.
66 |
67 | *Example*
68 |
69 | ```js
70 | graph.mergeEdgeWithKey('T->E', 'Thomas', 'Eric', {type: 'KNOWS'});
71 |
72 | const newGraph = graph.emptyCopy();
73 | newGraph.hasNode('Eric');
74 | >>> true
75 | newGraph.order
76 | >>> 2
77 | newGraph.size
78 | >>> 0
79 | newGraph.hasEdge('Thomas', 'Eric');
80 | >>> false
81 | graph.type === newGraph.type
82 | >>> true
83 | ```
84 |
85 | *Arguments*
86 |
87 | * **options** [object]: options to merge to create a graph with different characteristics.
88 |
--------------------------------------------------------------------------------
/properties.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: Properties
4 | nav_order: 4
5 | menu_toc:
6 | - "#.order"
7 | - "#.size"
8 | - "#.type"
9 | - "#.multi"
10 | - "#.allowSelfLoops"
11 | - "#.selfLoopCount"
12 | - "#.implementation"
13 | ---
14 |
15 | # Properties
16 |
17 | All the following properties are read-only and may not be changed by the user.
18 |
19 | ## #.order
20 |
21 | Number of nodes in the graph.
22 |
23 | *Example*
24 |
25 | ```js
26 | const graph = new Graph();
27 |
28 | graph.addNode('John');
29 | graph.addNode('Jack');
30 |
31 | graph.order;
32 | >>> 2
33 | ```
34 |
35 | ## #.size
36 |
37 | Number of edges in the graph.
38 |
39 | *Example*
40 |
41 | ```js
42 | const graph = new Graph();
43 |
44 | graph.addNode('John');
45 | graph.addNode('Jack');
46 |
47 | graph.addEdge('John', 'Jack');
48 |
49 | graph.size;
50 | >>> 1
51 | ```
52 |
53 | *Variants*
54 |
55 | * `#.directedSize`
56 | * `#.undirectedSize`
57 |
58 | ## #.type
59 |
60 | Type of the graph. One of `mixed`, `directed` or `undirected`.
61 |
62 | *Example*
63 |
64 | ```js
65 | const graph = new Graph();
66 | graph.type;
67 | >>> 'mixed'
68 |
69 | const directedGraph = new DirectedGraph();
70 | directedGraph.type;
71 | >>> 'directed'
72 | ```
73 |
74 | ## #.multi
75 |
76 | Whether the graph accepts parallel edges or not.
77 |
78 | *Example*
79 |
80 | ```js
81 | const graph = new Graph();
82 | graph.multi;
83 | >>> false
84 |
85 | const multiGraph = new MultiGraph();
86 | multiGraph.multi;
87 | >>> true
88 | ```
89 |
90 | ## #.allowSelfLoops
91 |
92 | Whether the graph accepts self loops or not.
93 |
94 | ```js
95 | const graph = new Graph();
96 | graph.allowSelfLoops;
97 | >>> true
98 |
99 | const otherGraph = new Graph({allowSelfLoops: false});
100 | graph.allowSelfLoops;
101 | >>> false
102 | ```
103 |
104 | ## #.selfLoopCount
105 |
106 | The total number of self loop included in the graph.
107 |
108 | ```js
109 | const graph = new Graph();
110 |
111 | graph.selfLoopCount
112 | >>> 0
113 |
114 | graph.mergeEdge('John', 'John');
115 |
116 | graph.selfLoopCount
117 | >>> 1
118 | ```
119 |
120 | *Variants*
121 |
122 | * `#.directedSelfLoopCount`
123 | * `#.undirectedSelfLoopCount`
124 |
125 | ## #.implementation
126 |
127 | A string containing the graph instance's implementation name.
128 |
129 | ```js
130 | import Graph from 'graphology';
131 |
132 | const graph = new Graph();
133 | graph.implementation;
134 | >>> 'graphology'
135 | ```
136 |
137 | It can be useful if you ever need to optimize libraries based upon the knowledge that the given instance is from a specific implementation.
138 |
--------------------------------------------------------------------------------
/Gemfile.lock:
--------------------------------------------------------------------------------
1 | GEM
2 | remote: https://rubygems.org/
3 | specs:
4 | addressable (2.8.7)
5 | public_suffix (>= 2.0.2, < 7.0)
6 | bigdecimal (3.1.8)
7 | colorator (1.1.0)
8 | concurrent-ruby (1.3.4)
9 | em-websocket (0.5.3)
10 | eventmachine (>= 0.12.9)
11 | http_parser.rb (~> 0)
12 | eventmachine (1.2.7)
13 | ffi (1.17.0-arm64-darwin)
14 | ffi (1.17.0-x86_64-darwin)
15 | ffi (1.17.0-x86_64-linux-gnu)
16 | forwardable-extended (2.6.0)
17 | google-protobuf (4.28.1-arm64-darwin)
18 | bigdecimal
19 | rake (>= 13)
20 | google-protobuf (4.28.1-x86_64-darwin)
21 | bigdecimal
22 | rake (>= 13)
23 | google-protobuf (4.28.1-x86_64-linux)
24 | bigdecimal
25 | rake (>= 13)
26 | http_parser.rb (0.8.0)
27 | i18n (1.14.6)
28 | concurrent-ruby (~> 1.0)
29 | jekyll (4.3.4)
30 | addressable (~> 2.4)
31 | colorator (~> 1.0)
32 | em-websocket (~> 0.5)
33 | i18n (~> 1.0)
34 | jekyll-sass-converter (>= 2.0, < 4.0)
35 | jekyll-watch (~> 2.0)
36 | kramdown (~> 2.3, >= 2.3.1)
37 | kramdown-parser-gfm (~> 1.0)
38 | liquid (~> 4.0)
39 | mercenary (>= 0.3.6, < 0.5)
40 | pathutil (~> 0.9)
41 | rouge (>= 3.0, < 5.0)
42 | safe_yaml (~> 1.0)
43 | terminal-table (>= 1.8, < 4.0)
44 | webrick (~> 1.7)
45 | jekyll-include-cache (0.2.1)
46 | jekyll (>= 3.7, < 5.0)
47 | jekyll-sass-converter (3.0.0)
48 | sass-embedded (~> 1.54)
49 | jekyll-seo-tag (2.8.0)
50 | jekyll (>= 3.8, < 5.0)
51 | jekyll-watch (2.2.1)
52 | listen (~> 3.0)
53 | just-the-docs (0.10.0)
54 | jekyll (>= 3.8.5)
55 | jekyll-include-cache
56 | jekyll-seo-tag (>= 2.0)
57 | rake (>= 12.3.1)
58 | kramdown (2.4.0)
59 | rexml
60 | kramdown-parser-gfm (1.1.0)
61 | kramdown (~> 2.0)
62 | liquid (4.0.4)
63 | listen (3.9.0)
64 | rb-fsevent (~> 0.10, >= 0.10.3)
65 | rb-inotify (~> 0.9, >= 0.9.10)
66 | mercenary (0.4.0)
67 | pathutil (0.16.2)
68 | forwardable-extended (~> 2.6)
69 | public_suffix (6.0.1)
70 | rake (13.2.1)
71 | rb-fsevent (0.11.2)
72 | rb-inotify (0.11.1)
73 | ffi (~> 1.0)
74 | rexml (3.3.7)
75 | rouge (4.3.0)
76 | safe_yaml (1.0.5)
77 | sass-embedded (1.78.0-arm64-darwin)
78 | google-protobuf (~> 4.27)
79 | sass-embedded (1.78.0-x86_64-darwin)
80 | google-protobuf (~> 4.27)
81 | sass-embedded (1.78.0-x86_64-linux-gnu)
82 | google-protobuf (~> 4.27)
83 | terminal-table (3.0.2)
84 | unicode-display_width (>= 1.1.1, < 3)
85 | unicode-display_width (2.6.0)
86 | webrick (1.8.1)
87 |
88 | PLATFORMS
89 | arm64-darwin
90 | x86_64-darwin-23
91 | x86_64-linux-gnu
92 |
93 | DEPENDENCIES
94 | jekyll (~> 4.3.4)
95 | just-the-docs (= 0.10.0)
96 |
97 | BUNDLED WITH
98 | 2.5.9
99 |
--------------------------------------------------------------------------------
/standard-library/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: Standard library
4 | nav_order: 1
5 | has_children: true
6 | has_toc: false
7 | ---
8 |
9 | # Standard library
10 |
11 | * [assertions](./assertions): *Miscellaneous assertions (same nodes, same edges etc.).*
12 | * [bipartite](./bipartite): *Bipartite graph helper functions (coloring, projection etc.).*
13 | * [canvas](./canvas): *Canvas rendering routines for graphs.*
14 | * [communities-louvain](./communities-louvain): *Louvain method for community detection.*
15 | * [components](./components): *Connected components (strong, weak etc.).*
16 | * [dag](./dag): *Functions related to directed acyclic graphs (cycle detection, topological sorting etc.).*
17 | * [cores](./cores): *Various utilities related to k-cores.*
18 | * [generators](./generators): *Graph generators (random graphs, complete graphs etc.).*
19 | * [gexf](./gexf): *Parsers & writers for the GEXF file format.*
20 | * [graphml](./graphml): *Parsers & writers for the GRAPHML file format.*
21 | * [indices](./indices): *Various specialized graph indices (neighborhood, louvain etc.)*
22 | * [layout](./layout): *Basic graph layouts (random, circle etc.).*
23 | * [layout-force](./layout-force): *Basic force layout algorithm.*
24 | * [layout-forceatlas2](./layout-forceatlas2): *ForceAtlas2 layout algorithm.*
25 | * [layout-noverlap](./layout-noverlap): *Noverlap anti-collision layout algorithm.*
26 | * [metrics](./metrics): *Modularity, density, centrality etc.*
27 | * [operators](./operators): *Graph unary, binary & cast operators (reverse, union, intersection, conversion etc.)*
28 | * [shortest-path](./shortest-path): *Shortest path functions (Dijkstra, A\* etc.)*
29 | * [simple-path](./simple-path): *Simple path related functions (e.g. all paths between source & target)*
30 | * [svg](./svg): *SVG export for graphs.*
31 | * [traversal](./traversal): *Traversal functions (DFS, BFS, etc.)*
32 | * [utils](./utils): *Miscellaneous utils used by most of the other modules.*
33 |
34 | ## Interactive rendering
35 |
36 | If what you need is interactive rendering of your graphs, in web applications for instance,
37 | be sure to check out [sigma.js](https://www.sigmajs.org/), a webgl renderer
38 | designed to work with `graphology` and which has been created for such endeavors.
39 |
40 | ## Installation
41 |
42 | Any of the above packages can be installed through npm likewise (just change the name to
43 | the desired package):
44 |
45 | ```
46 | npm install graphology-metrics
47 | ```
48 |
49 | For convenience, an aggregated package called `graphology-library` also exists
50 | and depends on all the listed packages at once for convenience (albeit maybe
51 | a little bit more complicated to optimize through tree-shaking).
52 |
53 | You can install it thusly:
54 |
55 | ```
56 | npm install graphology-library
57 | ```
58 |
59 | If you do so, here is how to access the required packages:
60 |
61 | ```js
62 | // Importing a sub package
63 | import * as metrics from 'graphology-library/metrics';
64 |
65 | metrics.density(graph);
66 |
67 | // Importing select parts of the library
68 | import {metrics, layout} from 'graphology-library';
69 |
70 | // Importing the whole library
71 | import * as lib from 'graphology-library';
72 |
73 | // Importing the browser-specific library
74 | // (this is important for xml parsers and some layout's webworkers)
75 | import * as lib from 'graphology-library/browser';
76 | ```
77 |
--------------------------------------------------------------------------------
/standard-library/canvas.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: canvas
4 | nav_order: 2
5 | parent: Standard library
6 | aux_links:
7 | "Library directory": "https://github.com/graphology/graphology/tree/master/src/canvas"
8 | "Changelog": "https://github.com/graphology/graphology/tree/master/src/canvas/CHANGELOG.md"
9 | ---
10 |
11 | # Graphology Canvas
12 |
13 | Canvas rendering routines for [`graphology`](..).
14 |
15 | ## Installation
16 |
17 | ```
18 | npm install graphology-canvas
19 | ```
20 |
21 | If you need to use this package's functions in node, you will also need to install [`node-canvas`](https://www.npmjs.com/package/canvas) thusly:
22 |
23 | ```
24 | npm install canvas
25 | ```
26 |
27 | If you experience any issue when installing the libray check that you have the required dependencies as listed [here](https://www.npmjs.com/package/canvas#compiling).
28 |
29 | ## Usage
30 |
31 | ### Pre-requisites
32 |
33 | Each node's position must be set before rendering a graph. Two attributes called `x` and `y` must therefore be defined for all the graph nodes. [graphology-layout](/standard-library/layout) or [graphology-layout-forceatlas2](/standard-library/layout-forceatlas2), for instance, can be used to give positions to nodes if they don't have one already.
34 |
35 | ### Rendering a graph in an arbitrary canvas context
36 |
37 | ```js
38 | import {render} from 'graphology-canvas';
39 |
40 | render(graph, context, settings);
41 | ```
42 |
43 | ### Rendering asynchronously to avoid freezing main thread
44 |
45 | ```js
46 | import {renderAsync} from 'graphology-canvas';
47 |
48 | renderAsync(graph, context, settings, function () {
49 | console.log('Done!');
50 | });
51 | ```
52 |
53 | ### Rendering a graph to PNG in node
54 |
55 | ```js
56 | import {renderToPNG} from 'graphology-canvas/node';
57 |
58 | renderToPNG(graph, './graph.png', () => console.log('Done!'));
59 | renderToPNG(graph, './graph.png', settings, () => console.log('Done!'));
60 | ```
61 |
62 | ### Settings
63 |
64 | - **width** ?number 2048: width of the canvas. Will be the same as `height` if not provided.
65 | - **height** ?number 2048: height of the canvas. Will be the same as `width` if not provided.
66 | - **padding** ?number 20: padding to keep around the drawing.
67 | - **nodes** ?object: node-related settings:
68 | - **defaultColor** ?string #999: default color for nodes.
69 | - **reducer** ?function: reducer fonction for nodes taking the rendering settings, the node key and its attributes and tasked to return rendering info such as `color`, `size` etc.
70 | - **edges** ?object: node-related settings:
71 | - **defaultColor** ?string #ccc: default color for edges.
72 | - **reducer** ?function: reducer fonction for edges taking the rendering settings, the node key and its attributes and tasked to return rendering info such as `color`, `size` etc.
73 |
74 | ### Async Settings
75 |
76 | - **batchSize** ?number 500: number of items to render on canvas on each animation frame, increase or decrease to tweak performance vs. UI availability.
77 |
78 |
--------------------------------------------------------------------------------
/standard-library/assertions.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: assertions
4 | nav_order: 0
5 | parent: Standard library
6 | aux_links:
7 | "Library directory": "https://github.com/graphology/graphology/tree/master/src/assertions"
8 | "Changelog": "https://github.com/graphology/graphology/tree/master/src/assertions/CHANGELOG.md"
9 | ---
10 |
11 | # Graphology Assertions
12 |
13 | Assertions to be used with [`graphology`](..).
14 |
15 | ## Installation
16 |
17 | ```
18 | npm install graphology-assertions
19 | ```
20 |
21 | ## Usage
22 |
23 | - [#.isGraph](#isgraph)
24 | - [#.isGraphConstructor](#isgraphconstructor)
25 | - [#.haveSameNodes](#hassamenodes)
26 | - [#.haveSameNodesDeep](#hassamenodesdeep)
27 | - [#.areSameGraphs](#issamegraph)
28 | - [#.areSameGraphsDeep](#issamegraphdeep)
29 | - [#.haveSameEdges](#havesameedges)
30 | - [#.haveSameEdgesDeep](#havesameedgesdeep)
31 |
32 | ### #.isGraph
33 |
34 | Function returning whether the given value is a `graphology` implementation's instance.
35 |
36 | ```js
37 | import {isGraph} from 'graphology-assertions';
38 |
39 | const graph = new Graph();
40 |
41 | isGraph(graph);
42 | >>> true
43 |
44 | isGraph(45);
45 | >>> false
46 |
47 | isGraph({hello: 'world'});
48 | >>> false
49 | ```
50 |
51 | _Arguments_
52 |
53 | - **value** _any_: value to test.
54 |
55 | ### #.isGraphConstructor
56 |
57 | Function returning whether the given value is a `graphology` constructor.
58 |
59 | ```js
60 | import {isGraphConstructor} from 'graphology-assertions';
61 |
62 | isGraphConstructor(Graph);
63 | >>> true
64 |
65 | isGraphConstructor(45);
66 | >>> false
67 |
68 | isGraphConstructor(new Graph());
69 | >>> false
70 | ```
71 |
72 | _Arguments_
73 |
74 | - **value** _any_: value to test.
75 |
76 | ### #.haveSameNodes
77 |
78 | Returns whether two graphs have the same nodes.
79 |
80 | ```js
81 | import {haveSameNodes} from 'graphology-assertions';
82 |
83 | haveSameNodes(G, H);
84 | ```
85 |
86 | ### #.haveSameNodesDeep
87 |
88 | Returns whether two graphs have the same nodes & whether those nodes have the same attributes.
89 |
90 | ```js
91 | import {haveSameNodesDeep} from 'graphology-assertions';
92 |
93 | haveSameNodesDeep(G, H);
94 | ```
95 |
96 | ### #.areSameGraphs
97 |
98 | Returns whether two graphs are the same.
99 |
100 | ```js
101 | import {areSameGraphs} from 'graphology-assertions';
102 |
103 | areSameGraphs(G, H);
104 | ```
105 |
106 | ### #.areSameGraphsDeep
107 |
108 | Returns whether two graphs as well as their node & edge attributes are the same.
109 |
110 | ```js
111 | import {areSameGraphsDeep} from 'graphology-assertions';
112 |
113 | areSameGraphsDeep(G, H);
114 | ```
115 |
116 | ### #.haveSameEdges
117 |
118 | Returns whether two graphs have the same edges. Note that it implies that both graphs' nodes are also the same.
119 |
120 | This is different than [areSameGraphs](#aresamegraphs) because it will allow different graph types to be compared, e.g. a mixed graph and a directed one having the same edges nonetheless.
121 |
122 | ```js
123 | import {haveSameEdges} from 'graphology-assertions';
124 |
125 | haveSameEdges(G, H);
126 | ```
127 |
128 | ### #.haveSameEdgesDeep
129 |
130 | Returns whether two graphs have the same edges & whether those edges have the same attributes. Note that it implies that both graphs' nodes are also the same.
131 |
132 | This is different than [areSameGraphsDeep](#aresamegraphsdeep) because it will allow different graph types to be compared, e.g. a mixed graph and a directed one having the same edges nonetheless.
133 |
134 | ```js
135 | import {haveSameEdgesDeep} from 'graphology-assertions';
136 |
137 | haveSameEdgesDeep(G, H);
138 | ```
139 |
140 |
--------------------------------------------------------------------------------
/standard-library/components.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: components
4 | nav_order: 4
5 | parent: Standard library
6 | aux_links:
7 | "Library directory": "https://github.com/graphology/graphology/tree/master/src/components"
8 | "Changelog": "https://github.com/graphology/graphology/tree/master/src/components/CHANGELOG.md"
9 | ---
10 |
11 | # Graphology Components
12 |
13 | Connected components for [`graphology`](..).
14 |
15 | ## Installation
16 |
17 | ```
18 | npm install graphology-components
19 | ```
20 |
21 | ## Usage
22 |
23 | - [forEachConnectedComponent](#foreachconnectedcomponent)
24 | - [forEachConnectedComponentOrder](#foreachconnectedcomponentorder)
25 | - [countConnectedComponents](#countconnectedcomponents)
26 | - [connectedComponents](#connectedcomponents)
27 | - [largestConnectedComponent](#largestconnectedcomponent)
28 | - [largestConnectedComponentSubgraph](#largestconnectedcomponentsubgraph)
29 | - [cropToLargestConnectedComponent](#cropToLargestConnectedComponent)
30 | - [stronglyConnectedComponents](#stronglyconnectedcomponents)
31 |
32 | ### forEachConnectedComponent
33 |
34 | Iterates over the connected components of the given graph using a callback.
35 |
36 | ```js
37 | import {forEachConnectedComponent} from 'graphology-components';
38 |
39 | forEachConnectedComponent(graph, component => {
40 | console.log(component);
41 | });
42 | ```
43 |
44 | ### forEachConnectedComponentOrder
45 |
46 | Specialized version of [forEachConnectedComponent](#foreachconnectedcomponent) that iterates over the connected component orders, i.e. the number of nodes they contain.
47 |
48 | It consumes less memory than a naive approach mapping the component lengths using `forEachConnectedComponent`.
49 |
50 | ```js
51 | import {forEachConnectedComponentOrder} from 'graphology-components';
52 |
53 | forEachConnectedComponentOrder(graph, order => {
54 | console.log(order);
55 | });
56 | ```
57 |
58 | ### countConnectedComponents
59 |
60 | Returns the number of connected components of the given graph.
61 |
62 | ```js
63 | import {countConnectedComponents} from 'graphology-components';
64 |
65 | const count = countConnectedComponents(graph);
66 | ```
67 |
68 | ### connectedComponents
69 |
70 | Returns the list of connected components of the given graph.
71 |
72 | ```js
73 | import {connectedComponents} from 'graphology-components';
74 |
75 | const components = connectedComponents(graph);
76 | ```
77 |
78 | If your graph is mixed or directed, the result will be what are usually called **weakly connected components**.
79 |
80 | ### largestConnectedComponent
81 |
82 | Returns the largest connected component of the given graph.
83 |
84 | ```js
85 | import {largestConnectedComponent} from 'graphology-components';
86 |
87 | const largest = largestConnectedComponent(graph);
88 | ```
89 |
90 | ### largestConnectedComponentSubgraph
91 |
92 | Returns a subgraph of the largest connected component of the given graph.
93 |
94 | ```js
95 | import {largestConnectedComponentSubgraph} from 'graphology-components';
96 |
97 | const subgraph = largestConnectedComponentSubgraph(graph);
98 | ```
99 |
100 | ### cropToLargestConnectedComponent
101 |
102 | Mutates the given graph to remove nodes and edges that are not part of its largest connected component.
103 |
104 | ```js
105 | import {cropToLargestConnectedComponent} from 'graphology-components';
106 |
107 | cropToLargestConnectedComponent(graph);
108 | ```
109 |
110 | ### stronglyConnectedComponents
111 |
112 | Returns the list of strongly connected components of the given graph. (mixed or directed)
113 |
114 | ```js
115 | import {stronglyConnectedComponents} from 'graphology-components';
116 |
117 | const components = stronglyConnectedComponents(graph);
118 | ```
119 |
120 |
--------------------------------------------------------------------------------
/serialization.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: Serialization
4 | nav_order: 12
5 | menu_toc:
6 | - "Format"
7 | - "#.import"
8 | - "#.export"
9 | ---
10 |
11 | # Serialization
12 |
13 | ## Format
14 |
15 | **Node**
16 |
17 | A node is serialized as an object containing the following keys:
18 | * **key** any The node's key,
19 | * **attributes** [object] The node's attributes (can be omitted or null).
20 |
21 | ```js
22 | graph.addNode('Thomas', {age: 34});
23 | // Serialized would be:
24 | >>> {key: 'Thomas', attributes: {age: 34}}
25 | ```
26 |
27 | **Edge**
28 |
29 | An edge is serialized as an object containing the following keys:
30 | * **key** [any] The edge's key (can be omitted or null on import),
31 | * **source** any The edge's source,
32 | * **target** any The edge's target,
33 | * **attributes** [object] The edge's attributes (can be omitted or null),
34 | * **undirected** [boolean] Whether the edge is undirected (can be omitted or null).
35 |
36 | ```js
37 | graph.mergeEdgeWithKey('T->E', 'Thomas', 'Eric', {type: 'KNOWS'});
38 | // Serialized would be:
39 | >>> {
40 | key: 'T->E',
41 | source: 'Thomas',
42 | target: 'Eric',
43 | attributes: {type: 'KNOWS'}
44 | }
45 | ```
46 |
47 | **Graph**
48 |
49 | A graph is serialized as an object containing an `attributes`, a `nodes` & an `edges` key:
50 | * object `attributes`: containing the attributes of the graph (can be omitted).
51 | * object `options`: containing the options of the graph (`allowSelfLoops`, `multi` and `type`).
52 | * object `nodes`: containing a list of serialized nodes (can be omitted when merging).
53 | * object `edges`: containing a list of serialized edges (can be omitted).
54 |
55 | ```js
56 | graph.mergeEdgeWithKey('T->E', 'Thomas', 'Eric', {type: 'KNOWS'});
57 | graph.setAttribute('name', 'My Graph');
58 | graph.export();
59 | >>> {
60 | attributes: {
61 | name: 'My Graph'
62 | },
63 | options: {
64 | allowSelfLoops: true,
65 | multi: false,
66 | type: 'mixed'
67 | },
68 | nodes: [
69 | {key: 'Thomas'},
70 | {key: 'Eric'}
71 | ],
72 | edges: [
73 | {
74 | key: 'T->E',
75 | source: 'Thomas',
76 | target: 'Eric',
77 | attributes: {type: 'KNOWS'}
78 | }
79 | ]
80 | }
81 | ```
82 |
83 | ## #.import
84 |
85 | Imports a whole serialized graph into the graph.
86 |
87 | *Example*
88 |
89 | ```js
90 | graph.import({
91 | attributes: {name: 'My Graph'},
92 | nodes: [{key: 'Thomas'}, {key: 'Eric'}],
93 | edges: [{source: 'Thomas', target: 'Eric'}]
94 | });
95 |
96 | graph.hasNode('Thomas');
97 | >>> true
98 | ```
99 |
100 | *Arguments*
101 |
102 | * **data** serialized graph|Graph: serialized graph data or another Graph instance.
103 | * **merge** [boolean] false: whether to merge the imported data.
104 |
105 | ## #.export
106 |
107 | Exports the whole instance's data as a serialized graph.
108 |
109 | *Example*
110 |
111 | ```js
112 | graph.mergeEdgeWithKey('T->E', 'Thomas', 'Eric', {type: 'KNOWS'});
113 | graph.setAttribute('name', 'My Graph');
114 | graph.export();
115 | >>> {
116 | attributes: {
117 | name: 'My Graph'
118 | },
119 | nodes: [
120 | {key: 'Thomas'},
121 | {key: 'Eric'}
122 | ],
123 | edges: [
124 | {
125 | key: 'T->E',
126 | source: 'Thomas',
127 | target: 'Eric',
128 | attributes: {type: 'KNOWS'}
129 | }
130 | ]
131 | }
132 | ```
133 |
--------------------------------------------------------------------------------
/instantiation.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: Instantiation
4 | nav_order: 3
5 | menu_toc:
6 | - Options
7 | - Generics
8 | - Specialized constructors
9 | - "Static #.from method"
10 | ---
11 |
12 | # Instantiation
13 |
14 | Instantiating a `graphology` Graph object is merely an issue of requiring an implementation and calling it with some options.
15 |
16 | Note that if you need to create a Graph using some serialized data or another Graph's data, you should probably check the static [#.from](#static-from-method).
17 |
18 | ```js
19 | import Graph from 'graphology';
20 |
21 | // Here you go:
22 | const graph = new Graph();
23 |
24 | // With options:
25 | const graph = new Graph(options);
26 | ```
27 |
28 | ## Options
29 |
30 | - **allowSelfLoops** [boolean] true: should the graph allow self-loops?
31 | - **multi** [boolean] false: Should the graph allow parallel edges?
32 | - **type** [string] "mixed": Type of the graph. One of `directed`, `undirected` or `mixed`.
33 |
34 | _Examples_
35 |
36 | ```js
37 | // Creating a multi-graph with no self-loops
38 | const graph = new Graph({multi: true, allowSelfLoops: false});
39 | ```
40 |
41 | ## Generics
42 |
43 | The Graph class TypeScript declaration exposes three optional generics that you can use to restrict, in this order: node attributes, edge attributes and finally graph attributes.
44 |
45 | The given types must extend `Attributes`, which is a shorthand for `{[name: string]: any}`.
46 |
47 | ```ts
48 | type NodeAttributes = {
49 | label: string;
50 | color: string;
51 | }
52 |
53 | type EdgeAttributes = {
54 | weight: number;
55 | }
56 |
57 | type GraphAttributes = {
58 | name?: string;
59 | }
60 |
61 | const graph: Graph = new Graph();
62 | ```
63 |
64 | ## Specialized constructors
65 |
66 | Rather than providing tedious options to the constructor, one can use one of the many handy constructors provided by the implementation to create the desired graph:
67 |
68 | ```js
69 | import {MultiDirectedGraph} from 'graphology';
70 |
71 | const myCustomGraph = new MultiDirectedGraph();
72 | ```
73 |
74 | By default, the `Graph` object is a simple mixed graph, but here are the different naming "components" that you can use to instantiate a more complex graph:
75 |
76 | - **Graph with parallel edges?**: `Multi` or none (simple graph).
77 | - **Type of the graph?**: `Directed`, `Undirected` or none (mixed graph).
78 |
79 | Then to build the name, one must order the components likewise:
80 |
81 | ```
82 | Multi? + Type? + Graph
83 | ```
84 |
85 | _List of all the specialized constructors_
86 |
87 | ```
88 | DirectedGraph
89 | UndirectedGraph
90 | MultiGraph
91 | MultiDirectedGraph
92 | MultiUndirectedGraph
93 | ```
94 |
95 | ## Static #.from method
96 |
97 | Alternatively, one can create a graph from a serialized graph or another `Graph` instance using the static `#.from` method:
98 |
99 | _Example_
100 |
101 | ```js
102 | const graph = Graph.from(data);
103 |
104 | // Need some options?
105 | const graph = Graph.from(data, options);
106 |
107 | // Also works with typed constructors
108 | const graph = UndirectedGraph.from(data);
109 | ```
110 |
111 | _Arguments_
112 |
113 | - **data** Graph|SerializedGraph: pre-existing data to give to the constructor. This data can either be an existing `Graph` instance, and in this case both nodes & edges will be imported from the given graph, or a serialized graph whose format is described [here](serialization#format).
114 | - **options** [object]: options passed to the created graph.
115 |
116 | Note that `graphology` will throw an error if you try to instantiate a [typed constructor](#typed-constructors) using inconsistent options.
117 |
--------------------------------------------------------------------------------
/standard-library/layout-noverlap.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: layout-noverlap
4 | nav_order: 14
5 | parent: Standard library
6 | aux_links:
7 | "Library directory": "https://github.com/graphology/graphology/tree/master/src/layout-noverlap"
8 | "Changelog": "https://github.com/graphology/graphology/tree/master/src/layout-noverlap/CHANGELOG.md"
9 | ---
10 |
11 | # Graphology Noverlap
12 |
13 | JavaScript implementation of the Noverlap anti-collision layout algorithm for [graphology](..).
14 |
15 | Note that this algorithm is iterative and might not converge easily in some cases.
16 |
17 | ## Installation
18 |
19 | ```
20 | npm install graphology-layout-noverlap
21 | ```
22 |
23 | ## Usage
24 |
25 | - [Pre-requisite](#pre-requisite)
26 | - [Settings](#settings)
27 | - [Synchronous layout](#synchronous-layout)
28 | - [Webworker](#webworker)
29 |
30 | ### Pre-requisites
31 |
32 | Each node's starting position must be set before running the Noverlap anti-collision layout. Two attributes called `x` and `y` must therefore be defined for all the graph nodes.
33 |
34 | ### Settings
35 |
36 | - **gridSize** ?number 20: number of grid cells horizontally and vertically subdivising the graph's space. This is used as an optimization scheme. Set it to `1` and you will have `O(n²)` time complexity, which can sometimes perform better with very few nodes.
37 | - **margin** ?number 5: margin to keep between nodes.
38 | - **expansion** ?number 1.1: percentage of current space that nodes could attempt to move outside of.
39 | - **ratio** ?number 1.0: ratio scaling node sizes.
40 | - **speed** ?number 3: dampening factor that will slow down node movements to ease the overall process.
41 |
42 | ### Synchronous layout
43 |
44 | ```js
45 | import noverlap from 'graphology-layout-noverlap';
46 |
47 | const positions = noverlap(graph, {maxIterations: 50});
48 |
49 | // With settings:
50 | const positions = noverlap(graph, {
51 | maxIterations: 50,
52 | settings: {
53 | ratio: 2
54 | }
55 | });
56 |
57 | // With a custom input reducer
58 | const positions = noverlap(graph, {
59 | inputReducer: (key, attr) => ({
60 | x: store[key].x,
61 | y: store[key].y,
62 | size: attr.size
63 | }),
64 | outputReducer: (key, pos) => ({x: pos.x * 10, y: pos.y * 10})
65 | });
66 |
67 | // To directly assign the positions to the nodes:
68 | noverlap.assign(graph);
69 | ```
70 |
71 | _Arguments_
72 |
73 | - **graph** _Graph_: target graph.
74 | - **options** _object_: options:
75 | - **maxIterations** ?number 500: maximum number of iterations to perform before stopping. Note that the algorithm will also stop as soon as converged.
76 | - **inputReducer** ?function: a function reducing each node attributes. This can be useful if the rendered positions/sizes of your graph are stored outside of the graph's data. This is the case when using sigma.js for instance.
77 | - **outputReducer** ?function: a function reducing node positions as computed by the layout algorithm. This can be useful to map back to a previous coordinates system. This is the case when using sigma.js for instance.
78 | - **settings** ?object: the layout's settings (see [#settings](#settings)).
79 |
80 | ### Webworker
81 |
82 | If you need to run the layout's computation in a web worker, the library comes with a utility to do so:
83 |
84 | _Example_
85 |
86 | ```js
87 | import NoverlapLayout from 'graphology-layout-noverlap/worker';
88 |
89 | const layout = new NoverlapLayout(graph, params);
90 |
91 | // To start the layout. It will automatically stop when converged
92 | layout.start();
93 |
94 | // To stop the layout
95 | layout.stop();
96 |
97 | // To kill the layout and release attached memory
98 | layout.kill();
99 |
100 | // Assess whether the layout is currently running
101 | layout.isRunning();
102 | ```
103 |
104 |
--------------------------------------------------------------------------------
/performance-tips.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: Performance tips
4 | nav_order: 2.5
5 | ---
6 |
7 | # Performance tips
8 | {: .no_toc }
9 |
10 | 1. TOC
11 | {:toc}
12 |
13 | ## Iterate using callback methods
14 |
15 | This might seem counter-intuitive but iteration methods accepting old-fashioned callbacks (such as `#.forEachNode`, `#.forEachEdge`, for instance), are the fastest way to iterate through a graph.
16 |
17 | Here are some reasons why:
18 |
19 | 1. `#.nodes` and `#.edges` must create an array and allocate memory by doing so and you will actually double your loop if you need to iterate over them once more afterwards.
20 | 2. Callback iteration methods gives you access to almost everything you could need without additional lookup of the graph, such as attributes, edge source & target etc.
21 | 3. Iterators are nice but are still quite badly optimized by JavaScript engines (including v8).
22 |
23 | Long story short: if performance is critical, prefer callback methods.
24 |
25 | ```javascript
26 | // Slowest...
27 | graph.nodes().forEach(node => {
28 | const attr = graph.getNodeAttributes(node);
29 | console.log(node, attr);
30 | });
31 |
32 | // Still quite slow...
33 | const nodes = graph.nodes();
34 |
35 | for (let i = 0; i < nodes.length; i++) {
36 | const node = nodes[i];
37 | const attr = graph.getNodeAttributes(node);
38 | console.log(node, attr);
39 | }
40 |
41 | // Ok, I guess...
42 | for (const [node, attr] of graph.nodeEntries()) {
43 | console.log(node, attr);
44 | }
45 |
46 | // Fast 🚀
47 | graph.forEachNode((node, attr) => {
48 | console.log(node, attr);
49 | });
50 | ```
51 |
52 | Be sure, also, to avoid callback nesting if you want to keep as fast as possible.
53 |
54 | ```javascript
55 | // BAD
56 | graph.forEachNode(node => {
57 |
58 | // You are creating a function at each step of the node loop here!
59 | graph.forEachNeighbor(node, neighbor => {
60 | console.log(node, neighbor);
61 | });
62 | });
63 |
64 | // EVEN BETTER BUT CURSED
65 | let currentNode;
66 |
67 | function neighborCallback(neighbor) {
68 | console.log(currentNode, neighbor);
69 | }
70 |
71 | graph.forEachNode(node => {
72 | currentNode = node;
73 | graph.forEachNeighbor(node, neighborCallback);
74 | });
75 | ```
76 |
77 | Finally, always know that this should only be a concern if you are implementing a library or writing low-level code. If not, please use what fits your style and personal preference as it will probably not matter.
78 |
79 | ## Handle edge keys by yourself
80 |
81 | If you know what you are doing, it can be a good idea to shunt the graph's automatic edge key creation by avoiding `#.addEdge` and relying on `#.addEdgeWithKey` instead.
82 |
83 | Indeed, the automatic edge key generator was designed to avoid many common pitfalls such as collision detection across instances and runtimes.
84 |
85 | So, if you know for sure how to avoid those pitfalls, you can probably generate keys yourself using a more performant method, such as basic incremental integers from `0` to `n`.
86 |
87 | ```javascript
88 | function incrementalId() {
89 | let i = 0;
90 |
91 | return () => i++;
92 | }
93 |
94 | const edgeKeyGenerator = incrementalId();
95 |
96 | const graph = new Graph();
97 | graph.addNode('one');
98 | graph.addNode('two');
99 | graph.addEdgeWithKey(edgeKeyGenerator(), 'one', 'two');
100 | ```
101 |
102 | ## Avoid iterating twice on edges in mixed graphs
103 |
104 | It is often desirable to handle directed & undirected egdes differently when operating on mixed graphs.
105 |
106 | However the following scheme might underperform:
107 |
108 | ```js
109 | graph.forEachDirectedEdge((edge) => {
110 | // Do something with directed edges...
111 | });
112 |
113 | graph.forEachUndirectedEdge((edge) => {
114 | // Do something with undirected edges...
115 | });
116 | ```
117 |
118 | This is because you will actually iterate twice on the internal edge map.
119 |
120 | You should probably prefer using the `undirected` argument of edge iteration likewise:
121 |
122 | ```js
123 | graph.forEachEdge((edge, attr, source, target, sa, ta, undirected) => {
124 | if (undirected) {
125 | // Do something with undirected edges...
126 | }
127 | else {
128 | // Do something with directed edges...
129 | }
130 | });
131 | ```
132 |
--------------------------------------------------------------------------------
/standard-library/simple-path.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: simple-path
4 | nav_order: 18
5 | parent: Standard library
6 | aux_links:
7 | "Library directory": "https://github.com/graphology/graphology/tree/master/src/simple-path"
8 |
9 | ---
10 |
11 | # Graphology Simple Path
12 |
13 | Simple path related functions to be used with [`graphology`](..). A "simple path" is a path where a node is not repeated.
14 |
15 | ## Installation
16 |
17 | ```
18 | npm install graphology-simple-path
19 | ```
20 |
21 | ## Usage
22 |
23 | - [allSimplePaths](#allsimplepaths)
24 | - [allSimpleEdgePaths](#allsimpleedgepaths)
25 | - [allSimpleEdgeGroupPaths](#allsimpleedgegrouppaths)
26 |
27 | ### allSimplePaths
28 |
29 | Collects every simple path between a source and a target node in the given graph.
30 |
31 | Note that this function also works with cycles.
32 |
33 | ```js
34 | import {allSimplePaths} from 'graphology-simple-path';
35 |
36 | const graph = new Graph();
37 | graph.mergeEdge('1', '2');
38 | graph.mergeEdge('1', '3');
39 | graph.mergeEdge('2', '3');
40 |
41 | const paths = allSimplePaths(graph, '1', '3');
42 | >>> [
43 | ['1', '3'],
44 | ['1', '2', '3']
45 | ]
46 |
47 | // To get cycles, just pass same source & target
48 | const cycles = allSimplePaths(graph, '1', '1');
49 |
50 | // To limit traversal to a certain depth
51 | const limitedPaths = allSimplePaths(graph, '1', '3', {maxDepth: 2});
52 | ```
53 |
54 | _Arguments_
55 |
56 | - **graph** _Graph_: target graph.
57 | - **source** _string_: source node.
58 | - **target** _string_: target node.
59 | - **options** ?object: options:
60 | - **maxDepth** ?number: max traversal depth (default - no limit).
61 |
62 | ### allSimpleEdgePaths
63 |
64 | Collects every simple path, represented by the followed edges, between a source and a target node in the given graph.
65 |
66 | Note that this function also works with cycles but does not work with multi graphs yet.
67 |
68 | ```js
69 | import {allSimpleEdgePaths} from 'graphology-simple-path';
70 |
71 | const graph = new Graph();
72 | graph.mergeEdgeWithKey('1->2', '1', '2');
73 | graph.mergeEdgeWithKey('1->3', '1', '3');
74 | graph.mergeEdgeWithKey('2->3', '2', '3');
75 |
76 | const paths = allSimpleEdgePaths(graph, '1', '3');
77 | >>> [
78 | ['1->3'],
79 | ['1->2', '2->3']
80 | ]
81 |
82 | // To get cycles, just pass same source & target
83 | const cycles = allSimpleEdgePaths(graph, '1', '1');
84 |
85 | // To limit traversal to a certain depth
86 | const limitedPaths = allSimpleEdgePaths(graph, '1', '3', {maxDepth: 2});
87 | ```
88 |
89 | _Arguments_
90 |
91 | - **graph** _Graph_: target graph.
92 | - **source** _string_: source node.
93 | - **target** _string_: target node.
94 | - **options** ?object: options:
95 | - **maxDepth** ?number: max traversal depth (default - no limit).
96 |
97 | ### allSimpleEdgeGroupPaths
98 |
99 | Collects every simple path, represented by groups of equivalent followed edges, between a source and a target node in the given multi graph.
100 |
101 | Note that this function also works with cycles and that, even if it can work with a simple graph, it has not be designed to be useful in this case.
102 |
103 | ```js
104 | import {allSimpleEdgeGroupPaths} from 'graphology-simple-path';
105 |
106 | const graph = new Graph();
107 | graph.mergeEdgeWithKey('1->2a', '1', '2');
108 | graph.mergeEdgeWithKey('1->2b', '1', '2');
109 | graph.mergeEdgeWithKey('1->3a', '1', '3');
110 | graph.mergeEdgeWithKey('2->3a', '2', '3');
111 |
112 | const paths = allSimpleEdgeGroupPaths(graph, '1', '3');
113 | >>> [
114 | [['1->3a']],
115 | [['1->2a', '1->2b'], ['2->3a']]
116 | ]
117 |
118 | // To get cycles, just pass same source & target
119 | const cycles = allSimpleEdgeGroupPaths(graph, '1', '1');
120 |
121 | // To limit traversal to a certain depth
122 | const limitedPaths = allSimpleEdgeGroupPaths(graph, '1', '3', {maxDepth: 2});
123 | ```
124 |
125 | _Arguments_
126 |
127 | - **graph** _Graph_: target graph.
128 | - **source** _string_: source node.
129 | - **target** _string_: target node.
130 | - **options** ?object: options:
131 | - **maxDepth** ?number: max traversal depth (default - no limit).
132 |
133 |
--------------------------------------------------------------------------------
/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: Home
4 | nav_order: 0
5 | ---
6 |
7 | # Graphology
8 |
9 | `graphology` is a robust & multipurpose `Graph` object for JavaScript and TypeScript.
10 |
11 | It aims at supporting various kinds of graphs with the same unified interface.
12 |
13 | A `graphology` graph can therefore be directed, undirected or mixed, allow self-loops or not, and can be simple or support parallel edges.
14 |
15 | Along with this `Graph` object, one will also find a comprehensive [standard library](standard-library) full of graph theory algorithms and common utilities such as graph generators, layouts, traversals etc.
16 |
17 | Finally, `graphology` graphs are able to emit a wide variety of [events](events), which makes them ideal to build interactive renderers for the browser. It is for instance used by [sigma.js](https://www.sigmajs.org/) as its data backend.
18 |
19 | ## Installation
20 |
21 | To install `graphology` using npm, run the following command:
22 |
23 | ```
24 | npm install graphology
25 | ```
26 |
27 | *Legacy bundle*
28 |
29 | Standalone builds of `graphology` and its full standard library can be found in the repository's [releases](https://github.com/graphology/graphology/releases) if you can only rely on your own `script` tags to load code.
30 |
31 | ```html
32 |
33 |
34 |
35 |
40 |
41 |
42 |
43 |
44 |
47 | ```
48 |
49 | Be warned that the standard library bundle often lags behind and is not always completely up to date.
50 |
51 | *TypeScript usage*
52 |
53 | Note that `graphology` also exports type declaration that are installed along using peer dependencies so it can be used with [TypeScript](https://www.typescriptlang.org/) out of the box.
54 |
55 | If your version of npm is a bit old, you may need to install `graphology-types` yourself if the peer dependency resolution is not made for you already:
56 |
57 | ```
58 | npm install graphology-types
59 | ```
60 |
61 | It can also be useful to pin `graphology-types` version in your `package.json` to avoid resolution issues sometimes.
62 |
63 | ## Quick Start
64 |
65 | ```js
66 | import Graph from 'graphology';
67 |
68 | const graph = new Graph();
69 |
70 | // Adding some nodes
71 | graph.addNode('John');
72 | graph.addNode('Martha');
73 |
74 | // Adding an edge
75 | graph.addEdge('John', 'Martha');
76 |
77 | // Displaying useful information about your graph
78 | console.log('Number of nodes', graph.order);
79 | console.log('Number of edges', graph.size);
80 |
81 | // Iterating over nodes
82 | graph.forEachNode(node => {
83 | console.log(node);
84 | });
85 | ```
86 |
87 | ## How to cite
88 |
89 | [](https://zenodo.org/badge/latestdoi/66482976)
90 |
91 | `graphology` is published on [Zenodo](https://zenodo.org/) as [https://doi.org/10.5281/zenodo.5681257](https://doi.org/10.5281/zenodo.5681257).
92 |
93 | You can cite it thusly:
94 |
95 | > Guillaume Plique. (2021). Graphology, a robust and multipurpose Graph object for JavaScript. Zenodo. https://doi.org/10.5281/zenodo.5681257
96 |
97 |
98 | ## Changelog
99 |
100 | A complete changelog can be found [here](https://github.com/graphology/graphology/blob/master/CHANGELOG.md).
101 |
102 | ## Implementing graphology
103 |
104 | There are many ways to implement a Graph data structure and even if `graphology` chose to optimize for most common use cases, you might need a more specialized implementation yourself.
105 |
106 | In this case, know that `graphology` can be re-implemented completely without losing the benefit of being able to use its [standard library](standard-library).
107 |
108 | For more information, be sure to read [this](implementing-graphology) section of the documentation.
109 |
110 | ## Acknowledgments
111 |
112 | This documentation has been built with [Jekyll](https://jekyllrb.com/) using the [Just the Docs](https://pmarsceill.github.io/just-the-docs/) theme.
113 |
--------------------------------------------------------------------------------
/standard-library/layout-force.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: layout-force
4 | nav_order: 12
5 | parent: Standard library
6 | aux_links:
7 | "Library directory": "https://github.com/graphology/graphology/tree/master/src/layout-force"
8 | "Changelog": "https://github.com/graphology/graphology/tree/master/src/layout-force/CHANGELOG.md"
9 | ---
10 |
11 | # Graphology Force layout
12 |
13 | JavaScript implementation of a basic [force directed layout algorithm](https://en.wikipedia.org/wiki/Force-directed_graph_drawing) for [graphology](..).
14 |
15 | In some few cases, for very small graphs, [ForceAtlas2](https://journals.plos.org/plosone/article?id=10.1371/journal.pone.0098679) can be "too efficient". This simpler force algorithm cannot spatialize larger networks, but will offer more organic movements which are more suited to some interactions with the graph such as drag and drop etc.
16 |
17 | ## Installation
18 |
19 | ```
20 | npm install graphology-layout-force
21 | ```
22 |
23 | ## Usage
24 |
25 | - [Pre-requisite](#pre-requisite)
26 | - [Settings](#settings)
27 | - [Synchronous layout](#synchronous-layout)
28 | - [Supervisor](#supervisor)
29 |
30 | ### Pre-requisites
31 |
32 | Each node's starting position must be set before running the force layout algorithm. Two attributes called `x` and `y` must therefore be defined for all the graph nodes.
33 |
34 | Note also that the algorithm has an edge-case where the layout cannot be computed if all of your nodes starts with `x=0` and `y=0`.
35 |
36 | ### Settings
37 |
38 | - **attraction** ?number 0.0005: importance of the attraction force, that attracts each pair of connected nodes like elastics.
39 | - **repulsion** ?number 0.1: importance of the repulsion force, that attracts each pair of nodes like magnets.
40 | - **gravity** ?number 0.0001: importance of the gravity force, that attracts all nodes to the center.
41 | - **inertia** ?number 0.6: percentage of a node vector displacement that is preserved at each step. `0` means no inertia, `1` means no friction.
42 | - **maxMove** ?number 200: Maximum length a node can travel at each step, in pixel.
43 |
44 | ### Synchronous layout
45 |
46 | ```js
47 | import forceLayout from 'graphology-layout-force';
48 |
49 | const positions = forceLayout(graph, {maxIterations: 50});
50 |
51 | // With settings:
52 | const positions = forceLayout(graph, {
53 | maxIterations: 50,
54 | settings: {
55 | gravity: 10
56 | }
57 | });
58 |
59 | // To directly assign the positions to the nodes:
60 | forceLayout.assign(graph);
61 | ```
62 |
63 | _Arguments_
64 |
65 | - **graph** _Graph_: target graph.
66 | - **options** _object_: options:
67 | - **nodeXAttribute** ?string x: name of the `x` position attribute for nodes.
68 | - **nodeYAttribute** ?string y: name of the `y` position attribute for edges.
69 | - **isNodeFixed** ?string\|function fixed: name of the `fixed` attribute for nodes or a function getting a node entry (key, attributes) and returning whether the node is fixed.
70 | - **shouldSkipNode** ?function: function returning whether the layout computations should skip this node.
71 | - **shouldSkipEdge** ?function: function returning whether the layout computations should skip this edge.
72 | - **maxIterations** ?number 500: maximum number of iterations to perform before stopping. Note that the algorithm will also stop as soon as converged.
73 | - **settings** ?object: the layout's settings (see [#settings](#settings)).
74 |
75 | ### Supervisor
76 |
77 | Layout supervisor relying on [`window.requestAnimationFrame`](https://developer.mozilla.org/fr/docs/Web/API/Window/requestAnimationFrame) to run the layout live without hampering the UI thread.
78 |
79 | _Example_
80 |
81 | ```js
82 | import ForceSupervisor from 'graphology-layout-force/worker';
83 |
84 | const layout = new ForceSupervisor(graph, params);
85 |
86 | // To start the layout. It will automatically stop when converged
87 | layout.start();
88 |
89 | // To stop the layout
90 | layout.stop();
91 |
92 | // To kill the layout and release attached memory and listeners
93 | layout.kill();
94 |
95 | // Assess whether the layout is currently running
96 | layout.isRunning();
97 | ```
98 |
99 |
--------------------------------------------------------------------------------
/standard-library/traversal.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: traversal
4 | nav_order: 20
5 | parent: Standard library
6 | aux_links:
7 | "Library directory": "https://github.com/graphology/graphology/tree/master/src/traversal"
8 | "Changelog": "https://github.com/graphology/graphology/tree/master/src/traversal/CHANGELOG.md"
9 | ---
10 |
11 | # Graphology Traversal
12 |
13 | Miscellaneous traversal functions to be used with [`graphology`](..).
14 |
15 | ## Installation
16 |
17 | ```
18 | npm install graphology-traversal
19 | ```
20 |
21 | ## Usage
22 |
23 | - [bfs](#bfs)
24 | - [bfsFromNode](#bfsfromnode)
25 | - [dfs](#dfs)
26 | - [dfsFromNode](#bfsfromnode)
27 |
28 | ### bfs
29 |
30 | Perform a BFS (Breadth-First Search) over the given graph using a callback.
31 |
32 | ```js
33 | import {bfs} from 'graphology-traversal';
34 | // Alternatively, to only load the relevant code
35 | import {bfs} from 'graphology-traversal/bfs';
36 |
37 | bfs(graph, function (node, attr, depth) {
38 | console.log(node, attr, depth);
39 | });
40 |
41 | // Stopping at depth 3
42 | bfs(graph, function (node, attr, depth) {
43 | return depth >= 3;
44 | });
45 | ```
46 |
47 | _Arguments_
48 |
49 | - **graph** _Graph_: a graphology instance.
50 | - **callback** _function_: iteration callback taking the traversed node, its attributes and the traversal's depth. Returning `true` will prevent the traversal from following the next neighbors.
51 | - **options** ?object: traversal options:
52 | - **mode** ?string outbound: type of neighbors to traverse.
53 |
54 | ### bfsFromNode
55 |
56 | Perform a BFS (Breadth-First Search) over the given graph, starting from the given node, using a callback.
57 |
58 | ```js
59 | import {bfsFromNode} from 'graphology-traversal';
60 | // Alternatively, to only load the relevant code
61 | import {bfsFromNode} from 'graphology-traversal/bfs';
62 |
63 | bfsFromNode(graph, 'node1', function (node, attr, depth) {
64 | console.log(node, attr, depth);
65 | });
66 |
67 | // Stopping at depth 3
68 | bfsFromNode(graph, 'node1', function (node, attr, depth) {
69 | return depth >= 3;
70 | });
71 | ```
72 |
73 | _Arguments_
74 |
75 | - **graph** _Graph_: a graphology instance.
76 | - **node** _string\|number_: starting node.
77 | - **callback** _function_: iteration callback taking the traversed node, its attributes and the traversal's depth. Returning `true` will prevent the traversal from following the next neighbors.
78 | - **options** ?object: traversal options:
79 | - **mode** ?string outbound: type of neighbors to traverse.
80 |
81 | ### dfs
82 |
83 | Perform a DFS (Depth-First Search) over the given graph using a callback.
84 |
85 | ```js
86 | import {dfs} from 'graphology-traversal';
87 | // Alternatively, to only load the relevant code
88 | import {dfs} from 'graphology-traversal/dfs';
89 |
90 | dfs(graph, function (node, attr, depth) {
91 | console.log(node, attr, depth);
92 | });
93 |
94 | // Stopping at depth 3
95 | dfs(graph, function (node, attr, depth) {
96 | return depth >= 3;
97 | });
98 | ```
99 |
100 | _Arguments_
101 |
102 | - **graph** _Graph_: a graphology instance.
103 | - **callback** _function_: iteration callback taking the traversed node, its attributes and the traversal's depth. Returning `true` will prevent the traversal from following the next neighbors.
104 | - **options** ?object: traversal options:
105 | - **mode** ?string outbound: type of neighbors to traverse.
106 |
107 | ### dfsFromNode
108 |
109 | Perform a DFS (Depth-First Search) over the given graph, starting from the given node, using a callback.
110 |
111 | ```js
112 | import {dfsFromNode} from 'graphology-traversal';
113 | // Alternatively, to only load the relevant code
114 | import {dfsFromNode} from 'graphology-traversal/dfs';
115 |
116 | dfsFromNode(graph, 'node1', function (node, attr, depth) {
117 | console.log(node, attr, depth);
118 | });
119 |
120 | // Stopping at depth 3
121 | dfsFromNode(graph, 'node1', function (node, attr, depth) {
122 | return depth >= 3;
123 | });
124 | ```
125 |
126 | _Arguments_
127 |
128 | - **graph** _Graph_: a graphology instance.
129 | - **node** _string\|number_: starting node.
130 | - **callback** _function_: iteration callback taking the traversed node, its attributes and the traversal's depth. Returning `true` will prevent the traversal from following the next neighbors.
131 | - **options** ?object: traversal options:
132 | - **mode** ?string outbound: type of neighbors to traverse.
133 |
134 |
--------------------------------------------------------------------------------
/standard-library/gexf.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: gexf
4 | nav_order: 8
5 | parent: Standard library
6 | aux_links:
7 | "Library directory": "https://github.com/graphology/graphology/tree/master/src/gexf"
8 | "Changelog": "https://github.com/graphology/graphology/tree/master/src/gexf/CHANGELOG.md"
9 | ---
10 |
11 | [](/standard-library/gexf/actions)
12 |
13 | # Graphology GEXF Utilities
14 |
15 | GEXF parser & writer for [`graphology`](..).
16 |
17 | For more information about the GEXF file format, you can head [there](https://gexf.net).
18 |
19 | ## Installation
20 |
21 | ```
22 | npm install graphology-gexf
23 | ```
24 |
25 | ## Usage
26 |
27 | - [Parser](#parser)
28 | - [Writer](#writer)
29 | - [Notes](#notes)
30 |
31 | ### Parser
32 |
33 | The parser must be passed a `graphology` constructor and is able to read either a string, or an `XMLDocument` instance.
34 |
35 | ```js
36 | var Graph = require('graphology');
37 |
38 | // Node
39 | var gexf = require('graphology-gexf');
40 | // Browser
41 | var gexf = require('graphology-gexf/browser');
42 |
43 | // Reading a string
44 | var graph = gexf.parse(Graph, string);
45 |
46 | // Reading a dom document
47 | var graph = gexf.parse(Graph, xmlDocument);
48 |
49 | // Passing options
50 | var graph = gexf.parse(Graph, string, {addMissingNodes: true});
51 | ```
52 |
53 | _Arguments_
54 |
55 | - **constructor** _GraphClass_: graphology constructor to use.
56 | - **source** _string\|Document_: source data to parse.
57 | - **options** ?object: parsing options:
58 | - **addMissingNodes** ?boolean false: whether to add missing nodes referenced in the file's edges.
59 | - **allowUndeclaredAttributes** ?boolean false: whether to allow undeclared attributes for both nodes & edges, which will be considered as strings.
60 | - **respectInputGraphType** ?boolean false: whether to make sure the output graph type is the same as the passed constructor. By default the parser will try to optimize the graph representation to avoid wasting time and memory. But if `respectInputGraphType` is `true` the output graph is guaranteed to be an instance of the typed constructor you gave as first argument. This also means the parser will throw when reading a graph that cannot be represented with the given typed constructor.
61 |
62 | ### Writer
63 |
64 | The writer must be passed a `graphology` instance and will output a GEXF string.
65 |
66 | ```js
67 | // Node
68 | var gexf = require('graphology-gexf');
69 | // Browser
70 | var gexf = require('graphology-gexf/browser');
71 |
72 | // Writing the graph
73 | var gexfString = gexf.write(graph);
74 |
75 | // Using custom formatting for nodes & edges
76 | var gexfString = gexf.write(graph, {
77 | formatNode: function (key, attributes) {
78 | return {
79 | label: attributes.label,
80 | attributes: {
81 | age: attributes.age,
82 | name: attributes.name
83 | },
84 | viz: {
85 | color: '#FF0',
86 | x: attributes.x,
87 | y: attributes.y,
88 | shape: 'circle',
89 | size: 20
90 | }
91 | };
92 | },
93 | formatEdge: function (key, attributes) {
94 | return {
95 | label: attributes.label,
96 | attributes: {
97 | number: attributes.number
98 | },
99 | weight: attributes.weight,
100 | viz: {
101 | color: '#FF0',
102 | x: attributes.x,
103 | y: attributes.y,
104 | shape: 'dotted',
105 | thickness: 20
106 | }
107 | };
108 | }
109 | });
110 | ```
111 |
112 | _Arguments_
113 |
114 | - **graph** _Graph_: graphology instance to write.
115 | - **options** ?object: Options:
116 | - **encoding** ?string UTF-8: encoding declaration.
117 | - **formatNode** ?function: function returning the node's data to write.
118 | - **formatEdge** ?function: function returning the edge's data to write.
119 | - **pretty** ?boolean true: pretty-print output?
120 | - **pedantic** ?boolean false: whether to output a stricter gexf file to make sure it can be validated using the most restrictive gexf xsd schemas. Note that the output may lose some graph attributes when doing so.
121 | - **version** ?string 1.2: gexf version to emit. Should be one of `1.2` or `1.3`.
122 |
123 | ### Notes
124 |
125 | Currently, `mutual` (a specific gexf type for edges that is seldom used in practice) edges are parsed as undirected ones rather than two directed ones because it could produce a key conflict. An option to deal differently with this may be added in the future if it becomes a problem.
126 |
127 |
--------------------------------------------------------------------------------
/standard-library/dag.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: dag
4 | nav_order: 5
5 | parent: Standard library
6 | aux_links:
7 | "Library directory": "https://github.com/graphology/graphology/tree/master/src/dag"
8 | "Changelog": "https://github.com/graphology/graphology/tree/master/src/dag/CHANGELOG.md"
9 | ---
10 |
11 | # Graphology DAG
12 |
13 | Functions related to Directed Acyclic Graphs (DAGs) and to be used with [`graphology`](..).
14 |
15 | ## Installation
16 |
17 | ```
18 | npm install graphology-dag
19 | ```
20 |
21 | ## Usage
22 |
23 | - [hasCycle](#hascycle)
24 | - [willCreateCycle](#willcreatecycle)
25 | - [topologicalSort](#topologicalsort)
26 | - [topologicalGenerations](#topologicalgenerations)
27 | - [forEachNodeInTopologicalOrder](#foreachnodeintopologicalorder)
28 | - [forEachTopologicalGeneration](#foreachtopologicalgeneration)
29 |
30 | ### hasCycle
31 |
32 | Function returning whether the given directed graph contains at least one cycle.
33 |
34 | Note that this function will also work with a disconnected graph.
35 |
36 | ```js
37 | import {hasCycle} from 'graphology-dag';
38 | // Alternatively, to load only the relevant code:
39 | import hasCycle from 'graphology-dag/has-cycle';
40 |
41 | const graph = new DirectedGraph();
42 | graph.mergeEdge(0, 1);
43 | graph.mergeEdge(1, 2);
44 | graph.mergeEdge(2, 3);
45 |
46 | hasCycle(graph);
47 | >>> false
48 |
49 | graph.mergeEdge(3, 0);
50 |
51 | hasCycle(graph);
52 | >>> true
53 | ```
54 |
55 | ### willCreateCycle
56 |
57 | Function returning whether adding the given directed edge to a DAG will create an undesired cycle.
58 |
59 | Note that this function expects a valid DAG and even if passing a cyclic graph could work it could also very well lead to undefined behavior ranging from an infinite loop to overkill memory usage.
60 |
61 | Note finally that this function will also work with DAG forests (sets of disconnected DAGs living in the same graph instance).
62 |
63 | ```js
64 | import {willCreateCycle} from 'graphology-dag';
65 | // Alternatively, to load only the relevant code:
66 | import willCreateCycle from 'graphology-dag/will-create-cycle';
67 |
68 | const graph = new DirectedGraph();
69 | graph.mergeEdge(0, 1);
70 | graph.mergeEdge(1, 2);
71 | graph.mergeEdge(2, 3);
72 |
73 | willCreateCycle(graph, 3, 0);
74 | >>> true
75 | willCreateCycle(graph, 0, 2);
76 | >>> false
77 | ```
78 |
79 | ### topologicalSort
80 |
81 | Function returning an array of nodes representing a possible topological ordering of the given DAG.
82 |
83 | Note that this function will throw if given graph has any cycle, is able to work on mixed graphs containing only directed edges and can work on disconnected graphs (a DAG forest).
84 |
85 | ```js
86 | import {topologicalSort} from 'graphology-dag';
87 | // Alternatively, to load only the relevant code:
88 | import {topologicalSort} from 'graphology-dag/topological-sort';
89 |
90 | const graph = new DirectedGraph();
91 | graph.mergeEdge(0, 1);
92 | graph.mergeEdge(1, 2);
93 | graph.mergeEdge(2, 3);
94 |
95 | topologicalSort(graph);
96 | >>> ['0', '1', '2', '3']
97 | ```
98 |
99 | ### topologicalGenerations
100 |
101 | Function returning an array of array of nodes representing the successive generations of the topological ordering of the given DAG.
102 |
103 | Note that this function will throw if given graph has any cycle, is able to work on mixed graphs containing only directed edges and can work on disconnected graphs (a DAG forest).
104 |
105 | ```js
106 | import {topologicalGenerations} from 'graphology-dag';
107 | // Alternatively, to load only the relevant code:
108 | import {topologicalGenerations} from 'graphology-dag/topological-sort';
109 |
110 | const graph = new DirectedGraph();
111 | graph.mergeEdge(0, 1);
112 | graph.mergeEdge(1, 2);
113 | graph.mergeEdge(0, 3);
114 |
115 | topologicalGenerations(graph);
116 | >>> [[ '0' ], ['1', '3'], ['2']]
117 | ```
118 |
119 | ### forEachNodeInTopologicalOrder
120 |
121 | Function iterating over the given DAG's nodes in topological order using a callback function.
122 |
123 | Note that this function will throw if given graph has any cycle, is able to work on mixed graphs containing only directed edges and can work on disconnected graphs (a DAG forest).
124 |
125 | ```js
126 | import {forEachNodeInTopologicalOrder} from 'graphology-dag';
127 | // Alternatively, to load only the relevant code:
128 | import {forEachNodeInTopologicalOrder} from 'graphology-dag/topological-sort';
129 |
130 | const graph = new DirectedGraph();
131 | graph.mergeEdge(0, 1);
132 | graph.mergeEdge(1, 2);
133 | graph.mergeEdge(2, 3);
134 |
135 | forEachNodeInTopologicalOrder(graph, (node, attr, generationIndex) => {
136 | // Note that generationIndex will be monotonically increasing from 0 to n.
137 | console.log(node, attr, generationIndex);
138 | });
139 | ```
140 |
141 | ### forEachTopologicalGeneration
142 |
143 | Function iterating over the given DAG's generations, represented by an array of node keys, using a callback function.
144 |
145 | Note that this function will throw if given graph has any cycle, is able to work on mixed graphs containing only directed edges and can work on disconnected graphs (a DAG forest).
146 |
147 | ```js
148 | import {forEachTopologicalGeneration} from 'graphology-dag';
149 | // Alternatively, to load only the relevant code:
150 | import {forEachTopologicalGeneration} from 'graphology-dag/topological-sort';
151 |
152 | const graph = new DirectedGraph();
153 | graph.mergeEdge(0, 1);
154 | graph.mergeEdge(1, 2);
155 | graph.mergeEdge(2, 3);
156 |
157 | forEachTopologicalGeneration(graph, generation => {
158 | console.log(generation);
159 | });
160 | ```
161 |
162 |
--------------------------------------------------------------------------------
/standard-library/layout-forceatlas2.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: layout-forceatlas2
4 | nav_order: 13
5 | parent: Standard library
6 | aux_links:
7 | "Library directory": "https://github.com/graphology/graphology/tree/master/src/layout-forceatlas2"
8 | "Changelog": "https://github.com/graphology/graphology/tree/master/src/layout-forceatlas2/CHANGELOG.md"
9 | ---
10 |
11 | # Graphology ForceAtlas2
12 |
13 | JavaScript implementation of the [ForceAtlas2](https://journals.plos.org/plosone/article?id=10.1371/journal.pone.0098679) algorithm for [graphology](..).
14 |
15 | ## Reference
16 |
17 | > Jacomy M, Venturini T, Heymann S, Bastian M (2014) ForceAtlas2, a Continuous Graph Layout Algorithm for Handy Network Visualization Designed for the Gephi Software. PLoS ONE 9(6): e98679. https://doi.org/10.1371/journal.pone.0098679
18 |
19 | ## Installation
20 |
21 | ```
22 | npm install graphology-layout-forceatlas2
23 | ```
24 |
25 | ## Usage
26 |
27 | - [Pre-requisite](#pre-requisite)
28 | - [Settings](#settings)
29 | - [Synchronous layout](#synchronous-layout)
30 | - [Webworker](#webworker)
31 | - [#.inferSettings](#infersettings)
32 |
33 | ### Pre-requisites
34 |
35 | Each node's starting position must be set before running ForceAtlas 2 layout. Two attributes called `x` and `y` must therefore be defined for all the graph nodes. [graphology-layout](/standard-library/layout) can be used to initialize these attributes to a [random](/standard-library/layout#random) or [circular](/standard-library/layout#circular) layout, if needed.
36 |
37 | Note also that the algorithm has an edge-case where the layout cannot be computed if all of your nodes starts with `x=0` and `y=0`.
38 |
39 | ### Settings
40 |
41 | - **adjustSizes** ?boolean false: should the node's sizes be taken into account?
42 | - **barnesHutOptimize** ?boolean false: whether to use the Barnes-Hut approximation to compute repulsion in `O(n*log(n))` rather than default `O(n^2)`, `n` being the number of nodes.
43 | - **barnesHutTheta** ?number 0.5: Barnes-Hut approximation theta parameter.
44 | - **edgeWeightInfluence** ?number 1: influence of the edge's weights on the layout. To consider edge weight, don't forget to pass `weighted` as `true` when applying the [synchronous layout](#synchronous-layout) or when instantiating the [worker](#webworker).
45 | - **gravity** ?number 1: strength of the layout's gravity.
46 | - **linLogMode** ?boolean false: whether to use Noack's LinLog model.
47 | - **outboundAttractionDistribution** ?boolean false
48 | - **scalingRatio** ?number 1
49 | - **slowDown** ?number 1
50 | - **strongGravityMode** ?boolean false
51 |
52 | ### Synchronous layout
53 |
54 | ```js
55 | import forceAtlas2 from 'graphology-layout-forceatlas2';
56 |
57 | const positions = forceAtlas2(graph, {iterations: 50});
58 |
59 | // With settings:
60 | const positions = forceAtlas2(graph, {
61 | iterations: 50,
62 | settings: {
63 | gravity: 10
64 | }
65 | });
66 |
67 | // To directly assign the positions to the nodes:
68 | forceAtlas2.assign(graph);
69 | ```
70 |
71 | _Arguments_
72 |
73 | - **graph** _Graph_: target graph.
74 | - **options** _object_: options:
75 | - **iterations** _number_: number of iterations to perform.
76 | - **getEdgeWeight** ?string\|function weight: name of the edge weight attribute or getter function. Defaults to `weight`.
77 | - **settings** ?object: the layout's settings (see [#settings](#settings)).
78 |
79 | ### Webworker
80 |
81 | If you need to run the layout's computation in a web worker, the library comes with a utility to do so:
82 |
83 | _Example_
84 |
85 | ```js
86 | import FA2Layout from 'graphology-layout-forceatlas2/worker';
87 |
88 | // The parameters are the same as for the synchronous version, minus `iterations` of course
89 | const layout = new FA2Layout(graph, {
90 | settings: {gravity: 1}
91 | });
92 |
93 | // To start the layout
94 | layout.start();
95 |
96 | // To stop the layout
97 | layout.stop();
98 |
99 | // To kill the layout and release attached memory
100 | layout.kill();
101 |
102 | // Assess whether the layout is currently running
103 | layout.isRunning();
104 | ```
105 |
106 | **WARNING!**: if you are using [`webpack`](https://webpack.js.org/) to bundle your code, avoid the `cheap-eval`-like options for the [`devtool`](https://webpack.js.org/configuration/devtool/) setting. Some users noticed that it interacts in mysterious ways with the library's code and cause performance to drop dramatically when using the worker. Note that this should have been fixed from v0.5.0.
107 |
108 | ### #.inferSettings
109 |
110 | If you don't know how to tune the layout's settings and want to infer them from your graph, you can use the `#.inferSettings` method:
111 |
112 | ```js
113 | import forceAtlas2 from 'graphology-layout-forceatlas2';
114 |
115 | const sensibleSettings = forceAtlas2.inferSettings(graph);
116 | const positions = forceAtlas2(graph, {
117 | iterations: 50,
118 | settings: sensibleSettings
119 | });
120 |
121 | // Alternatively using the graph's order instead of a graph instance
122 | const sensibleSettings = forceAtlas2.inferSettings(500);
123 | ```
124 |
125 |
--------------------------------------------------------------------------------
/standard-library/cores.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: cores
4 | nav_order: 6
5 | parent: Standard library
6 | aux_links:
7 | "Library directory": "https://github.com/graphology/graphology/tree/master/src/cores"
8 |
9 | ---
10 |
11 | # Graphology Cores
12 |
13 | Various functions related to k-cores of graphs and to be used with [graphology](..).
14 |
15 | The k-core of a graph is the maximal connected subgraph in which all nodes have a degree of k or more. The main core of a graph is the k-core subgraph with the highest possible k.
16 |
17 | If the graph is directed, node degrees are considered to be the sum of all the inbound and outbound neighbors of the node.
18 |
19 | > An O(m) Algorithm for Cores Decomposition of Networks Vladimir Batagelj and Matjaz Zaversnik, 2003. [https://arxiv.org/abs/cs.DS/0310049](https://arxiv.org/abs/cs.DS/0310049)
20 |
21 | > Generalized Cores Vladimir Batagelj and Matjaz Zaversnik, 2002. [https://arxiv.org/pdf/cs/0202039](https://arxiv.org/pdf/cs/0202039)
22 |
23 | ## Installation
24 |
25 | ```
26 | npm install graphology-cores
27 | ```
28 |
29 | ## Usage
30 |
31 | - [coreNumber](#corenumber)
32 | - [kCore](#kcore)
33 | - [kShell](#kshell)
34 | - [kCrust](#kcrust)
35 | - [kCorona](#kcorona)
36 | - [kTruss](#ktruss)
37 | - [onionLayers](#onionlayers)
38 |
39 | ### coreNumber
40 |
41 | Returns the core number for each node. The core number of a node is the largest k of a k-core subgraph containing this node.
42 |
43 | This implementation doesn't allow graphs with parallel edges or self loops.
44 |
45 | ```js
46 | import coreNumber from 'graphology-cores/coreNumber';
47 |
48 | // Return the core number for each node
49 | const numbers = coreNumber(graph);
50 |
51 | // Assign to each node its core number
52 | coreNumber.assign(graph);
53 |
54 | // Assign with a custom attribute label
55 | coreNumber.assign(graph, 'core');
56 | ```
57 |
58 | _Arguments_
59 |
60 | - **graph** _Graph_: target graph.
61 | - **nodeCoreAttribute** ?string : the name of the attribute to use if core numbers are assigned to the nodes.
62 |
63 | ### kCore
64 |
65 | Returns the maximal connected subgraph containing nodes with k degree or more. If k isn't provided, k is the highest core number present in the graph.
66 |
67 | ```js
68 | import kCore from 'graphology-cores/kCore';
69 |
70 | // Return the main k-core of the graph
71 | const core = kCore(graph);
72 |
73 | // Return the k-core subgraph with an arbitrary k value
74 | const core = kCore(graph, 4);
75 | ```
76 |
77 | _Arguments_
78 |
79 | - **graph** _Graph_: target graph.
80 | - **k** ?number: custom k value to use.
81 | - **customCore** ?object: custom core numbers to use.
82 |
83 | ### kShell
84 |
85 | Returns the k-shell subgraph. The k-shell subgraph is the maximal connected subgraph containing the nodes with k degree.
86 |
87 | ```js
88 | import kShell from 'graphology-cores/kShell';
89 |
90 | // Return the main k-shell of the graph
91 | const shell = kShell(graph);
92 |
93 | // Return the k-shell subgraph with an arbitrary k value
94 | const shell = kShell(graph, 5);
95 | ```
96 |
97 | _Arguments_
98 |
99 | - **graph** _Graph_: target graph.
100 | - **k** ?number: custom k value to use.
101 | - **customCore** ?object: custom core numbers to use.
102 |
103 | ### kCrust
104 |
105 | Returns the k-crust subgraph. The k-crust subgraph is the maximal connected subgraph containing nodes with less than k degree.
106 |
107 | ```js
108 | import kCrust from 'graphology-cores/kCrust';
109 |
110 | // Return the main k-crust of the graph
111 | const crust = kCrust(graph);
112 |
113 | // Return the k-crust subgraph with an arbitrary k value
114 | const crust = kCrust(graph, 4);
115 | ```
116 |
117 | _Arguments_
118 |
119 | - **graph** _Graph_: target graph.
120 | - **k** ?number: custom k value to use.
121 | - **customCore** ?object: custom core numbers to use.
122 |
123 | ### kCorona
124 |
125 | Returns the k-corona subgraph. The k-corona subgraph contains nodes in the k-core with exactly k neighbors in the k-core.
126 |
127 | ```js
128 | import kCorona from 'graphology-cores/kCorona';
129 |
130 | // Return the main k-corona of the graph
131 | const corona = kCorona(graph);
132 |
133 | // Return the k-corona subgraph with an arbitrary k value
134 | const corona = kCorona(graph, 4);
135 | ```
136 |
137 | _Arguments_
138 |
139 | - **graph** _Graph_: target graph.
140 | - **k** ?number: custom k value to use.
141 | - **customCore** ?object: custom core numbers to use.
142 |
143 | ### kTruss
144 |
145 | Returns the k-truss subgraph. The k-truss subgraph contains at least three nodes for which every edge is incident to at least `k-2` triangles.
146 |
147 | K-Truss is not implemented for directed graphs and multigraphs.
148 |
149 | ```js
150 | import kTruss from 'graphology-cores/kTruss';
151 |
152 | // Return the k-truss of the graph with k = 4
153 | const truss = kTruss(graph, 4);
154 | ```
155 |
156 | _Arguments_
157 |
158 | - **graph** _Graph_: target graph.
159 | - **k** _number_: k value to use.
160 |
161 | ### onionLayers
162 |
163 | Computes the onion decomposition of a given graph. Onion layers can't be calculated if the graph is directed.
164 |
165 | > Multi-scale structure and topological anomaly detection via a new network statistic: The onion decomposition L. Hébert-Dufresne, J. A. Grochow, and A. Allard Scientific Reports 6, 31708 (2016) [http://doi.org/10.1038/srep31708](http://doi.org/10.1038/srep31708)
166 |
167 | ```js
168 | import onionLayers from 'graphology-cores/onionLayers';
169 |
170 | // Return the onion layers for each node
171 | const onion = onionLayers(graph);
172 |
173 | // Assign to each node its onion layer
174 | onionLayers.assign(graph);
175 |
176 | // Assign with a custom attribute label
177 | onionLayers.assign(graph, 'onion');
178 | ```
179 |
180 | _Arguments_
181 |
182 | - **graph** _Graph_: target graph.
183 | - **nodeOnionLayerAttribute** ?string : the name of the attribute to use if onion layers are assigned to the nodes.
184 |
185 |
--------------------------------------------------------------------------------
/standard-library/communities-louvain.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: communities-louvain
4 | nav_order: 3
5 | parent: Standard library
6 | aux_links:
7 | "Library directory": "https://github.com/graphology/graphology/tree/master/src/communities-louvain"
8 | "Changelog": "https://github.com/graphology/graphology/tree/master/src/communities-louvain/CHANGELOG.md"
9 | ---
10 |
11 | # Graphology Communities Louvain
12 |
13 | Implementation of the [Louvain algorihtm](https://en.wikipedia.org/wiki/Louvain_modularity) for community detection to be used with [`graphology`](..).
14 |
15 | ## References
16 |
17 | > M. E. J. Newman, « Modularity and community structure in networks », Proc. Natl. Acad. Sci. USA, vol. 103, no 23, 2006, p. 8577–8582 https://dx.doi.org/10.1073%2Fpnas.0601602103
18 |
19 | > Newman, M. E. J. « Community detection in networks: Modularity optimization and maximum likelihood are equivalent ». Physical Review E, vol. 94, no 5, novembre 2016, p. 052315. arXiv.org, doi:10.1103/PhysRevE.94.052315. https://arxiv.org/pdf/1606.02319.pdf
20 |
21 | > Blondel, Vincent D., et al. « Fast unfolding of communities in large networks ». Journal of Statistical Mechanics: Theory and Experiment, vol. 2008, no 10, octobre 2008, p. P10008. DOI.org (Crossref), doi:10.1088/1742-5468/2008/10/P10008. https://arxiv.org/pdf/0803.0476.pdf
22 |
23 | > Nicolas Dugué, Anthony Perez. Directed Louvain: maximizing modularity in directed networks. [Research Report] Université d’Orléans. 2015. hal-01231784 https://hal.archives-ouvertes.fr/hal-01231784
24 |
25 | > R. Lambiotte, J.-C. Delvenne and M. Barahona. Laplacian Dynamics and Multiscale Modular Structure in Networks, doi:10.1109/TNSE.2015.2391998. https://arxiv.org/abs/0812.1770
26 |
27 | > Traag, V. A., et al. « From Louvain to Leiden: Guaranteeing Well-Connected Communities ». Scientific Reports, vol. 9, no 1, décembre 2019, p. 5233. DOI.org (Crossref), doi:10.1038/s41598-019-41695-z. https://arxiv.org/abs/1810.08473
28 |
29 | ## Installation
30 |
31 | ```
32 | npm install graphology-communities-louvain
33 | ```
34 |
35 | ## Usage
36 |
37 | Runs the Louvain algorithm to detect communities in the given graph. It works both for undirected & directed graph by using the relevant modularity computations.
38 |
39 | This function also works on multi graphs but won't work with mixed graph as it is not trivial to adapt modularity to this case. As such, if you need to process a true mixed graph (this function will correctly handle mixed graphs containing only directed or undirected edges), cast your graph as either directed or undirected using [graphology-operators](/standard-library/operators) dedicated functions.
40 |
41 | Note also that this algorithm's run time is bounded by the number of edges in your graph. As such, it might be preferable, in some cases, to cast your multi graph as a simple one using [graphology-operators](/standard-library/operators) functions for better performance.
42 |
43 | Note that the community labels are returned as an integer range from 0 to n.
44 |
45 | ```js
46 | import louvain from 'graphology-communities-louvain';
47 |
48 | // To retrieve the partition
49 | const communities = louvain(graph);
50 |
51 | // To directly assign communities as a node attribute
52 | louvain.assign(graph);
53 |
54 | // If you need to pass custom options
55 | louvain.assign(graph, {
56 | resolution: 0.8
57 | });
58 |
59 | // If you want to return some details about the algorithm's execution
60 | var details = louvain.detailed(graph);
61 |
62 | // If you want to ignore your graph's weights
63 | louvain.assign(graph, {getEdgeWeight: null});
64 | ```
65 |
66 | _Arguments_
67 |
68 | - **graph** _Graph_: target graph.
69 | - **options** ?object: options:
70 | - **getEdgeWeight** ?string\|function weight: name of the edges' weight attribute or getter function.
71 | - **nodeCommunityAttribute** ?string community: name of the community attribute.
72 | - **fastLocalMoves** ?boolean true: whether to use a well-known optimization relying on a queue set to traverse the graph more efficiently.
73 | - **randomWalk** ?boolean true: whether to traverse the graph randomly.
74 | - **resolution** ?number 1: resolution parameter. An increased resolution should produce more communities.
75 | - **rng** ?function Math.random: RNG function to use for `randomWalk`. Useful if you need to seed your rng using, for instance, [seedrandom](https://www.npmjs.com/package/seedrandom).
76 |
77 | _Detailed Output_
78 |
79 | - **communities** object: partition of the graph.
80 | - **count** number: number of communities in the partition.
81 | - **deltaComputations** number: number of delta computations that were run to produce the partition.
82 | - **dendrogram** array: array of partitions.
83 | - **modularity** number: final modularity of the graph given the found partition.
84 | - **moves** array: array of array of number of moves if `fastLocalMoves` was false or array of number of moves if `fastLocalMoves` was true.
85 | - **nodesVisited** number: number of times nodes were visited.
86 |
87 | ## Benchmark
88 |
89 | To run the benchmark:
90 |
91 | ```
92 | npm install --no-save ngraph.louvain.native
93 | node benchmark/comparison.js
94 | ```
95 |
96 | ```
97 | Clustered Undirected graph with 1000 nodes and 9724 edges.
98 |
99 | graphology undirected1000: 52.732ms
100 | Communities 8
101 | Modularity 0.42944314393593924
102 |
103 | jlouvain undirected1000: 2368.053ms
104 | Communities 8
105 | Modularity 0.4302331134880074
106 |
107 | ngraph.louvain undirected1000: 71.108ms
108 | Communities 8
109 |
110 | ngraph.louvain.native undirected1000: 39.185ms
111 | Communities 7
112 |
113 | ---
114 |
115 | EuroSIS Directed graph with 1285 nodes and 7524 edges.
116 |
117 | graphology euroSis: 30.809ms
118 | Communities 19
119 | Modularity 0.7375260763995757
120 |
121 | jlouvain euroSis: 1310.008ms
122 | Communities 23
123 | Modularity 0.7376116434498033
124 |
125 | ngraph euroSis: 38.262ms
126 | Communities 16
127 |
128 | ngraph.native euroSis: 20.018ms
129 | Communities 16
130 |
131 | ---
132 |
133 | Big Undirected graph with 50000 nodes and 994713 edges.
134 |
135 | graphology bigGraph: 937.942ms
136 | Communities 43
137 | Modularity 0.481431448861252
138 |
139 | jLouvain is too slow...
140 |
141 | ngraph bigGraph: 7783.050ms
142 | Communities 44
143 |
144 | ngraph.native bigGraph: 8415.692ms
145 | Communities 1
146 | ```
147 |
148 |
--------------------------------------------------------------------------------
/events.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: Events
4 | nav_order: 11
5 | menu_toc:
6 | - nodeAdded
7 | - edgeAdded
8 | - nodeDropped
9 | - edgeDropped
10 | - cleared
11 | - edgesCleared
12 | - attributesUpdated
13 | - nodeAttributesUpdated
14 | - edgeAttributesUpdated
15 | - eachNodeAttributesUpdated
16 | - eachEdgeAttributesUpdated
17 | ---
18 |
19 |
20 | # Events
21 |
22 | The `Graph` instance is a node.js-like event emitter. As such, you can listen to its events in order to be able to react. This is particularly useful if you need to render your graph or maintain external indexes.
23 |
24 | Documentation about node.js event emitters can be found [here](https://nodejs.org/api/events.html).
25 |
26 | Note that the emitted payload is always an object with various keys.
27 |
28 | ## nodeAdded
29 |
30 | Emitted whenever a node is added to the graph.
31 |
32 | *Example*
33 |
34 | ```js
35 | graph.on('nodeAdded', function({key}) {
36 | console.log(key);
37 | })
38 |
39 | graph.addNode('Thomas');
40 | // Will print:
41 | >>> 'Thomas'
42 | ```
43 |
44 | *Payload*
45 |
46 | * **key** any: the added node.
47 | * **attributes** object: the node's attributes.
48 |
49 | ## edgeAdded
50 |
51 | Emitted whenever an edge is added to the graph.
52 |
53 | *Example*
54 |
55 | ```js
56 | graph.on('edgeAdded', function({key, source, target}) {
57 | console.log(key, source, target);
58 | })
59 |
60 | graph.addEdgeWithKey('T->R', 'Thomas', 'Richard');
61 | // Will print:
62 | >>> 'T->R', 'Thomas', 'Richard'
63 | ```
64 |
65 | *Payload*
66 |
67 | * **key** any: the added edge.
68 | * **source** any: the added edge's source.
69 | * **target** any: the added edge's target.
70 | * **attributes** object: the edge's attributes.
71 | * **undirected** boolean: whether the edge is undirected.
72 |
73 | ## nodeDropped
74 |
75 | Emitted whenever a node is dropped from the graph.
76 |
77 | *Example*
78 |
79 | ```js
80 | graph.on('nodeDropped', function({key}) {
81 | console.log(key);
82 | })
83 |
84 | graph.dropNode('Thomas');
85 | // Will print:
86 | >>> 'Thomas'
87 | ```
88 |
89 | *Payload*
90 |
91 | * **key** any: the dropped node's key.
92 | * **attributes** object: the node's attributes.
93 |
94 | ## edgeDropped
95 |
96 | Emitted whenever an edge is dropped from the graph.
97 |
98 | *Example*
99 |
100 | ```js
101 | graph.on('edgeDropped', function({key, source, target}) {
102 | console.log(key, source, target);
103 | })
104 |
105 | graph.addEdgeWithKey('T->R', 'Thomas', 'Richard');
106 | graph.dropEdge('T->R');
107 | // Will print:
108 | >>> 'T->R', 'Thomas', 'Richard'
109 | ```
110 |
111 | *Payload*
112 |
113 | * **key** any: the dropped edge's key.
114 | * **source** any: the dropped edge's source.
115 | * **target** any: the dropped edge's target.
116 | * **attributes** object: the edge's attributes.
117 | * **undirected** boolean: whether the edge is undirected.
118 |
119 | ## cleared
120 |
121 | Emitted whenever the graph is cleared when using the [`#.clear`](mutations#clear) method. Note that when using this method, the `nodeDropped` & the `edgeDropped` events won't be emitted.
122 |
123 | *Example*
124 |
125 | ```js
126 | graph.on('cleared', function() {
127 | console.log(graph.order, graph.size);
128 | });
129 |
130 | graph.clear();
131 | // Will print:
132 | >>> 0, 0
133 | ```
134 |
135 | ## edgesCleared
136 |
137 | Emitted whenever the graph is cleared of its edges when using the [`#.clearEdges`](mutations#clearedges) method. Note that when using this method the `edgeDropped` events won't be emitted.
138 |
139 | *Example*
140 |
141 | ```js
142 | graph.on('edgesCleared', function() {
143 | console.log(graph.order, graph.size);
144 | });
145 |
146 | graph.clearEdges();
147 | // Will print:
148 | >>> 45, 0
149 | ```
150 |
151 | ## attributesUpdated
152 |
153 | Emitted whenever the attributes of the graph are updated.
154 |
155 | *Example*
156 |
157 | ```js
158 | graph.on('attributesUpdated', function({type}) {
159 | console.log(type);
160 | });
161 |
162 | graph.setAttribute('name', 'My Beautiful Graph');
163 | // Will print:
164 | 'set'
165 | ```
166 |
167 | *Payload*
168 |
169 | * **type** string: type of the update, one of `set`, `remove`, `replace`, `merge` or `update`.
170 | * **attributes** object: the graph's attributes.
171 | * **name** [string]: the name of the edited attributes if type is `set` or `remove`.
172 | * **data** [object]: merged data in case the type is `merge`.
173 |
174 | ## nodeAttributesUpdated
175 |
176 | Emitted whenever the attributes of the node are updated.
177 |
178 | *Example*
179 |
180 | ```js
181 | graph.on('nodeAttributesUpdated', function({key, type}) {
182 | console.log(key, type);
183 | });
184 |
185 | graph.setNodeAttribute('Thomas', 'age', 54);
186 | // Will print:
187 | 'Thomas', 'set'
188 | ```
189 |
190 | *Payload*
191 |
192 | * **type** string: type of the update, one of `set`, `remove`, `replace`, `merge` or `update`.
193 | * **key** string: the affected node's key.
194 | * **attributes** object: the node's attributes.
195 | * **name** [string]: the name of the edited attributes if type is `set` or `remove`.
196 | * **data** [object]: merged data in case the type is `merge`.
197 |
198 | ## edgeAttributesUpdated
199 |
200 | Emitted whenever the attributes of the edge are updated.
201 |
202 | *Example*
203 |
204 | ```js
205 | graph.on('edgeAttributesUpdated', function({key, type}) {
206 | console.log(key, type);
207 | });
208 |
209 | graph.setEdgeAttribute('T->R', 'type', 'KNOWS');
210 | // Will print:
211 | 'Thomas', 'set'
212 | ```
213 |
214 | *Payload*
215 |
216 | * **type** string: type of the update, one of `set`, `remove`, `replace`, `merge` or `update`.
217 | * **key** string: the affected edge's key.
218 | * **attributes** object: the edge's attributes.
219 | * **name** [string]: the name of the edited attributes if type is `set` or `remove`.
220 | * **data** [object]: merged data in case the type is `merge`.
221 |
222 | ## eachNodeAttributesUpdated
223 |
224 | Emitted whenever the [#.updateEachNodeAttributes](attributes#updateeachnodeattributes) is called.
225 |
226 | *Payload*
227 |
228 | * **hints** [object]: hints (only if they were provided by user, else `null`):
229 | * **attributes** [array]: the list of updated attribute names.
230 |
231 | ## eachEdgeAttributesUpdated
232 |
233 | Emitted whenever the [#.updateEachEdgeAttributes](attributes#updateeachedgeattributes) is called.
234 |
235 | *Payload*
236 |
237 | * **hints** [object]: hints (only if they were provided by user, else `null`):
238 | * **attributes** [array]: the list of updated attribute names.
239 |
--------------------------------------------------------------------------------
/standard-library/shortest-path.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: shortest-path
4 | nav_order: 17
5 | parent: Standard library
6 | aux_links:
7 | "Library directory": "https://github.com/graphology/graphology/tree/master/src/shortest-path"
8 | "Changelog": "https://github.com/graphology/graphology/tree/master/src/shortest-path/CHANGELOG.md"
9 | ---
10 |
11 | # Graphology Shortest Path
12 |
13 | Shortest path functions for [`graphology`](..).
14 |
15 | ## Installation
16 |
17 | ```
18 | npm install graphology-shortest-path
19 | ```
20 |
21 | ## Usage
22 |
23 | - [Unweighted](#unweighted)
24 | - [bidirectional](#bidirectional)
25 | - [singleSource](#singlesource)
26 | - [singleSourceLength](#singlesourcelength)
27 | - [undirectedSingleSourceLength](#undirectedsinglesourcelength)
28 | - [Dijkstra](#dijkstra)
29 | - [bidirectional](#dijkstra-bidirectional)
30 | - [singleSource](#dijkstra-singlesource)
31 | - [A-star](#a-star)
32 | - [bidirectional](#astar-bidirectional)
33 | - [Utilities](#utilities)
34 | - [edgePathFromNodePath](#edgepathfromnodepath)
35 |
36 | ## Unweighted
37 |
38 | ### bidirectional
39 |
40 | Returns the shortest path in the graph between source & target or `null` if such a path does not exist.
41 |
42 | ```js
43 | import {bidirectional} from 'graphology-shortest-path';
44 | // Alternatively, if you want to load only the relevant code
45 | import {bidirectional} from 'graphology-shortest-path/unweighted';
46 |
47 | // Returning the shortest path between source & target
48 | const path = bidirectional(graph, source, target);
49 | ```
50 |
51 | _Arguments_
52 |
53 | - **graph** _Graph_: a `graphology` instance.
54 | - **source** _any_: source node.
55 | - **target** _any_: target node.
56 |
57 | ### singleSource
58 |
59 | Return a map of every shortest path between the given source & all the nodes of the graph.
60 |
61 | ```js
62 | import {singleSource} from 'graphology-shortest-path';
63 | // Alternatively, if you want to load only the relevant code
64 | import {singleSource} from 'graphology-shortest-path/unweighted';
65 |
66 | // Returning every shortest path between source & every node of the graph
67 | const paths = singleSource(graph, source);
68 | ```
69 |
70 | _Arguments_
71 |
72 | - **graph** _Graph_: a `graphology` instance.
73 | - **source** _any_: source node.
74 |
75 | ### singleSourceLength
76 |
77 | Return a map of every shortest path length between the given source & all the nodes of the graph.
78 |
79 | ```js
80 | import {singleSourceLength} from 'graphology-shortest-path';
81 | // Alternatively, if you want to load only the relevant code
82 | import {singleSourceLength} from 'graphology-shortest-path/unweighted';
83 |
84 | // Returning every shortest path between source & every node of the graph
85 | const paths = singleSourceLength(graph, source);
86 | ```
87 |
88 | _Arguments_
89 |
90 | - **graph** _Graph_: a `graphology` instance.
91 | - **source** _any_: source node.
92 |
93 | ### undirectedSingleSourceLength
94 |
95 | Return a map of every shortest path length between the given source & all the nodes of the graph. This is basically the same as [singleSourceLength](#singlesourcelength) except that it will consider any given graph as undirected when traversing.
96 |
97 | ```js
98 | import {undirectedSingleSourceLength} from 'graphology-shortest-path';
99 | // Alternatively, if you want to load only the relevant code
100 | import {undirectedSingleSourceLength} from 'graphology-shortest-path/unweighted';
101 |
102 | // Returning every shortest path between source & every node of the graph
103 | const paths = undirectedSingleSourceLength(graph, source);
104 | ```
105 |
106 | _Arguments_
107 |
108 | - **graph** _Graph_: a `graphology` instance.
109 | - **source** _any_: source node.
110 |
111 | ## Dijkstra
112 |
113 | bidirectional
114 |
115 | Returns the shortest path in the weighted graph between source & target or `null` if such a path does not exist.
116 |
117 | ```js
118 | import {dijkstra} from 'graphology-shortest-path';
119 | // Alternatively, if you want to load only the relevant code
120 | import dijkstra from 'graphology-shortest-path/dijkstra';
121 |
122 | // Returning the shortest path between source & target
123 | const path = dijkstra.bidirectional(graph, source, target);
124 |
125 | // If you store edges' weight in custom attribute
126 | const path = dijkstra.bidirectional(graph, source, target, 'customWeight');
127 |
128 | // Using a custom weight getter function
129 | const path = dijkstra.bidirectional(
130 | graph,
131 | source,
132 | target,
133 | (_, attr) => attr.importance
134 | );
135 | ```
136 |
137 | _Arguments_
138 |
139 | - **graph** _Graph_: a `graphology` instance.
140 | - **source** _any_: source node.
141 | - **target** _any_: target node.
142 | - **getEdgeWeight** ?string\|function weight: name of the weight attribute or getter function.
143 |
144 | singleSource
145 |
146 | Return a map of every shortest path between the given source & all the nodes of the weighted graph.
147 |
148 | ```js
149 | import {dijkstra} from 'graphology-shortest-path';
150 | // Alternatively, if you want to load only the relevant code
151 | import dijkstra from 'graphology-shortest-path/dijkstra';
152 |
153 | // Returning every shortest path between source & every node of the graph
154 | const paths = dijkstra.singleSource(graph, source);
155 |
156 | // If you store edges' weight in custom attribute
157 | const paths = dijkstra.singleSource(graph, source, 'customWeight');
158 |
159 | // Using a custom weight getter function
160 | const path = dijkstra.singleSource(graph, source, (_, attr) => attr.importance);
161 | ```
162 |
163 | _Arguments_
164 |
165 | - **graph** _Graph_: a `graphology` instance.
166 | - **source** _any_: source node.
167 | - **getEdgeWeight** ?string\|function weight: name of the weight attribute or getter function.
168 |
169 | ## A-star
170 |
171 | bidirectional
172 |
173 | Returns the shortest path in the weighted graph between source & target or `null` if such a path does not exist.
174 |
175 | ```js
176 | import {astar} from 'graphology-shortest-path';
177 | // Alternatively, if you want to load only the relevant code
178 | import astar from 'graphology-shortest-path/astar';
179 |
180 | // Returning the shortest path between source & target
181 | const path = astar.bidirectional(
182 | graph,
183 | source,
184 | target,
185 | (_, attr) => attr.importance
186 | (node, finalTarget) => euclideanDistance(points[node], points[finalTarget])
187 | );
188 | ```
189 |
190 | _Arguments_
191 |
192 | - **graph** _Graph_: a `graphology` instance.
193 | - **source** _any_: source node.
194 | - **target** _any_: target node.
195 | - **getEdgeWeight** ?string\|function weight: name of the weight attribute or getter function.
196 | - **heuristic** ?function: heuristic function to compute distance between current node and final target.
197 |
198 | ## Utilities
199 |
200 | ### edgePathFromNodePath
201 |
202 | Helper function that can convert a node path to an edge path.
203 |
204 | ```js
205 | import {edgePathFromNodePath} from 'graphology-shortest-path';
206 | // Alternatively, if you want to load only the relevant code
207 | import {edgePathFromNodePath} from 'graphology-shortest-path/utils';
208 |
209 | const edgePath = edgePathFromNodePath(graph, nodePath);
210 | ```
211 |
212 | _Arguments_
213 |
214 | - **graph** _Graph_: a `graphology` instance.
215 | - **nodePath** _Array_: node path to convert.
216 |
217 |
--------------------------------------------------------------------------------
/standard-library/operators.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: operators
4 | nav_order: 16
5 | parent: Standard library
6 | aux_links:
7 | "Library directory": "https://github.com/graphology/graphology/tree/master/src/operators"
8 | "Changelog": "https://github.com/graphology/graphology/tree/master/src/operators/CHANGELOG.md"
9 | ---
10 |
11 | # Graphology Operators
12 |
13 | Miscellaneous operators to be used with [`graphology`](..).
14 |
15 | ## Installation
16 |
17 | ```
18 | npm install graphology-operators
19 | ```
20 |
21 | ## Usage
22 |
23 | _Unary_
24 |
25 | - [subgraph](#subgraph)
26 | - [reverse](#reverse)
27 |
28 | _Binary_
29 |
30 | - [disjointUnion](#disjointunion)
31 | - [union](#union)
32 |
33 | _Cast_
34 |
35 | - [toDirected](#todirected)
36 | - [toMixed](#tomixed)
37 | - [toMulti](#tomulti)
38 | - [toSimple](#tosimple)
39 | - [toUndirected](#toundirected)
40 |
41 | ### subgraph
42 |
43 | Return a graph's subgraph containing the given nodes and their relevant edges.
44 |
45 | ```js
46 | import {subgraph} from 'graphology-operators';
47 | // Alternatively, to load only the relevant code:
48 | import subgraph from 'graphology-operators/subgraph';
49 |
50 | // From an array of nodes
51 | const sub = subgraph(graph, ['John', 'Mary', 'Sue']);
52 |
53 | // From a set of nodes
54 | const sub = subgraph(graph, new Set(['John', 'Mary', 'Sue']));
55 |
56 | // From a filtering function
57 | const sub = subgraph(graph, function (key, attr) {
58 | return key.startsWith('J') || attr.color === 'red';
59 | });
60 | ```
61 |
62 | _Arguments_
63 |
64 | - **graph** _Graph_: target graph.
65 | - **nodes** _array\|Set\|function_: either an array of nodes to keep, or a set of nodes to keep or a function taking a node's key and its attributes and tasked to filter the nodes to keep.
66 |
67 | ### reverse
68 |
69 | Reverse the given graph's directed edges.
70 |
71 | ```js
72 | import {reverse} from 'graphology-operators';
73 | // Alternatively, to load only the relevant code:
74 | import reverse from 'graphology-operators/reverse';
75 |
76 | const reversedGraph = reverse(graph);
77 | ```
78 |
79 | _Arguments_
80 |
81 | - **graph** _Graph_: target graph.
82 |
83 | ### disjointUnion
84 |
85 | Returns the disjoin union of the given graphs. To do so, the function will
86 | relabel your nodes & edges so both graphs can remain disjoint.
87 |
88 | ```js
89 | import {disjointUnion} from 'graphology-operators';
90 | // Alternatively, to load only the relevant code:
91 | import disjointUnion from 'graphology-operators/disjoint-union';
92 |
93 | const R = disjointUnion(G, H);
94 | ```
95 |
96 | _Arguments_
97 |
98 | - **G** _Graph_: first graph.
99 | - **H** _Graph_: second graph.
100 |
101 | ### union
102 |
103 | Returns the union of the given graphs. Nodes & edges present in both graph will have their attributes merges with precedence given to the second graph.
104 |
105 | ```js
106 | import {union} from 'graphology-operators';
107 | // Alternatively, to load only the relevant code:
108 | import union from 'graphology-operators/union';
109 |
110 | const R = union(G, H);
111 | ```
112 |
113 | _Arguments_
114 |
115 | - **G** _Graph_: first graph.
116 | - **H** _Graph_: second graph.
117 |
118 | ### toDirected
119 |
120 | Returns the directed version of the given graph where any undirected edge will be now considered as mutual.
121 |
122 | Note that you can pass a function to merge edge attributes in case of mixed edges conflicts. This can be useful to sum weights and so on...
123 |
124 | If an already directed graph is passed, the function will only return a copy of it.
125 |
126 | If passing a multi graph, undirected edges will only be converted as pairs ofmutual ones and will never be merged.
127 |
128 | ```js
129 | import {toDirected} from 'graphology-operators';
130 | // Alternatively, to load only the relevant code:
131 | import toDirected from 'graphology-operators/to-directed';
132 |
133 | const directedGraph = toDirected(graph);
134 |
135 | // Using a merging function
136 | const directedGraph = toDirected(graph, (currentAttr, nextAttr) => {
137 | return {
138 | ...currentAttr,
139 | weight: currentAttr.weight + nextAttr.weight
140 | };
141 | });
142 | ```
143 |
144 | _Arguments_
145 |
146 | - **graph** _Graph_: target graph.
147 | - **mergeOrOptions** ?function\|object: either a merging function or an options object:
148 | - **mergeEdge** ?function: merging function to use.
149 |
150 | ### toMixed
151 |
152 | Returns the given graph as mixed.
153 |
154 | If an already mixed graph is passed, the function will only return a copy of it.
155 |
156 | ```js
157 | import {toMixed} from 'graphology-operators';
158 | // Alternatively, to load only the relevant code:
159 | import toMixed from 'graphology-operators/to-mixed';
160 |
161 | const mixedGraph = toMixed(graph);
162 | ```
163 |
164 | ### toMulti
165 |
166 | Returns the given graph as multi.
167 |
168 | If an already multi graph is passed, the function will only return a copy of it.
169 |
170 | ```js
171 | import {toMulti} from 'graphology-operators';
172 | // Alternatively, to load only the relevant code:
173 | import toMulti from 'graphology-operators/to-multi';
174 |
175 | const mixedGraph = toMulti(graph);
176 | ```
177 |
178 | ### toSimple
179 |
180 | Returns the simple version of the given multigraph where we only keep a single edge of each type between nodes.
181 |
182 | Note that you can pass a function to merge edge attributes in case of mutual edges or mixed edges conflicts. This can be useful to sum weights and so on...
183 |
184 | If an already simple graph is passed, the function will only return a copy of it.
185 |
186 | ```js
187 | import {toSimple} from 'graphology-operators';
188 | // Alternatively, to load only the relevant code:
189 | import toSimple from 'graphology-operators/to-simple';
190 |
191 | const simpleGraph = toSimple(multiGraph);
192 |
193 | // Using a merging function
194 | const simpleGraph = toSimple(graph, (currentAttr, nextAttr) => {
195 | return {
196 | ...currentAttr,
197 | weight: currentAttr.weight + nextAttr.weight
198 | };
199 | });
200 | ```
201 |
202 | _Arguments_
203 |
204 | - **graph** _Graph_: target graph.
205 | - **mergeOrOptions** ?function|object: either a merging function or an options object:
206 | - **mergeEdge** ?function: merging function to use.
207 |
208 | ### toUndirected
209 |
210 | Returns the undirected version of the given graph where any directed edge will be now considered as undirected.
211 |
212 | Note that you can pass a function to merge edge attributes in case of mutual edges or mixed edges conflicts. This can be useful to sum weights and so on...
213 |
214 | If an already undirected graph is passed, the function will only return a copy of it.
215 |
216 | If passing a multi graph, directed edges will only be converted as undirected ones and will never be merged.
217 |
218 | ```js
219 | import {toUndirected} from 'graphology-operators';
220 | // Alternatively, to load only the relevant code:
221 | import toUndirected from 'graphology-operators/to-undirected';
222 |
223 | const undirectedGraph = toUndirected(graph);
224 |
225 | // Using a merging function
226 | const undirectedGraph = toUndirected(graph, (currentAttr, nextAttr) => {
227 | return {
228 | ...currentAttr,
229 | weight: currentAttr.weight + nextAttr.weight
230 | };
231 | });
232 | ```
233 |
234 | _Arguments_
235 |
236 | - **graph** _Graph_: target graph.
237 | - **mergeOrOptions** ?function|object: either a merging function or an options object:
238 | - **mergeEdge** ?function: merging function to use.
239 |
240 |
--------------------------------------------------------------------------------
/standard-library/utils.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: utils
4 | nav_order: 21
5 | parent: Standard library
6 | aux_links:
7 | "Library directory": "https://github.com/graphology/graphology/tree/master/src/utils"
8 | "Changelog": "https://github.com/graphology/graphology/tree/master/src/utils/CHANGELOG.md"
9 | ---
10 |
11 | # Graphology Utils
12 |
13 | Miscellaneous utility functions to be used with [`graphology`](..).
14 |
15 | ## Installation
16 |
17 | ```
18 | npm install graphology-utils
19 | ```
20 |
21 | ## Usage
22 |
23 | _Assertions_
24 |
25 | - [#.isGraph](#isgraph)
26 | - [#.isGraphConstructor](#isgraphconstructor)
27 |
28 | _Introspection_
29 |
30 | - [#.inferMulti](#infermulti)
31 | - [#.inferType](#infertype)
32 |
33 | _Typical edge patterns_
34 |
35 | - [#.mergeClique](#mergeclique)
36 | - [#.mergeCycle](#mergecycle)
37 | - [#.mergePath](#mergepath)
38 | - [#.mergeStar](#mergestar)
39 |
40 | _Miscellaneous helpers_
41 |
42 | - [#.renameGraphKeys](#renamegraphkeys)
43 | - [#.updateGraphKeys](#updategraphkeys)
44 |
45 | ### #.isGraph
46 |
47 | Function returning whether the given value is a `graphology` implementation's instance.
48 |
49 | ```js
50 | import {isGraph} from 'graphology-utils';
51 | // Alternatively, if you want to only load the relevant code:
52 | import isGraph from 'graphology-utils/is-graph';
53 |
54 | const graph = new Graph();
55 |
56 | isGraph(graph);
57 | >>> true
58 |
59 | isGraph(45);
60 | >>> false
61 |
62 | isGraph({hello: 'world'});
63 | >>> false
64 | ```
65 |
66 | _Arguments_
67 |
68 | - **value** _any_: value to test.
69 |
70 | ### #.isGraphConstructor
71 |
72 | Function returning whether the given value is a `graphology` constructor.
73 |
74 | ```js
75 | import {isGraphConstructor} from 'graphology-utils';
76 | // Alternatively, if you want to only load the relevant code:
77 | import isGraphConstructor from 'graphology-utils/is-graph-constructor';
78 |
79 | isGraphConstructor(Graph);
80 | >>> true
81 |
82 | isGraphConstructor(45);
83 | >>> false
84 |
85 | isGraphConstructor(new Graph());
86 | >>> false
87 | ```
88 |
89 | _Arguments_
90 |
91 | - **value** _any_: value to test.
92 |
93 | ### #.inferMulti
94 |
95 | Function returning whether the given graph is truly multi, i.e. if we can find at least one occurrence of multiple edges of the same type and direction between two nodes.
96 |
97 | ```js
98 | import {inferMulti} from 'graphology-utils';
99 | // Alternatively, if you want to only load the relevant code:
100 | import inferMulti from 'graphology-utils/infer-multi';
101 |
102 | const graph = new MultiGraph();
103 | graph.addEdge(1, 2);
104 |
105 | inferMulti(graph);
106 | >>> false
107 |
108 | graph.addEdge(1, 2);
109 |
110 | inferMulti(graph);
111 | >>> true
112 | ```
113 |
114 | ### #.inferType
115 |
116 | Function returning the inferred type of the given graph. This function is useful to check whether a given mixed graph is in fact a mere `directed` or `undirected` graph based on its actual edges.
117 |
118 | ```js
119 | import {inferType} from 'graphology-utils';
120 | // Alternatively, if you want to only load the relevant code:
121 | import inferType from 'graphology-utils/infer-type';
122 |
123 | const graph = new Graph();
124 | graph.addUndirectedEdge(1, 2);
125 |
126 | inferType(graph);
127 | >>> 'directed'
128 | ```
129 |
130 | ### #.mergeClique
131 |
132 | Function adding a clique to the given graph.
133 |
134 | ```js
135 | import {mergeClique} from 'graphology-utils';
136 | // Alternatively, if you want to only load the relevant code:
137 | import mergeClique from 'graphology-utils/merge-clique';
138 |
139 | const graph = new Graph();
140 |
141 | mergeClique(graph, [1, 2, 3]);
142 | graph.edges().map(e => graph.extremities(e));
143 | >>> [[1, 2], [1, 3], [2, 3]]
144 | ```
145 |
146 | ### #.mergeCycle
147 |
148 | Function adding a cycle to the given graph.
149 |
150 | ```js
151 | import {mergeCycle} from 'graphology-utils';
152 | // Alternatively, if you want to only load the relevant code:
153 | import mergeCycle from 'graphology-utils/merge-cycle';
154 |
155 | const graph = new Graph();
156 |
157 | mergeCycle(graph, [1, 2, 3, 4, 5]);
158 | graph.edges().map(e => graph.extremities(e));
159 | >>> [[1, 2], [2, 3], [3, 4], [4, 5], [5, 1]]
160 | ```
161 |
162 | _Arguments_
163 |
164 | - **graph** _Graph_: target graph.
165 | - **cycle** _array_: array of nodes representing the cycle to add.
166 |
167 | ### #.mergePath
168 |
169 | Function adding a path to the given graph.
170 |
171 | ```js
172 | import {mergePath} from 'graphology-utils';
173 | // Alternatively, if you want to only load the relevant code:
174 | import mergePath from 'graphology-utils/merge-path';
175 |
176 | const graph = new Graph();
177 |
178 | mergePath(graph, [1, 2, 3, 4, 5]);
179 | graph.edges().map(e => graph.extremities(e));
180 | >>> [[1, 2], [2, 3], [3, 4], [4, 5]]
181 | ```
182 |
183 | _Arguments_
184 |
185 | - **graph** _Graph_: target graph.
186 | - **path** _array_: array of nodes representing the path to add.
187 |
188 | ### #.mergeStar
189 |
190 | Function adding a star to the given graph.
191 |
192 | ```js
193 | import {mergeStar} from 'graphology-utils';
194 | // Alternatively, if you want to only load the relevant code:
195 | import mergeStar from 'graphology-utils/merge-star';
196 |
197 | const graph = new Graph();
198 |
199 | mergeStar(graph, [1, 2, 3, 4, 5]);
200 | graph.edges().map(e => graph.extremities(e));
201 | >>> [[1, 2], [1, 3], [1, 4], [1, 5]]
202 | ```
203 |
204 | _Arguments_
205 |
206 | - **graph** _Graph_: target graph.
207 | - **star** _array_: array of nodes representing the star to add.
208 |
209 | ### #.renameGraphKeys
210 |
211 | Function renaming the nodes & edges key of a graph using mappings and returning a new graph with renamed keys.
212 |
213 | ```js
214 | import {renameGraphKeys} from 'graphology-utils';
215 | // Alternatively, if you want to only load the relevant code:
216 | import renameGraphKeys from 'graphology-utils/rename-graph-keys';
217 |
218 | const graph = new Graph();
219 | graph.addNode('Martha');
220 | graph.addNode('Catherine');
221 | graph.addNode('John');
222 | graph.addEdgeWithKey('M->C', 'Martha', 'Catherine');
223 | graph.addEdgeWithKey('C->J', 'Catherine', 'John');
224 |
225 | const renamedGraph = renameGraphKeys(
226 | graph,
227 | {Martha: 1, Catherine: 2, John: 3},
228 | {'M->C': 'rel1', 'C->J': 'rel2'}
229 | );
230 |
231 | renamedGraph.nodes();
232 | >>> [1, 2, 3];
233 |
234 | renamedGraph.edges();
235 | >>> ['rel1', 'rel2'];
236 | ```
237 |
238 | _Arguments_
239 |
240 | - **graph** _Graph_: target graph.
241 | - **nodeKeyMapping** _object_: A key/value map for the node key mapping.
242 | - **edgeKeyMapping** ?object: A key/value map for the edge key mapping.
243 |
244 | ### #.updateGraphKeys
245 |
246 | Function updating the nodes & edges key of a graph using functions and returning a new graph with updated keys.
247 |
248 | ```js
249 | import {updateGraphKeys} from 'graphology-utils';
250 | // Alternatively, if you want to only load the relevant code:
251 | import updateGraphKeys from 'graphology-utils/update-graph-keys';
252 |
253 | const graph = new Graph();
254 | graph.addNode('Martha');
255 | graph.addNode('Catherine');
256 | graph.addNode('John');
257 | graph.addEdgeWithKey('M->C', 'Martha', 'Catherine');
258 | graph.addEdgeWithKey('C->J', 'Catherine', 'John');
259 |
260 | const updatedGraph = updateGraphKeys(
261 | graph,
262 | (key)=> {
263 | if (key === 'Martha') return 1;
264 | if (key === 'Catherine') return 2;
265 | return 3;
266 | },
267 | (key) => {
268 | if (key === 'M->C') return 'rel1';
269 | return 'rel2';
270 | }
271 | );
272 |
273 | updatedGraph.nodes();
274 | >>> [1, 2, 3];
275 |
276 | updatedGraph.edges();
277 | >>> ['rel1', 'rel2'];
278 | ```
279 |
280 | _Arguments_
281 |
282 | - **graph** _Graph_: target graph.
283 | - **nodeKeyUdater** _function_: A function to compute a new node key from the same arguments that would be given to [`#.forEachNode`](https://graphology.github.io/iteration.html#foreachnode).
284 | - **edgeKeyUpdater** _function_: A function to compute a new edge key from the same arguments that would be given to [`#.forEachEdge`](https://graphology.github.io/iteration.html#foreachedge).
285 |
286 |
--------------------------------------------------------------------------------
/read.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: Read
4 | nav_order: 5
5 | menu_toc:
6 | - "#.hasNode"
7 | - "#.hasEdge"
8 | - "#.edge"
9 | - "#.degree"
10 | - "#.degreeWithoutSelfLoops"
11 | - "#.source"
12 | - "#.target"
13 | - "#.opposite"
14 | - "#.extremities"
15 | - "#.hasExtremity"
16 | - "#.isDirected"
17 | - "#.isSelfLoop"
18 | - "#.areNeighbors"
19 | ---
20 |
21 | # Read
22 |
23 | ## #.hasNode
24 |
25 | Returns whether the given node is found in the graph.
26 |
27 | *Example*
28 |
29 | ```js
30 | graph.addNode('Timothy');
31 |
32 | graph.hasNode('Timothy');
33 | >>> true
34 |
35 | graph.hasNode('Jack');
36 | >>> false
37 | ```
38 |
39 | *Arguments*
40 |
41 | * **node** any: node to find.
42 |
43 | ## #.hasEdge
44 |
45 | Returns whether the given edge is found in the graph or whether an edge links the given source & target.
46 |
47 | See also [#.areNeighbors](#areneighbors).
48 |
49 | *Example*
50 |
51 | ```js
52 | graph.addNode('Timothy');
53 | graph.addNode('Clarice');
54 | const edge = graph.addEdge('Clarice', 'Timothy');
55 |
56 | // Using the edge's key:
57 | graph.hasEdge(edge);
58 | >>> true
59 |
60 | // Using the edge's source & target:
61 | graph.hasEdge('Clarice', 'Timothy');
62 | >>> true
63 |
64 | graph.hasEdge('Clarice', 'John');
65 | >>> false
66 | ```
67 |
68 | *Arguments*
69 |
70 | 1. Using the key:
71 | * **edge** any: edge to find.
72 | 2. Using the source & target:
73 | * **source** any: source of the edge to find.
74 | * **target** any: target of the edge to find.
75 |
76 | *Variants*
77 |
78 | * `#.hasDirectedEdge`
79 | * `#.hasUndirectedEdge`
80 |
81 | ## #.edge
82 |
83 | Returns the key of the edge between given source & target or `undefined` if such an edge does not exist.
84 |
85 | Note that this method will throw if either source or target is not found in the graph.
86 |
87 | In addition, this method won't work on a multi graph and will throw because the graph cannot know which edge to return since there might be multiple edges between source & target.
88 |
89 | *Example*
90 |
91 | ```js
92 | graph.addNode('Timothy');
93 | graph.addNode('Clarice');
94 | graph.addNode('Olivia');
95 | graph.addEdgeWithKey('C->T', 'Clarice', 'Timothy');
96 |
97 | graph.edge('Clarice', 'Timothy');
98 | >>> 'C->T'
99 |
100 | graph.edge('Clarice', 'Olivia');
101 | >>> undefined
102 | ```
103 |
104 | *Arguments*
105 |
106 | * **source** any: source of the edge to find.
107 | * **target** any: target of the edge to find.
108 |
109 | *Variants*
110 |
111 | * `#.directedEdge`
112 | * `#.undirectedEdge`
113 |
114 | ## #.degreeWithoutSelfLoops
115 |
116 | Returns the degree of the given node, without taking self loops into account.
117 |
118 | Will throw if the node is not found in the graph.
119 |
120 | *Example*
121 |
122 | ```js
123 | graph.addNodeFrom(['Timothy', 'Jack', 'Clarice', 'Martha']);
124 | graph.addEdge('Timothy', 'Timothy');
125 | graph.addEdge('Timothy', 'Jack');
126 | graph.addEdge('Timothy', 'Clarice');
127 | graph.addEdge('Martha', 'Timothy');
128 |
129 | graph.degreeWithoutSelfLoops('Timothy');
130 | >>> 3
131 | graph.inWithoutSelfLoops('Timothy');
132 | >>> 1
133 | graph.outWithoutSelfLoops('Timothy');
134 | >>> 2
135 | ```
136 |
137 | *Arguments*
138 |
139 | * **node** any: target node.
140 |
141 | *Variants*
142 |
143 | * `#.inDegreeWithoutSelfLoops`
144 | * `#.outDegreeWithoutSelfLoops`
145 | * `#.directedDegreeWithoutSelfLoops` (`#.inDegreeWithoutSelfLoops` + `#.outDegreeWithoutSelfLoops`)
146 | * `#.undirectedDegreeWithoutSelfLoops`
147 | * `#.degreeWithoutSelfLoops` (`#.directedDegreeWithoutSelfLoops` + `#.undirectedDegreeWithoutSelfLoops`)
148 |
149 | ## #.degree
150 |
151 | Returns the degree of the given node.
152 |
153 | Will throw if the node is not found in the graph.
154 |
155 | *Example*
156 |
157 | ```js
158 | graph.addNodeFrom(['Timothy', 'Jack', 'Clarice', 'Martha']);
159 | graph.addEdge('Timothy', 'Jack');
160 | graph.addEdge('Timothy', 'Clarice');
161 | graph.addEdge('Martha', 'Timothy');
162 |
163 | graph.degree('Timothy');
164 | >>> 3
165 | graph.inDegree('Timothy');
166 | >>> 1
167 | graph.outDegree('Timothy');
168 | >>> 2
169 | ```
170 |
171 | *Arguments*
172 |
173 | * **node** any: target node.
174 |
175 | *Variants*
176 |
177 | * `#.inDegree`
178 | * `#.outDegree`
179 | * `#.directedDegree` (`#.inDegree` + `#.outDegree`)
180 | * `#.undirectedDegree`
181 | * `#.degree` (`#.directedDegree` + `#.undirectedDegree`)
182 |
183 | ## #.source
184 |
185 | Returns the source of the given edge.
186 |
187 | *Example*
188 |
189 | ```js
190 | graph.addNode('Timothy');
191 | graph.addNode('Clarice');
192 | const edge = graph.addEdge('Clarice', 'Timothy');
193 |
194 | graph.source(edge);
195 | >>> 'Clarice'
196 | ```
197 |
198 | *Arguments*
199 |
200 | * **edge** any: target edge.
201 |
202 | ## #.target
203 |
204 | Returns the target of the given edge.
205 |
206 | *Example*
207 |
208 | ```js
209 | graph.addNode('Timothy');
210 | graph.addNode('Clarice');
211 | const edge = graph.addEdge('Clarice', 'Timothy');
212 |
213 | graph.target(edge);
214 | >>> 'Timothy'
215 | ```
216 |
217 | *Arguments*
218 |
219 | * **edge** any: target edge.
220 |
221 | ## #.opposite
222 |
223 | Given a node & an edge, returns the node at the other end of the edge.
224 |
225 | *Example*
226 |
227 | ```js
228 | graph.addNode('Timothy');
229 | graph.addNode('Clarice');
230 | const edge = graph.addEdge('Clarice', 'Timothy');
231 |
232 | graph.opposite('Timothy', edge);
233 | >>> 'Clarice'
234 | ```
235 |
236 | *Arguments*
237 |
238 | * **node** any: target node.
239 | * **edge** any: target edge.
240 |
241 | ## #.extremities
242 |
243 | Returns both extremities of the given edge.
244 |
245 | *Example*
246 |
247 | ```js
248 | graph.addNode('Timothy');
249 | graph.addNode('Clarice');
250 | const edge = graph.addEdge('Clarice', 'Timothy');
251 |
252 | graph.extremities(edge);
253 | >>> ['Timothy', 'Clarice']
254 | ```
255 |
256 | *Arguments*
257 |
258 | * **edge** any: target edge.
259 |
260 | ## #.hasExtremity
261 |
262 | Returns whether the given edge has the given node as extremity.
263 |
264 | ```js
265 | graph.addNode('Lucy');
266 | graph.addNode('Timothy');
267 | graph.addNode('Clarice');
268 | const edge = graph.addEdge('Clarice', 'Timothy');
269 |
270 | graph.hasExtremity(edge, 'Timothy');
271 | >>> true
272 |
273 | graph.hasExtremity(edge, 'Lucy');
274 | >>> false
275 | ```
276 |
277 | ## #.isDirected
278 |
279 | Returns whether the given edge is directed.
280 |
281 | *Example*
282 |
283 | ```js
284 | graph.addNode('Timothy');
285 | graph.addNode('Clarice');
286 | const edge = graph.addEdge('Clarice', 'Timothy');
287 | const undirectedEdge = graph.addUndirectedEdge('Clarice', 'Timothy');
288 |
289 | graph.isDirected(edge);
290 | >>> true
291 | graph.isDirected(undirectedEdge);
292 | >>> false
293 | ```
294 |
295 | *Arguments*
296 |
297 | * **edge** any: target edge.
298 |
299 | *Variants*
300 |
301 | * `#.isUndirected`
302 |
303 | ## #.isSelfLoop
304 |
305 | Returns whether the given edge is a self-loop.
306 |
307 | *Example*
308 |
309 | ```js
310 | graph.addNode('Timothy');
311 | const edge = graph.addEdge('Timothy', 'Timothy');
312 |
313 | graph.isSelfLoop(edge);
314 | >>> true
315 | ```
316 |
317 | *Arguments*
318 |
319 | * **edge** any: target edge.
320 |
321 | ## #.areNeighbors
322 |
323 | Returns whether both nodes are neighbors.
324 |
325 | See also [#.hasEdge](#hasedge).
326 |
327 | *Examples*
328 |
329 | ```js
330 | graph.addNode('Timothy');
331 | graph.addNode('Clarice');
332 | graph.addNode('Zendar');
333 | graph.addEdge('Clarice', 'Timothy');
334 |
335 | graph.areNeighbors('Clarice', 'Timothy');
336 | >>> true
337 |
338 | graph.areNeighbors('Zendar', 'Clarice');
339 | >>> false
340 | ```
341 |
342 | *Arguments*
343 |
344 | * **node** any: target node.
345 | * **neighbord** any: potential neighbor.
346 |
347 | *Variants*
348 |
349 | * `#.areDirectedNeighbors`
350 | * `#.areUndirectedNeighbors`
351 | * `#.areInNeighbors`
352 | * `#.areOutNeighbors`
353 | * `#.areInboundNeighbors` (in + undirected)
354 | * `#.areOutboundNeighbors` (out + undirected)
355 |
--------------------------------------------------------------------------------
/standard-library/layout.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: layout
4 | nav_order: 11
5 | parent: Standard library
6 | aux_links:
7 | "Library directory": "https://github.com/graphology/graphology/tree/master/src/layout"
8 | "Changelog": "https://github.com/graphology/graphology/tree/master/src/layout/CHANGELOG.md"
9 | ---
10 |
11 | # Graphology Layout
12 |
13 | Collection of basic layout algorithms to be used with [`graphology`](..).
14 |
15 | ## Installation
16 |
17 | ```
18 | npm install graphology-layout
19 | ```
20 |
21 | ## Usage
22 |
23 | _Basic_
24 |
25 | - [circular](#circular)
26 | - [random](#random)
27 |
28 | _Advanced_
29 |
30 | - [circlePack](#circlePack)
31 |
32 | _Utilities_
33 |
34 | - [rotation](#rotation)
35 | - [collectLayout](#collectlayout)
36 | - [collectLayoutAsFlatArray](#collectlayoutasflatarray)
37 | - [assignLayout](#assignlayout)
38 | - [assignLayoutAsFlatArray](#assignlayoutasflatarray)
39 |
40 | ### circular
41 |
42 | Arranges the node in a circle (or an sphere/hypersphere in higher dimensions).
43 |
44 | _Example_
45 |
46 | ```js
47 | import {circular} from 'graphology-layout';
48 | // Alternatively, to load only the relevant code:
49 | import circular from 'graphology-layout/circular';
50 |
51 | const positions = circular(graph);
52 |
53 | // With options:
54 | const positions = circular(graph, {scale: 100});
55 |
56 | // To directly assign the positions to the nodes:
57 | circular.assign(graph);
58 |
59 | // To pass custom dimensions
60 | const positions = random(graph, {dimensions: ['x1', 'x2']});
61 | ```
62 |
63 | _Arguments_
64 |
65 | - **graph** _Graph_: target graph.
66 | - **options** ?object: options:
67 | - **dimensions** ?array ['x', 'y']: dimensions of the layout. Cannot work with dimensions != 2.
68 | - **center** ?number 0.5: center of the layout.
69 | - **scale** ?number 1: scale of the layout.
70 |
71 | ### random
72 |
73 | Random layout positioning every node by choosing each coordinates uniformly at random on the interval `[0, 1)`.
74 |
75 | _Example_
76 |
77 | ```js
78 | import {random} from 'graphology-layout';
79 | // Alternatively, to load only the relevant code:
80 | import random from 'graphology-layout/random';
81 |
82 | const positions = random(graph);
83 |
84 | // With options:
85 | const positions = random(graph, {rng: customRngFunction});
86 |
87 | // To directly assign the positions to the nodes:
88 | random.assign(graph);
89 |
90 | // To pass custom dimensions
91 | const positions = random(graph, {dimensions: ['x', 'y', 'z']});
92 | ```
93 |
94 | _Arguments_
95 |
96 | - **graph** _Graph_: target graph.
97 | - **options** ?object: options:
98 | - **dimensions** ?array ['x', 'y']: dimensions of the layout.
99 | - **center** ?number 0.5: center of the layout.
100 | - **rng** ?function Math.random: custom RNG function to use.
101 | - **scale** ?number 1: scale of the layout.
102 |
103 | ### circlePack
104 |
105 | Arranges the nodes as a bubble chart, according to specified attributes.
106 |
107 | _Example_
108 |
109 | ```js
110 | import {circlepack} from 'graphology-layout';
111 | // Alternatively, to load only the relevant code:
112 | import circlepack from 'graphology-layout/circlepack';
113 |
114 | const positions = circlepack(graph);
115 |
116 | // With options
117 | const positions = circlepack(graph, {
118 | hierarchyAttributes: ['degree', 'community'],
119 | rng: customRngFunction
120 | });
121 |
122 | // To directly assign the positions to the nodes:
123 | circlepack.assign(graph);
124 | ```
125 |
126 | _Arguments_
127 |
128 | - **graph** _Graph_: target graph.
129 | - **options** ?object: options:
130 | - **attributes** ?object: attributes to map:
131 | - **x** ?string x: name of the x position.
132 | - **y** ?string y: name of the y position.
133 | - **center** ?number 0: center of the layout.
134 | - **hierarchyAttributes** ?list []: attributes used to group nodes.
135 | - **rng** ?function Math.random: custom RNG function to use.
136 | - **scale** ?number 1: scale of the layout.
137 |
138 | ### rotation
139 |
140 | Rotates the node coordinates of the given graph by the given angle in radians (or in degrees using an option).
141 |
142 | Note that this function rotates your graph based on its center. If you want to use zero as the center for your rotation, use the `centeredOnZero` option. This option can also be used as an optimization strategy if you know your graph is already centered on zero to avoid needing to compute the graph's extent.
143 |
144 | _Example_
145 |
146 | ```js
147 | import {rotation} from 'graphology-layout';
148 | // Alternatively, to load only the relevant code:
149 | import rotation from 'graphology-layout/rotation';
150 |
151 | const positions = rotation(graph, Math.PI / 2);
152 |
153 | // With options:
154 | const positions = rotation(graph, Math.PI / 2, {centeredOnZero: true});
155 |
156 | // To directly assign the positions to the nodes:
157 | rotation.assign(graph, Math.PI / 2);
158 | ```
159 |
160 | _Arguments_
161 |
162 | - **graph** _Graph_: target graph.
163 | - **angle** _number_: rotation angle in radians (or degrees using an option below).
164 | - **options** ?object: options:
165 | - **dimensions** ?array ['x', 'y']: dimensions to use for the rotation. Cannot work with dimensions != 2.
166 | - **degrees** ?boolean false: whether the given angle is in degrees.
167 | - **centeredOnZero** ?boolean false: whether to rotate the graph around `0`, rather than the graph's center.
168 |
169 | ### collectLayout
170 |
171 | Function returning the given graph's layout as `{node: {x, y}}`.
172 |
173 | _Example_
174 |
175 | ```js
176 | import {collectLayout} from 'graphology-layout/utils';
177 |
178 | collectLayout(graph);
179 |
180 | // Custom dimensions
181 | collectLayout(graph, {dimensions: ['x', 'y', 'z']});
182 |
183 | // Non exhaustive (i.e. node having missing dimensions will be returned also)
184 | collectLayout(graph, {exhaustive: false});
185 | ```
186 |
187 | _Arguments_
188 |
189 | - **graph** _Graph_: target graph.
190 | - **options** ?object: options:
191 | - **dimensions** ?array ['x', 'y']: array of attribute names for the dimensions.
192 | - **exhaustive** ?boolean true: whether to collect positions of nodes having all the dimensions set.
193 |
194 | ### collectLayoutAsFlatArray
195 |
196 | Function returning the given graph's layout as a flat array of length `order * dimensions`.
197 |
198 | _Example_
199 |
200 | ```js
201 | import {collectLayoutAsFlatArray} from 'graphology-layout/utils';
202 |
203 | collectLayoutAsFlatArray(graph);
204 |
205 | // Custom dimensions
206 | collectLayoutAsFlatArray(graph, {dimensions: ['x', 'y', 'z']});
207 |
208 | // Custom type
209 | collectLayoutAsFlatArray(graph, {type: Float32Array});
210 | ```
211 |
212 | _Arguments_
213 |
214 | - **graph** _Graph_: target graph.
215 | - **options** ?object: options:
216 | - **dimensions** ?array ['x', 'y']: array of attribute names for the dimensions.
217 | - **type** ?constructor Float64Array: array class to use.
218 |
219 | ### assignLayout
220 |
221 | Function assigning a `{node: {x, y}}` layout to the given graph.
222 |
223 | _Example_
224 |
225 | ```js
226 | import {assignLayout} from 'graphology-layout/utils';
227 |
228 | assignLayout(graph, layout);
229 |
230 | // Custom dimensions
231 | assignLayout(graph, layout, {dimensions: ['x', 'y', 'z']});
232 | ```
233 |
234 | _Arguments_
235 |
236 | - **graph** _Graph_: target graph.
237 | - **layout** _object_: layout mapping.
238 | - **options** ?object: options:
239 | - **dimensions** ?array ['x', 'y']: array of attribute names for the dimensions.
240 |
241 | ### assignLayoutAsFlatArray
242 |
243 | Function assigning a flat array layout to the given graph.
244 |
245 | _Example_
246 |
247 | ```js
248 | import {assignLayoutAsFlatArray} from 'graphology-layout/utils';
249 |
250 | assignLayoutAsFlatArray(graph, layout);
251 |
252 | // Custom dimensions
253 | assignLayoutAsFlatArray(graph, layout, {dimensions: ['x', 'y', 'z']});
254 | ```
255 |
256 | _Arguments_
257 |
258 | - **graph** _Graph_: target graph.
259 | - **layout** _array_: layout flat array.
260 | - **options** ?object: options:
261 | - **dimensions** ?array ['x', 'y']: array of attribute names for the dimensions.
262 |
263 |
--------------------------------------------------------------------------------
/design-choices.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: Design choices
4 | nav_order: 2
5 | ---
6 |
7 | # Design choices
8 | {: .no_toc }
9 |
10 | 1. TOC
11 | {:toc}
12 |
13 | ## Keys
14 |
15 | Both nodes & edges are represented by keys in the graph. For simplicity's sake, like JavaScript's native objects, the graph will always coerce the given keys as strings.
16 |
17 | We could technically handle references as keys but finally decided against it for the following reasons:
18 |
19 | * Ensure that serialization remains as straightforward as possible.
20 | * Not to put a pressure on end-users' code by having to force the usage of, for instance, ES6 Maps to ensure their code will handle every Graph case possible.
21 |
22 | This said, the user should keep in mind that the graph have the same quirks as a JavaScript native object:
23 |
24 | * Numbers as keys will be coerced to strings.
25 | * Giving objects as keys will result in a `[object Object]` key etc.
26 |
27 | ## #.addEdge as sugar
28 |
29 | As explained in the [keys](#keys) section above, *all* edges must have a key in a `graphology` instance.
30 |
31 | Unfortunately it can be tedious to force users to provide their own key each time they want to add an edge to the graph. And even if edge keys can be very practical sometimes - especially with multigraphs - users do not even care about those in simpler use-cases since they can still reach those edges through their source & target very easily.
32 |
33 | So to make sure `graphology` remains convenient to use, we added an [`#.addEdge`](mutation#addedge) method that actually automatically creates a key for the user and returns it.
34 |
35 | As such, this method should be considered as [sugar](https://en.wikipedia.org/wiki/Syntactic_sugar) as it will not create a special kind of edge that would be different than any other one stored within a `graphology` instance.
36 |
37 | This means, for instance, that serialized edges exported from `graphology` will always have a key and that this key outlives the current instance if you want to use it in a direct copy, or across runtimes.
38 |
39 | This decision seemed the best to us, in a Social Network Analysis context where serialization and portability across many tools is to be ensured and where many paradigms coexists regarding the identification of edges in a graph, with or without a key, sometimes even both.
40 |
41 | Here are two other solutions that we considered at one point but finally dismissed:
42 |
43 | 1. Distinguishing between edges having a key and edges without one.
We did not choose this solution because, even if edges without keys can be accessed through their source & target, it makes edge indexing outside a graph (as it is often the case in outside library when aggregating metrics, for instance) very painful.
44 | 2. Using ES6 Symbol as keys for edges created without one.
We did not choose this solution for the following reasons:
45 | 1. This would mean that those keys would be instance-specific or at least runtime-specific.
46 | 2. This would usually lead to mixed-type indexing (both symbols and strings) in objects or maps outside of the graph and those are often badly optimized by most JS engines.
47 | 3. Symbols are not very well known by most JS developers and have many quirks, such as the fact they are not enumerable which can very easily confuse beginners.
48 | 3. Using number keys for edges created without one.
We did not choose this solution for the same reasons as symbols, namely mixed indexing, the quirkiness of it all and the fact that JavaScript has a tradition of coercing object keys to strings that would make them unfit for external indexing of edges.
49 |
50 | ## Mixed graphs & type precedence
51 |
52 | When using mixed graphs, one should consider that directed edges will always take precedence over the undirected ones.
53 |
54 | Use the typed methods to solve the ambiguity.
55 |
56 | ```js
57 | import Graph from 'graphology';
58 |
59 | const graph = new Graph();
60 | graph.addNode(1);
61 | graph.addNode(2);
62 | graph.addNode(3);
63 |
64 | // This will add a directed edge
65 | graph.addEdge(1, 2);
66 | // Same as:
67 | graph.addDirectedEdge(1, 2);
68 |
69 | // This will add an undirected edge
70 | graph.addUndirectedEdge(1, 2);
71 |
72 | // So, for instance, if you need to target the undirected edge
73 | graph.setUndirectedEdgeAttribute(1, 2, 'type', 'LIKES');
74 | ```
75 |
76 | ## Errors
77 |
78 | Rather than failing silently, `graphology` API will often throw errors to notify the developer that something inconsistent was performed so they can fix their code.
79 |
80 | `graphology` errors are designed to be as helpful as possible to help the developer fix the issue. For instance, the implementation will gladly tell you not to use the `#.addUndirectedEdge` method on a `directed` graph and point you towards the `#.addEdge` or `#.addDirectedEdge` method instead.
81 |
82 | ```js
83 | import {DirectedGraph} from 'graphology';
84 |
85 | const graph = new DirectedGraph();
86 | graph.addNode('Lucy');
87 | graph.addNode('Catherine');
88 | graph.addUndirectedEdge('Lucy', 'Catherine');
89 | >>> Error `DirectedGraph.addUndirectedEdge: You cannot add an undirected edge.
90 | to a directed graph Use the #.addEdge or #.addDirectedEdge method instead.`
91 | ```
92 |
93 | ## Chaining
94 |
95 | By convention, you can assume that if the documentation does not tell you what a specific method returns then it will return the instance itself for chaining purposes.
96 |
97 | One might note that, contrary to some other libraries, `graphology` returns the node or edge on the `#.addNode` & `#.addEdge` method rather than enabling chaining methods. This was made so that the "get/has" pattern remains usable and to avoid unnecessary reads of the graph when building one.
98 |
99 | ## Concerning order
100 |
101 | The user should not expect the `Graph` to retain insertion order. It might be a side effect of the used implementation to retain an order but it is not guaranteed by the specification.
102 |
103 | However, if no node/edge was added or dropped from the graph, the order should remain stable from one iteration to the next.
104 |
105 | ```js
106 | const graph = new Graph();
107 | graph.addNode('First Node');
108 | graph.addNode('Second Node');
109 |
110 | // Won't necessarily print 'First Node' then 'Second Node'
111 | // Might be the other way around.
112 | graph.forEachNode(node => {
113 | console.log(node);
114 | });
115 | ```
116 |
117 | ## Polling edges
118 |
119 | Note that two different ways are generally accessible to you when targeting edges in the graph:
120 |
121 | * Either you can provide their key.
122 | * Or you can use their source & target to find them.
123 |
124 | Note however that, since graph instances can support parallel edges, you might sometimes want to avoid using the second way since it will throw if you handle a multi-graph.
125 |
126 | ```js
127 | const graph = new Graph();
128 | graph.addNode('Eric');
129 | graph.addNode('Martha');
130 |
131 | // Adding our edge
132 | const edge = graph.addEdge('Eric', 'Martha');
133 |
134 | // Now we can see if the edge exists either by key:
135 | graph.hasEdge(edge);
136 | >>> true
137 |
138 | // or by source & target:
139 | graph.hasEdge('Eric', 'Martha');
140 | >>> true
141 | ```
142 |
143 | ## Avoiding methods affecting indexing constraints
144 |
145 | TL;DR: we won't be adding methods like `#.renameNode`, `#.renameEdge` or `#.setNodeExtremities` etc.
146 |
147 | Indeed, even though is possible to expose methods able to change a node's key, or even an edge's extremities, we decided against it for the following reasons:
148 |
149 | 1. It affects indexing constraints that may be enforced outside of the graph, using events for instance, and this needlessly complexify what you need to react to when developing external indexations of the graphs. For instance, instead of `addNode` and `dropNode` one would also be required to handle something like `renameNode`.
150 | 2. In most languages, one is not able to change dictionary keys. But you can still somehow do it by deleting the key and add its value using another one. You can also do so with a `Graph`, even if it can feel more cumbersome. But under the hood, since the internal indices will need to update this unique key constraint, an internal method would probably amount to the same operations.
151 |
152 | Finally, note that [`graphology-utils`](standard-library/utils) exposes helpers for those kind of scenarios such as the [`renameGraphKeys`](standard-library/utils#renamegraphkeys) function.
153 |
154 | ## Order of undirected edge extremities
155 |
156 | By convention, undirected edge extremities are recorded in the order they were first provided by the user.
157 |
158 | Also, it can be surprising but when iterating over undirected edges, the argument given as source may not be the node from which we are iterating from:
159 |
160 | ```js
161 | graph.forEachUndirectedEdge(node, (edge, attr, source, target) => {
162 | console.log(node === source); // Sometimes true, sometimes false
163 | });
164 | ```
165 |
166 | Indeed, we chose to guarantee that the "source" & the "target" will always be the same when accessing information about an undirected edge.
167 |
168 | This means that, even if this feels arbitrary because source & target are irrelevant for an undirected edge, the [`#.source`](read#source) method will always return the same node, and will always be referenced as this edge's source when iterating, even from a node.
169 |
170 | It could be nice sugar to reorder source & target of undirected edges in iteration but it would definitely be confusing or make no sense in some scenarios as `graphology` Graphs can be many things. For instance, let's consider the case when we want to iterate over inbound (undirected + in) or even all edges in a mixed graph.
171 |
--------------------------------------------------------------------------------
/standard-library/generators.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: generators
4 | nav_order: 7
5 | parent: Standard library
6 | aux_links:
7 | "Library directory": "https://github.com/graphology/graphology/tree/master/src/generators"
8 |
9 | ---
10 |
11 | # Graphology Generators
12 |
13 | Various graph generators to be used with [`graphology`](..).
14 |
15 | ## Installation
16 |
17 | ```
18 | npm install graphology-generators
19 | ```
20 |
21 | ## Usage
22 |
23 | - [Classic graphs](#classic-graphs)
24 | - [Complete](#complete)
25 | - [Empty](#empty)
26 | - [Ladder](#ladder)
27 | - [Path](#path)
28 | - [Community graphs](#community-graphs)
29 | - [Caveman](#caveman)
30 | - [Connected Caveman](#connected-caveman)
31 | - [Random graphs](#random-graphs)
32 | - [Clusters](#clusters)
33 | - [Erdos-Renyi](#erdos-renyi)
34 | - [Girvan-Newman](#girvan-newman)
35 | - [Small graphs](#small-graphs)
36 | - [Krackhardt Kite](#krackhardt-kite)
37 | - [Social graphs](#social-graphs)
38 | - [Florentine Families](#florentine-families)
39 | - [Karate Club](#karate-club)
40 |
41 | ### Classic graphs
42 |
43 | #### Complete
44 |
45 | Creates a [complete](https://en.wikipedia.org/wiki/Complete_graph) graph.
46 |
47 | ```js
48 | import Graph, {UndirectedGraph} from 'graphology';
49 | import {complete} from 'graphology-generators/classic';
50 | // Alternatively, if you only want to load relevant code
51 | import complete from 'graphology-generators/classic/complete';
52 |
53 | // Creating a complete graph
54 | const graph = complete(Graph, 10);
55 |
56 | // Using another constuctor to create, say, a complete undirected graph
57 | const graph = complete(UndirectedGraph, 10);
58 | ```
59 |
60 | **Arguments**
61 |
62 | - **constructor** _Class_: a `graphology` constructor.
63 | - **order** _number_: number of nodes in the generated graph.
64 |
65 | #### Empty
66 |
67 | Creates an empty graph with the desired number of nodes and no edges.
68 |
69 | ```js
70 | import Graph, {UndirectedGraph} from 'graphology';
71 | import {empty} from 'graphology-generators/classic';
72 | // Alternatively, if you only want to load relevant code
73 | import empty from 'graphology-generators/classic/empty';
74 |
75 | // Creating an empty graph
76 | const graph = empty(Graph, 10);
77 |
78 | // Using another constuctor to create, say, an empty undirected graph
79 | const graph = empty(UndirectedGraph, 10);
80 | ```
81 |
82 | **Arguments**
83 |
84 | - **constructor** _Class_: a `graphology` constructor.
85 | - **order** _number_: number of nodes in the generated graph.
86 |
87 | #### Ladder
88 |
89 | Creates a ladder graph with the desired length. Note that the generated graph will logically have twice the number of nodes.
90 |
91 | ```js
92 | import Graph, {UndirectedGraph} from 'graphology';
93 | import {ladder} from 'graphology-generators/classic';
94 | // Alternatively, if you only want to load relevant code
95 | import ladder from 'graphology-generators/classic/ladder';
96 |
97 | // Creating a ladder graph
98 | const graph = ladder(Graph, 10);
99 |
100 | // Using another constuctor to create, say, a undirected ladder graph
101 | const graph = ladder(UndirectedGraph, 10);
102 | ```
103 |
104 | **Arguments**
105 |
106 | - **constructor** _Class_: a `graphology` constructor.
107 | - **length** _number_: length of the ladder.
108 |
109 | #### Path
110 |
111 | Creates a path graph.
112 |
113 | ```js
114 | import Graph, {UndirectedGraph} from 'graphology';
115 | import {path} from 'graphology-generators/classic';
116 | // Alternatively, if you only want to load relevant code
117 | import path from 'graphology-generators/classic/path';
118 |
119 | // Creating a path graph
120 | const graph = path(Graph, 10);
121 |
122 | // Using another constuctor to create, say, a path undirected graph
123 | const graph = path(UndirectedGraph, 10);
124 | ```
125 |
126 | **Arguments**
127 |
128 | - **constructor** _Class_: a `graphology` constructor.
129 | - **order** _number_: number of nodes in the generated graph.
130 |
131 | ### Community graphs
132 |
133 | #### Caveman
134 |
135 | Creates a Caveman graph containing `l` components of `k` nodes.
136 |
137 | ```js
138 | import Graph, {UndirectedGraph} from 'graphology';
139 | import {caveman} from 'graphology-generators/community';
140 | // Alternatively, if you only want to load relevant code
141 | import caveman from 'graphology-generators/community/caveman';
142 |
143 | // Creating a caveman graph
144 | const graph = caveman(Graph, 6, 8);
145 | ```
146 |
147 | **Arguments**
148 |
149 | - **constructor** _Class_: a `graphology` constructor.
150 | - **l** _number_: number of components in the graph.
151 | - **k** _number_: number of nodes of the components.
152 |
153 | #### Connected Caveman
154 |
155 | Creates a Connected Caveman graph containing `l` components of `k` nodes.
156 |
157 | ```js
158 | import Graph, {UndirectedGraph} from 'graphology';
159 | import {connectedCaveman} from 'graphology-generators/community';
160 | // Alternatively, if you only want to load relevant code
161 | import connectedCaveman from 'graphology-generators/community/connected-caveman';
162 |
163 | // Creating a connected caveman graph
164 | const graph = connectedCaveman(Graph, 6, 8);
165 | ```
166 |
167 | **Arguments**
168 |
169 | - **constructor** _Class_: a `graphology` constructor.
170 | - **l** _number_: number of components in the graph.
171 | - **k** _number_: number of nodes of the components.
172 |
173 | ### Random graphs
174 |
175 | #### Clusters
176 |
177 | Creates a graph with the desired number of nodes & edges and having a given number of clusters.
178 |
179 | ```js
180 | import Graph from 'graphology';
181 | import {clusters} from 'graphology-generators/random';
182 | // Alternatively, if you only want to load relevant code
183 | import clusters from 'graphology-generators/random/clusters';
184 |
185 | // Creating a random clustered graph
186 | const graph = clusters(Graph, {
187 | order: 100,
188 | size: 1000,
189 | clusters: 5
190 | });
191 | ```
192 |
193 | **Arguments**
194 |
195 | - **constructor** _Class_: a `graphology` constructor.
196 | - **options** _object_: options:
197 | - **order** _number_: number of nodes of the generated graph.
198 | - **size** _number_: number of edges of the generated graph.
199 | - **clusters** _number_: number of clusters of the generated graph.
200 | - **clusterDensity** ?number 0.5: Probability that an edge will link two nodes of the same cluster.
201 | - **rng** ?function: custom RNG function.
202 |
203 | #### Erdos-Renyi
204 |
205 | Creates an [Erdos-Renyi](https://en.wikipedia.org/wiki/Erd%C5%91s%E2%80%93R%C3%A9nyi_model), or binomial graph.
206 |
207 | ```js
208 | import Graph from 'graphology';
209 | import {erdosRenyi} from 'graphology-generators/random';
210 | // Alternatively, if you only want to load relevant code
211 | import erdosRenyi from 'graphology-generators/random/erdos-renyi';
212 |
213 | // Creating a binomial graph
214 | const graph = erdosRenyi(Graph, {order: 10, probability: 0.5});
215 |
216 | // If your graph is sparse (low probability), you can use the `sparse` version
217 | // which runs in O(m + n) rather than O(n^2)
218 | const graph = erdosRenyi.sparse(Graph, {order: 1000, probability: 0.1});
219 | ```
220 |
221 | **Arguments**
222 |
223 | - **constructor** _Class_: a `graphology` constructor.
224 | - **options** _object_: options:
225 | - **order** _number_: number of nodes of the generated graph.
226 | - **probability** _number_: probability for edge creation. (i.e. density you try to approximate in the generated graph).
227 | - **approximateSize**: alternatively, you can pass an approximate number of edges you are trying to get in the generated graph.
228 | - **rng** ?function: custom RNG function.
229 |
230 | #### Girvan-Newman
231 |
232 | Creates a [Girvan-Newman](http://www.pnas.org/content/99/12/7821.full.pdf) random graph as described in:
233 |
234 | > Community Structure in social and biological networks. Girvan Newman, 2002. PNAS June, vol 99 n 12
235 |
236 | ```js
237 | import Graph from 'graphology';
238 | import {girvanNewman} from 'graphology-generators/random';
239 | // Alternatively, if you only want to load relevant code
240 | import girvanNewman from 'graphology-generators/random/girvan-newman';
241 |
242 | // Creating a binomial graph
243 | const graph = girvanNewman(Graph, {zOut: 4});
244 | ```
245 |
246 | **Arguments**
247 |
248 | - **constructor** _Class_: a `graphology` constructor.
249 | - **options** _object_: options:
250 | - **zOut** _number_: _zout_ parameter.
251 | - **rng** ?function: custom RNG function.
252 |
253 | ### Small graphs
254 |
255 | #### Krackhardt kite
256 |
257 | Returns the [Krackhardt kite](https://en.wikipedia.org/wiki/Krackhardt_kite_graph) graph.
258 |
259 | ```js
260 | import Graph from 'graphology';
261 | import {krackhardtKite} from 'graphology-generators/small';
262 | // Alternatively, if you only want to load relevant code
263 | import krackhardtKite from 'graphology-generators/small/krackhardt-kite';
264 |
265 | // Creating a random clustered graph
266 | const graph = krackhardtKite(Graph);
267 | ```
268 |
269 | **Arguments**
270 |
271 | - **constructor** _Class_: a `graphology` constructor.
272 |
273 | ### Social graphs
274 |
275 | #### Florentine Families
276 |
277 | Returns the Florentine families' graph.
278 |
279 | ```js
280 | import Graph from 'graphology';
281 | import {florentineFamilies} from 'graphology-generators/florentine-families';
282 | // Alternatively, if you only want to load relevant code
283 | import florentineFamilies from 'graphology-generators/social/florentine-families';
284 |
285 | // Generating the graph
286 | const graph = florentineFamilies(Graph);
287 | ```
288 |
289 | **Arguments**
290 |
291 | - **constructor** _Class_: a `graphology` constructor.
292 |
293 | #### Karate Club
294 |
295 | Returns [Zachary's karate club](https://en.wikipedia.org/wiki/Zachary%27s_karate_club) graph.
296 |
297 | ```js
298 | import Graph from 'graphology';
299 | import {karateClub} from 'graphology-generators/karate-club';
300 | // Alternatively, if you only want to load relevant code
301 | import karateClub from 'graphology-generators/social/karate-club';
302 |
303 | // Generating the graph
304 | const graph = karateClub(Graph);
305 | ```
306 |
307 | **Arguments**
308 |
309 | - **constructor** _Class_: a `graphology` constructor.
310 |
311 |
--------------------------------------------------------------------------------
/mutation.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: Mutation
4 | nav_order: 6
5 | menu_toc:
6 | - "#.addNode"
7 | - "#.mergeNode"
8 | - "#.updateNode"
9 | - "#.addEdge"
10 | - "#.addEdgeWithKey"
11 | - "#.mergeEdge"
12 | - "#.mergeEdgeWithKey"
13 | - "#.updateEdge"
14 | - "#.updateEdgeWithKey"
15 | - "#.dropNode"
16 | - "#.dropEdge"
17 | - "#.clear"
18 | - "#.clearEdges"
19 | ---
20 |
21 |
22 | # Mutation
23 |
24 | ## #.addNode
25 |
26 | Adds a single node to the graph with optional attributes and returns the node.
27 |
28 | Will throw if the node already exists in the graph.
29 |
30 | *Example*
31 |
32 | ```js
33 | // Adding a simple node:
34 | const node = graph.addNode('John');
35 |
36 | // Adding a node with attributes:
37 | const node = graph.addNode('John', {
38 | age: 24,
39 | eyes: 'blue'
40 | });
41 | ```
42 |
43 | *Arguments*
44 |
45 | * **node** any: the key referencing the node.
46 | * **attributes** [object]: optional attributes.
47 |
48 | ## #.mergeNode
49 |
50 | Adds a node only if the node does not exist in the graph yet. Else it will merge the provided attributes with the already existing ones.
51 |
52 | This methods return a 2-tuple containing:
53 |
54 | 1. the node's key
55 | 2. a boolean indicating whether a node was actually added.
56 |
57 | *Example*
58 |
59 | ```js
60 | // Since 'John' does not exist in the graph, a node will be added
61 | graph.mergeNode('John');
62 |
63 | // Since 'John' already exists in the graph, this will do nothing
64 | graph.mergeNode('John');
65 |
66 | // Note that if the node already exists, attributes are merged
67 | graph.mergeNode('John', {eyes: 'blue'});
68 | graph.getNodeAttributes('John');
69 | >>> {
70 | eyes: 'blue'
71 | }
72 |
73 | // The method returns a 2-tuple containing useful info
74 | const [key, nodeWasAdded] = graph.mergeNode('John');
75 | ```
76 |
77 | *Arguments*
78 |
79 | * **node** any: the node's key.
80 | * **attributes** object: the node's initial attributes or attributes to merge with the already existing ones.
81 |
82 |
83 | ## #.updateNode
84 |
85 | Adds a node only if the node does not exist in the graph yet. Else it will update the already existing node's attributes using the provided function.
86 |
87 | If the node does not yet exist, the updated function must still return the initial attributes and will be given an empty object to do so.
88 |
89 | This methods return a 2-tuple containing:
90 |
91 | 1. the node's key
92 | 2. a boolean indicating whether a node was actually added.
93 |
94 | *Example*
95 |
96 | ```js
97 | // Since 'John' does not exist in the graph, a node will be added
98 | graph.updateNode('John', attr => {
99 | return {
100 | ...attr,
101 | count: (attr.count || 0) + 1
102 | };
103 | });
104 |
105 | // Since 'John' already exist in the graph, this time its count will get incremented
106 | graph.updateNode('John', attr => {
107 | return {
108 | ...attr,
109 | count: (attr.count || 0) + 1
110 | };
111 | });
112 |
113 | graph.getNodeAttribute('John', 'count');
114 | >>> 2
115 |
116 | // The method returns a 2-tuple containing useful info
117 | const [key, nodeWasAdded] = graph.updateNode('John');
118 | ```
119 |
120 | *Arguments*
121 |
122 | * **node** any: the node's key.
123 | * **updater** [function]: a function tasked to update target node's attributes.
124 |
125 | ## #.addEdge
126 |
127 | Adds a single directed edge if the graph is `directed` or `mixed`, or an undirected edge if the graph is `undirected` and returns the automatically generated edge's key.
128 |
129 | *Example*
130 |
131 | ```js
132 | graph.addNode('John');
133 | graph.addNode('Jack');
134 |
135 | // Adding a simple edge between John & Jack:
136 | const edge = graph.addEdge('John', 'Jack');
137 |
138 | // Adding an edge with attributes between John & Jack;
139 | const edge = graph.addEdge('John', 'Jack', {
140 | type: 'KNOWS',
141 | weight: 0
142 | });
143 | ```
144 |
145 | *Arguments*
146 |
147 | * **source** any: the source node.
148 | * **target** any: the target node.
149 | * **attributes** [object]: optional attributes.
150 |
151 | *Important*
152 |
153 | This method is a convenience built on top of the [`#.addEdgeWithKey`](#addedgewithkey) method so that the user may add an edge in the graph without having to create a specific key for it.
154 |
155 | For more information, check out this [section](design-choices#addedge-as-sugar) of the design choices.
156 |
157 | *Variants*
158 |
159 | * `#.addDirectedEdge`
160 | * `#.addUndirectedEdge`
161 |
162 | ## #.addEdgeWithKey
163 |
164 | Adds a single directed edge if the graph is `directed` or `mixed`, or an undirected edge if the graph is `undirected`, using the provided key, and returns the edge's key.
165 |
166 | This is quite useful when dealing with a `MultiGraph` if you need to retrieve precise edges since polling the graph using both the source & the target node might return several edges rather than only one.
167 |
168 | *Example*
169 |
170 | ```js
171 | graph.addNode('John');
172 | graph.addNode('Jack');
173 |
174 | // Adding a simple edge between John & Jack:
175 | const edge = graph.addEdgeWithKey('John->Jack', 'John', 'Jack');
176 |
177 | // Adding an edge with attributes between John & Jack;
178 | const edge = graph.addEdgeWithKey('John->Jack', 'John', 'Jack', {
179 | type: 'KNOWS',
180 | weight: 0
181 | });
182 | ```
183 |
184 | *Arguments*
185 |
186 | * **edge** any: the key referencing the edge.
187 | * **source** any: the source node.
188 | * **target** any: the target node.
189 | * **attributes** [object]: optional attributes.
190 |
191 | *Variants*
192 |
193 | * `#.addDirectedEdgeWithKey`
194 | * `#.addUndirectedEdgeWithKey`
195 |
196 | ## #.mergeEdge
197 |
198 | Adds an edge with the given key only if the edge does not exist in the graph yet. Else it will merge the provided attributes with the already existing ones.
199 |
200 | Furthermore, this method will also add the source and/or target nodes to the graph if not found.
201 |
202 | Note that an edge is deemed to already exist in a simple graph if the graph can find one edge of same type going from the same source to the same target.
203 |
204 | In a multi graph, this method will therefore always add a new edge.
205 |
206 | This methods return a 4-tuple containing:
207 |
208 | 1. the edge's key
209 | 2. a boolean indicating whether an edge was actually added.
210 | 3. a boolean indicating whether the source node was added to the graph.
211 | 4. a boolean indicating whether the target node was added to the graph.
212 |
213 | ```js
214 | const graph = new UndirectedGraph();
215 |
216 | // Since the edge does not exist, it will be added
217 | graph.mergeEdge('John', 'Martha');
218 |
219 | // Now, since the edge already exists, this will do nothing
220 | graph.mergeEdge('John', 'Martha');
221 |
222 | // Note that if the edge already exists, attributes are merged
223 | graph.mergeEdge('John', 'Martha', {type: 'KNOWS'});
224 | graph.getEdgeAttributes('John', 'Martha');
225 | >>> {
226 | type: 'KNOWS'
227 | }
228 |
229 | // The method returns a 4-tuple containing useful info
230 | const [key, edgeWasAdded, sourceWasAdded, targetWasAdded] = graph.mergeEdge('John', 'Martha');
231 | ```
232 |
233 | *Arguments*
234 |
235 | * **source** any: the source node.
236 | * **target** any: the target node.
237 | * **attributes** [object]: optional attributes to merge.
238 |
239 | *Variants*
240 |
241 | * `#.mergeDirectedEdge`
242 | * `#.mergeUndirectedEdge`
243 |
244 | ## #.mergeEdgeWithKey
245 |
246 | Adds an edge with the given key only if the edge does not exist in the graph yet. Else it will merge the provided attributes with the already existing ones.
247 |
248 | Furthermore, this method will also add the source and/or target nodes to the graph if not found.
249 |
250 | Note that in this case, an edge is deemed to already exist in the graph if an edge with the same key, same type and same source & target is found in the graph.
251 |
252 | If one tries to add an edge with the given key and if the graph has an edge with the same key but a different source & target, the method will throw to notify of the inconsistency.
253 |
254 | This methods return a 4-tuple containing:
255 |
256 | 1. the edge's key
257 | 2. a boolean indicating whether an edge was actually added.
258 | 3. a boolean indicating whether the source node was added to the graph.
259 | 4. a boolean indicating whether the target node was added to the graph.
260 |
261 | ```js
262 | const graph = new UndirectedGraph();
263 | graph.addNode('John');
264 | graph.addNode('Martha');
265 | graph.addNode('Thomas');
266 |
267 | // Since the edge does not exist, it will be added
268 | graph.mergeEdgeWithKey('J->M', 'John', 'Martha');
269 |
270 | // Now, since the edge already exists, this will do nothing
271 | graph.mergeEdgeWithKey('J->M', 'John', 'Martha');
272 |
273 | // Note that if the edge already exists, attributes are merged
274 | graph.mergeEdgeWithKey('J->M', 'John', 'Martha', {type: 'KNOWS'});
275 | graph.getEdgeAttributes('J->M');
276 | >>> {
277 | type: 'KNOWS'
278 | }
279 |
280 | // However, the following will throw an error
281 | graph.mergeEdgeWithKey('J->M', 'Thomas', 'Martha');
282 |
283 | // The method returns a 4-tuple containing useful info
284 | const [key, edgeWasAdded, sourceWasAdded, targetWasAdded] = graph.mergeEdgeWithKey('J->M', 'John', 'Martha');
285 | ```
286 |
287 | *Arguments*
288 |
289 | * **edge** any: the edge's key.
290 | * **source** any: the source node.
291 | * **target** any: the target node.
292 | * **attributes** [object]: optional attributes to merge.
293 |
294 | *Variants*
295 |
296 | * `#.mergeDirectedEdgeWithKey`
297 | * `#.mergeUndirectedEdgeWithKey`
298 |
299 | ## #.updateEdge
300 |
301 | Adds an edge with the given key only if the edge does not exist in the graph yet. Else it will update the already existing edge's attributes using the provided function.
302 |
303 | If the edge does not yet exist, the updated function must still return the initial attributes and will be given an empty object to do so.
304 |
305 | Furthermore, this method will also add the source and/or target nodes to the graph if not found.
306 |
307 | Note that an edge is deemed to already exist in a simple graph if the graph can find one edge of same type going from the same source to the same target.
308 |
309 | In a multi graph, this method will therefore always add a new edge.
310 |
311 | This methods return a 4-tuple containing:
312 |
313 | 1. the edge's key
314 | 2. a boolean indicating whether an edge was actually added.
315 | 3. a boolean indicating whether the source node was added to the graph.
316 | 4. a boolean indicating whether the target node was added to the graph.
317 |
318 | ```js
319 | const graph = new UndirectedGraph();
320 |
321 | // Since the edge does not exist, it will be added
322 | graph.updateEdgeWithKey('John', 'Martha', attr => {
323 | return {
324 | ...attr,
325 | weight: (attr.weight || 0) + 1
326 | };
327 | });
328 |
329 | // Since the edge already exist, its weight will get incremented this time
330 | graph.updateEdge('John', 'Martha', attr => {
331 | return {
332 | ...attr,
333 | weight: (attr.weight || 0) + 1
334 | };
335 | });
336 |
337 | graph.getEdgeAttribute('John', 'Martha', 'weight');
338 | >>> 2
339 |
340 | // The method returns a 4-tuple containing useful info
341 | const [key, edgeWasAdded, sourceWasAdded, targetWasAdded] = graph.updateEdge('John', 'Martha');
342 | ```
343 |
344 | *Arguments*
345 |
346 | * **edge**
347 | * **source** any: the source node.
348 | * **target** any: the target node.
349 | * **updater** [function]: optional function tasked to update the edge's attributes.
350 |
351 | *Variants*
352 |
353 | * `#.updateDirectedEdge`
354 | * `#.updateUndirectedEdge`
355 |
356 | ## #.updateEdgeWithKey
357 |
358 | Adds an edge with the given key only if the edge does not exist in the graph yet. Else it will update the already existing edge's attributes using the provided function.
359 |
360 | If the edge does not yet exist, the updated function must still return the initial attributes and will be given an empty object to do so.
361 |
362 | Furthermore, this method will also add the source and/or target nodes to the graph if not found.
363 |
364 | Note that in this case, an edge is deemed to already exist in the graph if an edge with the same key, same type and same source & target is found in the graph.
365 |
366 | If one tries to add an edge with the given key and if the graph has an edge with the same key but a different source & target, the method will throw to notify of the inconsistency.
367 |
368 | This methods return a 4-tuple containing:
369 |
370 | 1. the edge's key
371 | 2. a boolean indicating whether an edge was actually added.
372 | 3. a boolean indicating whether the source node was added to the graph.
373 | 4. a boolean indicating whether the target node was added to the graph.
374 |
375 | ```js
376 | const graph = new UndirectedGraph();
377 |
378 | // Since the edge does not exist, it will be added
379 | graph.updateEdgeWithKey('J->M', 'John', 'Martha', attr => {
380 | return {
381 | ...attr,
382 | weight: (attr.weight || 0) + 1
383 | };
384 | });
385 |
386 | // Since the edge already exist, its weight will get incremented this time
387 | graph.updateEdgeWithKey('J->M', 'John', 'Martha', attr => {
388 | return {
389 | ...attr,
390 | weight: (attr.weight || 0) + 1
391 | };
392 | });
393 |
394 | graph.getEdgeAttribute('J->M', 'weight');
395 | >>> 2
396 |
397 | // The method returns a 4-tuple containing useful info
398 | const [key, edgeWasAdded, sourceWasAdded, targetWasAdded] = graph.updateEdgeWithKey('J->M', 'John', 'Martha');
399 | ```
400 |
401 | *Arguments*
402 |
403 | * **edge** any: the edge's key.
404 | * **source** any: the source node.
405 | * **target** any: the target node.
406 | * **updater** [function]: optional function tasked to update the edge's attributes.
407 |
408 | *Variants*
409 |
410 | * `#.updateDirectedEdgeWithKey`
411 | * `#.updateUndirectedEdgeWithKey`
412 |
413 | ## #.dropNode
414 |
415 | Drops a single node & all its attached edges from the graph.
416 |
417 | *Example*
418 |
419 | ```js
420 | graph.addNode('John');
421 | graph.dropNode('John');
422 |
423 | graph.dropNode('Martha');
424 | >>> Error "Martha not in the graph"
425 | ```
426 |
427 | *Arguments*
428 |
429 | * **node** any: the node to drop.
430 |
431 | ## #.dropEdge
432 |
433 | Drops a single edge from the graph.
434 |
435 | *Example*
436 |
437 | ```js
438 | graph.addNode('John');
439 | graph.addNode('Martha');
440 |
441 | const edge = graph.addEdge('John', 'Martha');
442 |
443 | // Dropping the edge using its key:
444 | graph.dropEdge(edge);
445 |
446 | // Dropping the first matching edge between John & Martha
447 | graph.dropEdge('John', 'Martha');
448 | ```
449 |
450 | *Arguments*
451 |
452 | 1. Using the key:
453 | * **edge** any: the edge to drop.
454 | 2. Using the source & target:
455 | * **source** any: source node of the edge to drop.
456 | * **target** any: target node of the edge to drop.
457 |
458 | *Variants*
459 |
460 | * `#.dropDirectedEdge`
461 | * `#.dropUndirectedEdge`
462 |
463 | ## #.clear
464 |
465 | Drop every node & every edge from the graph, leaving it empty.
466 |
467 | *Example*
468 |
469 | ```js
470 | graph.addNode('John');
471 | graph.addNode('Jack');
472 | graph.addEdge('John', 'Jack');
473 |
474 | console.log(graph.order, graph.size);
475 | >>> 2, 1
476 |
477 | graph.clear();
478 |
479 | console.log(graph.order, graph.size);
480 | >>> 0, 0
481 |
482 | graph.hasNode('John');
483 | >>> false
484 | ```
485 |
486 | ## #.clearEdges
487 |
488 | Drop every every edge from the graph, keeping only nodes.
489 |
490 | *Example*
491 |
492 | ```js
493 | graph.addNode('John');
494 | graph.addNode('Jack');
495 | graph.addEdge('John', 'Jack');
496 |
497 | console.log(graph.order, graph.size);
498 | >>> 2, 1
499 |
500 | graph.clearEdges();
501 |
502 | console.log(graph.order, graph.size);
503 | >>> 2, 0
504 |
505 | graph.hasEdge('John', 'Jack');
506 | >>> false
507 | ```
508 |
--------------------------------------------------------------------------------
/standard-library/metrics.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: metrics
4 | nav_order: 15
5 | parent: Standard library
6 | aux_links:
7 | "Library directory": "https://github.com/graphology/graphology/tree/master/src/metrics"
8 | "Changelog": "https://github.com/graphology/graphology/tree/master/src/metrics/CHANGELOG.md"
9 | ---
10 |
11 | # Graphology metrics
12 |
13 | Miscellaneous metrics to be used with [`graphology`](..).
14 |
15 | ## Installation
16 |
17 | ```
18 | npm install graphology-metrics
19 | ```
20 |
21 | ## Usage
22 |
23 | _Graph metrics_
24 |
25 | - [Density](#density)
26 | - [Diameter](#diameter)
27 | - [Extent](#extent)
28 | - [Modularity](#modularity)
29 | - [Simple size](#simple-size)
30 | - [Weighted size](#weighted-size)
31 |
32 | _Node metrics_
33 |
34 | - [Eccentricity](#eccentricity)
35 | - [Weighted degree](#weighted-degree)
36 |
37 | _Edge metrics_
38 |
39 | - [Disparity](#disparity)
40 | - [Simmelian strength](#simmelian-strength)
41 |
42 | _Centrality_
43 |
44 | - [Betweenness centrality](#betweenness-centrality)
45 | - [Edge betweenness centrality](#edge-betweenness-centrality)
46 | - [Closeness centrality](#closeness-centrality)
47 | - [Degree centrality](#degree-centrality)
48 | - [Eigenvector centrality](#eigenvector-centrality)
49 | - [HITS](#hits)
50 | - [Pagerank](#pagerank)
51 |
52 | _Layout quality metrics_
53 |
54 | - [Connected Closeness](#connected-closeness)
55 | - [Edge Uniformity](#edge-uniformity)
56 | - [Neighborhood Preservation](#neighborhood-preservation)
57 | - [Stress](#stress)
58 |
59 | ## Graph metrics
60 |
61 | ### Density
62 |
63 | Computes the density of the given graph. Note that multi variants can exceed `0`, as it is also the case when considering self loops.
64 |
65 | ```js
66 | import {density} from 'graphology-metrics/graph/density';
67 |
68 | // Passing a graph instance
69 | const d = density(graph);
70 |
71 | // Passing the graph's order & size
72 | const d = density(order, size);
73 |
74 | // Or to force the kind of density being computed
75 | import {
76 | mixedDensity,
77 | directedDensity,
78 | undirectedDensity,
79 | multiMixedDensity,
80 | multiDirectedDensity,
81 | multiUndirectedDensity
82 | } from 'graphology-metric/graph/density';
83 |
84 | const d = undirectedDensity(mixedGraph);
85 |
86 | // If you need to chose the kind of density dynamically
87 | import {abstractDensity} from 'graphology-metric/graph/density';
88 |
89 | abstractDensity('directed', true, 10, 24);
90 | ```
91 |
92 | _Arguments_
93 |
94 | Either:
95 |
96 | - **graph** _Graph_: target graph.
97 |
98 | Or:
99 |
100 | - **order** _number_: number of nodes in the graph.
101 | - **size** _number_: number of edges in the graph.
102 |
103 | _Abstract version arguments_
104 |
105 | Either:
106 |
107 | - **type** _string_: type of density to compute (`directed`, `undirected` or `mixed`).
108 | - **multi** _boolean_: whether to compute density for the multi of simple case.
109 | - **graph** _Graph_: target graph.
110 |
111 | Or:
112 |
113 | - **type** _string_: type of density to compute (`directed`, `undirected` or `mixed`).
114 | - **multi** _boolean_: whether to compute density for the multi of simple case.
115 | - **order** _number_: number of nodes in the graph.
116 | - **size** _number_: number of edges in the graph.
117 |
118 | ### Diameter
119 |
120 | Computes the diameter, i.e the maximum eccentricity of any node of the given graph.
121 |
122 | ```js
123 | import diameter from 'graphology-metrics/graph/diameter';
124 |
125 | const graph = new Graph();
126 | graph.addNode('1');
127 | graph.addNode('2');
128 | graph.addNode('3');
129 | graph.addUndirectedEdge(1, 2);
130 | graph.addUndirectedEdge(2, 3);
131 |
132 | diameter(graph);
133 | >>> 2
134 |
135 | ```
136 |
137 | _Arguments_
138 |
139 | - **graph** _Graph_: target graph.
140 |
141 | ### Extent
142 |
143 | Computes the extent - min, max - of a node or edge's attribute.
144 |
145 | ```js
146 | import {nodeExtent, edgeExtent} from 'graphology-metrics/graph';
147 | // Alternatively, to load only the relevant code:
148 | import {nodeExtent, edgeExtent} from 'graphology-metrics/graph/extent';
149 |
150 | // Retrieving a single node attribute's extent
151 | nodeExtent(graph, 'size');
152 | >>> [1, 34]
153 |
154 | // Retrieving multiple node attributes' extents
155 | nodeExtent(graph, ['x', 'y']);
156 | >>> {x: [-4, 3], y: [-34, 56]}
157 |
158 | // The same for edges
159 | edgeExtent(graph, 'weight');
160 | >>> [0, 5.7]
161 | ```
162 |
163 | _Arguments_
164 |
165 | - **graph** _Graph_: target graph.
166 | - **attributes** _string|array_: single attribute names or array of attribute names.
167 |
168 | ### Modularity
169 |
170 | Computes the modularity, given the graph and a node partition. It works on both directed & undirected networks and will return the relevant modularity.
171 |
172 | ```js
173 | import modularity from 'graphology-metrics/graph/modularity';
174 |
175 | // Simplest way
176 | const Q = modularity(graph);
177 |
178 | // Custom node partition
179 | const Q = modularity(graph, {
180 | getNodeCommunity(node, attr) {
181 | return attr.customPartition;
182 | }
183 | });
184 | ```
185 |
186 | _Arguments_
187 |
188 | - **graph** _Graph_: target graph.
189 | - **options** ?object: options:
190 | - **getNodeCommunity** ?string\|function community: name of the node community attribute or getter function.
191 | - **getEdgeWeight** ?string\|function weight: name of the edges' weight attribute or getter function.
192 | - **resolution** ?number: resolution parameter (`γ`).
193 |
194 | ### Simple size
195 |
196 | Computes the simple size of a given graph, i.e. its number of edges if we consider the graph simple, even if it has multiple edges between pairs of nodes.
197 |
198 | ```js
199 | import {simpleSize} from 'graphology-metrics';
200 | // Alternatively, to load only the relevant code:
201 | import simpleSize from 'graphology-metrics/graph/simple-size';
202 |
203 | const graph = new MultiGraph();
204 | graph.mergeEdge(1, 2);
205 | graph.mergeEdge(1, 2);
206 | graph.mergeEdge(4, 3);
207 | graph.mergeUndirectedEdge(5, 6);
208 |
209 | simpleSize(graph);
210 | >>> 3
211 | ```
212 |
213 | ### Weighted size
214 |
215 | Computes the weighted size, i.e. the sum of the graph's edges' weight, of the given graph.
216 |
217 | ```js
218 | import weightedSize from 'graphology-metrics/graph/weighted-size';
219 |
220 | const graph = new Graph();
221 | graph.mergeEdge(1, 2, {weight: 3});
222 | graph.mergeEdge(1, 2, {weight: 1});
223 |
224 | // Simplest way
225 | weightedSize(graph);
226 | >>> 4
227 |
228 | // With custom weight attribute
229 | weightedSize(graph, 'myWeightAttribute');
230 | >>> 4
231 |
232 | // With custom getter
233 | weightedSize(graph, (_, attr) => attr.importance);
234 | ```
235 |
236 | _Arguments_
237 |
238 | - **graph** _Graph_: target graph.
239 | - **getEdgeWeight** ?string\|function weight: name of the weight attribute or getter function.
240 |
241 | ## Node metrics
242 |
243 | ### Weighted degree
244 |
245 | Computes the weighted degree of nodes. The weighted degree of a node is the sum of its edges' weights.
246 |
247 | ```js
248 | import {
249 | weightedDegree,
250 | weightedInDegree,
251 | weightedOutDegree,
252 | weightedInboundDegree,
253 | weightedOutboundDegree,
254 | weightedUndirectedDegree,
255 | weightedDirectedDegree
256 | } from 'graphology-metrics/node/weighted-degree';
257 |
258 | // To compute weighted degree of a node
259 | weightedDegree(graph, 'A');
260 |
261 | // To use a custom weight
262 | weightedDegree(graph, 'A', function (_, attr) {
263 | return attr.importance;
264 | });
265 | ```
266 |
267 | _Arguments_
268 |
269 | - **graph** _Graph_: target graph.
270 | - **node** _any_: desired node.
271 | - **getEdgeWeight** ?string\|function: name of the edge weight attribute or getter function.
272 |
273 | ### Eccentricity
274 |
275 | Computes the eccentricity which is the maximum of the shortest paths between the given node and any other node.
276 |
277 | ```js
278 | import eccentricity from 'graphology-metrics/node/eccentricity';
279 |
280 | graph.addNode('1');
281 | graph.addNode('2');
282 | graph.addNode('3');
283 | graph.addNode('4');
284 | graph.addUndirectedEdge(1, 2);
285 | graph.addUndirectedEdge(2, 3);
286 | graph.addUndirectedEdge(3, 1);
287 | graph.addUndirectedEdge(3, 4);
288 |
289 | eccentricity(graph, 3) >> 1;
290 | ```
291 |
292 | _Arguments_
293 |
294 | - **graph** _Graph_: target graph.
295 | - **node** _any_: desired node.
296 |
297 | ## Edge metrics
298 |
299 | ### Disparity
300 |
301 | Function computing a score for each edge which is necessary to apply a "disparity filter" as described in the following paper:
302 |
303 | > Serrano, M. Ángeles, Marián Boguná, and Alessandro Vespignani. "Extracting the multiscale backbone of complex weighted networks." Proceedings of the national academy of sciences 106.16 (2009): 6483-6488.
304 |
305 | Note that this metric requires a weighted graph or will return a useless result.
306 |
307 | Beware, the results must be interpreted thusly: a lower score means a more relevant edge, as is intuited in the paper's formulae. This means you can prune edges that have a score greater than a given threshold, as a statistical test. Some other implementations might differ in that they offer the opposite intuition (i.e. greater score = more relevant edge).
308 |
309 | ```js
310 | import disparity from 'graphology-metrics/edge/disparity';
311 |
312 | // To compute strength for every edge:
313 | const disparities = disparity(graph);
314 |
315 | // To directly map the result onto edge attributes (`disparity`):
316 | disparity.assign(graph);
317 |
318 | // Using custom weights
319 | disparity.assign(graph, {getEdgeWeight: (_, attr) => attr.importance});
320 | ```
321 |
322 | _Arguments_
323 |
324 | - **graph** _Graph_: target graph.
325 | - **options** ?object: options:
326 | - **edgeDisparityAttribute** ?string disparity: Name of the disparity attribute to assign.
327 | - **getEdgeWeight** ?string\|function weight: Name of the edge weight attribute or getter function.
328 |
329 | ### Simmelian strength
330 |
331 | Function returning the simmelian strength, i.e. the number of triangles an edge is part of, of all the edges in the given graph.
332 |
333 | ```js
334 | import simmelianStrength from 'graphology-metrics/edge/simmelian-strength';
335 |
336 | // To compute strength for every edge:
337 | const strengths = simmelianStrength(graph);
338 |
339 | // To directly map the result onto edge attributes (`simmelianStrength`):
340 | simmelianStrength.assign(graph);
341 | ```
342 |
343 | ## Centrality
344 |
345 | ### Betweenness centrality
346 |
347 | Computes the betweenness centrality for every node.
348 |
349 | ```js
350 | import betweennessCentrality from 'graphology-metrics/centrality/betweenness';
351 |
352 | // To compute centrality for every node:
353 | const centralities = betweennessCentrality(graph);
354 |
355 | // To directly map the result onto nodes' attributes (`betweennessCentrality`):
356 | betweennessCentrality.assign(graph);
357 |
358 | // To directly map the result onto a custom attribute:
359 | betweennessCentrality.assign(graph, {nodeCentralityAttribute: 'myCentrality'});
360 |
361 | // To ignore weights
362 | const centralities = betweennessCentrality(graph, {getEdgeWeight: null});
363 |
364 | // To use a getter function for weights
365 | const centralities = betweennessCentrality(graph, {
366 | getEdgeWeight: (_, attr) => attr.importance
367 | });
368 | ```
369 |
370 | _Arguments_
371 |
372 | - **graph** _Graph_: target graph.
373 | - **options** ?object: options:
374 | - **nodeCentralityAttribute** ?string betweennessCentrality: Name of the centrality attribute to assign.
375 | - **getEdgeWeight** ?string\|function weight: Name of the edge weight attribute or getter function.
376 | - **normalized** ?boolean true: should the result be normalized?
377 |
378 | ### Edge betweenness centrality
379 |
380 | Computes the betweenness centrality for every edge.
381 |
382 | ```js
383 | import edgeBetweennessCentrality from 'graphology-metrics/centrality/edge-betweenness';
384 |
385 | // To compute centrality for every edge:
386 | const centralities = edgeBetweennessCentrality(graph);
387 |
388 | // To directly map the result onto edges' attributes (`edgeBetweennessCentrality`):
389 | edgeBetweennessCentrality.assign(graph);
390 |
391 | // To directly map the result onto a custom attribute:
392 | edgeBetweennessCentrality.assign(graph, {
393 | edgeCentralityAttribute: 'myCentrality'
394 | });
395 |
396 | // To ignore weights
397 | const centralities = edgeBetweennessCentrality(graph, {getEdgeWeight: null});
398 |
399 | // To use a getter function for weights
400 | const centralities = edgeBetweennessCentrality(graph, {
401 | getEdgeWeight: (_, attr) => attr.importance
402 | });
403 | ```
404 |
405 | _Arguments_
406 |
407 | - **graph** _Graph_: target graph.
408 | - **options** ?object: options:
409 | - **edgeCentralityAttribute** ?string betweennessCentrality: Name of the centrality attribute to assign.
410 | - **getEdgeWeight** ?string\|function weight: Name of the edge weight attribute or getter function.
411 | - **normalized** ?boolean true: should the result be normalized?
412 |
413 | ### Closeness centrality
414 |
415 | Computes the closeness centrality of a graph's nodes.
416 |
417 | ```js
418 | import closenessCentrality from 'graphology-metrics/centrality/closeness';
419 |
420 | // To compute the eigenvector centrality and return the score per node:
421 | const scores = closenessCentrality(graph);
422 |
423 | // To directly map the result to nodes' attributes:
424 | closenessCentrality.assign(graph);
425 |
426 | // Note that you can also pass options to customize the algorithm:
427 | const p = closenessCentrality(graph, {wassermanFaust: true});
428 | ```
429 |
430 | _Arguments_
431 |
432 | - **graph** _Graph_: target graph.
433 | - **options** ?object: options:
434 | - **nodeCentralityAttribute** ?string closenessCentrality: name of the node attribute that will be assigned the closeness centrality.
435 | - **wassermanFaust** ?boolean false: whether to use Wasserman & Faust's normalization scheme.
436 |
437 | ### Degree centrality
438 |
439 | Computes the degree centrality for every node.
440 |
441 | ```js
442 | import {
443 | degreeCentrality,
444 | inDegreeCentrality,
445 | outDegreeCentrality
446 | } from 'graphology-metrics/centrality/degree';
447 |
448 | // To compute degree centrality for every node:
449 | const centralities = degreeCentrality(graph);
450 |
451 | // To directly map the result onto nodes' attributes (`degreeCentrality`):
452 | degreeCentrality.assign(graph);
453 |
454 | // To directly map the result onto a custom attribute:
455 | degreeCentrality.assign(graph, {nodeCentralityAttribute: 'myCentrality'});
456 | ```
457 |
458 | _Arguments_
459 |
460 | - **graph** _Graph_: target graph.
461 | - **options** ?object: options:
462 | - **nodeCentralityAttribute** ?string degreeCentrality: name of the centrality attribute to assign.
463 |
464 | ### Eigenvector centrality
465 |
466 | Computes the eigenvector centrality of a graph's nodes.
467 |
468 | ```js
469 | import eigenvectorCentrality from 'graphology-metrics/centrality/eigenvector';
470 |
471 | // To compute the eigenvector centrality and return the score per node:
472 | const scores = eigenvectorCentrality(graph);
473 |
474 | // To directly map the result to nodes' attributes:
475 | eigenvectorCentrality.assign(graph);
476 |
477 | // Note that you can also pass options to customize the algorithm:
478 | const p = eigenvectorCentrality(graph, {tolerance: 1e-3});
479 |
480 | // To ignore your graph's weights
481 | eigenvectorCentrality.assign(graph, {getEdgeWeight: null});
482 | ```
483 |
484 | _Arguments_
485 |
486 | - **graph** _Graph_: target graph.
487 | - **options** ?object: options:
488 | - **nodeCentralityAttribute** ?string eigenvectorCentrality: name of the node attribute that will be assigned the eigenvector centrality.
489 | - **getEdgeWeight** ?string\|function weight: name of the edges' weight attribute or getter function.
490 | - **maxIterations** ?number 100: maximum number of iterations to perform.
491 | - **tolerance** ?number 1.e-6: convergence error tolerance.
492 |
493 | ### HITS
494 |
495 | Computes the hub/authority metrics for each node using the HITS algorithm.
496 |
497 | ```js
498 | import hits from 'graphology-metrics/centrality/hits';
499 |
500 | // To compute and return the result as 'hubs' & 'authorities':
501 | const {hubs, authorities} = hits(graph);
502 |
503 | // To directly map the result to nodes' attributes:
504 | hits.assign(graph);
505 |
506 | // Note that you can also pass options to customize the algorithm:
507 | const {hubs, authorities} = hits(graph, {normalize: false});
508 | ```
509 |
510 | _Arguments_
511 |
512 | - **graph** _Graph_: target graph.
513 | - **options** ?object: options:
514 | - **getEdgeWeight** ?string\|function weight: name of the edges' weight attribute or getter function.
515 | - **nodeHubAttribute** ?string hub: name of the node attribute holding hub information.
516 | - **nodeAuthorityAttribute** ?string authority: name of the node attribute holding authority information.
517 | - **maxIterations** ?number 100: maximum number of iterations to perform.
518 | - **normalize** ?boolean true: should the result be normalized by the sum of values.
519 | - **tolerance** ?number 1.e-8: convergence error tolerance.
520 |
521 | ### Pagerank
522 |
523 | Computes the pagerank metrics for each node.
524 |
525 | ```js
526 | import pagerank from 'graphology-metrics/centrality/pagerank';
527 |
528 | // To compute pagerank and return the score per node:
529 | const scores = pagerank(graph);
530 |
531 | // To directly map the result to nodes' attributes:
532 | pagerank.assign(graph);
533 |
534 | // Note that you can also pass options to customize the algorithm:
535 | const p = pagerank(graph, {alpha: 0.9});
536 |
537 | // To ignore your graph's weights
538 | pagerank.assign(graph, {getEdgeWeight: null});
539 | ```
540 |
541 | _Arguments_
542 |
543 | - **graph** _Graph_: target graph.
544 | - **options** ?object: options:
545 | - **nodePagerankAttribute** ?string pagerank: name of the node attribute that will be assigned the pagerank score.
546 | - **getEdgeWeight** ?string\|function weight: name of the edges' weight attribute or getter function.
547 | - **alpha** ?number 0.85: damping parameter of the algorithm.
548 | - **maxIterations** ?number 100: maximum number of iterations to perform.
549 | - **tolerance** ?number 1.e-6: convergence error tolerance.
550 |
551 | ## Layout quality metrics
552 |
553 | ### Connected Closeness
554 |
555 | TODO...
556 |
557 | ### Edge Uniformity
558 |
559 | Computes the edge uniformity layout quality metric from the given graph having `x` and `y` positions attached to its nodes. Edge uniformity is the normalized standard deviation of edge length of the graph. Lower values should be synonym of better layout according to this particular metric.
560 |
561 | Runs in `O(E)`.
562 |
563 | ```js
564 | import edgeUniformity from 'graphology-metrics/layout-quality/edge-uniformity';
565 |
566 | edgeUniformity(graph);
567 | >>> ~1.132
568 | ```
569 |
570 | ### Neighborhood preservation
571 |
572 | Computes the "neighborhood preservation" layout quality metric from the given graph having `x` and `y` positions attached to its nodes. Neighborhood preservation is the average proportion of node neighborhood being the same both in the graph's topology and its 2d layout space. The metric is therefore comprised between `0` and `1`, `1` being the best, meaning that every node keeps its neighborhood perfectly intact within the layout space.
573 |
574 | Runs in approximately `O(N * log(N))`.
575 |
576 | ```js
577 | import neighborhoodPreservation from 'graphology-metrics/layout-quality/neighborhood-preservation';
578 |
579 | neighborhoodPreservation(graph);
580 | // >>> 0.456
581 | ```
582 |
583 | ### Stress
584 |
585 | Computes the "stress" layout quality metric from the given graph having `x` and `y` positions attached to its nodes. Stress is the sum of normalized delta between node topology distances and their layout space distances. Lower values should be synonym of better layout according to this particular metric.
586 |
587 | Note that this metric does not work very well when the graph has multiple connected components.
588 |
589 | Note also that this metric traverses any given graph as an undirected one.
590 |
591 | Runs in `O(N^2)`.
592 |
593 | ```js
594 | import stress from 'graphology-metrics/layout-quality/stress';
595 |
596 | stress(graph);
597 | // >>> ~24510.2914
598 | ```
599 |
600 |
--------------------------------------------------------------------------------