Skip to content

Commit 9478a62

Browse files
authored
ENH: SharedWalls length (pysal#238)
1 parent 3f768f5 commit 9478a62

File tree

4 files changed

+71
-24
lines changed

4 files changed

+71
-24
lines changed

docs/api.rst

+1
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ spatial distribution
7777
NeighboringStreetOrientationDeviation
7878
Neighbors
7979
Orientation
80+
SharedWalls
8081
SharedWallsRatio
8182
StreetAlignment
8283

docs/bibtex.json

+3
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,9 @@
6868
"generated/momepy.Rectangularity": [
6969
"dibble2017"
7070
],
71+
"generated/momepy.SharedWalls": [
72+
"hamaina2012a"
73+
],
7174
"generated/momepy.SharedWallsRatio": [
7275
"hamaina2012a"
7376
],

momepy/distribution.py

+58-22
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
# definitions of spatial distribution characters
66

77
import math
8-
import warnings
98

109
import networkx as nx
1110
import numpy as np
@@ -16,6 +15,7 @@
1615

1716
__all__ = [
1817
"Orientation",
18+
"SharedWalls",
1919
"SharedWallsRatio",
2020
"StreetAlignment",
2121
"CellAlignment",
@@ -106,7 +106,55 @@ def _dist(a, b):
106106
self.series = pd.Series(results_list, index=gdf.index)
107107

108108

109-
class SharedWallsRatio:
109+
class SharedWalls:
110+
"""
111+
Calculate the length of shared walls of adjacent elements (typically buildings)
112+
113+
.. math::
114+
\\textit{length of shared walls}
115+
116+
Note that data needs to be topologically correct. Overlapping polygons will lead to
117+
incorrect results.
118+
119+
Adapted from :cite:`hamaina2012a`.
120+
121+
Parameters
122+
----------
123+
gdf : GeoDataFrame
124+
GeoDataFrame containing gdf to analyse
125+
126+
Attributes
127+
----------
128+
series : Series
129+
Series containing resulting values
130+
gdf : GeoDataFrame
131+
original GeoDataFrame
132+
133+
Examples
134+
--------
135+
>>> buildings_df['swr'] = momepy.SharedWalls(buildings_df).series
136+
137+
See also
138+
--------
139+
SharedWallsRatio
140+
"""
141+
142+
def __init__(self, gdf):
143+
self.gdf = gdf
144+
145+
inp, res = gdf.sindex.query_bulk(gdf.geometry, predicate="intersects")
146+
left = gdf.geometry.take(inp).reset_index(drop=True)
147+
right = gdf.geometry.take(res).reset_index(drop=True)
148+
intersections = left.intersection(right).length
149+
results = intersections.groupby(inp).sum().reset_index(
150+
drop=True
151+
) - gdf.geometry.length.reset_index(drop=True)
152+
results.index = gdf.index
153+
154+
self.series = results
155+
156+
157+
class SharedWallsRatio(SharedWalls):
110158
"""
111159
Calculate shared walls ratio of adjacent elements (typically buildings)
112160
@@ -122,8 +170,7 @@ class SharedWallsRatio:
122170
----------
123171
gdf : GeoDataFrame
124172
GeoDataFrame containing gdf to analyse
125-
unique_id : (deprecated)
126-
perimeters : str, list, np.array, pd.Series (default None)
173+
perimeters : str, list, np.array, pd.Series (default None, optional)
127174
the name of the dataframe column, ``np.array``, or ``pd.Series`` where is stored perimeter value
128175
129176
Attributes
@@ -140,15 +187,14 @@ class SharedWallsRatio:
140187
>>> buildings_df['swr'] = momepy.SharedWallsRatio(buildings_df).series
141188
>>> buildings_df['swr'][10]
142189
0.3424804411228673
143-
"""
144190
145-
def __init__(self, gdf, unique_id=None, perimeters=None):
146-
if unique_id is not None:
147-
warnings.warn(
148-
"unique_id is deprecated and will be removed in v0.4.", FutureWarning,
149-
)
191+
See also
192+
--------
193+
SharedWalls
194+
"""
150195

151-
self.gdf = gdf
196+
def __init__(self, gdf, perimeters=None):
197+
super(SharedWallsRatio, self).__init__(gdf)
152198

153199
if perimeters is None:
154200
self.perimeters = gdf.geometry.length
@@ -157,17 +203,7 @@ def __init__(self, gdf, unique_id=None, perimeters=None):
157203
else:
158204
self.perimeters = perimeters
159205

160-
inp, res = gdf.sindex.query_bulk(gdf.geometry, predicate="intersects")
161-
left = gdf.geometry.take(inp).reset_index(drop=True)
162-
right = gdf.geometry.take(res).reset_index(drop=True)
163-
intersections = left.intersection(right).length
164-
results = (
165-
intersections.groupby(inp).sum().reset_index(drop=True)
166-
- self.perimeters.reset_index(drop=True)
167-
) / self.perimeters.reset_index(drop=True)
168-
results.index = gdf.index
169-
170-
self.series = results
206+
self.series = self.series / self.perimeters
171207

172208

173209
class StreetAlignment:

tests/test_distribution.py

+9-2
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,15 @@ def test_Orientation(self):
3232
check = 40.7607
3333
assert self.df_streets["orient"][0] == pytest.approx(check)
3434

35+
@pytest.mark.skipif(not GPD_08, reason="requires geopandas > 0.7")
36+
def test_SharedWalls(self):
37+
self.df_buildings["swr"] = mm.SharedWalls(self.df_buildings).series
38+
nonconsecutive = self.df_buildings.drop(2)
39+
result = mm.SharedWalls(nonconsecutive).series
40+
check = 39.395484381507075
41+
assert self.df_buildings["swr"][10] == check
42+
assert result[10] == check
43+
3544
@pytest.mark.skipif(not GPD_08, reason="requires geopandas > 0.7")
3645
def test_SharedWallsRatio(self):
3746
self.df_buildings["swr"] = mm.SharedWallsRatio(self.df_buildings).series
@@ -44,8 +53,6 @@ def test_SharedWallsRatio(self):
4453
assert self.df_buildings["swr"][10] == check
4554
assert self.df_buildings["swr_array"][10] == check
4655
assert result[10] == check
47-
with pytest.warns(FutureWarning):
48-
mm.SharedWallsRatio(self.df_buildings, "uID")
4956

5057
def test_StreetAlignment(self):
5158
self.df_buildings["orient"] = orient = mm.Orientation(self.df_buildings).series

0 commit comments

Comments
 (0)