summaryrefslogtreecommitdiff
path: root/_downloads/8ca1ed8a4cf00870baa5a8020931ba46
diff options
context:
space:
mode:
authorjarrodmillman <jarrod.millman@gmail.com>2022-12-14 17:21:13 +0000
committerjarrodmillman <jarrod.millman@gmail.com>2022-12-14 17:21:13 +0000
commit832c558e3507e5cb667a622b5372f91384ab026f (patch)
tree74481f14ab9cfb5c6984ab59b378cdc857a8180d /_downloads/8ca1ed8a4cf00870baa5a8020931ba46
parent71985f91c82bf85657dce6a74669e93ec8d29e11 (diff)
downloadnetworkx-832c558e3507e5cb667a622b5372f91384ab026f.tar.gz
Deploying to gh-pages from @ networkx/networkx@6be702047b1bb596a8010cf80911bb6ea939b1d1 🚀
Diffstat (limited to '_downloads/8ca1ed8a4cf00870baa5a8020931ba46')
-rw-r--r--_downloads/8ca1ed8a4cf00870baa5a8020931ba46/plot_lines.py110
1 files changed, 110 insertions, 0 deletions
diff --git a/_downloads/8ca1ed8a4cf00870baa5a8020931ba46/plot_lines.py b/_downloads/8ca1ed8a4cf00870baa5a8020931ba46/plot_lines.py
new file mode 100644
index 00000000..616db374
--- /dev/null
+++ b/_downloads/8ca1ed8a4cf00870baa5a8020931ba46/plot_lines.py
@@ -0,0 +1,110 @@
+"""
+==========================
+Graphs from a set of lines
+==========================
+
+This example shows how to build a graph from a set of geographic lines
+(sometimes called "linestrings") using GeoPandas, momepy and alternatively
+PySAL. We'll plot some rivers and streets, as well as their graphs formed
+from the segments.
+
+There are generally two ways of creating graph object from line geometry.
+Let's use an example of street network to illustrate both:
+
+The first way is a so-called primal approach, where each intersection is
+a node and each linestring segment connecting two intersections is an edge.
+
+The second way is so-called dual approach, where each line is a node and
+intersection topology is turned into edges. One of the options how this is
+used for street network analysis is an angular analysis, where your routing
+is weighted via angles between street segments on intersections.
+
+We will use GeoPandas to read spatial data and momepy to generate first
+primal graph and then dual graph. Furthermore, we will use PySAL to
+illustrate an alternative way of creating raw dual graph.
+"""
+
+
+import geopandas
+import matplotlib.pyplot as plt
+import momepy
+import networkx as nx
+from contextily import add_basemap
+from libpysal import weights
+
+# %%
+# Read in example river geometry from GeoJSON. Source of example data:
+# https://doi.org/10.3390/data5010008 (Nicolas Cadieux)
+rivers = geopandas.read_file("rivers.geojson")
+
+# %%
+# Construct the primal graph. momepy automatically preserves all attributes
+# from GeoDataFrame and stores then as edge attributes.
+G = momepy.gdf_to_nx(rivers, approach="primal")
+
+# %%
+# Each node is encoded by its coordinates, which allows us to use them
+# in plotting.
+positions = {n: [n[0], n[1]] for n in list(G.nodes)}
+
+# Plot
+f, ax = plt.subplots(1, 2, figsize=(12, 6), sharex=True, sharey=True)
+rivers.plot(color="k", ax=ax[0])
+for i, facet in enumerate(ax):
+ facet.set_title(("Rivers", "Graph")[i])
+ facet.axis("off")
+nx.draw(G, positions, ax=ax[1], node_size=5)
+
+# %%
+# Once we finish graph-based analysis, we can convert graph back
+# to GeoDataFrames. momepy can return nodes as point geometry,
+# edges as original line geometry and W object, which is PySAL
+# spatial weights matrix encoding original graph so we can use
+# it with node GeoDataFrame.
+nodes, edges, W = momepy.nx_to_gdf(G, spatial_weights=True)
+
+
+# Read in example street network from GeoPackage
+streets = geopandas.read_file(momepy.datasets.get_path("bubenec"), layer="streets")
+
+# Construct the primal graph
+G_primal = momepy.gdf_to_nx(streets, approach="primal")
+
+# Plot
+f, ax = plt.subplots(1, 2, figsize=(12, 6), sharex=True, sharey=True)
+streets.plot(color="k", ax=ax[0])
+for i, facet in enumerate(ax):
+ facet.set_title(("Streets", "Graph")[i])
+ facet.axis("off")
+ add_basemap(facet)
+nx.draw(
+ G_primal, {n: [n[0], n[1]] for n in list(G_primal.nodes)}, ax=ax[1], node_size=50
+)
+
+# %%
+# Construct the dual graph. momepy will store row attributes as node attributes and
+# automatically measures angle between lines.
+G_dual = momepy.gdf_to_nx(streets, approach="dual")
+
+# Plot
+f, ax = plt.subplots(1, 2, figsize=(12, 6), sharex=True, sharey=True)
+streets.plot(color="k", ax=ax[0])
+for i, facet in enumerate(ax):
+ facet.set_title(("Streets", "Graph")[i])
+ facet.axis("off")
+ add_basemap(facet)
+nx.draw(G_dual, {n: [n[0], n[1]] for n in list(G_dual.nodes)}, ax=ax[1], node_size=50)
+plt.show()
+
+# Convert dual graph back to GeoDataFrame. Returns only original line geometry.
+lines = momepy.nx_to_gdf(G_dual)
+
+# %%
+# We can also construct the dual graph using PySAL. Note that it only encodes
+# relationship between geometries and do not any store attributes. However, it is
+# significantly faster than momepy.gdf_to_nx().
+# Create PySAL weights (graph).
+W = weights.Queen.from_dataframe(streets)
+
+# Convert the graph to networkx
+G_dual = W.to_networkx()