Repository: martinfleis/momepy
Pull request #196 (2020-07-28 11:13:46)

PERF: refactor linearity


Patch:
diff --git a/momepy/shape.py b/momepy/shape.py
index 492e721..51843f0 100644
--- a/momepy/shape.py
+++ b/momepy/shape.py
@@ -1161,26 +1161,20 @@ class Linearity:
     Examples
     --------
     >>> streets_df['linearity'] = momepy.Linearity(streets_df).series
-    100%|██████████| 33/33 [00:00<00:00, 1737.64it/s]
     >>> streets_df['linearity'][0]
     1.0
     """
 
     def __init__(self, gdf, verbose=True):
         self.gdf = gdf
-        # define empty list for results
-        results_list = []
 
-        lenghts = gdf.geometry.length
-        # fill new column with the value of area, iterating over rows one by one
-        # TODO use math instead of shapely points
-        for index, geom in tqdm(
-            gdf.geometry.iteritems(), total=gdf.shape[0], disable=not verbose
-        ):
-            euclidean = Point(geom.coords[0]).distance(Point(geom.coords[-1]))
-            results_list.append(euclidean / lenghts.loc[index])
+        euclidean = gdf.geometry.apply(
+            lambda geom: self._dist(geom.coords[0], geom.coords[-1])
+        )
+        self.series = euclidean / gdf.geometry.length
 
-        self.series = pd.Series(results_list, index=gdf.index)
+    def _dist(self, a, b):
+        return math.hypot(b[0] - a[0], b[1] - a[1])
 
 
 class CompactnessWeightedAxis:
diff --git a/momepy/utils.py b/momepy/utils.py
index b53c1c4..3a1c9d9 100644
--- a/momepy/utils.py
+++ b/momepy/utils.py
@@ -459,7 +459,7 @@ def preprocess(
     return blg[buildings.columns]
 
 
-def network_false_nodes(gdf, tolerance=0.1, precision=3):
+def network_false_nodes(gdf, tolerance=0.1, precision=3, verbose=True):
     """
     Check topology of street network and eliminate nodes of degree 2 by joining
     affected edges.
@@ -473,6 +473,8 @@ def network_false_nodes(gdf, tolerance=0.1, precision=3):
     precision : int
         rounding parameter in estimating uniqueness of two points based on their
         coordinates
+    verbose : bool
+        if True, shows progress bars in loops
 
     Returns
     -------
@@ -492,8 +494,12 @@ def network_false_nodes(gdf, tolerance=0.1, precision=3):
     sindex = streets.sindex
 
     false_xy = []
-    print("Identifying false points...")
-    for line in tqdm(streets.geometry, total=streets.shape[0]):
+    for line in tqdm(
+        streets.geometry,
+        total=streets.shape[0],
+        desc="Identifying false points",
+        disable=not verbose,
+    ):
         l_coords = list(line.coords)
         start = Point(l_coords[0]).buffer(tolerance)
         end = Point(l_coords[-1]).buffer(tolerance)
@@ -534,24 +540,21 @@ def network_false_nodes(gdf, tolerance=0.1, precision=3):
     geoms = streets
     idx = max(geoms.index) + 1
 
-    print("Merging segments...")
-    for x, y, point in tqdm(zip(x, y, points)):
+    for x, y, point in tqdm(
+        zip(x, y, points), desc="Merging segments", total=len(x), disable=not verbose
+    ):
 
         if GPD_08:
             predic = geoms.sindex.query(point, predicate="intersects")
-            matches = geoms.iloc[predic].index
+            matches = geoms.iloc[predic].geometry
         else:
             pos = list(geoms.sindex.intersection(point.bounds))
             mat = geoms.iloc[pos]
-            matches = mat[mat.intersects(point)].index
+            matches = mat[mat.intersects(point)].geometry
 
         try:
-            snap = shapely.ops.snap(
-                geoms.geometry.loc[matches[0]],
-                geoms.geometry.loc[matches[1]],
-                tolerance,
-            )
-            multiline = snap.union(geoms.geometry.loc[matches[1]])
+            snap = shapely.ops.snap(matches.iloc[0], matches.iloc[1], tolerance,)
+            multiline = snap.union(matches.iloc[1])
             linestring = shapely.ops.linemerge(multiline)
             if linestring.type == "LineString":
                 if series:
@@ -567,7 +570,7 @@ def network_false_nodes(gdf, tolerance=0.1, precision=3):
                         geoms.loc[idx, "geometry"] = g
                     idx += 1
 
-            geoms = geoms.drop(matches)
+            geoms = geoms.drop(matches.index)
         except (IndexError, ValueError):
             import warnings
 


Test patch:
diff --git a/tests/test_shape.py b/tests/test_shape.py
index 0a0e4fe..7579713 100644
--- a/tests/test_shape.py
+++ b/tests/test_shape.py
@@ -213,7 +213,7 @@ class TestShape:
             Point(self.df_streets.geometry[0].coords[-1])
         )
         check = euclidean / self.df_streets.geometry[0].length
-        assert self.df_streets["lin"][0] == check
+        assert self.df_streets["lin"][0] == approx(check, rel=1e-6)
 
     def test_CompactnessWeightedAxis(self):
         self.df_buildings["cwa"] = mm.CompactnessWeightedAxis(self.df_buildings).series