Non-planar enforced touches#

import geopandas
import numpy
import matplotlib.pyplot as plt
import geoplanar
import libpysal
from shapely.geometry import Polygon
c1 = [[0,0], [0, 10], [10, 10], [10, 0], [0, 0]]
p1 = Polygon(c1)
c2 = [[10, 2], [20, 8], [20, 2], [10, 2]]
p2 = Polygon(c2)
gdf = geopandas.GeoDataFrame(geometry=[p1, p2])
base = gdf.plot(edgecolor='k', facecolor="none",alpha=0.5)
c1 = numpy.array(c1)
c2 = numpy.array(c2)
_ = base.scatter(c1[:,0], c1[:,1])
_ =base.scatter(c2[:,0], c2[:,1])
_images/6798dbaa594839a2562c580559bbd6bc0204cb1773576fcf35e5d520f641b747.png

The two polygons are visually contiguous share no vertices. This will result in the two polygons not being Queen neighbors, since a necessary (and sufficient) condition for the latter is at least one shared vertex.

w = libpysal.weights.Queen.from_dataframe(gdf)
/home/serge/anaconda3/envs/dev39/lib/python3.10/site-packages/libpysal/weights/weights.py:172: UserWarning: The weights matrix is not fully connected: 
 There are 2 disconnected components.
 There are 2 islands with ids: 0, 1.
  warnings.warn(message)

Detecting nonplanar touches#

geoplanar can detect and report nonplanar edges:

geoplanar.non_planar_edges(gdf)
defaultdict(set, {0: {1}})

Fixing nonplanar edges#

gdf1 = geoplanar.fix_npe_edges(gdf)
/home/serge/anaconda3/envs/dev39/lib/python3.10/site-packages/libpysal/weights/weights.py:172: UserWarning: The weights matrix is not fully connected: 
 There are 2 disconnected components.
 There are 2 islands with ids: 0, 1.
  warnings.warn(message)
geoplanar.non_planar_edges(gdf1)
defaultdict(set, {})
w1 = libpysal.weights.Queen.from_dataframe(gdf1)
w1.neighbors
{0: [1], 1: [0]}

Default is to work on a copy#

geoplanar.non_planar_edges(gdf)
/home/serge/anaconda3/envs/dev39/lib/python3.10/site-packages/libpysal/weights/weights.py:172: UserWarning: The weights matrix is not fully connected: 
 There are 2 disconnected components.
 There are 2 islands with ids: 0, 1.
  warnings.warn(message)
defaultdict(set, {0: {1}})
geoplanar.fix_npe_edges(gdf, inplace=True)
geometry
0 POLYGON ((0.00000 0.00000, 0.00000 10.00000, 1...
1 POLYGON ((10.00000 2.00000, 20.00000 8.00000, ...
geoplanar.non_planar_edges(gdf)
defaultdict(set, {})
w = libpysal.weights.Queen.from_dataframe(gdf)
w.neighbors
{0: [1], 1: [0]}

Handle MultiPolygons#

from shapely.geometry import MultiPolygon
c1 = [[0,0], [0, 10], [10, 10], [10, 0], [0, 0]]
p1 = Polygon(c1)
c2 = [[10, 2], [20, 8], [20, 2], [10, 2]]
p3 = Polygon([ [21, 2], [21, 4], [23,3] ])

#p2 = Polygon(c2)
p2 = MultiPolygon([Polygon(c2), p3])

gdf = geopandas.GeoDataFrame(geometry=[p1, p2])
base = gdf.plot(edgecolor='k', facecolor="none",alpha=0.5)
c1 = numpy.array(c1)
c2 = numpy.array(c2)
_ = base.scatter(c1[:,0], c1[:,1])
_ =base.scatter(c2[:,0], c2[:,1])
_images/06e152bf972f9cf042163d4bb1d7df4709746959454bfcc911e04acc082bda8c.png
res = geoplanar.non_planar_edges(gdf)
/home/serge/anaconda3/envs/dev39/lib/python3.10/site-packages/libpysal/weights/weights.py:172: UserWarning: The weights matrix is not fully connected: 
 There are 2 disconnected components.
 There are 2 islands with ids: 0, 1.
  warnings.warn(message)
res
defaultdict(set, {0: {1}})
gdf1 = geoplanar.fix_npe_edges(gdf)
/home/serge/anaconda3/envs/edu_concordance/lib/python3.9/site-packages/libpysal/weights/weights.py:172: UserWarning: The weights matrix is not fully connected: 
 There are 2 disconnected components.
 There are 2 islands with ids: 0, 1.
  warnings.warn(message)
gdf1.geometry[0].wkt
'POLYGON ((0 0, 0 10, 10 10, 10 2, 10 0, 0 0))'
gdf.geometry[0].wkt
'POLYGON ((0 0, 0 10, 10 10, 10 0, 0 0))'