Example #1
0
class Graph(object):
    def __init__(self, data=None, **attr):
        # the init could be
        # graph = Graph(g) where g is a Graph
        # graph = Graph((v,e)) where v is Graph.v like and e is Graph.e like
        # graph = Graph(({},e)) for an edgelist with no specified nodes
        # others with classmethods like
        # Graph.from_adjacency_matrix(m)
        # Graph.from_adjacency_list(l)
        #
        # should abstract the data here
        self._nodedata = {}  # empty node attribute dict
        self._adjacency = {}  # empty adjacency dict
        # the interface is n,e,a,data
        self.n = Nodes(self._nodedata, self._adjacency) # rename to self.nodes
        self.e = Edges(self._nodedata, self._adjacency) # rename to self.edges
        self.a = Adjacency(self._adjacency) # rename to self.adjacency
        self.data = {}   # dictionary for graph attributes
        # load with data
        if hasattr(data,'n') and not hasattr(data,'name'): # it is a new graph
            self.n.update(data.n)
            self.e.update(data.e)
            self.data.update(data.data)
            data = None
        try:
            nodes,edges = data # containers of edges and nodes
            self.n.update(nodes)
            self.e.update(edges)
        except: # old style
            if data is not None:
                convert.to_networkx_graph(data, create_using=self)
        # load __init__ graph attribute keywords
        self.data.update(attr)


    def s(self, nbunch):
        H = Subgraph(self, nbunch)
        return H

    # crazy use of call - get subgraph?
    def __call__(self, nbunch):
        return self.s(nbunch)

    # rewrite these in terms of new interface
    def __iter__(self):
        return iter(self.n)

    def __len__(self):
        return len(self.n)

    def clear(self):
        self.name = ''
        self.n.clear()
        self.e.clear()
        self.data.clear()

    def copy(self, with_data=True):
        if with_data:
            return deepcopy(self)
        G = self.__class__()
        G.n.update(self.n)
        G.e.update(self.e)
        return G

    def is_multigraph(self):
        """Return True if graph is a multigraph, False otherwise."""
        return False

    def is_directed(self):
        """Return True if graph is directed, False otherwise."""
        return False

    def order(self):
        return len(self.n)

    def size(self, weight=None):
        s = sum(d for v, d in self.n.degree(weight=weight))
        # If `weight` is None, the sum of the degrees is guaranteed to be
        # even, so we can perform integer division and hence return an
        # integer. Otherwise, the sum of the weighted degrees is not
        # guaranteed to be an integer, so we perform "real" division.
        return s // 2 if weight is None else s / 2

    @classmethod
    def from_adjacency_matrix(self, matrix):
        import numpy as np
        kind_to_python_type={'f':float,
                             'i':int,
                             'u':int,
                             'b':bool,
                             'c':complex,
                             'S':str,
                             'V':'void'}
        try: # Python 3.x
            blurb = chr(1245) # just to trigger the exception
            kind_to_python_type['U']=str
        except ValueError: # Python 2.6+
            kind_to_python_type['U']=unicode
        n,m=matrix.shape
        if n!=m:
            raise nx.NetworkXError("Adjacency matrix is not square.",
                               "nx,ny=%s"%(matrix.shape,))
        dt=matrix.dtype
        try:
            python_type=kind_to_python_type[dt.kind]
        except:
            raise TypeError("Unknown numpy data type: %s"%dt)

        # Make sure we get even the isolated nodes of the graph.
        nodes = range(n)
        # Get a list of all the entries in the matrix with nonzero entries. These
        # coordinates will become the edges in the graph.
        edges = zip(*(np.asarray(matrix).nonzero()))
        # handle numpy constructed data type
        if python_type is 'void':
        # Sort the fields by their offset, then by dtype, then by name.
            fields = sorted((offset, dtype, name) for name, (dtype, offset) in
                            matrix.dtype.fields.items())
            triples = ((u, v, {name: kind_to_python_type[dtype.kind](val)
                               for (_, dtype, name), val in zip(fields, matrix[u, v])})
                       for u, v in edges)
        else:  # basic data type
            triples = ((u, v, dict(weight=python_type(matrix[u, v])))
                       for u, v in edges)
        graph = self((nodes, triples))
        return graph

    @classmethod
    def from_adjacency_list(self, adjlist):
        nodes = range(len(adjlist))
        edges = [(node,n) for node,nbrlist in enumerate(adjlist) for n in nbrlist]
        return self((nodes,edges))
