Download jsnetworkx.js and include it in your page:
<script src="jsnetworkx.js"></script>
If you want to visualize graphs,
you have to include D3.js as well.
Install JSNetworkX with npm
npm install jsnetworkx
and import it in your application
var jsnx = require('jsnetworkx');
Array.from
, which allows you
to easily convert an iterable to an array.
If you are already familiar with NetworkX, then most of the following information will already be familiar to you. Most (if not all) method and function names are the same as in NetworkX.
Once you included JSNetworkX you can start working with graphs. If you are
working in a browser environment, including jsnetworkx.js will create a global
variable jsnx
, which is an object. All functions/methods/modules
are properties of this object. In Node.js use the name of variable you assigned
the module to.
There are basically three ways to create a new graph:
Graph
constructor or one of its subclasses (DiGraph
, MultiGraph
or MultiDiGraph
).G.subgraph
or convert an undirected graph to a directed one (G.toDirected
).completeGraph().
Here are some examples:
// This creates a new empty, undirected graph var G = new jsnx.Graph(); // Generates a complete graph with six nodes var G = jsnx.completeGraph(6); // Generates a random graph with six nodes and // an edge between each node is created with a probability of 0.3 var G = jsnx.binomialGraph(6, 0.3);
jsnx.binomial_graph(...)
) instead of camelCase.
JSNetworkX provides support for four types of graphs:
undirected graphs ( Graph
),
directed graphs (DiGraph
),
multi edge undirected graphs
(MultiGraph
) and multi edge directed graphs ( MultiDiGraph
).
Each type provides specific methods to access and extract information about the
structure of the graph.
Once you obtained a graph, you can modify it, by adding or removing nodes and edges, or access node and edge information.
Single nodes can be added with G.addNode
and a collection
of nodes with G.addNodesFrom
. Typically the collection will
be an array, but it could be another graph as well, or any node collection
returned by another library function.
Lets have a look at an example and let us print the nodes:
var G = new jsnx.Graph(); G.addNode(1); G.addNodesFrom([3, 5, 7, 11]); console.log(G.nodes()); // shows [1, 3, 5, 7, 11] -- v0.2.0 // shows ["1", "3", "5", "7", "11"] -- v0.1.1 and below
G.nodes
returns an array nodes, which shows us that the graph
now has four nodes, namely 1, 3, 5 and 7.
Removing nodes is as simple as adding them. You can use either G.removeNode
or G.removeNodesFrom
.
G.removeNode(11); // same as G.removeNode("5"); console.log(G.nodes()); // shows [1, 3, 5, 7] -- v0.2.0 // shows ["1", "3", "5", "7"] -- v0.1.1 and below
Adding and removing edges works pretty much the same way, with the methods
G.addEdge
which accepts two nodes as arguments, and
G.addEdgesFrom
which accepts a list of 2-tuples (arrays).
G.addEdge(1,3); G.addEdge(3,1); // does not do anything in undirected graphs G.addEdgesFrom([[1,5], [1,7], [7,3], [7,9]]); // node 9 does not exist! console.log(G.nodes()); // shows [1, 3, 5, 7, 9] -- v0.2.0 // shows ["1", "3", "5", "7", "9"] -- v0.1.1 and below console.log(G.edges()); // shows [[1, 3], [1, 5], [1, 7], [7, 3], [7, 9]] -- v0.2.0 // shows [["1", "3"], ["1", "5"], ["1", "7"], ["7", "3"], ["7", "9"]] -- v0.1.1 and below
Edges are removed with G.removeEdge
and G.removeEdgesFrom
.
G.removeEdge(5,1); // or G.removeEdge(1,5); G.removeEdgesFrom([[9,7], [7,1]]); // Removing a node removes its connected edges as well G.removeNode(3); console.log(G.nodes()); // shows [1, 5, 7, 9] -- v0.2.0 // shows ["1", "5", "7", "9"] -- v0.1.1 and below console.log(G.edges()); // shows []
A great feature of NetworkX is the possibility to assign arbitrary attributes to nodes and edges and of course JSNetworkX allows you to do this too.
G.addNode
accepts an object as second argument. Its properties will be the node's
attributes. Similarly, G.addNodesFrom
accepts a list of
2-tuples, where the first element is the node, and the second
element is a data object. It also accepts an object as second argument.
Attributes passed through this object will be added to all nodes.
var G = new jsnx.Graph(); // Adds a new node, 10, with the attribute {someData: 42} G.addNode(10, {someData: 42}); // Adds the nodes, "foo" and "bar", with individual attributes and // attributes for both nodes G.addNodesFrom([['foo', {size: 5}], ['bar', {size: 10}]], {color: 'blue'}); // Passing `true` to `G.nodes` changes the return value to include the attributes for each node console.log(G.nodes(true)); // shows // [ // [10,{"someData":42}], // ["foo",{"color":"blue","size":5}], // ["bar",{"color":"blue","size":10}] // ]
It works the same for edges: G.addEdge
accepts an object as third
argument and G.addEdgesFrom
a list of 3-tuples, where the first two
elements are nodes and the third one is an attributes object.
You have two ways to set attributes on existing nodes and edges:
Either just add the node (edge) again, the passed data will be merged,
or access the nodes (edges) via the graphs G.node
(G.adj
)
properties.
var G = new jsnx.Graph(); G.addNodesFrom([0,1]); G.addEdge(0,1); G.node.get(0).foo = 'bar'; // G.node[0].foo = 'bar'; // v0.1.1 and below G.adj.get(0).get(1).color = 'blue'; // G.adj[0][1].color = 'blue'; // v0.1.1 and below console.log(G.nodes(true)); // shows [[0,{"foo":"bar"}],[1,{}]] console.log(G.edges(true)); // shows [[0,1,{"color":"blue"}]]
G.nodes
or G.adj
properties, since this can lead to inconsistency within the graph.
That is really up to your use case. For example, if you are modeling a social network, the node data can contain more detailed information about a person. If you are modeling a street network, the edge data could contain timeseries data about congestion.
Node and edge data can be very useful if you want to customize the style of nodes and edges in a visualization. This will be explained later, but here is already a short example of how this can look like:
var G = new jsnx.Graph(); G.addNodesFrom([ [1, {color: 'red'}], [2, {color: 'green'}], [3, {color: 'white'}] ]); G.addEdgesFrom([[1,2], [1,3]]); // `jsnx.draw` accept a graph and configuration object jsnx.draw(G, { element: '#demo-canvas', withLabels: true, nodeStyle: { fill: function(d) { return d.data.color; } } });
NetworkX provides a variety of algorithms to analyze graphs, such as detecting cliques, computing shortest paths or the centrality of a graph. JSNetworkX aims to provide those algorithms as well. You can see the progress and which algorithms are available on the API progress page. To learn about the algorithms which are generally available, have a look at the NetworkX documentation.
Most functions implementing those algorithms are available on the
jsnx
object (just like with NetworkX). Here is a small example,
which computes the shortest path between two nodes, draws the graph and colors
the found nodes differently.
// This is a graph generator var G = jsnx.cycleGraph(6); // Compute the shortest path between 0 and 4 var path = jsnx.bidirectionalShortestPath(G, 0, 4); // A simple way to color all nodes in the path: G.addNodesFrom(path, {color: '#FFF'}); // Color the start and end differently G.node.get(0).color = '#0F0'; // start is green G.node.get(4).color = '#F00'; // end is red jsnx.draw(G, { element: '#demo-canvas', withLabels: true, nodeStyle: { fill: function(d) { return d.data.color || '#AAA'; // any node without color is gray } } });
You already have seen some examples of how to draw graphs. Here is a more detailed introduction.
JSNetworkX uses D3.js to draw graphs as SVG. D3 is a very powerful library to bind data to DOM elements and provides many useful methods for data visualization. You are encouraged to learn more about it to get the most out of drawing graphs. JSNetworkX takes care of setting up the connections between the graph, the layout and the SVG elements, and lets you apply custom styles to nodes and edges.
jsnx.draw
is the method with which you can draw a graph and
it accepts the following arguments:
jsnx.draw(G, options [, update]);
G
can be either a directed or undirected graph. Multi edge graphs are not supported.options
is an object which controls the look and behavior of the visualization.update
is a boolean value and controls whether modifications to the graph should be reflects in the visualization.A complete list of options with explanation can be found in the wiki. In the following we will describe the most important options and concepts you need to know about.
The only required option is element
, so that the library
knows where to draw the graph. It can either be a CSS selector or a DOM element.
Internally, the method uses d3.select
to select the element.
jsnx.draw
will add a new <svg>
container to
the element, which by default has the same width and height as its parent. You
can explicitly set the dimensions by specifying the width
and
height
options.
The most interesting options are probably nodeStyle
,
nodeAttr
, edgeStyle
and edgeAttr
, which
with you can specify the look of nodes and edges. Since the graph is drawn
with SVG elements, the *Style
options should hold values for
CSS properties and the *Attr
options values for element attributes.
If you are not very familiar with SVG, have a look at the MDN SVG documentation.
The options are explained in greater detail in the next section.
As mentioned earlier, D3's main feature is the binding of data to DOM elements.
This is also the foundation for the graph visualization: Each SVG element
representing a node or edge has an object bound to it, with various information.
By using a function as one of the style or attribute values, you will have access to that information,
because internally, the library just passes the values along to
D3's .style
and
.attr
methods.
The data object bound to an element for a node has the following properties:
node
, the node valuedata
, the node data from the graph (see Node and edge data)G
, a reference to the graph object
The data object for an edge has similar properties:
edge
, a 2-tuple (array) containing the nodes this edge connectsdata
, the edge data from the graph (see Node and edge data)G
, a reference to the graph object
To better illustrate this concept, here is a small example: Each node in
the graph has a property count
. We will later use this
property to draw the nodes in different sizes. The nodes are drawn as
<circle>
SVG elements and the radius is controlled by the
elements r
attribute. Hence we have to use the
nodeAttr
option.
var G = new jsnx.Graph(); G.addNode(1, {count: 12}); G.addNode(2, {count: 8}); G.addNode(3, {count: 15}); G.addEdgesFrom([[1,2],[2,3]]); jsnx.draw(G, { element: '#demo-canvas', withLabels: true, nodeAttr: { r: function(d) { // `d` has the properties `node`, `data` and `G` return d.data.count; } } });
JSNetworkX currently only supports a force based layout but we will add other layouts in the future.
SVG has its pros and cons. It is easier to add interaction but there is an upper limit of how elements can be drawn, which depends a lot on the user's computer and browser.
We aim to support different drawing techniques, like canvas and WebGL and with the expectation that this will allow us to draw larger graphs reasonably well.