UNPKG

jsnetworkx

Version:

A graph processing and visualization library for JavaScript (port of NetworkX for Python).

619 lines (547 loc) 17.5 kB
'use strict'; 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