Exemplo n.º 1
0
def examine_node_attributes():
    '''
    A node can contain arbitrary attributes
    - The <Graph>.node attribute is a regular Python dict whose key-value pairs are node identifiers and Python dicts
        - The documentation says that nodes cannot be added to the graph through <Graph>.node, but the code shows they can!
            - However, doing this can mess up the structure of the graph. The newly added node might not have its own Python dict if the update was
              done incorrectly
            - "Warning: adding a node to G.node does not add it to the graph." Listen to the documentation and never try to add nodes via <Graph>.node
    '''
    g = Graph([(1, 5), (5, 5)])
    print(g.nodes())  # [1, 5]
    print(g.edges())  # [(1, 5), (5, 5)]
    print(type(g.node))  # <class 'dict'>
    # Get the dict of an arbitrary node, but not the node itself (annoying)
    print(type(g.node[5]))  # <class 'dict'>
    print(g.node[5])  # {}
    g.node[5]['pet'] = 'cat'
    print(g.node[5])  # {'pet': 'cat'}
    ## NEVER DO THIS
    # This is how to mess up the graph
    g.node[6] = 'psych'
    # The node exists, but are there underlying problems I'm not aware of?
    print(g.nodes())  # [1, 5, 6]
    # Here's the first problem. This should be a dict, but it's a str
    print(type(g.node[6]))  # <class 'str'>
    # This error occurs because of the abuse of the API
    #g.add_node(6) # AttributeError: 'str' object has no attribute 'update'
    # This is how to "correctly" add a node via <Graph>.node, but never do this
    g.node[6] = {'psych': 'psych'}
    g.add_node(6)
    print(g.nodes())  # [1, 5, 6]
Exemplo n.º 2
0
def add_node():
    '''
    - Adding a duplicate node does not add another node to the graph
        - Nodes must be unique. I cannot add two different nodes with the same value
            - Use the ability to add arbitrary attributes to nodes in order to make multiple nodes have the same "value"
                - From a technical standpoint, there is no reason why I can't have two nodes that are identified by the number 5. However, from a
                    traveral perspective, it makes sense to require that nodes be unique. If I had two nodes whose primary identifier was 5, how would
                    the code know which node I was interested in when I looked up 5? 
                    - What's annoying about this is that since nodes must be unique, then there's no reason why I can't look them up by key!
                        - This restriction must be due to performance?
                            - But this can't be! There IS already a dictionary that contains a reference to every node! It's <Graph>.node! So it's
                              just poor design
    - Adding a duplicate node can update the aribtrary node attribute dict (see below)
    - A node can be added along with attributes
    '''
    g = Graph([(1, 5), (5, 5)])
    g.node[5]['foo'] = 'bar'
    # A duplicate node cannot remove existing arbitrary node attributes
    #g.add_node(5, {})
    #print(g.node[5]) # {'foo': 'bar'}
    # A duplicate node can overwrite existing arbitrary node attributes
    #g.add_node(5, foo='bleh')
    #print(g.node[5]) # {'foo': 'bleh'}
    # A duplicate node can add new arbitrary node attributes
    #g.add_node(5, bless='you')
    #print(g.node[5]) # {'foo': 'bar', 'bless': 'you'}
    print(g.nodes())  # [1, 5]
    g.add_node(6, size='big', sound='quack')
    print(g.node[6])  # {'size': 'big', 'sound': 'quack'}
Exemplo n.º 3
0
 def add_node(self, n):
     if n in self:
         return # already in tree
     elif len(self.adj)==0:
         Graph.add_node(self,n) # first node
     else:  # not allowed
         raise NetworkXError(\
             "adding single node %s not allowed in non-empty tree"%(n))
Exemplo n.º 4
0
def add_node_():
    g = Graph()
    attributes = {'foo': 'bar'}
    # Wrong in v2.4
    #g.add_node('9', attr_dict=attributes)
    # Right in v2.4
    g.add_node('9', **attributes)
    print(g.nodes(data=True)) # [('9', {'foo': 'bar'})]
Exemplo n.º 5
0
 def add_node(self, n):
     if n in self:
         return  # already in tree
     elif len(self.adj) == 0:
         Graph.add_node(self, n)  # first node
     else:  # not allowed
         raise NetworkXError(\
             "adding single node %s not allowed in non-empty tree"%(n))
