Source code for networkx_temporal.utils.convert.snap

from typing import Optional, Union

import networkx as nx

from ...classes.types import is_static_graph, is_temporal_graph
from ...typing import StaticGraph, TemporalGraph


[docs] def to_snap( G: Union[StaticGraph, TemporalGraph, list], node_id: Optional[str] = "id", node_attrs: Optional[Union[bool, list]] = True, edge_attrs: Optional[Union[bool, list]] = True, ): """ Convert from NetworkX to `SNAP <https://snap.stanford.edu/>`__. :param object G: Graph object. Accepts a :class:`~networkx_temporal.classes.TemporalGraph`, a single static NetworkX graph, or a list of static NetworkX graphs as input. :param node_id: Attribute key to use as node identifier. Optional. Default is ``'id'``. :param node_attrs: Boolean or list of node attributes to include in the conversion. Optional. Default is ``True``. :param edge_attrs: Boolean or list of edge attributes to include in the conversion. Optional. Default is ``True``. :rtype: snap.TGraph """ import snap if not (is_temporal_graph(G) or is_static_graph(G)): raise TypeError("Input must be a temporal or static NetworkX graph.") if is_temporal_graph(G) or type(G) == list: return [to_snap(H, node_id=node_id, node_attrs=node_attrs, edge_attrs=edge_attrs) for H in G] if type(node_id) != str: raise TypeError( f"Node identifier must be a string, received: {type(node_id)}." ) if node_attrs is not None and type(node_attrs) not in (bool, list): raise TypeError( f"Node attributes expects a boolean or list, received: {type(node_attrs)}." ) if edge_attrs is not None and type(edge_attrs) not in (bool, list): raise TypeError( f"Edge attributes expects a boolean or list, received: {type(edge_attrs)}." ) if not (type(node_attrs) != list or node_id not in node_attrs): raise ValueError( f"Node identifier ('{node_id}') cannot be included as a node attribute." ) directed = G.is_directed() multigraph = G.is_multigraph() # Create new graph object. if node_id or node_attrs or edge_attrs or multigraph: H = snap.TNEANet.New() elif directed: H = snap.TNGraph.New() else: H = snap.TUNGraph.New() # Obtain node mapping and add nodes to graph. nodes = {str(n): i for i, n in enumerate(G.nodes(data=False))} list(map(lambda n: H.AddNode(nodes[n]), G.nodes(data=False))) # Add edges to graph (and reversed edges if necessary). for i, e in enumerate(G.edges(data=False)): H.AddEdge(nodes[e[0]], nodes[e[1]], i) if not directed and (multigraph or node_attrs or edge_attrs): for i, e in enumerate(G.edges(data=False)): H.AddEdge(nodes[e[1]], nodes[e[0]], i + G.size()) # Add node indices. if node_id: H.AddStrAttrN(node_id) for n in nodes: H.AddStrAttrDatN(nodes[n], n, node_id) # Add node attributes. if node_attrs: added_node_attrs = set() for n in G.nodes(data=node_attrs): for k, v in n[-1].items(): # Add node attribute to the graph. if k not in added_node_attrs: if isinstance(v, int): H.AddIntAttrN(k) elif isinstance(v, float): H.AddFltAttrN(k) else: H.AddStrAttrN(k) added_node_attrs.add(k) # Add attribute value to the node. if isinstance(v, int): H.AddIntAttrDatN(nodes[n], v, k) elif isinstance(v, float): H.AddFltAttrDatN(nodes[n], v, k) else: H.AddStrAttrDatN(nodes[n], v, k) # Add edge attributes. if edge_attrs: added_edge_attrs = set() for i, e in enumerate(G.edges(data=edge_attrs)): for k, v in e[-1].items(): # Add edge attribute to the graph. if k not in added_edge_attrs: if isinstance(v, int): H.AddIntAttrE(k) elif isinstance(v, float): H.AddFltAttrE(k) else: H.AddStrAttrE(k) added_edge_attrs.add(k) # Add attribute value to the edge. if isinstance(v, int): H.AddIntAttrDatE(i, v, k) elif isinstance(v, float): H.AddFltAttrDatE(i, v, k) else: H.AddStrAttrDatE(i, v, k) # Add reversed edge attributes. if not directed and (multigraph or node_attrs or edge_attrs): for i, e in enumerate(G.edges(data=edge_attrs)): if isinstance(v, int): H.AddIntAttrDatE(i + G.size(), v, k) elif isinstance(v, float): H.AddFltAttrDatE(i + G.size(), v, k) else: H.AddStrAttrDatE(i + G.size(), v, k) return H