#

Note

This documents the development version of NetworkX. Documentation for the current release can be found here.

#

MultiGraph—Undirected graphs with self loops and parallel edges

Overview

class MultiGraph(incoming_graph_data=None, **attr)[source]

An undirected graph class that can store multiedges.

Multiedges are multiple edges between two nodes. Each edge can hold optional data or attributes.

A MultiGraph holds undirected edges. Self loops are allowed.

Nodes can be arbitrary (hashable) Python objects with optional key/value attributes. By convention None is not used as a node.

Edges are represented as links between nodes with optional key/value attributes.

Parameters
  • incoming_graph_data (input graph (optional, default: None)) – Data to initialize graph. If None (default) an empty graph is created. The data can be any format that is supported by the to_networkx_graph() function, currently including edge list, dict of dicts, dict of lists, NetworkX graph, NumPy matrix or 2d ndarray, SciPy sparse matrix, or PyGraphviz graph.

  • attr (keyword arguments, optional (default= no attributes)) – Attributes to add to graph as key=value pairs.

Examples

Create an empty graph structure (a “null graph”) with no nodes and no edges.

>>> G = nx.MultiGraph()

G can be grown in several ways.

Nodes:

Add one node at a time:

>>> G.add_node(1)

Add the nodes from any container (a list, dict, set or even the lines from a file or the nodes from another graph).

>>> G.add_nodes_from([2, 3])
>>> G.add_nodes_from(range(100, 110))
>>> H = nx.path_graph(10)
>>> G.add_nodes_from(H)

In addition to strings and integers any hashable Python object (except None) can represent a node, e.g. a customized node object, or even another Graph.

>>> G.add_node(H)

Edges:

G can also be grown by adding edges.

Add one edge,

>>> key = G.add_edge(1, 2)

a list of edges,

>>> keys = G.add_edges_from([(1, 2), (1, 3)])

or a collection of edges,

>>> keys = G.add_edges_from(H.edges)

If some edges connect nodes not yet in the graph, the nodes are added automatically. If an edge already exists, an additional edge is created and stored using a key to identify the edge. By default the key is the lowest unused integer.

>>> keys = G.add_edges_from([(4, 5, {"route": 28}), (4, 5, {"route": 37})])
>>> G[4]
AdjacencyView({3: {0: {}}, 5: {0: {}, 1: {'route': 28}, 2: {'route': 37}}})

Attributes:

Each graph, node, and edge can hold key/value attribute pairs in an associated attribute dictionary (the keys must be hashable). By default these are empty, but can be added or changed using add_edge, add_node or direct manipulation of the attribute dictionaries named graph, node and edge respectively.

>>> G = nx.MultiGraph(day="Friday")
>>> G.graph
{'day': 'Friday'}

Add node attributes using add_node(), add_nodes_from() or G.nodes

>>> G.add_node(1, time="5pm")
>>> G.add_nodes_from([3], time="2pm")
>>> G.nodes[1]
{'time': '5pm'}
>>> G.nodes[1]["room"] = 714
>>> del G.nodes[1]["room"]  # remove attribute
>>> list(G.nodes(data=True))
[(1, {'time': '5pm'}), (3, {'time': '2pm'})]

Add edge attributes using add_edge(), add_edges_from(), subscript notation, or G.edges.

>>> key = G.add_edge(1, 2, weight=4.7)
>>> keys = G.add_edges_from([(3, 4), (4, 5)], color="red")
>>> keys = G.add_edges_from([(1, 2, {"color": "blue"}), (2, 3, {"weight": 8})])
>>> G[1][2][0]["weight"] = 4.7
>>> G.edges[1, 2, 0]["weight"] = 4

Warning: we protect the graph data structure by making G.edges[1, 2] a read-only dict-like structure. However, you can assign to attributes in e.g. G.edges[1, 2]. Thus, use 2 sets of brackets to add/change data attributes: G.edges[1, 2]['weight'] = 4 (For multigraphs: MG.edges[u, v, key][name] = value).