Exemplo n.º 6
0
def create_graph_from_graph():
    '''Passing another graph object appears to have the same net result as <Graph>.copy()'''
    g = Graph([(1, 5), (5, 5)])
    g.add_node(6)
    h = Graph(g)
    print(h.nodes())  # [1, 5, 6]
    print(h.edges())  # [(1, 5), (5, 5)]
    g.node[1]['color'] = 'black'
    print(g.node[1])  # {'color': 'black'}
    print(h.node[1])  # {}
Exemplo n.º 7
0
def examine_node_attributes():
    '''
    The v2.4 API is slightly different because it uses <Graph>.nodes (or <Graph>.nodes()) while <Graph>.node doesn't exist
    - Even though the NodeView is new, the underlying Python dicts that store attributes are the same as v1.11
    '''
    g = Graph([(1, 5), (5, 5)])
    g.add_node(5)
    print(g.nodes())  # [1, 5]
    print(g.edges())  # [(1, 5), (5, 5)]
    #print(g.node[5]) # AttributeError: 'Graph' object has no attribute 'node'
    print(g.nodes[5])  # {}
    g.nodes[5]['foo'] = 'bar'
    print(g.nodes[5])  # {'foo': 'bar'}
Exemplo n.º 8
0
def get_nodes():
    '''
    <Graph>.nodes() returns a new list that contains the unique identifiers that represent nodes in the graph
    - Modifying this list does nothing to the original graph
    - I can only access nodes by index, not key
    '''
    g = Graph([(1, 5), (5, 5)])
    g.add_node(5)
    print(type(g.nodes()))  # <class 'list'>
    print(g.nodes())  # [1, 5]
    print(g.nodes()[0])  # 1
    g.nodes().append(6)
    print(g.nodes())  # [1, 5]
Exemplo n.º 9
0
def create_graph_from_edgeview():
    '''
    Fortunately, creating a graph from the EdgeView of another graph does not perform a shallow copy of the original graph
    - The new graph gets entirely new edges
        - Arbitrary attributes of the old edges are not copied
    - This approach will miss copying nodes who had no edges
    '''
    g = Graph([(1, 'foo'), (1, 3)])
    g.add_node(4)
    h = Graph(g.edges)
    g.edges[1, 'foo']['key'] = 'value'
    print(h.nodes)  # [1, 'foo', 3]
    print(h.edges)  # [(1, 'foo'), (1, 3)]
    print(h.edges[1, 'foo'])  # {}
    print(g.edges[1, 'foo'])  # {'key': 'value'}
Exemplo n.º 10
0
def create_graph_with_new_data():
    '''
    - Parallel edges are not allowed
    - The data can be:
        - An edge list
        - Any NetworkX graph object
    - The data cannot be a flat list of nodes!
        - It can't be a list of nodes because a bunch of unconnected nodes don't compose a very interesting graph
            - Nodes can be any hashable object. Recall that immutable objects are implicitly hashable: int, string, tuple, etc.
    '''
    # Create with edge list. Since this is an undirected graph, there is only one edge between 1 and 3
    g = Graph([(1, 'foo'), (1, 3), (3, 1)])
    g.add_node(6)
    # Create with another graph
    print(g.nodes())  # [1, 'foo', 3, 6]
    print(g.edges())  # [(1, 'foo'), (1, 3)]
def make_nonmultigraph(multigraph):
    """
        Removes duplicate edges. Instead of having multiple edges going from the same source to the same target,
        this function adds one edge with a weight attribute,
        Parameters:
            multigraph: The multi-graph with multi-edges
        Return:
            G: A new graph which is equivalent to the multi-graph.
    """
    G = Graph()
    for node in multigraph.nodes_iter():
        G.add_node(node)
    for edge in multigraph.edges_iter():
        for existing_edge in G.edges_iter():
            if existing_edge[0] == edge[0] and existing_edge[1] == edge[1]: #If the edge is already in the existing edge list...
                G.edge[edge[0]][edge[1]]['weight'] += 1 # the existing edge's weight is incremented
        G.add_edge(edge[0], edge[1], weight=1)
    return G
