5

I have a series of many GeoPandas Polygon objects, each with an associated exposure time. My goal is to find the union of all the Polygons in order to create an exposure time map.

For each Polygon in the final exposure map, I want to have the total exposure time, which is defined as the sum of the exposure times of each overlapping Polygon.

I think I have it working for the case of 2 geodataframes:

import geopandas as gpd
import numpy as np
from rtree import index
from shapely.geometry import Polygon
from shapely.ops import unary_union


coordinates1a = [(1,1), (1, 2), (2, 2), (2, 1)]
coordinates1b = [(2.1,2.1), (2.1, 3.1), (3.1, 3.1), (3.1, 2.1)]
coordinates2a = [(0.5,0.5), (0.5, 1.5), (1.5, 1.5), (1.5, 0.5)]
coordinates2b = [(1.6,1.6), (1.6, 2.6), (2.6, 2.6), (2.6, 1.6)]

# Create a Shapely polygon from the coordinate-tuple lists
poly1a = Polygon(coordinates1a)
poly1b = Polygon(coordinates1b)
poly2a = Polygon(coordinates2a)
poly2b = Polygon(coordinates2b)

polys1 = gpd.GeoSeries([poly1a, poly1b])
polys2 = gpd.GeoSeries([poly2a, poly2b])

# Create geodataframes
df1 = gpd.GeoDataFrame({'geometry': polys1, 'df1':[1,2], 'exposure_time': 10.7})
df2 = gpd.GeoDataFrame({'geometry': polys2, 'df2':[1,2], 'exposure_time': 9.7})

res_union = gpd.overlay(df1, df2, how='union')

# Find the list of all exposure time column names
exp_cols = [c for c in res_union.columns if 'exposure_time' in c]

# Sum the contributing exposure times in each polygon of the union
for i in range(len(res_union)):
    exptime = np.sum(res_union.loc[i, exp_cols])
    all_exptimes.append(exptime)
    res_union.loc[i, 'total_exposure_time'] = exptime
    res_union.loc[i, 'area'] = res_union.loc[i, 'geometry'].area

How do I do the same for the case of N geodataframes, where N might be tens or hundreds?

I tried using an rtree index and unary_union(), but couldn't quite get it to work, plus that only seemed to work on the Polygons themselves rather than the geodataframes, meaning that the exposure time information was lost. I am a complete novice with GeoPandas, so maybe I'm missing something obvious, but after a lot of searching and reading documentation yesterday, I'm stumped.

# Try using rtree
df_array = [df1, df2]
polygon_array = [poly1a, poly1b, poly2a, poly2b]

# Need to populate the index with Polygons, rather than geodataframes,
# so how do we keep track of the exposure time information?
intersections = []
idx = index.Index()
pos = 0
for polygons in df_array:
    for index in range(len(polygons)):
        idx.insert(pos, polygons.loc[index, 'geometry'].bounds)
        pos += 1

# This seems like the more natural way to do it, but exposure time
# info is not present
for polygon in polygon_array:
    merged_polygons = unary_union([polygon_array[pos] for pos in idx.intersection(polygon.bounds) if polygon_array[pos] != polygon])
    intersections.append(polygon.intersection(merged_polygons))

intersection = unary_union(intersections)

Here's an image of a case closer to what I eventually want to have. My goal is to have a total exposure time associated with each polygon. In this image, I'm showing the union of three geodataframes, where each geodataframe contains 4 non-overlapping squares. The squares' locations relative to one another are fixed across all geodataframes, but all 4 squares can shift as a unit, from geodataframe to geodataframe.

Union of three geodataframes, where each geodataframe contains 4 non-overlapping squares. The squares' locations relative to one another are fixed, but all 4 squares can shift as a unit, from geodataframe to geodataframe.

1 Answer 1

1

You can use union together with reduce.

# -*- coding: utf-8 -*-
import geopandas as gpd
import shapely, numpy, uuid
from functools import reduce