Example #2
0
class Graph(object):
    def __init__(self, data=None, **attr):
        # the init could be
        # graph = Graph(g) where g is a Graph
        # graph = Graph((v,e)) where v is Graph.v like and e is Graph.e like
        # graph = Graph(({},e)) for an edgelist with no specified nodes
        # others with classmethods like
        # Graph.from_adjacency_matrix(m)
        # Graph.from_adjacency_list(l)
        #
        # should abstract the data here
        self._nodedata = {}  # empty node attribute dict
        self._adjacency = {}  # empty adjacency dict
        # the interface is n,e,a,data
        self.n = Nodes(self._nodedata, self._adjacency)  # rename to self.nodes
        self.e = Edges(self._nodedata, self._adjacency)  # rename to self.edges
        self.a = Adjacency(self._adjacency)  # rename to self.adjacency
        self.data = {}  # dictionary for graph attributes
        # load with data
        if hasattr(data, "n") and not hasattr(data, "name"):  # it is a new graph
            self.n.update(data.n)
            self.e.update(data.e)
            self.data.update(data.data)
            data = None
        try:
            nodes, edges = data  # containers of edges and nodes
            self.n.update(nodes)
            self.e.update(edges)
        except:  # old style
            if data is not None:
                convert.to_networkx_graph(data, create_using=self)
        # load __init__ graph attribute keywords
        self.data.update(attr)

    def s(self, nbunch):
        H = Subgraph(self, nbunch)
        return H

    # crazy use of call - get subgraph?
    def __call__(self, nbunch):
        return self.s(nbunch)

    # rewrite these in terms of new interface
    def __iter__(self):
        return iter(self.n)

    def __len__(self):
        return len(self.n)

    def clear(self):
        self.name = ""
        self.n.clear()
        self.e.clear()
        self.data.clear()

    def copy(self, with_data=True):
        if with_data:
            return deepcopy(self)
        G = self.__class__()
        G.n.update(self.n)
        G.e.update(self.e)
        return G

    def is_multigraph(self):
        """Return True if graph is a multigraph, False otherwise."""
        return False

    def is_directed(self):
        """Return True if graph is directed, False otherwise."""
        return False

    def order(self):
        return len(self.n)

    def size(self, weight=None):
        s = sum(d for v, d in self.n.degree(weight=weight))
        # If `weight` is None, the sum of the degrees is guaranteed to be
        # even, so we can perform integer division and hence return an
        # integer. Otherwise, the sum of the weighted degrees is not
        # guaranteed to be an integer, so we perform "real" division.
        return s // 2 if weight is None else s / 2

    @classmethod
    def from_adjacency_matrix(self, matrix):
        import numpy as np

        kind_to_python_type = {"f": float, "i": int, "u": int, "b": bool, "c": complex, "S": str, "V": "void"}
        try:  # Python 3.x
            blurb = chr(1245)  # just to trigger the exception
            kind_to_python_type["U"] = str
        except ValueError:  # Python 2.6+
            kind_to_python_type["U"] = unicode
        n, m = matrix.shape
        if n != m:
            raise nx.NetworkXError("Adjacency matrix is not square.", "nx,ny=%s" % (matrix.shape,))
        dt = matrix.dtype
        try:
            python_type = kind_to_python_type[dt.kind]
        except:
            raise TypeError("Unknown numpy data type: %s" % dt)

        # Make sure we get even the isolated nodes of the graph.
        nodes = range(n)
        # Get a list of all the entries in the matrix with nonzero entries. These
        # coordinates will become the edges in the graph.
        edges = zip(*(np.asarray(matrix).nonzero()))
        # handle numpy constructed data type
        if python_type is "void":
            # Sort the fields by their offset, then by dtype, then by name.
            fields = sorted((offset, dtype, name) for name, (dtype, offset) in matrix.dtype.fields.items())
            triples = (
                (
                    u,
                    v,
                    {name: kind_to_python_type[dtype.kind](val) for (_, dtype, name), val in zip(fields, matrix[u, v])},
                )
                for u, v in edges
            )
        else:  # basic data type
            triples = ((u, v, dict(weight=python_type(matrix[u, v]))) for u, v in edges)
        graph = self((nodes, triples))
        return graph

    @classmethod
    def from_adjacency_list(self, adjlist):
        nodes = range(len(adjlist))
        edges = [(node, n) for node, nbrlist in enumerate(adjlist) for n in nbrlist]
        return self((nodes, edges))