Exemplo n.º 12
0
def get_nodes_and_data():
    '''
    The <Graph>.nodes() method accepts an optional kwarg "data" that, regardless of value, is interpreted as a truthy or falsy value
    - If truthy, a list of 2-tuples is returned. Each 2-tuple consists of (<key>, <attr dict>)
    - If falsy, a list of keys is returned
    In v1.11 that's all that happens. It's very simple
    '''
    g = Graph()
    g.add_nodes_from(['a', 'b'], data='quack')
    g.add_node('c', data=False)
    g.add_node('d')
    print(g.nodes())  # ['a', 'b', 'c', 'd']
    print(g.nodes(data=False))  # ['a', 'b', 'c', 'd']
    print(
        g.nodes(data=True)
    )  # [('a', {'data': 'quack'}), ('b', {'data': 'quack'}), ('c', {'data': False}), ('d', {})]
    print(
        g.nodes(data='no')
    )  # [('a', {'data': 'quack'}), ('b', {'data': 'quack'}), ('c', {'data': False}), ('d', {})]
Exemplo n.º 13
0
def create_graph_from_edges():
    '''
    - Don't use this strategy alone to copy a graph
    - None of the arbitrary attributes from nodes, edges, or the graph are copied
    - When a new graph is created from the edges of an existing graph, the nodes that form each edge are also created
        - Thus, creating a copy from edges is almost a true copy
            - It is NOT a true copy because any nodes without edges are not copied!
    '''
    g = Graph([(1, 5), (5, 5)])
    g.add_node(6)
    g.edge[1][5]['foo'] = 'bar'
    print(g.edge[1][5])  # {'foo': 'bar'}
    print(g.nodes())  # [1, 5, 6]
    h = Graph()
    # Yes, this is the required syntax to do this
    h.add_edges_from(g.edges())
    print(h.edge[1][5])  # {}
    print(h.nodes())  # [1, 5]
    print(h.edges())  # [(1, 5), (5, 5)]
Exemplo n.º 14
0
def create_true_graph_copy():
    '''
    - <Graph>.copy() returns a true copy of the original graph
        - == operator for graph objects is useless, or perhaps __eq__ isn't implemented so it falls back to "is" behavior
    - This is NOT what I want if I don't want to copy attributes
    '''
    g = Graph([(1, 5), (5, 5)])
    g.add_node(6)
    g.graph['pie'] = 'apple'
    g.node[1]['pet'] = 'fish'
    g.edge[5][5]['sound'] = 'clink'
    h = g.copy()
    print(h.nodes())  # [1, 5, 6]
    print(h.edges())  # [(1, 5), (5, 5)]
    print(h.graph)  # {'pie': 'apple'}
    print(h.node)  # {1: {'pet': 'fish'}, 5: {}, 6: {}}
    print(h.edge)  # {1: {5: {}}, 5: {1: {}, 5: {'sound': 'clink'}}, 6: {}}
    print(h is g)  # False
    print(h == g)  # False
Exemplo n.º 15
0
def create_graph_from_nodes():
    '''
    The net result is the same as in v1.11: the new graph gets all new nodes that are copies of the original nodes
    - No edges are copied
    - No arbitrary attributes are copied
    '''
    g = Graph([(1, 5), (5, 5)])
    g.graph['baz'] = 'boo'
    g.add_node(6)
    print(g.nodes())  # [1, 5, 6]
    print(g.edges())  # [(1, 5), (5, 5)]
    g.nodes[5]['foo'] = 'bar'
    print(g.nodes[5])  # {'foo': 'bar'}
    h = Graph()
    h.add_nodes_from(g)
    print(h.graph)  # {}
    print(h.nodes())  # [1, 5, 6]
    print(h.edges())  # {}
    print(h.nodes[5])  # {}
Exemplo n.º 16
0
def create_graph_from_nodes():
    '''
    - Don't use this strategy alone to copy a graph
    - None of the arbitrary attributes from nodes, edges, or the graph are copied
    - If the nodes of a graph object are used to create a new graph object:
        - No edges are created in the new graph.
    '''
    g = Graph([(1, 5), (5, 5)])
    g.graph['baz'] = 'boo'
    g.add_node(6)
    print(g.nodes())  # [1, 5, 6]
    print(g.edges())  # [(1, 5), (5, 5)]
    g.node[5]['foo'] = 'bar'
    print(g.node[5])  # {'foo': 'bar'}
    h = Graph()
    h.add_nodes_from(g)
    print(h.graph)  # {}
    print(h.nodes())  # [1, 5, 6]
    print(h.edges())  # {}
    print(h.node[5])  # {}
