Reorganize sides/edges into their appropriate polygons

Question:

How do I reorganize the result (list_) into their appropriate polygons?

We have several polygons

import geopandas as gpd
import matplotlib.pyplot as plt

polys = gpd.GeoSeries([Polygon([(0,0), (2,0), (2, 1.5), (2,2), (0,2)]),
                     Polygon([(0,2), (2,2), (2,4), (0,4)]),
                     Polygon([(2,0), (5,0), (5,1.5), (2,1.5)]),
                     Polygon([(3,3), (5,3), (5,5), (3,5)])])

fp = gpd.GeoDataFrame({'geometry': polys, 'name': ['a', 'b', 'c', 'd'],
                      'grnd': [25, 25, 25, 25],
                      'rf': [29, 35, 26, 31]})

fig, ax = plt.subplots(figsize=(5, 5))
fp.plot(ax=ax, alpha=0.3, cmap='tab10', edgecolor='k',)
fp.apply(lambda x: ax.annotate(text=x['name'], xy=x.geometry.centroid.coords[0], ha='center'), axis=1)
plt.show()

enter image description here

And we want to harvest some attribute (grnd or name or rf) on either side of an edge.

# Create a series of all the line segments
lines = fp.geometry.apply(lambda x: list(map(
    LineString, 
    zip(x.boundary.coords[:-1], x.boundary.coords[1:]))
)).explode()

result = {line : list(fp.loc[
          (fp.geometry.touches(line)) # line touches the polygon
          & (fp.geometry.intersection(line).length > 0), # And the intersection is more than just a point 
          'rf'].values)
          for line in lines}
result
{<LINESTRING (0 0, 2 0)>: [29],
 <LINESTRING (2 0, 2 1.5)>: [29, 26],
 <LINESTRING (2 1.5, 2 2)>: [29],
 <LINESTRING (2 2, 0 2)>: [29, 35],
 <LINESTRING (0 2, 0 0)>: [29],
 <LINESTRING (0 2, 2 2)>: [29, 35],
 <LINESTRING (2 2, 2 4)>: [35],
 <LINESTRING (2 4, 0 4)>: [35],
 <LINESTRING (0 4, 0 2)>: [35],
 <LINESTRING (2 0, 5 0)>: [26],
 <LINESTRING (5 0, 5 1.5)>: [26],
 <LINESTRING (5 1.5, 2 1.5)>: [26],
 <LINESTRING (2 1.5, 2 0)>: [29, 26],
 <LINESTRING (3 3, 5 3)>: [31],
 <LINESTRING (5 3, 5 5)>: [31],
 <LINESTRING (5 5, 3 5)>: [31],
 <LINESTRING (3 5, 3 3)>: [31]}

It’s possible to determine the number of sides/edges each polygon has:

s = fp.geometry.apply(lambda x: len(x.exterior.coords)) - 1
s
0    5
1    4
2    4
3    4
Name: geometry, dtype: int64

I can combine (without duplicates) and sort the attributes but do not know how to group the sides/edges into their polygons.

list_ = []
for k, v in result.items():
    l = [l.tolist() for l in result[k]]
    if len(l) > 1:
        list_.append(sorted(set(l)))
    else:
        list_.append(l)
print(list_)

[[29], [26, 29], [29], [29, 35], [29], [29, 35], [35], [35], [35], [26], [26], [26], [26, 29], [31], [31], [31], [31]]

How do I group list_ into their polygons; where a list (one level up from each edge) is a polygon? Something like.

[[[29], [26, 29], [29], [29, 35], [29]], 
[[29, 35], [35], [35], [35]],
[[26], [26], [26], [26, 29]], 
[[31], [31], [31], [31]]]
Asked By: arkriger

||

Answers:

Reorder within the original function that creates the ‘sides with common edges’ dict

with warnings.catch_warnings():
    warnings.simplefilter('ignore')
    result = {poly_name: {
        'sides': list(poly_sides),
        'edges': [list(fp.loc[
            (fp.geometry.touches(line)) # line touches the polygons
            & (fp.geometry.intersection(line).length > 0), # And the intersection is more than just a point 
            'rf'].values.tolist())
                  for line in poly_sides]}
              for poly_name, poly_sides in lines.groupby(fp.name)}
result
{'a': {'sides': [<LINESTRING (0 0, 2 0)>,
   <LINESTRING (2 0, 2 1.5)>,
   <LINESTRING (2 1.5, 2 2)>,
   <LINESTRING (2 2, 0 2)>,
   <LINESTRING (0 2, 0 0)>],
  'edges': [[29], [29, 26], [29], [29, 35], [29]]},
 'b': {'sides': [<LINESTRING (0 2, 2 2)>,
   <LINESTRING (2 2, 2 4)>,
   <LINESTRING (2 4, 0 4)>,
   <LINESTRING (0 4, 0 2)>],
  'edges': [[29, 35], [35], [35], [35]]},
 'c': {'sides': [<LINESTRING (2 0, 5 0)>,
   <LINESTRING (5 0, 5 1.5)>,
   <LINESTRING (5 1.5, 2 1.5)>,
   <LINESTRING (2 1.5, 2 0)>],
  'edges': [[26], [26], [26], [29, 26]]},
 'd': {'sides': [<LINESTRING (3 3, 5 3)>,
   <LINESTRING (5 3, 5 5)>,
   <LINESTRING (5 5, 3 5)>,
   <LINESTRING (3 5, 3 3)>],
  'edges': [[31], [31], [31], [31]]}}
Answered By: arkriger
Categories: questions Tags: , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.