Shortcuts:

Many common graph features allow python syntax to speed reporting.

>>> 1 in G  # check if node in graph
True
>>> [n for n in G if n < 3]  # iterate through nodes
[1, 2]
>>> len(G)  # number of nodes in graph
5
>>> G[1]  # adjacency dict-like view keyed by neighbor to edge attributes
AdjacencyView({2: {0: {'weight': 4}, 1: {'color': 'blue'}}})

Often the best way to traverse all edges of a graph is via the neighbors. The neighbors are reported as an adjacency-dict G.adj or G.adjacency().

>>> for n, nbrsdict in G.adjacency():
...     for nbr, keydict in nbrsdict.items():
...         for key, eattr in keydict.items():
...             if "weight" in eattr:
...                 # Do something useful with the edges
...                 pass

But the edges() method is often more convenient:

>>> for u, v, keys, weight in G.edges(data="weight", keys=True):
...     if weight is not None:
...         # Do something useful with the edges
...         pass

Reporting:

Simple graph information is obtained using methods and object-attributes. Reporting usually provides views instead of containers to reduce memory usage. The views update as the graph is updated similarly to dict-views. The objects nodes, `edges and adj provide access to data attributes via lookup (e.g. nodes[n], `edges[u, v], adj[u][v]) and iteration (e.g. nodes.items(), nodes.data('color'), nodes.data('color', default='blue') and similarly for edges) Views exist for nodes, edges, neighbors()/adj and degree.

For details on these and other miscellaneous methods, see below.

Subclasses (Advanced):

The MultiGraph class uses a dict-of-dict-of-dict-of-dict data structure. The outer dict (node_dict) holds adjacency information keyed by node. The next dict (adjlist_dict) represents the adjacency information and holds edge_key dicts keyed by neighbor. The edge_key dict holds each edge_attr dict keyed by edge key. The inner dict (edge_attr_dict) represents the edge data and holds edge attribute values keyed by attribute names.

Each of these four dicts in the dict-of-dict-of-dict-of-dict structure can be replaced by a user defined dict-like object. In general, the dict-like features should be maintained but extra features can be added. To replace one of the dicts create a new graph class by changing the class(!) variable holding the factory for that dict-like structure. The variable names are node_dict_factory, node_attr_dict_factory, adjlist_inner_dict_factory, adjlist_outer_dict_factory, edge_key_dict_factory, edge_attr_dict_factory and graph_attr_dict_factory.

node_dict_factoryfunction, (default: dict)

Factory function to be used to create the dict containing node attributes, keyed by node id. It should require no arguments and return a dict-like object

node_attr_dict_factory: function, (default: dict)

Factory function to be used to create the node attribute dict which holds attribute values keyed by attribute name. It should require no arguments and return a dict-like object

adjlist_outer_dict_factoryfunction, (default: dict)

Factory function to be used to create the outer-most dict in the data structure that holds adjacency info keyed by node. It should require no arguments and return a dict-like object.

adjlist_inner_dict_factoryfunction, (default: dict)

Factory function to be used to create the adjacency list dict which holds multiedge key dicts keyed by neighbor. It should require no arguments and return a dict-like object.

edge_key_dict_factoryfunction, (default: dict)

Factory function to be used to create the edge key dict which holds edge data keyed by edge key. It should require no arguments and return a dict-like object.

edge_attr_dict_factoryfunction, (default: dict)

Factory function to be used to create the edge attribute dict which holds attribute values keyed by attribute name. It should require no arguments and return a dict-like object.

graph_attr_dict_factoryfunction, (default: dict)

Factory function to be used to create the graph attribute dict which holds attribute values keyed by attribute name. It should require no arguments and return a dict-like object.

Typically, if your extension doesn’t impact the data structure all methods will inherited without issue except: to_directed/to_undirected. By default these methods create a DiGraph/Graph class and you probably want them to create your extension of a DiGraph/Graph. To facilitate this we define two class variables that you can set in your subclass.

