def get_edges(): ''' <Graph>.edges AND <Graph>.edges() return the SAME EdgeView of the edges in the graph - An EdgeView is a strange data structure - It require a tuple index to access - What's really going on? Just look at the library code. It's simple really - At each tuple index, it stores a Python dict - This syntax makes more sense than the v1.11 syntax - Edges are stored as 2-tuples (which are immutable) - ''' g = Graph([(1, 5), [5, 5]]) print(type(g.edges)) # <class 'networkx.classes.reportviews.EdgeView'> print(type(g.edges())) # <class 'networkx.classes.reportviews.EdgeView'> print(g.edges()) # [(1, 5), (5, 5)] # Invalid syntax #print(g.edges[1]) # TypeError: 'int' object is not iterable # Missing keys #print(g.edges[0, 1]) # KeyError: 1 #print(g.edges[1, 2]) # KeyError: 2 # Correct syntax print(type(g.edges[1, 5])) # <class 'dict'> print(g.edges[1, 5]) # {} # I can view the 2-tuples but can't modify them for e in g.edges(): pass
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]
def get_edges(): '''<Graph>.edges() returns a Python list of tuples, where each 2-tuple represents an edge between two nodes''' g = Graph([(1, 5), (5, 5)]) #print(type(g.edges())) # <class 'list'> #print(g.edges()) # [(1, 5), (5, 5)] # Iterate over 2-tuples for e in g.edges(): print(e) # (1, 5)\n(5, 5)
def add_edges(): '''Including an arbitrary attribute with newly added edges will add that attribute to all of the new edges''' g = Graph([(1, 5), (5, 5)]) g.add_edges_from([[4, 6], (7, 8)], win='yes') print(g.nodes()) # [1, 5, 4, 6, 7, 8] print(g.edges()) # [(1, 5), (5, 5), (4, 6), (7, 8)] print( g.edge ) # {1: {5: {}}, 5: {1: {}, 5: {}}, 4: {6: {'win': 'yes'}}, 6: {4: {'win': 'yes'}}, 7: {8: {'win': 'yes'}}, 8: {7: {'win': 'yes'}}}
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)]
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]) # {}
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]) # {}
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]) # {}
def construct(G: Graph, weight="weight"): e_weight = {} adj, radj = {}, {} edges = G.edges() for e in edges: e_weight[e] = edges[e][weight] if e[0] not in adj: adj[e[0]] = [] adj[e[0]].append(e[1]) if e[1] not in radj: radj[e[1]] = [] radj[e[1]].append(e[0]) return e_weight, [adj, radj]
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'}
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)]