Skip to main content
`Ctrl`+`K`

# MultiGraph—Undirected graphs with self loops and parallel edges

## Overview

class MultiGraph(incoming_graph_data=None, multigraph_input=None, **attr)

  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, in a MultiGraph each edge has a key to distinguish between multiple edges that have the same source and destination nodes.

  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, 2D NumPy array, SciPy sparse array, or PyGraphviz graph.

    multigraph_input bool or None (default None)

      Note: Only used when `incoming_graph_data` is a dict. If True, `incoming_graph_data` is assumed to be a dict-of-dict-of-dict-of-dict structure keyed by node to neighbor to edge keys to edge data for multi-edges. A NetworkXError is raised if this is not the case. If False, `to_networkx_graph()` is used to try to determine the dict’s graph data structure as either a dict-of-dict-of-dict keyed by node to neighbor to edge data, or a dict-of-iterable keyed by node to neighbors. If None, the treatment for True is tried, but if it fails, the treatment for False is tried.

    attr keyword arguments, optional (default= no attributes)

      Attributes to add to graph as key=value pairs.

  See also

  `Graph`
  `DiGraph`
  `MultiDiGraph`

  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, 0]` a read-only dict-like structure. However, you can assign to attributes in e.g. `G.edges[1, 2, 0]`. Thus, use 2 sets of brackets to add/change data attributes: `G.edges[1, 2, 0]['weight'] = 4`.

  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 mapping neighbor -> edge key -> 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, k]`, `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.

  Subclassing Example

  Create a low memory graph class that effectively disallows edge attributes by using a single attribute dict for all edges. This reduces the memory used, but you lose edge attributes.

      >>> class ThinGraph(nx.Graph):
      ...     all_edge_dict = {"weight": 1}
      ...
      ...     def single_edge_dict(self):
      ...         return self.all_edge_dict
      ...
      ...     edge_attr_dict_factory = single_edge_dict
      >>> G = ThinGraph()
      >>> G.add_edge(2, 1)
      >>> G[2][1]
      {'weight': 1}
      >>> G.add_edge(2, 2)
      >>> G[2][1] is G[2][2]
      True

## 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, key).
`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.