jsnetworkx
Version:
A graph processing and visualization library for JavaScript (port of NetworkX for Python).
619 lines (547 loc) • 17.5 kB
JavaScript
var _slicedToArray = require('babel-runtime/helpers/sliced-to-array')['default'];
var _Object$create = require('babel-runtime/core-js/object/create')['default'];
var _Array$from = require('babel-runtime/core-js/array/from')['default'];
var _getIterator = require('babel-runtime/core-js/get-iterator')['default'];
var _regeneratorRuntime = require('babel-runtime/regenerator')['default'];
var _interopRequireWildcard = require('babel-runtime/helpers/interop-require-wildcard')['default'];
var _interopRequireDefault = require('babel-runtime/helpers/interop-require-default')['default'];
Object.defineProperty(exports, '__esModule', {
value: true
});
exports.toNetworkxGraph = toNetworkxGraph;
exports.convertToUndirected = convertToUndirected;
exports.convertToDirected = convertToDirected;
exports.toDictOfLists = toDictOfLists;
exports.fromDictOfLists = fromDictOfLists;
exports.toDictOfDicts = toDictOfDicts;
exports.fromDictOfDicts = fromDictOfDicts;
exports.toEdgelist = toEdgelist;
exports.fromEdgelist = fromEdgelist;
/**
* This module provides functions to convert
* NetworkX graphs to and from other formats.
*
* The preferred way of converting data to a NetworkX graph
* is through the graph constuctor. The constructor calls
* the to_networkx_graph() function which attempts to guess the
* input type and convert it automatically.
*/
var _contribConvert = require('./contrib/convert');
var convertMap = _interopRequireWildcard(_contribConvert);
var _contribPrepCreateUsing = require('./contrib/prepCreateUsing');
var _contribPrepCreateUsing2 = _interopRequireDefault(_contribPrepCreateUsing);
var _lodashObjectMapValues = require('lodash/object/mapValues');
var _lodashObjectMapValues2 = _interopRequireDefault(_lodashObjectMapValues);
var _internals = require('./_internals');
var hasOwn = Object.prototype.hasOwnProperty;
/**
* Make a JSNetworkX graph from a known data structure.
*
* The preferred way to call this is automatically from the class constructor
*
* ```
* var data = {0: {1 : {weight: 1}}} // object of objects single edge (0,1)
* var G = new jsnx.Graph(d);
* ```
*
* instead of the equivalent
*
* ```
* var G = jsnx.fromDictOfDicts(d);
* ```
*
* @param {?} data An object to be converted
* Current accepts types are:
*
* - any JSNetworkX graph
* - object of objects
* - object of lists
* - list of edges
*
* @param {Graph=} optCreateUsing NetworkX graph
* Use specified graph for result. Otherwise a new graph is created.
* @param {boolean=} optMultigraphInput
* If `true` and `data` is an object of objects,
* try to create a multigraph assuming object of objects of lists
* If data and createUsing are both multigraphs then create
* a multigraph from a multigraph.
* @return {Graph}
*/
function toNetworkxGraph(data, optCreateUsing) {
var optMultigraphInput = arguments.length <= 2 || arguments[2] === undefined ? false : arguments[2];
var result = null;
// jsnx graph
if (hasOwn.call(data, 'adj')) {
try {
result = convertMap.fromMapOfMaps(data.adj, optCreateUsing, data.isMultigraph());
if (hasOwn.call(data, 'graph') && typeof data.graph === 'object') {
result.graph = (0, _internals.clone)(data.graph);
}
if (hasOwn.call(data, 'node') && (0, _internals.isMap)(data.node)) {
result.node = new _internals.Map();
data.node.forEach(function (element, k) {
return result.node.set(k, (0, _internals.clone)(element));
});
}
return result;
} catch (ex) {
throw ex;
}
}
// map of maps / lists
if ((0, _internals.isMap)(data)) {
try {
return convertMap.fromMapOfMaps(data, optCreateUsing, optMultigraphInput);
} catch (e) {
try {
return convertMap.fromMapOfLists(data, optCreateUsing);
} catch (ex) {
throw new Error('Map data structure cannot be converted to a graph.');
}
}
}
// dict of dicts / lists
if ((0, _internals.isPlainObject)(data)) {
try {
return fromDictOfDicts(data, optCreateUsing, optMultigraphInput);
} catch (e) {
try {
return fromDictOfLists(data, optCreateUsing);
} catch (ex) {
throw new Error('Object data structure cannot be converted to a graph.');
}
}
}
// list of edges
if ((0, _internals.isArrayLike)(data)) {
try {
return fromEdgelist(data, optCreateUsing);
} catch (e) {
throw new Error('Input is not a valid edge list');
}
}
return result;
}
/**
* Return a new undirected representation of the graph G.
*
* @param {Graph} G Graph to convert
* @return {!Graph}
*/
function convertToUndirected(G) {
return G.toUndirected();
}
/**
* Return a new directed representation of the graph G.
*
* @param {Graph} G Graph to convert
* @return {!Graph}
*/
function convertToDirected(G) {
return G.toDirected();
}
/**
* Return adjacency representation of graph as a dictionary of lists.
*
* Completely ignores edge data for MultiGraph and MultiDiGraph.
*
* @param {Graph} G A JSNetworkX graph
* @param {Iterable=} optNodelist Use only nodes specified in nodelist
*
* @return {!Object.<Array>}
*/
function toDictOfLists(G, optNodelist) {
var contains = function contains(n) {
return optNodelist.indexOf(n) > -1;
};
var d = _Object$create(null);
if (optNodelist == null) {
optNodelist = G;
contains = function (n) {
return optNodelist.hasNode(n);
};
} else {
optNodelist = _Array$from(optNodelist);
}
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;
try {
for (var _iterator = _getIterator(optNodelist), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
var n = _step.value;
d[n] = G.neighbors(n).filter(contains);
}
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
try {
if (!_iteratorNormalCompletion && _iterator['return']) {
_iterator['return']();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
}
return d;
}
/**
* Return a graph from a dictionary of lists.
*
* ### Examples
*
* ```
* var data = {0: [1]}; // single edge (0,1)
* var G = jsnx.fromDictOfLists(data);
* // or
* var G = new jsnx.Graph(data);
* ```
*
* @param {!Object.<Array>} d A dictionary of lists adjacency representation.
* @param {Graph=} optCreateUsing Use specified graph for result.
* Otherwise a new graph is created.
* @return {!Graph}
*/
function fromDictOfLists(d, optCreateUsing) {
var G = (0, _contribPrepCreateUsing2['default'])(optCreateUsing);
// Convert numeric property names to numbers
G.addNodesFrom(_regeneratorRuntime.mark(function callee$1$0() {
var n;
return _regeneratorRuntime.wrap(function callee$1$0$(context$2$0) {
while (1) switch (context$2$0.prev = context$2$0.next) {
case 0:
context$2$0.t0 = _regeneratorRuntime.keys(d);
case 1:
if ((context$2$0.t1 = context$2$0.t0()).done) {
context$2$0.next = 7;
break;
}
n = context$2$0.t1.value;
context$2$0.next = 5;
return isNaN(n) ? n : +n;
case 5:
context$2$0.next = 1;
break;
case 7:
case 'end':
return context$2$0.stop();
}
}, callee$1$0, this);
})());
var node;
var nbrlist;
if (G.isMultigraph() && !G.isDirected()) {
// a dict_of_lists can't show multiedges. BUT for undirected graphs,
// each edge shows up twice in the dict_of_lists.
// So we need to treat this case separately.
var seen = new _internals.Set();
for (node in d) {
nbrlist = d[node];
// treat numeric keys like numbers
node = isNaN(node) ? node : +node;
/*eslint no-loop-func:0*/
(0, _internals.forEach)(nbrlist, function (nbr) {
if (!seen.has(nbr)) {
G.addEdge(node, nbr);
}
});
seen.add(node); // don't allow reverse edge to show up
}
} else {
var edgeList = [];
for (node in d) {
nbrlist = d[node];
// treat numeric keys like numbers
node = isNaN(node) ? node : +node;
(0, _internals.forEach)(nbrlist, function (nbr) {
edgeList.push([node, nbr]);
});
}
G.addEdgesFrom(edgeList);
}
return G;
}
/**
* Return adjacency representation of graph as a dictionary of dictionaries.
*
* @param {Graph} G A jsnx Graph
* @param {Iterable=} optNodelist Use only nodes specified in nodelist
* @param {Object=} optEdgeData If provided, the value of the dictionary will
* be set to edgeData for all edges. This is useful to make
* an adjacency matrix type representation with 1 as the edge data.
* If edgedata is null or undefined, the edgedata in G is used to fill
* the values.
* If G is a multigraph, the edgedata is a dict for each pair (u,v).
* @return {!Object.<Object>}
*/
function toDictOfDicts(G, optNodelist, optEdgeData) {
var dod = {};
if (optNodelist != null) {
optNodelist = _Array$from(optNodelist);
if (optEdgeData != null) {
optNodelist.forEach(function (u) {
dod[u] = {};
G.get(u).forEach(function (data, v) {
if (optNodelist.indexOf(v) > -1) {
dod[u][v] = optEdgeData;
}
});
});
} else {
// nodelist and edgeData are defined
optNodelist.forEach(function (u) {
dod[u] = {};
G.get(u).forEach(function (data, v) {
if (optNodelist.indexOf(v) > -1) {
dod[u][v] = data;
}
});
});
}
} else {
// nodelist is undefined
if (optEdgeData != null) {
// dn = [nbrdict, u]
var _iteratorNormalCompletion2 = true;
var _didIteratorError2 = false;
var _iteratorError2 = undefined;
try {
for (var _iterator2 = _getIterator(G.adjacencyIter()), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
var _step2$value = _slicedToArray(_step2.value, 2);
var nbrdict = _step2$value[0];
var u = _step2$value[1];
/*jshint loopfunc:true*/
dod[u] = (0, _lodashObjectMapValues2['default'])(nbrdict, function () {
return optEdgeData;
});
}
} catch (err) {
_didIteratorError2 = true;
_iteratorError2 = err;
} finally {
try {
if (!_iteratorNormalCompletion2 && _iterator2['return']) {
_iterator2['return']();
}
} finally {
if (_didIteratorError2) {
throw _iteratorError2;
}
}
}
} else {
// edge_data is defined
// dn = [nbrdict, u]
var _iteratorNormalCompletion3 = true;
var _didIteratorError3 = false;
var _iteratorError3 = undefined;
try {
for (var _iterator3 = _getIterator(G.adjacencyIter()), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
var _step3$value = _slicedToArray(_step3.value, 2);
var nbrdict = _step3$value[0];
var u = _step3$value[1];
dod[u] = (0, _internals.clone)(nbrdict);
}
} catch (err) {
_didIteratorError3 = true;
_iteratorError3 = err;
} finally {
try {
if (!_iteratorNormalCompletion3 && _iterator3['return']) {
_iterator3['return']();
}
} finally {
if (_didIteratorError3) {
throw _iteratorError3;
}
}
}
}
}
return dod;
}
/**
* Return a graph from a dictionary of dictionaries.
*
*
* ### Examples
*
* ```
* var data = {0: {1: {weight: 1}}}; // single edge (0,1)
* var G = jsnx.fromDictOfDicts(data);
* // or
* var G = new jsnx.Graph(data);
* ```
*
* @param {!Object.<!Object>} d A dictionary of dictionaries adjacency
* representation.
* @param {Graph=} optCreateUsing Use specified graph for result.
* Otherwise a new graph is created.
* @param {boolean=} optMultigraphInput
* When `true`, the values of the inner object are assumed
* to be containers of edge data for multiple edges.
* Otherwise this routine assumes the edge data are singletons.
*
* @return {Graph}
*/
function fromDictOfDicts(d, optCreateUsing) {
var optMultigraphInput = arguments.length <= 2 || arguments[2] === undefined ? false : arguments[2];
var G = (0, _contribPrepCreateUsing2['default'])(optCreateUsing);
var seen = new _internals.Set();
// Convert numeric property names to numbers
G.addNodesFrom(_regeneratorRuntime.mark(function callee$1$0() {
var n;
return _regeneratorRuntime.wrap(function callee$1$0$(context$2$0) {
while (1) switch (context$2$0.prev = context$2$0.next) {
case 0:
context$2$0.t0 = _regeneratorRuntime.keys(d);
case 1:
if ((context$2$0.t1 = context$2$0.t0()).done) {
context$2$0.next = 7;
break;
}
n = context$2$0.t1.value;
context$2$0.next = 5;
return isNaN(n) ? n : +n;
case 5:
context$2$0.next = 1;
break;
case 7:
case 'end':
return context$2$0.stop();
}
}, callee$1$0, this);
})());
// is dict a MultiGraph or MultiDiGraph?
if (optMultigraphInput) {
// make a copy of the list of edge data (but not the edge data)
if (G.isDirected()) {
for (var u in d) {
var nbrs = d[u];
if ((0, _internals.isArrayLike)(nbrs)) {
// throw exception of not dict (object)
throw new TypeError('Inner object seems to be an array');
}
// treat numeric keys like numbers
u = isNaN(u) ? u : +u;
for (var v in nbrs) {
var datadict = nbrs[v];
// treat numeric keys like numbers
v = isNaN(v) ? v : +v;
for (var key in datadict) {
if (G.isMultigraph()) {
G.addEdge(u, v, key, datadict[key]);
} else {
G.addEdge(u, v, datadict[key]);
}
}
}
}
} else {
// undirected
// don't add both directions of undirected graph
for (var u in d) {
var nbrs = d[u];
if ((0, _internals.isArrayLike)(nbrs)) {
// throw exception of not dict (object)
throw new TypeError('Inner object seems to be an array');
}
// treat numeric keys like numbers
u = isNaN(u) ? u : +u;
for (var v in nbrs) {
var datadict = nbrs[v];
// treat numeric keys like numbers
v = isNaN(v) ? v : +v;
if (!seen.has([u, v])) {
for (var key in datadict) {
if (G.isMultigraph()) {
G.addEdge(u, v, key, datadict[key]);
} else {
G.addEdge(u, v, datadict[key]);
}
}
seen.add([v, u]);
}
}
}
}
} else {
// not a multigraph to multigraph transfer
if (G.isMultigraph() && !G.isDirected()) {
// d can have both representations u-v, v-u in dict. Only add one.
// We don't need this check for digraphs since we add both directions,
// or for Graph() since it is done implicitly (parallel edges not allowed)
for (var u in d) {
var nbrs = d[u];
if ((0, _internals.isArrayLike)(nbrs)) {
// throw exception of not dict (object)
throw new TypeError('Inner object seems to be an array');
}
// treat numeric keys like numbers
u = isNaN(u) ? u : +u;
for (var v in nbrs) {
var data = nbrs[v];
v = isNaN(v) ? v : +v;
if (!seen.has([u, v])) {
G.addEdge(u, v, data);
seen.add([v, u]);
}
}
}
} else {
for (var u in d) {
var nbrs = d[u];
if ((0, _internals.isArrayLike)(nbrs)) {
// throw exception of not dict (object)
throw new TypeError('Inner object seems to be an array');
}
// treat numeric keys like numbers
u = isNaN(u) ? u : +u;
for (var v in nbrs) {
var data = nbrs[v];
// treat numeric keys like numbers
v = isNaN(v) ? v : +v;
G.addEdge(u, v, data);
}
}
}
}
return G;
}
/**
* Return a list of edges in the graph.
*
* @param {Graph} G A JSNetworkX graph
* @param {Iterable=} optNodelist Use only nodes specified in nodelist
* @return {!Array}
*/
function toEdgelist(G, optNodelist) {
if (optNodelist != null) {
return G.edges(optNodelist, true);
} else {
return G.edges(null, true);
}
}
/**
* Return a graph from a list of edges.
*
* @param {Array.<Array>} edgelist Edge tuples
* @param {Graph=} optCreateUsing Use specified graph for result.
* Otherwise a new graph is created.
* @return {!Graph}
*/
function fromEdgelist(edgelist, optCreateUsing) {
var G = (0, _contribPrepCreateUsing2['default'])(optCreateUsing);
G.addEdgesFrom(edgelist);
return G;
}
// NOT IMPLEMENTED
// to_numpy_matrix
// from_numpy_matrix
// to_numpy_recarray
// to_scipy_sparse_matrix
// from_scipy_sparse_matrix
// setup_module
;