Repository: martinfleis/momepy
Pull request #59 (2019-08-14 10:06:36)

API: Queen_higher -> sw_high
Change `Queen_higher` to `sw_high` to make explicit that it can make higher order of anything. Allow rook.

codecov[bot]: # [Codecov](https://codecov.io/gh/martinfleis/momepy/pull/59?src=pr&el=h1) Report
> Merging [#59](https://codecov.io/gh/martinfleis/momepy/pull/59?src=pr&el=desc) into [master](https://codecov.io/gh/martinfleis/momepy/commit/da3c0672e13d32b1f74cabdf177bad1854c8f3e3?src=pr&el=desc) will **increase** coverage by `<.01%`.
> The diff coverage is `100%`.

[![Impacted file tree graph](https://codecov.io/gh/martinfleis/momepy/pull/59/graphs/tree.svg?width=650&token=i04999UxkK&height=150&src=pr)](https://codecov.io/gh/martinfleis/momepy/pull/59?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##           master      #59      +/-   ##
==========================================
+ Coverage   92.87%   92.88%   +<.01%     
==========================================
  Files           9        9              
  Lines        2148     2150       +2     
==========================================
+ Hits         1995     1997       +2     
  Misses        153      153
```


| [Impacted Files](https://codecov.io/gh/martinfleis/momepy/pull/59?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [momepy/intensity.py](https://codecov.io/gh/martinfleis/momepy/pull/59/diff?src=pr&el=tree#diff-bW9tZXB5L2ludGVuc2l0eS5weQ==) | `96.47% <ø> (ø)` | :arrow_up: |
| [momepy/diversity.py](https://codecov.io/gh/martinfleis/momepy/pull/59/diff?src=pr&el=tree#diff-bW9tZXB5L2RpdmVyc2l0eS5weQ==) | `90.59% <ø> (ø)` | :arrow_up: |
| [momepy/dimension.py](https://codecov.io/gh/martinfleis/momepy/pull/59/diff?src=pr&el=tree#diff-bW9tZXB5L2RpbWVuc2lvbi5weQ==) | `99.33% <ø> (ø)` | :arrow_up: |
| [momepy/distribution.py](https://codecov.io/gh/martinfleis/momepy/pull/59/diff?src=pr&el=tree#diff-bW9tZXB5L2Rpc3RyaWJ1dGlvbi5weQ==) | `98.3% <100%> (ø)` | :arrow_up: |
| [momepy/utils.py](https://codecov.io/gh/martinfleis/momepy/pull/59/diff?src=pr&el=tree#diff-bW9tZXB5L3V0aWxzLnB5) | `78.26% <100%> (+0.12%)` | :arrow_up: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/martinfleis/momepy/pull/59?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/martinfleis/momepy/pull/59?src=pr&el=footer). Last update [da3c067...5d089c2](https://codecov.io/gh/martinfleis/momepy/pull/59?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).


Patch:
diff --git a/momepy/dimension.py b/momepy/dimension.py
index f4979a3..22576ac 100644
--- a/momepy/dimension.py
+++ b/momepy/dimension.py
@@ -713,7 +713,7 @@ def covered_area(gdf, spatial_weights, unique_id):
 
     Examples
     --------
-    >>> sw = momepy.Queen_higher(k=3, geodataframe=tessellation_df, ids='uID')
+    >>> sw = momepy.sw_high(k=3, gdf=tessellation_df, ids='uID')
     >>> tessellation_df['covered3steps'] = mm.covered_area(tessellation_df, sw, 'uID')
     Calculating covered area...
     100%|██████████| 144/144 [00:00<00:00, 549.15it/s]
diff --git a/momepy/distribution.py b/momepy/distribution.py
index cfd1f81..3d31bd6 100644
--- a/momepy/distribution.py
+++ b/momepy/distribution.py
@@ -521,9 +521,9 @@ def mean_interbuilding_distance(gdf, spatial_weights, unique_id, spatial_weights
     print('Calculating mean interbuilding distances...')
     if spatial_weights_higher is None:
         print('Generating weights matrix (Queen) of {} topological steps...'.format(order))
-        from momepy import Queen_higher
+        from momepy import sw_high
         # matrix to define area of analysis (more steps)
-        spatial_weights_higher = Queen_higher(k=order, weights=spatial_weights)
+        spatial_weights_higher = sw_high(k=order, weights=spatial_weights)
 
     # define empty list for results
     results_list = []
diff --git a/momepy/diversity.py b/momepy/diversity.py
index b0ee30b..04b0412 100644
--- a/momepy/diversity.py
+++ b/momepy/diversity.py
@@ -47,7 +47,7 @@ def rng(gdf, values, spatial_weights, unique_id, rng=(0, 100), **kwargs):
 
     Examples
     --------
-    >>> sw = momepy.Queen_higher(k=3, geodataframe=tessellation_df, ids='uID')
+    >>> sw = momepy.sw_high(k=3, gdf=tessellation_df, ids='uID')
     >>> tessellation_df['area_IQR_3steps'] = mm.rng(tessellation_df, 'area', sw, 'uID', rng=(25, 75))
     Calculating range...
     100%|██████████| 144/144 [00:00<00:00, 722.50it/s]
@@ -111,7 +111,7 @@ def theil(gdf, values, spatial_weights, unique_id, rng=None):
 
     Examples
     --------
-    >>> sw = momepy.Queen_higher(k=3, geodataframe=tessellation_df, ids='uID')
+    >>> sw = momepy.sw_high(k=3, gdf=tessellation_df, ids='uID')
     >>> tessellation_df['area_Theil'] = mm.theil(tessellation_df, 'area', sw, 'uID')
     Calculating Theil index...
     100%|██████████| 144/144 [00:00<00:00, 597.37it/s]
@@ -201,7 +201,7 @@ def simpson(gdf, values, spatial_weights, unique_id, binning='HeadTailBreaks', *
 
     Examples
     --------
-    >>> sw = momepy.Queen_higher(k=3, geodataframe=tessellation_df, ids='uID')
+    >>> sw = momepy.sw_high(k=3, gdf=tessellation_df, ids='uID')
     >>> tessellation_df['area_Simpson'] = mm.simpson(tessellation_df, 'area', sw, 'uID')
     Calculating Simpson's diversity index...
     100%|██████████| 144/144 [00:00<00:00, 455.83it/s]
@@ -302,7 +302,7 @@ def gini(gdf, values, spatial_weights, unique_id, rng=None):
 
     Examples
     --------
-    >>> sw = momepy.Queen_higher(k=3, geodataframe=tessellation_df, ids='uID')
+    >>> sw = momepy.sw_high(k=3, gdf=tessellation_df, ids='uID')
     >>> tessellation_df['area_Gini'] = mm.gini(tessellation_df, 'area', sw, 'uID')
     Calculating Gini index...
     100%|██████████| 144/144 [00:00<00:00, 597.37it/s]
diff --git a/momepy/intensity.py b/momepy/intensity.py
index f52ac90..87a4952 100644
--- a/momepy/intensity.py
+++ b/momepy/intensity.py
@@ -259,7 +259,7 @@ def blocks_count(gdf, block_id, spatial_weights, unique_id):
 
     Examples
     --------
-    >>> sw4 = mm.Queen_higher(k=4, geodataframe='tessellation_df', ids='uID')
+    >>> sw4 = mm.sw_high(k=4, gdf='tessellation_df', ids='uID')
     >>> tessellation_df['blocks_within_4'] = mm.blocks(tessellation_df, 'bID', sw4, 'uID')
     Calculating blocks...
     Blocks calculated.
diff --git a/momepy/utils.py b/momepy/utils.py
index 6aa01e9..72cd937 100644
--- a/momepy/utils.py
+++ b/momepy/utils.py
@@ -33,21 +33,25 @@ def unique_id(objects):
     return series
 
 
-def Queen_higher(k, geodataframe=None, weights=None, ids=None):
+def sw_high(k, gdf=None, weights=None, ids=None, contiguity='queen'):
     """
-    Generate spatial weights based on Queen contiguity of order k
+    Generate spatial weights based on Queen or Rook contiguity of order k.
 
-    Pass either geoDataFrame or weights. If both are passed, weights is used.
+    Adjacent are all features within <= k steps. Pass either gdf or weights.
+    If both are passed, weights is used. If weights are passed, contiguity is
+    ignored and high order spatial weights based on `weights` are computed.
 
     Parameters
     ----------
     k : int
         order of contiguity
-    geodataframe : GeoDataFrame
+    gdf : GeoDataFrame
         GeoDataFrame containing objects to analyse. Index has to be consecutive range 0:x.
         Otherwise, spatial weights will not match objects.
     weights : libpysal.weights
         libpysal.weights of order 1
+    contiguity : str (default 'queen')
+        type of contiguity weights. Can be 'queen' or 'rook'.
 
     Returns
     -------
@@ -59,17 +63,20 @@ def Queen_higher(k, geodataframe=None, weights=None, ids=None):
     >>> first_order = libpysal.weights.Queen.from_dataframe(geodataframe)
     >>> first_order.mean_neighbors
     5.848032564450475
-    >>> fourth_order = Queen_higher(k=4, geodataframe=geodataframe)
+    >>> fourth_order = sw_high(k=4, gdf=geodataframe)
     >>> fourth.mean_neighbors
     85.73188602442333
 
     """
     if weights is not None:
         first_order = weights
-    elif geodataframe is not None:
-        if not all(geodataframe.index == range(len(geodataframe))):
-            raise ValueError('Index is not consecutive range 0:x, spatial weights will not match objects.')
-        first_order = libpysal.weights.Queen.from_dataframe(geodataframe, ids=ids)
+    elif gdf is not None:
+        if contiguity == 'queen':
+            first_order = libpysal.weights.Queen.from_dataframe(gdf, ids=ids)
+        elif contiguity == 'rook':
+            first_order = libpysal.weights.Rook.from_dataframe(gdf, ids=ids)
+        else:
+            raise ValueError('{} is not supported. Use \'queen\' or \'rook\'.'.format(contiguity))
     else:
         raise Warning('GeoDataFrame of spatial weights must be given.')
 


Test patch:
diff --git a/tests/test_dimension.py b/tests/test_dimension.py
index f20886f..680dd3b 100644
--- a/tests/test_dimension.py
+++ b/tests/test_dimension.py
@@ -5,7 +5,7 @@ from shapely.geometry import Polygon
 import numpy as np
 
 from momepy.shape import _make_circle
-from momepy import Queen_higher
+from momepy import sw_high
 
 
 class TestDimensions:
@@ -99,7 +99,7 @@ class TestDimensions:
         assert self.df_buildings['long_axis'][0] == check
 
     def test_average_character(self):
-        spatial_weights = Queen_higher(k=3, geodataframe=self.df_tessellation, ids='uID')
+        spatial_weights = sw_high(k=3, gdf=self.df_tessellation, ids='uID')
         self.df_tessellation['area'] = area = self.df_tessellation.geometry.area
         self.df_tessellation['mesh_ar'] = mm.average_character(self.df_tessellation, values='area', spatial_weights=spatial_weights,
                                                                unique_id='uID', mode='mode')
@@ -137,29 +137,29 @@ class TestDimensions:
         assert results['heights_deviations'][0] == 5.526848034418866
 
     def test_weighted_character_sw(self):
-        sw = Queen_higher(k=3, geodataframe=self.df_tessellation, ids='uID')
+        sw = sw_high(k=3, gdf=self.df_tessellation, ids='uID')
         weighted = mm.weighted_character(self.df_buildings, 'height', sw, 'uID')
         assert weighted[38] == 18.301521351817303
 
     def test_weighted_character_area(self):
         self.df_buildings['area'] = self.df_buildings.geometry.area
-        sw = Queen_higher(k=3, geodataframe=self.df_tessellation, ids='uID')
+        sw = sw_high(k=3, gdf=self.df_tessellation, ids='uID')
         weighted = mm.weighted_character(self.df_buildings, 'height', sw, 'uID', 'area')
         assert weighted[38] == 18.301521351817303
 
     def test_weighted_character_array(self):
         area = self.df_buildings.geometry.area
-        sw = Queen_higher(k=3, geodataframe=self.df_tessellation, ids='uID')
+        sw = sw_high(k=3, gdf=self.df_tessellation, ids='uID')
         weighted = mm.weighted_character(self.df_buildings, self.df_buildings.height, sw, 'uID', area)
         assert weighted[38] == 18.301521351817303
 
     def test_covered_area(self):
-        sw = Queen_higher(geodataframe=self.df_tessellation, k=1, ids='uID')
+        sw = sw_high(gdf=self.df_tessellation, k=1, ids='uID')
         covered_sw = mm.covered_area(self.df_tessellation, sw, 'uID')
         assert covered_sw[0] == 24115.667218339422
 
     def test_wall(self):
-        sw = Queen_higher(geodataframe=self.df_buildings, k=1)
+        sw = sw_high(gdf=self.df_buildings, k=1)
         wall = mm.wall(self.df_buildings)
         wall_sw = mm.wall(self.df_buildings, sw)
         assert wall[0] == wall_sw[0]
diff --git a/tests/test_distribution.py b/tests/test_distribution.py
index 05cae7c..76b39fa 100644
--- a/tests/test_distribution.py
+++ b/tests/test_distribution.py
@@ -75,7 +75,7 @@ class TestDistribution:
 
     def test_mean_interbuilding_distance(self):
         sw = Queen.from_dataframe(self.df_tessellation, ids='uID')
-        swh = mm.Queen_higher(k=3, geodataframe=self.df_tessellation, ids='uID')
+        swh = mm.sw_high(k=3, gdf=self.df_tessellation, ids='uID')
         self.df_buildings['m_dist_sw'] = mm.mean_interbuilding_distance(self.df_buildings, sw, 'uID', swh)
         self.df_buildings['m_dist'] = mm.mean_interbuilding_distance(self.df_buildings, sw, 'uID', order=3)
         check = 29.305457092042744
@@ -89,7 +89,7 @@ class TestDistribution:
 
     def test_building_adjacency(self):
         sw = Queen.from_dataframe(self.df_buildings, ids='uID')
-        swh = mm.Queen_higher(k=3, geodataframe=self.df_tessellation, ids='uID')
+        swh = mm.sw_high(k=3, gdf=self.df_tessellation, ids='uID')
         self.df_buildings['adj_sw'] = mm.building_adjacency(self.df_buildings, spatial_weights=sw, unique_id='uID', spatial_weights_higher=swh)
         self.df_buildings['adj_sw_none'] = mm.building_adjacency(self.df_buildings, unique_id='uID', spatial_weights_higher=swh)
         check = 0.2613824113909074
diff --git a/tests/test_diversity.py b/tests/test_diversity.py
index eda54ab..952fa0a 100644
--- a/tests/test_diversity.py
+++ b/tests/test_diversity.py
@@ -2,7 +2,7 @@ import momepy as mm
 import geopandas as gpd
 import numpy as np
 
-from momepy import Queen_higher
+from momepy import sw_high
 
 import pytest
 
@@ -16,7 +16,7 @@ class TestDiversity:
         self.df_tessellation = gpd.read_file(test_file_path, layer='tessellation')
         self.df_buildings['height'] = np.linspace(10., 30., 144)
         self.df_tessellation['area'] = mm.area(self.df_tessellation)
-        self.sw = Queen_higher(k=3, geodataframe=self.df_tessellation, ids='uID')
+        self.sw = sw_high(k=3, gdf=self.df_tessellation, ids='uID')
 
     def test_rng(self):
         full_sw = mm.rng(self.df_tessellation, 'area', self.sw, 'uID')
diff --git a/tests/test_intensity.py b/tests/test_intensity.py
index 09d5db0..f4b794e 100644
--- a/tests/test_intensity.py
+++ b/tests/test_intensity.py
@@ -58,7 +58,7 @@ class TestIntensity:
         assert courtyards_wm.mean() == check
 
     def test_blocks_count(self):
-        sw = mm.Queen_higher(k=5, geodataframe=self.df_tessellation, ids='uID')
+        sw = mm.sw_high(k=5, gdf=self.df_tessellation, ids='uID')
         count = mm.blocks_count(self.df_tessellation, 'bID', sw, 'uID')
         count2 = mm.blocks_count(self.df_tessellation, self.df_tessellation.bID, sw, 'uID')
         check = 3.142437439120778e-05
@@ -73,7 +73,7 @@ class TestIntensity:
         area_v = mm.reached(self.df_streets, self.df_buildings, 'nID', mode='sum', values='fl_area')
         mean_v = mm.reached(self.df_streets, self.df_buildings, 'nID', mode='mean', values='fl_area')
         std_v = mm.reached(self.df_streets, self.df_buildings, 'nID', mode='std', values='fl_area')
-        sw = mm.Queen_higher(k=2, geodataframe=self.df_streets)
+        sw = mm.sw_high(k=2, gdf=self.df_streets)
         count_sw = mm.reached(self.df_streets, self.df_buildings, 'nID', sw)
         assert max(count) == 18
         assert max(area) == 18085.45897711331
@@ -88,14 +88,14 @@ class TestIntensity:
         nx = mm.gdf_to_nx(self.df_streets)
         nx = mm.node_degree(nx)
         nodes, edges, W = mm.nx_to_gdf(nx, spatial_weights=True)
-        sw = mm.Queen_higher(k=3, weights=W)
+        sw = mm.sw_high(k=3, weights=W)
         density = mm.node_density(nodes, edges, sw)
         weighted = mm.node_density(nodes, edges, sw, weighted=True, node_degree='degree')
         assert density.mean() == 0.012690163074599968
         assert weighted.mean() == 0.023207675994368446
 
     def test_density(self):
-        sw = mm.Queen_higher(k=3, geodataframe=self.df_tessellation, ids='uID')
+        sw = mm.sw_high(k=3, gdf=self.df_tessellation, ids='uID')
         dens = mm.density(self.df_tessellation, self.df_buildings['fl_area'], sw, 'uID', self.df_tessellation.area)
         dens2 = mm.density(self.df_tessellation, self.df_buildings['fl_area'], sw, 'uID')
         check = 1.6615871155383324
diff --git a/tests/test_utils.py b/tests/test_utils.py
index 1e6757e..b008723 100644
--- a/tests/test_utils.py
+++ b/tests/test_utils.py
@@ -20,21 +20,21 @@ class TestUtils:
         with pytest.raises(ValueError):
             mm.datasets.get_path('sffgkt')
 
-    def test_Queen_higher(self):
+    def test_sw_high(self):
         first_order = libpysal.weights.Queen.from_dataframe(self.df_tessellation)
-        from_sw = mm.Queen_higher(2, geodataframe=None, weights=first_order)
-        from_df = mm.Queen_higher(2, geodataframe=self.df_tessellation)
+        from_sw = mm.sw_high(2, gdf=None, weights=first_order)
+        from_df = mm.sw_high(2, gdf=self.df_tessellation)
+        rook = mm.sw_high(2, gdf=self.df_tessellation, contiguity='rook')
         check = [133, 134, 111, 112, 113, 114, 115, 121, 125]
         assert from_sw.neighbors[0] == check
         assert from_df.neighbors[0] == check
+        assert rook.neighbors[0] == check
 
         with pytest.raises(Warning):
-            mm.Queen_higher(2, geodataframe=None, weights=None)
+            mm.sw_high(2, gdf=None, weights=None)
 
         with pytest.raises(ValueError):
-            gdf = self.df_tessellation
-            gdf.index = gdf.index + 20
-            mm.Queen_higher(2, geodataframe=gdf, weights=None)
+            mm.sw_high(2, gdf=self.df_tessellation, contiguity='nonexistent')
 
     def test_gdf_to_nx(self):
         nx = mm.gdf_to_nx(self.df_streets)