Skip to content

Commit

Permalink
MAINT: compatibility, warning cleanup, test lint (#574)
Browse files Browse the repository at this point in the history
* compat, warning cleanup, test lint

* osmnx 2.0 compat

* two more
  • Loading branch information
martinfleis committed Apr 29, 2024
1 parent 8e93b6c commit 36b13f8
Show file tree
Hide file tree
Showing 20 changed files with 158 additions and 79 deletions.
2 changes: 1 addition & 1 deletion momepy/coins.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ class COINS:
-----
The LineStrings of the ``edge_gdf`` are not expected to overlap. If you are creating
it using OSMnx, don't forget to cast the graph to undirected using
``osmnx.get_undirected(G)`` prior converting it to a GeoDataFrame.
``osmnx.convert.to_undirected(G)`` prior converting it to a GeoDataFrame.
"""

def __init__(self, edge_gdf, angle_threshold=0):
Expand Down
19 changes: 16 additions & 3 deletions momepy/dimension.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,19 @@

import math

import geopandas as gpd
import numpy as np
import pandas as pd
import scipy as sp
import shapely
from packaging.version import Version
from tqdm.auto import tqdm

from .shape import _circle_radius

GPD_GE_10 = Version(gpd.__version__) >= Version("1.0dev")


__all__ = [
"Area",
"Perimeter",
Expand Down Expand Up @@ -903,7 +908,9 @@ def __init__(self, gdf, spatial_weights=None, verbose=True):
print("Calculating spatial weights...") if verbose else None
from libpysal.weights import Queen

spatial_weights = Queen.from_dataframe(gdf, silence_warnings=True)
spatial_weights = Queen.from_dataframe(
gdf, silence_warnings=True, use_index=False
)
print("Spatial weights ready...") if verbose else None
self.sw = spatial_weights

Expand All @@ -921,7 +928,11 @@ def __init__(self, gdf, spatial_weights=None, verbose=True):
to_join = components[components == comp].index
joined = geom.iloc[to_join]
# buffer to avoid multipolygons where buildings touch by corners only
dissolved = joined.buffer(0.01).unary_union
dissolved = (
joined.buffer(0.01).union_all()
if GPD_GE_10
else joined.buffer(0.01).unary_union
)
for b in to_join:
walls[b] = dissolved.exterior.length

Expand Down Expand Up @@ -986,7 +997,9 @@ def __init__(self, gdf, spatial_weights=None, mean=False, verbose=True):
print("Calculating spatial weights...") if verbose else None
from libpysal.weights import Queen

spatial_weights = Queen.from_dataframe(gdf, silence_warnings=True)
spatial_weights = Queen.from_dataframe(
gdf, silence_warnings=True, use_index=False
)
print("Spatial weights ready...") if verbose else None
self.sw = spatial_weights

Expand Down
26 changes: 16 additions & 10 deletions momepy/elements.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
]

GPD_GE_013 = Version(gpd.__version__) >= Version("0.13.0")
GPD_GE_10 = Version(gpd.__version__) >= Version("1.0dev")


def buffered_limit(gdf, buffer=100):
Expand All @@ -52,7 +53,9 @@ def buffered_limit(gdf, buffer=100):
>>> type(limit)
shapely.geometry.polygon.Polygon
"""
return gdf.buffer(buffer).unary_union
return (
gdf.buffer(buffer).union_all() if GPD_GE_10 else gdf.buffer(buffer).unary_union
)


class Tessellation:
Expand Down Expand Up @@ -242,7 +245,7 @@ def __init__(
)
else:
if isinstance(limit, gpd.GeoSeries | gpd.GeoDataFrame):
limit = limit.unary_union
limit = limit.union_all() if GPD_GE_10 else limit.unary_union

bounds = shapely.bounds(limit)
centre_x = (bounds[0] + bounds[2]) / 2
Expand Down Expand Up @@ -624,7 +627,9 @@ def __init__(self, tessellation, edges, buildings, id_name, unique_id):
how="difference",
)
cut = cut.explode(ignore_index=True)
weights = libpysal.weights.Queen.from_dataframe(cut, silence_warnings=True)
weights = libpysal.weights.Queen.from_dataframe(
cut, silence_warnings=True, use_index=False
)
cut["component"] = weights.component_labels
buildings_c = buildings.copy()
buildings_c.geometry = buildings_c.representative_point() # make points
Expand Down Expand Up @@ -986,15 +991,15 @@ def enclosures(
"""
if limit is not None:
if isinstance(limit, BaseGeometry):
limit = gpd.GeoSeries([limit])
limit = gpd.GeoSeries([limit], crs=primary_barriers.crs)
if limit.geom_type.isin(["Polygon", "MultiPolygon"]).any():
limit_b = limit.boundary
else:
limit_b = limit
barriers = pd.concat([primary_barriers.geometry, limit_b.geometry])
else:
barriers = primary_barriers
unioned = barriers.unary_union
unioned = barriers.union_all() if GPD_GE_10 else barriers.unary_union
polygons = polygonize(unioned)
enclosures = gpd.GeoSeries(list(polygons), crs=primary_barriers.crs)

Expand Down Expand Up @@ -1034,11 +1039,12 @@ def enclosures(
) # keep only those within original polygon
new += list(polygons[within])

final_enclosures = (
pd.concat(
[gpd.GeoSeries(enclosures).drop(unique), gpd.GeoSeries(new)]
).reset_index(drop=True)
).set_crs(primary_barriers.crs)
final_enclosures = pd.concat(
[
gpd.GeoSeries(enclosures).drop(unique),
gpd.GeoSeries(new, crs=primary_barriers.crs),
]
).reset_index(drop=True)

final_enclosures = gpd.GeoDataFrame(
{enclosure_id: range(len(final_enclosures))}, geometry=final_enclosures
Expand Down
2 changes: 1 addition & 1 deletion momepy/functional/_elements.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from packaging.version import Version

GPD_GE_013 = Version(gpd.__version__) >= Version("0.13.0")
GPD_GE_10 = Version(gpd.__version__) >= Version("1.0.0")
GPD_GE_10 = Version(gpd.__version__) >= Version("1.0dev")

__all__ = [
"morphological_tessellation",
Expand Down
5 changes: 4 additions & 1 deletion momepy/functional/tests/test_elements.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ def setup_method(self):
self.df_streets = gpd.read_file(test_file_path, layer="streets")
self.limit = mm.buffered_limit(self.df_buildings, 50)
self.enclosures = mm.enclosures(
self.df_streets, gpd.GeoSeries([self.limit.exterior])
self.df_streets,
gpd.GeoSeries([self.limit.exterior], crs=self.df_streets.crs),
)

def test_morphological_tessellation(self):
Expand Down Expand Up @@ -77,6 +78,7 @@ def test_morphological_tessellation_errors(self):
affinity.rotate(df.geometry.iloc[0], 12),
],
index=[144, 145, 146],
crs=df.crs,
),
]
)
Expand Down Expand Up @@ -155,6 +157,7 @@ def test_verify_tessellation(self):
Polygon([(x, y), (x, y + 1), (x + 1, y)]),
],
index=[144],
crs=df.crs,
),
]
)
Expand Down
14 changes: 12 additions & 2 deletions momepy/intensity.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,14 @@

import collections

import geopandas as gpd
import numpy as np
import pandas as pd
from packaging.version import Version
from tqdm.auto import tqdm # progress bar

GPD_GE_10 = Version(gpd.__version__) >= Version("1.0dev")

__all__ = [
"AreaRatio",
"Count",
Expand Down Expand Up @@ -247,7 +251,9 @@ def __init__(self, gdf, spatial_weights=None, verbose=True):
print("Calculating spatial weights...") if verbose else None
from libpysal.weights import Queen

spatial_weights = Queen.from_dataframe(gdf, silence_warnings=True)
spatial_weights = Queen.from_dataframe(
gdf, silence_warnings=True, use_index=False
)

self.sw = spatial_weights
# dict to store nr of courtyards for each uID
Expand All @@ -264,7 +270,11 @@ def __init__(self, gdf, spatial_weights=None, verbose=True):
to_join = components[components == comp].index
joined = gdf.loc[to_join]
# buffer to avoid multipolygons where buildings touch by corners only
dissolved = joined.geometry.buffer(0.01).unary_union
dissolved = (
joined.buffer(0.01).union_all()
if GPD_GE_10
else joined.buffer(0.01).unary_union
)
interiors = len(list(dissolved.interiors))
for b in to_join:
courtyards[b] = interiors # fill dict with values
Expand Down
21 changes: 11 additions & 10 deletions momepy/preprocessing.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,9 @@ def preprocess(
print("Loop", loop + 1, f"out of {loops}.") if verbose else None
blg.reset_index(inplace=True, drop=True)
blg["mm_uid"] = range(len(blg))
sw = libpysal.weights.contiguity.Rook.from_dataframe(blg, silence_warnings=True)
sw = libpysal.weights.contiguity.Rook.from_dataframe(
blg, silence_warnings=True, use_index=False
)
blg["neighbors"] = sw.neighbors.values()
blg["n_count"] = blg.apply(lambda row: len(row.neighbors), axis=1)
blg["circu"] = CircularCompactness(blg).series
Expand Down Expand Up @@ -152,7 +154,7 @@ def preprocess(
if not subset.empty:
geoms.append(blg[blg["mm_uid"] == j].iloc[0].geometry)
blg.drop(blg[blg["mm_uid"] == j].index[0], inplace=True)
new_geom = shapely.ops.unary_union(geoms)
new_geom = shapely.union_all(geoms)
blg.loc[blg.loc[blg["mm_uid"] == key].index[0], blg.geometry.name] = (
new_geom
)
Expand Down Expand Up @@ -238,13 +240,13 @@ def remove_false_nodes(gdf):

# remove incorrect geometries and append fixed versions
df = df.drop(merge)
final = gpd.GeoSeries(new).explode(ignore_index=True)
final = gpd.GeoSeries(new, crs=df.crs).explode(ignore_index=True)
if isinstance(gdf, gpd.GeoDataFrame):
return pd.concat(
[
df,
gpd.GeoDataFrame(
{df.geometry.name: final}, geometry=df.geometry.name
{df.geometry.name: final}, geometry=df.geometry.name, crs=df.crs
),
],
ignore_index=True,
Expand Down Expand Up @@ -757,7 +759,7 @@ def _selecting_rabs_from_poly(
rab_adj.index.name = "index"

# adding a hausdorff_distance threshold
rab_adj["hdist"] = 0
rab_adj["hdist"] = 0.0
# TODO: (should be a way to vectorize)
for i, group in rab_adj.groupby("index_right"):
for g in group.itertuples():
Expand Down Expand Up @@ -1312,7 +1314,7 @@ def _get_rebuilt_edges(
cols_drop = ["new_origin_pt", "new_destination_pt"]
new_edges_gdf = new_edges_gdf.drop(columns=cols_drop)

new_edges_gdf = new_edges_gdf.set_geometry("new_geometry", drop=True)
new_edges_gdf = new_edges_gdf.set_geometry("new_geometry")
new_edges_gdf.loc[:, "length"] = new_edges_gdf.length

# Update the indices:
Expand Down Expand Up @@ -1573,10 +1575,9 @@ def __init__(
# Polygonize street network
polygons = gpd.GeoSeries(
shapely.polygonize( # polygonize
[gdf.unary_union]
).geoms, # get parts of the collection from polygonize
crs=gdf.crs,
).explode(ignore_index=True) # shouldn't be needed but doesn't hurt to ensure
[gdf.dissolve().geometry.item()]
)
).explode(ignore_index=True)

# Store geometries as a GeoDataFrame
self.polygons = gpd.GeoDataFrame(geometry=polygons)
Expand Down
2 changes: 1 addition & 1 deletion momepy/tests/test_dimension.py
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ def test_StreetProfile(self):

# avoid infinity
blg = gpd.GeoDataFrame(
dict(height=[2, 5]),
{"height": [2, 5]},
geometry=[
Point(0, 0).buffer(10, cap_style=3),
Point(30, 0).buffer(10, cap_style=3),
Expand Down
6 changes: 4 additions & 2 deletions momepy/tests/test_distribution.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
import numpy as np
import pytest
import shapely
from packaging.version import Version
from libpysal.weights import Queen
from packaging.version import Version

import momepy as mm

Expand Down Expand Up @@ -173,7 +173,9 @@ def test_NeighboringStreetOrientationDeviation(self):
assert self.df_streets["dev"].mean() == pytest.approx(check)

def test_BuildingAdjacency(self):
sw = Queen.from_dataframe(self.df_buildings, ids="uID", silence_warnings=True)
sw = Queen.from_dataframe(
self.df_buildings, ids="uID", silence_warnings=True, use_index=False
)
swh = mm.sw_high(k=3, gdf=self.df_tessellation, ids="uID")
self.df_buildings["adj_sw"] = mm.BuildingAdjacency(
self.df_buildings,
Expand Down
6 changes: 4 additions & 2 deletions momepy/tests/test_diversity.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ def test_Gini(self):
self.df_tessellation.area - self.df_tessellation.area.mean()
)
with pytest.raises(ValueError):
mm.Gini(self.df_tessellation, "negative", self.sw, "uID").series
mm.Gini(self.df_tessellation, "negative", self.sw, "uID").series # noqa: B018
assert (
mm.Gini(self.df_tessellation, "area", self.sw_drop, "uID")
.series.isna()
Expand Down Expand Up @@ -220,7 +220,9 @@ def test_Percentile(self):

_data = {"uID": [9999], "area": 1.0}
_pgon = [Polygon(((0, 0), (0, 1), (1, 1), (1, 0)))]
_gdf = gpd.GeoDataFrame(_data, index=[9999], geometry=_pgon)
_gdf = gpd.GeoDataFrame(
_data, index=[9999], geometry=_pgon, crs=self.df_tessellation.crs
)

perc = mm.Percentiles(
pd.concat([self.df_tessellation, _gdf]),
Expand Down
Loading

0 comments on commit 36b13f8

Please sign in to comment.