to_directed_classcallable, (default: DiGraph or MultiDiGraph)

Class to create a new graph structure in the to_directed method. If None, a NetworkX class (DiGraph or MultiDiGraph) is used.

to_undirected_classcallable, (default: Graph or MultiGraph)

Class to create a new graph structure in the to_undirected method. If None, a NetworkX class (Graph or MultiGraph) is used.

Examples

Please see ordered for examples of creating graph subclasses by overwriting the base class dict with a dictionary-like object.

Methods

Adding and removing nodes and edges

MultiGraph.__init__([incoming_graph_data])

Initialize a graph with edges, name, or graph attributes.

MultiGraph.add_node(node_for_adding, **attr)

Add a single node node_for_adding and update node attributes.

MultiGraph.add_nodes_from(nodes_for_adding, …)

Add multiple nodes.

MultiGraph.remove_node(n)

Remove node n.

MultiGraph.remove_nodes_from(nodes)

Remove multiple nodes.

MultiGraph.add_edge(u_for_edge, v_for_edge)

Add an edge between u and v.

MultiGraph.add_edges_from(ebunch_to_add, **attr)

Add all the edges in ebunch_to_add.

MultiGraph.add_weighted_edges_from(ebunch_to_add)

Add weighted edges in ebunch_to_add with specified weight attr

MultiGraph.new_edge_key(u, v)

Returns an unused key for edges between nodes u and v.

MultiGraph.remove_edge(u, v[, key])

Remove an edge between u and v.

MultiGraph.remove_edges_from(ebunch)

Remove all edges specified in ebunch.

MultiGraph.update([edges, nodes])

Update the graph using nodes/edges/graphs as input.

MultiGraph.clear()

Remove all nodes and edges from the graph.

MultiGraph.clear_edges()

Remove all edges from the graph without altering nodes.

Reporting nodes edges and neighbors

MultiGraph.nodes

A NodeView of the Graph as G.nodes or G.nodes().

MultiGraph.__iter__()

Iterate over the nodes.

MultiGraph.has_node(n)

Returns True if the graph contains the node n.

MultiGraph.__contains__(n)

Returns True if n is a node, False otherwise.

MultiGraph.edges

Returns an iterator over the edges.

MultiGraph.has_edge(u, v[, key])

Returns True if the graph has an edge between nodes u and v.

MultiGraph.get_edge_data(u, v[, key, default])

Returns the attribute dictionary associated with edge (u, v).

MultiGraph.neighbors(n)

Returns an iterator over all neighbors of node n.

MultiGraph.adj

Graph adjacency object holding the neighbors of each node.

MultiGraph.__getitem__(n)

Returns a dict of neighbors of node n.

MultiGraph.adjacency()

Returns an iterator over (node, adjacency dict) tuples for all nodes.

MultiGraph.nbunch_iter([nbunch])

Returns an iterator over nodes contained in nbunch that are also in the graph.

Counting nodes edges and neighbors

MultiGraph.order()

Returns the number of nodes in the graph.

MultiGraph.number_of_nodes()

Returns the number of nodes in the graph.

MultiGraph.__len__()

Returns the number of nodes in the graph.

MultiGraph.degree

A DegreeView for the Graph as G.degree or G.degree().

MultiGraph.size([weight])

Returns the number of edges or total of all edge weights.

MultiGraph.number_of_edges([u, v])

Returns the number of edges between two nodes.

Making copies and subgraphs

MultiGraph.copy([as_view])

Returns a copy of the graph.

MultiGraph.to_undirected([as_view])

Returns an undirected copy of the graph.

MultiGraph.to_directed([as_view])

Returns a directed representation of the graph.

MultiGraph.subgraph(nodes)

Returns a SubGraph view of the subgraph induced on nodes.

MultiGraph.edge_subgraph(edges)

Returns the subgraph induced by the specified edges.