# NetworkX graphΒΆ

WNTR uses NetworkX data objects to store network connectivity as a graph.
A **graph** is a collection of nodes that are connected by links.
For water networks, nodes represent junctions, tanks, and reservoirs while links represent pipes, pumps, and valves.

Water networks are stored as directed multigraphs.
A **directed multigraph** is a graph with direction associated with links and
the graph can have multiple links with the same start and end node.
A simple example is shown in Figure 5.
For water networks, the link direction is from the start node to the end node.
The link direction is used as a reference to track flow direction in the network.
For example, positive flow indicates that the flow direction is from the start node to the end node
while negative flow indicates that the flow direction is from the end node to the start node.
Multiple links with the same start and end node can be used to represent redundant pipes or backup pumps.
In WNTR, the graph stores
the start and end node of each link,
node coordinates,
and node and link types (i.e., tank, reservoir, valve).
WNTR updates the graph as elements are added and removed from the water network model.

NetworkX includes numerous methods to analyze the structure of complex networks.
For more information on NetworkX, see https://networkx.github.io/.
WNTR includes a custom Graph Class,
`WntrMultiDiGraph`

.
This class inherits from NetworkX MulitDigraph and includes additional methods
that are specific to WNTR.
The example **networkx_graph.py** can be used to generate a graph from a water network model.

A copy of the graph can an be obtained using the following function:

```
G = wn.get_graph_deep_copy()
```

The graph is stored as a nested dictionary. The nodes and links (note that links are called edges in NetworkX) can be accessed using the following:

```
node_name = '123'
print(G.node[node_name])
print(G.edge[node_name])
```

The graph can be used to access NetworkX methods, for example:

```
import networkx as nx
node_degree = G.degree()
bet_cen = nx.betweenness_centrality(G)
wntr.graphics.plot_network(wn, node_attribute=bet_cen, node_size=30,
title='Betweenness Centrality')
```

Some methods in NetworkX require that networks are undirected.
An **undirected graph** is a graph with no direction associated with links.
The following NetworkX method can be used to convert a directed graph to an undirected graph:

```
uG = G.to_undirected()
```

Some methods in NetworkX require that networks are connected.
A **connected graph** is a graph where a path exists between every node in the network (i.e., no node is disconnected).
The following NetworkX method can be used to check if a graph is connected:

```
print(nx.is_connected(uG))
```

Some methods in NetworkX can use weighted graphs.
A **weighted graph** is a graph in which each link is given a weight.
The WNTR method `weight_graph`

can be used to weight the graph by any attribute.
In the following example, the graph is weighted by length. This graph can then be used to compute path lengths:

```
length = wn.query_link_attribute('length')
G.weight_graph(link_attribute = length)
```