Exemplo n.º 17
0
def make_nonmultigraph(multigraph):
    """
        Removes duplicate edges. Instead of having multiple edges going from the same source to the same target,
        this function adds one edge with a weight attribute,
        Parameters:
            multigraph: The multi-graph with multi-edges
        Return:
            G: A new graph which is equivalent to the multi-graph.
    """
    G = Graph()
    for node in multigraph.nodes_iter():
        G.add_node(node)
    for edge in multigraph.edges_iter():
        for existing_edge in G.edges_iter():
            if existing_edge[0] == edge[0] and existing_edge[1] == edge[
                    1]:  #If the edge is already in the existing edge list...
                G.edge[edge[0]][edge[1]][
                    'weight'] += 1  # the existing edge's weight is incremented
        G.add_edge(edge[0], edge[1], weight=1)
    return G
Exemplo n.º 18
0
def get_nodes_and_data():
    '''
    <Graph>.nodes() is completely different in v2.4
    - The "data" kwarg can do three things:
        - If data==True, return all node keys and all their data
        - If data==False, return just a list of node keys
        - If data==<attribute key>, return all node keys with the attribute key, along with the value of the attribute
    - In combination with "data", the "default" kwarg will substitute <value> for every node that doesn't have the searched-for attribute key
    '''
    g = Graph()
    g.add_nodes_from(['a', 'b'], data='quack', size='tiny')
    g.add_node('c', data=False)
    g.add_node('d')
    print(g.nodes()) # ['a', 'b', 'c', 'd']
    # Get no node attribute values
    print(g.nodes(data=False)) # ['a', 'b', 'c', 'd']
    # Get all node attribute key-value pairs
    print(g.nodes(data=True)) # [('a', {'data': 'quack', 'size': 'tiny'}), ('b', {'data': 'quack', 'size': 'tiny'}), ('c', {'data': False}), ('d', {})]
    # Get all node keys and attribute values for the given attribute key
    print(g.nodes(data='size')) # [('a', 'tiny'), ('b', 'tiny'), ('c', None), ('d', None)]
    # Substitute a value for nodes that don't have the key
    print(g.nodes(data='size', default='purple')) # [('a', 'tiny'), ('b', 'tiny'), ('c', 'purple'), ('d', 'purple')]
Exemplo n.º 19
0
    def _check_cycle(mode_declarations):
        g = Graph().to_directed()

        for decl in mode_declarations:
            input_args = decl.input_arguments()
            output_args = decl.output_arguments()

            for o in output_args:
                g.add_node(o.name)

            for i in input_args:
                g.add_node(i.name)

                for o in output_args:
                    g.add_edge(i.name, o.name)

        try:
            res = find_cycle(g)
        except NetworkXNoCycle:
            return

        raise CheckFailed('Cycle found: %s' % str(res))
Exemplo n.º 20
0
class RouterBase(Routable):
    def __init__(self):
        super().__init__()
        self._table = {self.url: self.url}
        self._graph = Graph()

    def addItem(self, dst_url):
        pass

    def removeNeighbor(self, downs):
        for url in downs:
            if url in self._table:
                del self._table[url]

    def getNextHop(self, dst_url):
        downs = []
        for url in self.neighbors:
            try:
                s = self.getProxy(url)
                s.testProxy(0)
            except OSError:
                downs.append(url)
        if downs:
            self.removeNeighbor(downs)
        if dst_url not in self._table:
            self.addItem(dst_url)
        try:
            return self._table[dst_url]
        except KeyError:
            return ""

    @property
    def neighbors(self):
        if self.url not in self._graph:
            self._graph.add_node(self.url)
        return self._graph[self.url]
Exemplo n.º 21
0
 def add_node(self, n):
     Graph.add_node(self, n)
     # this is not called from add_edge so we must assign
     # and component (else that is assigned in add_edge)
     self.comp[n] = self.nc
     self.nc += 1
Exemplo n.º 22
0
 def add_node(self, n):
     Graph.add_node(self,n)
     # this is not called from add_edge so we must assign
     # and component (else that is assigned in add_edge)
     self.comp[n]=self.nc
     self.nc+=1