Skip to content

Commit dc6228b

Browse files
committed
Update materials for creating a simple graph from scratch
1 parent 1df4a00 commit dc6228b

2 files changed

Lines changed: 583 additions & 13 deletions

File tree

source/part2/chapter-08/md/00-introduction-to-spatial-network-analysis.md

Lines changed: 164 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ jupyter:
1212
name: python3
1313
---
1414

15+
<!-- #region editable=true slideshow={"slide_type": ""} -->
1516
# Representing geographic data as networks
1617

1718
Contents:
@@ -21,8 +22,10 @@ Contents:
2122
- How to create a graph from a file representing streets
2223
- How to create a routable graph from OpenStreetMap
2324
- Other uses of graphs - morphology, spatial weights, etc.
25+
- Saving graphs to disk
26+
<!-- #endregion -->
2427

25-
28+
<!-- #region editable=true slideshow={"slide_type": ""} -->
2629
## Basic concepts
2730

2831
As we briefly introduced in Chapter 5.2, networks are data structures that consists of nodes that are connected to other nodes via edges which ultimately construct a network (or a graph as it is referred in graph theory). As networks are widely used in various domains, the names used for these basic elements of a network can sometime vary. To clarify some of the ambiguity related to these terms, we list commonly used terms related to spatial networks below:
@@ -35,7 +38,7 @@ In Python, most of the network analysis related libraries (e.g. `networkx`, `igr
3538

3639

3740

38-
41+
<!-- #endregion -->
3942

4043
## Creating a simple graph from scratch
4144

@@ -175,7 +178,7 @@ positions = {node: attrs["coords"] for node, attrs in G2.nodes.data()}
175178
edge_labels = {(u, v): attrs["weight"] for u, v, attrs in G2.edges.data()}
176179
```
177180

178-
```python
181+
```python editable=true slideshow={"slide_type": ""}
179182
nx.draw(G2,
180183
with_labels=True,
181184
pos=positions,
@@ -191,12 +194,169 @@ nx.draw_networkx_edge_labels(
191194
);
192195
```
193196

197+
```python editable=true slideshow={"slide_type": ""}
198+
distance, path = nx.single_source_dijkstra(G=G2,
199+
source="a",
200+
target="e",
201+
weight="weight",
202+
)
203+
```
204+
205+
```python
206+
print("Distance:", distance)
207+
print("Path / visited nodes:", path)
208+
```
209+
210+
```python
211+
distance, path = nx.single_source_dijkstra(G=G2,
212+
source="e",
213+
target="a",
214+
weight="weight",
215+
)
216+
```
217+
218+
```python
219+
print("Distance:", distance)
220+
print("Path / visited nodes:", path)
221+
```
222+
223+
```python
224+
path_edges = list(zip(path,path[1:]))
225+
path_edges
226+
```
227+
228+
```python
229+
nx.draw(G2,
230+
with_labels=True,
231+
pos=positions,
232+
font_color="white",
233+
node_color="grey")
234+
235+
nx.draw_networkx_nodes(G2, positions, nodelist=path, node_color='r')
236+
nx.draw_networkx_edges(G2, positions, edgelist=path_edges, edge_color='r', width=3);
237+
```
238+
194239
### Directed graph
195240

196241
```python
197-
G2 = nx.MultiDiGraph()
242+
G_directed = nx.MultiDiGraph()
243+
```
244+
245+
```python
246+
node_collection = [("a", {"coords": (0,5)}),
247+
("b", {"coords": (5,5)}),
248+
("c", {"coords": (0,0)}),
249+
("d", {"coords": (5,0)}),
250+
("e", {"coords": (10,0)}),
251+
]
252+
```
253+
254+
```python
255+
edge_collection = [("a", "b", {"weight": 1, "color": "red"}),
256+
# bidirectional a<->c
257+
("a", "c", {"weight": 2, "color": "green"}),
258+
("c", "a", {"weight": 2, "color": "green"}),
259+
# bidirectional b<->d
260+
("b", "d", {"weight": 1, "color": "green"}),
261+
("d", "b", {"weight": 1, "color": "green"}),
262+
263+
("c", "d", {"weight": 1, "color": "red"}),
264+
("d", "e", {"weight": 3, "color": "red"}),
265+
]
266+
```
267+
268+
```python
269+
# Add nodes and edges from the collections
270+
G_directed.add_nodes_from(node_collection)
271+
G_directed.add_edges_from(edge_collection)
272+
273+
# Extract exact node locations
274+
positions = {node: attrs["coords"] for node, attrs in G_directed.nodes.data()}
275+
276+
# Parse edge labels
277+
edge_labels = {(u, v): attrs["weight"] for u, v, attrs in G_directed.edges.data()}
278+
279+
# Parse edge colors
280+
edge_colors = [attrs["color"] for u, v, attrs in G_directed.edges.data()]
281+
```
282+
283+
```python
284+
nx.draw(G_directed,
285+
with_labels=True,
286+
pos=positions,
287+
font_color="white",
288+
node_color="grey",
289+
edge_color=edge_colors
290+
)
291+
292+
nx.draw_networkx_edge_labels(
293+
G_directed,
294+
positions,
295+
edge_labels=edge_labels,
296+
font_color='red',
297+
font_weight="bold",
298+
);
299+
```
300+
301+
```python editable=true slideshow={"slide_type": ""}
302+
distance, path = nx.single_source_dijkstra(G=G_directed,
303+
source="a",
304+
target="e",
305+
weight="weight",
306+
)
198307
```
199308

200309
```python
310+
path_edges = list(zip(path,path[1:]))
311+
path_edges
312+
```
313+
314+
```python
315+
nx.draw(G_directed,
316+
with_labels=True,
317+
pos=positions,
318+
font_color="white",
319+
node_color="grey")
320+
321+
nx.draw_networkx_nodes(G_directed, positions, nodelist=path, node_color='r')
322+
nx.draw_networkx_edges(G_directed, positions, edgelist=path_edges, edge_color='r', width=3);
323+
```
324+
325+
#### Question 8.1
326+
327+
What is the path length and route from `e` to `a` using the directed graph?
328+
329+
```python editable=true slideshow={"slide_type": ""}
330+
# You can use this cell to enter your solution.
331+
```
332+
333+
```python editable=true slideshow={"slide_type": ""} tags=["remove_book_cell", "hide-cell"]
334+
# Solution
335+
336+
# This is a trick question: Because our graph is directed
337+
# and there is no way out from node 'e', there is no path nor length
338+
# from e to a
339+
340+
# When searching for such a path, networkx raises an error
341+
342+
# Uncomment to test yourself
343+
# distance, path = nx.single_source_dijkstra(G=G_directed, source="e", target="a", weight="weight")
344+
```
345+
346+
<!-- #region editable=true slideshow={"slide_type": ""} -->
347+
## Creating a graph from LineStrings
348+
<!-- #endregion -->
349+
350+
<!-- #region editable=true slideshow={"slide_type": ""} -->
351+
Data was obtained from
352+
<!-- #endregion -->
353+
354+
```python editable=true slideshow={"slide_type": ""}
355+
import geopandas as gpd
356+
import momepy
357+
from contextily import add_basemap
358+
```
359+
360+
```python editable=true slideshow={"slide_type": ""}
201361

202362
```

0 commit comments

Comments
 (0)