#100 squares as wkt, many overlapping
wkts = ['Polygon ((409913 6434838, 409913 6435838, 410913 6435838, 410913 6434838, 409913 6434838))', 'Polygon ((427061 6435487, 427061 6436487, 428061 6436487, 428061 6435487, 427061 6435487))', 'Polygon ((410980 6431145, 410980 6432145, 411980 6432145, 411980 6431145, 410980 6431145))', 'Polygon ((413645 6436214, 413645 6437214, 414645 6437214, 414645 6436214, 413645 6436214))', 'Polygon ((417644 6429398, 417644 6430398, 418644 6430398, 418644 6429398, 417644 6429398))', 'Polygon ((415147 6432176, 415147 6433176, 416147 6433176, 416147 6432176, 415147 6432176))', 'Polygon ((424191 6433128, 424191 6434128, 425191 6434128, 425191 6433128, 424191 6433128))', 'Polygon ((420750 6440149, 420750 6441149, 421750 6441149, 421750 6440149, 420750 6440149))', 'Polygon ((425755 6431572, 425755 6432572, 426755 6432572, 426755 6431572, 425755 6431572))', 'Polygon ((424930 6436692, 424930 6437692, 425930 6437692, 425930 6436692, 424930 6436692))', 'Polygon ((420019 6428963, 420019 6429963, 421019 6429963, 421019 6428963, 420019 6428963))', 'Polygon ((415114 6431282, 415114 6432282, 416114 6432282, 416114 6431282, 415114 6431282))', 'Polygon ((415490 6439373, 415490 6440373, 416490 6440373, 416490 6439373, 415490 6439373))', 'Polygon ((418650 6436552, 418650 6437552, 419650 6437552, 419650 6436552, 418650 6436552))', 'Polygon ((427746 6432732, 427746 6433732, 428746 6433732, 428746 6432732, 427746 6432732))', 'Polygon ((415598 6431878, 415598 6432878, 416598 6432878, 416598 6431878, 415598 6431878))', 'Polygon ((421498 6429911, 421498 6430911, 422498 6430911, 422498 6429911, 421498 6429911))', 'Polygon ((412411 6432770, 412411 6433770, 413411 6433770, 413411 6432770, 412411 6432770))', 'Polygon ((419239 6439264, 419239 6440264, 420239 6440264, 420239 6439264, 419239 6439264))', 'Polygon ((411041 6434576, 411041 6435576, 412041 6435576, 412041 6434576, 411041 6434576))', 'Polygon ((419712 6437285, 419712 6438285, 420712 6438285, 420712 6437285, 419712 6437285))', 'Polygon ((419751 6434026, 419751 6435026, 420751 6435026, 420751 6434026, 419751 6434026))', 'Polygon ((422365 6432805, 422365 6433805, 423365 6433805, 423365 6432805, 422365 6432805))', 'Polygon ((421123 6431359, 421123 6432359, 422123 6432359, 422123 6431359, 421123 6431359))', 'Polygon ((421602 6438852, 421602 6439852, 422602 6439852, 422602 6438852, 421602 6438852))', 'Polygon ((426974 6433665, 426974 6434665, 427974 6434665, 427974 6433665, 426974 6433665))', 'Polygon ((417694 6429933, 417694 6430933, 418694 6430933, 418694 6429933, 417694 6429933))', 'Polygon ((426621 6438798, 426621 6439798, 427621 6439798, 427621 6438798, 426621 6438798))', 'Polygon ((411201 6429209, 411201 6430209, 412201 6430209, 412201 6429209, 411201 6429209))', 'Polygon ((416041 6436888, 416041 6437888, 417041 6437888, 417041 6436888, 416041 6436888))', 'Polygon ((415589 6432857, 415589 6433857, 416589 6433857, 416589 6432857, 415589 6432857))', 'Polygon ((424151 6438657, 424151 6439657, 425151 6439657, 425151 6438657, 424151 6438657))', 'Polygon ((419144 6431421, 419144 6432421, 420144 6432421, 420144 6431421, 419144 6431421))', 'Polygon ((409762 6438572, 409762 6439572, 410762 6439572, 410762 6438572, 409762 6438572))', 'Polygon ((416665 6440720, 416665 6441720, 417665 6441720, 417665 6440720, 416665 6440720))', 'Polygon ((427547 6441319, 427547 6442319, 428547 6442319, 428547 6441319, 427547 6441319))', 'Polygon ((418307 6432052, 418307 6433052, 419307 6433052, 419307 6432052, 418307 6432052))', 'Polygon ((422561 6430350, 422561 6431350, 423561 6431350, 423561 6430350, 422561 6430350))', 'Polygon ((425448 6438541, 425448 6439541, 426448 6439541, 426448 6438541, 425448 6438541))', 'Polygon ((413234 6438178, 413234 6439178, 414234 6439178, 414234 6438178, 413234 6438178))', 'Polygon ((414300 6440283, 414300 6441283, 415300 6441283, 415300 6440283, 414300 6440283))', 'Polygon ((414065 6435122, 414065 6436122, 415065 6436122, 415065 6435122, 414065 6435122))', 'Polygon ((414987 6436424, 414987 6437424, 415987 6437424, 415987 6436424, 414987 6436424))', 'Polygon ((414312 6432807, 414312 6433807, 415312 6433807, 415312 6432807, 414312 6432807))', 'Polygon ((427525 6436285, 427525 6437285, 428525 6437285, 428525 6436285, 427525 6436285))', 'Polygon ((425153 6438616, 425153 6439616, 426153 6439616, 426153 6438616, 425153 6438616))', 'Polygon ((416764 6432260, 416764 6433260, 417764 6433260, 417764 6432260, 416764 6432260))', 'Polygon ((415650 6432678, 415650 6433678, 416650 6433678, 416650 6432678, 415650 6432678))', 'Polygon ((424695 6432540, 424695 6433540, 425695 6433540, 425695 6432540, 424695 6432540))', 'Polygon ((421566 6432094, 421566 6433094, 422566 6433094, 422566 6432094, 421566 6432094))', 'Polygon ((417298 6431086, 417298 6432086, 418298 6432086, 418298 6431086, 417298 6431086))', 'Polygon ((425373 6439582, 425373 6440582, 426373 6440582, 426373 6439582, 425373 6439582))', 'Polygon ((415640 6439849, 415640 6440849, 416640 6440849, 416640 6439849, 415640 6439849))', 'Polygon ((417496 6433073, 417496 6434073, 418496 6434073, 418496 6433073, 417496 6433073))', 'Polygon ((420732 6439661, 420732 6440661, 421732 6440661, 421732 6439661, 420732 6439661))', 'Polygon ((418986 6434069, 418986 6435069, 419986 6435069, 419986 6434069, 418986 6434069))', 'Polygon ((419566 6436903, 419566 6437903, 420566 6437903, 420566 6436903, 419566 6436903))', 'Polygon ((410027 6433315, 410027 6434315, 411027 6434315, 411027 6433315, 410027 6433315))', 'Polygon ((413869 6434087, 413869 6435087, 414869 6435087, 414869 6434087, 413869 6434087))', 'Polygon ((415722 6435074, 415722 6436074, 416722 6436074, 416722 6435074, 415722 6435074))', 'Polygon ((420900 6428853, 420900 6429853, 421900 6429853, 421900 6428853, 420900 6428853))', 'Polygon ((417503 6433870, 417503 6434870, 418503 6434870, 418503 6433870, 417503 6433870))', 'Polygon ((420121 6438064, 420121 6439064, 421121 6439064, 421121 6438064, 420121 6438064))', 'Polygon ((420325 6433476, 420325 6434476, 421325 6434476, 421325 6433476, 420325 6433476))', 'Polygon ((418782 6432845, 418782 6433845, 419782 6433845, 419782 6432845, 418782 6432845))', 'Polygon ((422261 6436931, 422261 6437931, 423261 6437931, 423261 6436931, 422261 6436931))', 'Polygon ((415037 6428901, 415037 6429901, 416037 6429901, 416037 6428901, 415037 6428901))', 'Polygon ((412692 6436547, 412692 6437547, 413692 6437547, 413692 6436547, 412692 6436547))', 'Polygon ((412802 6434747, 412802 6435747, 413802 6435747, 413802 6434747, 412802 6434747))', 'Polygon ((425839 6437917, 425839 6438917, 426839 6438917, 426839 6437917, 425839 6437917))', 'Polygon ((418637 6430072, 418637 6431072, 419637 6431072, 419637 6430072, 418637 6430072))', 'Polygon ((419739 6430466, 419739 6431466, 420739 6431466, 420739 6430466, 419739 6430466))', 'Polygon ((413241 6430161, 413241 6431161, 414241 6431161, 414241 6430161, 413241 6430161))', 'Polygon ((426927 6435373, 426927 6436373, 427927 6436373, 427927 6435373, 426927 6435373))', 'Polygon ((415067 6432692, 415067 6433692, 416067 6433692, 416067 6432692, 415067 6432692))', 'Polygon ((422039 6438899, 422039 6439899, 423039 6439899, 423039 6438899, 422039 6438899))', 'Polygon ((416900 6433286, 416900 6434286, 417900 6434286, 417900 6433286, 416900 6433286))', 'Polygon ((421750 6429474, 421750 6430474, 422750 6430474, 422750 6429474, 421750 6429474))', 'Polygon ((426051 6431115, 426051 6432115, 427051 6432115, 427051 6431115, 426051 6431115))', 'Polygon ((423245 6436802, 423245 6437802, 424245 6437802, 424245 6436802, 423245 6436802))', 'Polygon ((420461 6433204, 420461 6434204, 421461 6434204, 421461 6433204, 420461 6433204))', 'Polygon ((420774 6436488, 420774 6437488, 421774 6437488, 421774 6436488, 420774 6436488))', 'Polygon ((410664 6429998, 410664 6430998, 411664 6430998, 411664 6429998, 410664 6429998))', 'Polygon ((412784 6432691, 412784 6433691, 413784 6433691, 413784 6432691, 412784 6432691))', 'Polygon ((421625 6438958, 421625 6439958, 422625 6439958, 422625 6438958, 421625 6438958))', 'Polygon ((427081 6437477, 427081 6438477, 428081 6438477, 428081 6437477, 427081 6437477))', 'Polygon ((426415 6432929, 426415 6433929, 427415 6433929, 427415 6432929, 426415 6432929))', 'Polygon ((424261 6429438, 424261 6430438, 425261 6430438, 425261 6429438, 424261 6429438))', 'Polygon ((424957 6433640, 424957 6434640, 425957 6434640, 425957 6433640, 424957 6433640))', 'Polygon ((427300 6441131, 427300 6442131, 428300 6442131, 428300 6441131, 427300 6441131))', 'Polygon ((411846 6441285, 411846 6442285, 412846 6442285, 412846 6441285, 411846 6441285))', 'Polygon ((420692 6437106, 420692 6438106, 421692 6438106, 421692 6437106, 420692 6437106))', 'Polygon ((412980 6435795, 412980 6436795, 413980 6436795, 413980 6435795, 412980 6435795))', 'Polygon ((423912 6437978, 423912 6438978, 424912 6438978, 424912 6437978, 423912 6437978))', 'Polygon ((418872 6435141, 418872 6436141, 419872 6436141, 419872 6435141, 418872 6435141))', 'Polygon ((415462 6430938, 415462 6431938, 416462 6431938, 416462 6430938, 415462 6430938))', 'Polygon ((415620 6437671, 415620 6438671, 416620 6438671, 416620 6437671, 415620 6437671))', 'Polygon ((425204 6431117, 425204 6432117, 426204 6432117, 426204 6431117, 425204 6431117))', 'Polygon ((416165 6433319, 416165 6434319, 417165 6434319, 417165 6433319, 416165 6433319))', 'Polygon ((413173 6430413, 413173 6431413, 414173 6431413, 414173 6430413, 413173 6430413))']

#Create 10 dataframes from them and store in frames list
frames = []
for i in range(10,110,10):
    subsetdata = (wkts[i-10:i])
    df = gpd.GeoDataFrame(geometry=[shapely.wkt.loads(poly) for poly in subsetdata], crs="epsg:3006")
    df["exposure_time"] = numpy.random.uniform(low=0.1, high=1, size=df.shape[0]).round(1)
    
    #The column names needs to be unique or union can fail, so I add a uuid string to each frames time column
    df = df.rename(columns={"exposure_time":f"time_{str(uuid.uuid4())[:4]}"})
    df = df[[col for col in df.columns if ("time" in col or "geom" in col)]] #Drop all columns but time and geometry
    frames.append(df)

#Union them 
unions = reduce(lambda frame1, frame2: gpd.overlay(frame1, frame2, how="union"), frames) #Union all frames
unions = unions.fillna(0)

#Sum the time columns
unions["totexp"] = unions[[c for c in unions.columns if "time" in c]].sum(axis=1)
unions.to_file(r"C:\GIS\data\testdata\unions.shp")

enter image description here

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.