import geopandas as gpd
from geopandas.tools import sjoin
for k, v in gdfLeftDict.items():
#create convexhull for the left geodfs
geometryLeft = v.geometry
gdfConvexhull = gpd.GeoDataFrame(geometry=geometryLeft)
gdfConvexhull = gdfConvexhull.set_crs('epsg:XXXX')
convexhull = gdfConvexhull.unary_union.convex_hull
df_convexhull = pd.DataFrame({'FeatureInLeftDF':k, 'geometry':[convexhull]})
gdf_convexhull = gpd.GeoDataFrame(df_convexhull, geometry='geometry')
gdf_convexhull = gdf_convexhull.set_crs('epsg:XXXX')
gdf_convexhull.sindex
#select the rigth dataframe for the current uniqueFeatureInBothDF in both DFsfeatrue/chunk
gdfRigthBeforeFiltering = gdfRigthDict[k]
#spatial index the data
gdfRigthBeforeFiltering.sindex
#filter the data
gdfRigthAfterFiltering = sjoin(
gdfRigthBeforeFiltering,
gdf_convexhull,
how="inner", #not left or rigth!
op="intersects",
)
gdfRigthAfterFiltering.drop("index_right", axis=1, inplace=True)
#update the rigth dictionary with the filtered data
gdfRigthDict[k] = gdfRigthAfterFiltering
import geopandas as gpd
from geopandas.tools import sjoin
for k, v in gdfLeftDict.items():
#create convexhull for the left geodfs
geometryLeft = v.geometry
gdfConvexhull = gpd.GeoDataFrame(geometry=geometryLeft)
gdfConvexhull = gdfConvexhull.set_crs('epsg:XXXX')
convexhull = gdfConvexhull.unary_union.convex_hull
df_convexhull = pd.DataFrame({'FeatureInLeftDF':k, 'geometry':[convexhull]})
gdf_convexhull = gpd.GeoDataFrame(df_convexhull, geometry='geometry')
gdf_convexhull = gdf_convexhull.set_crs('epsg:XXXX')
gdf_convexhull.sindex
#select the rigth dataframe for the current uniqueFeatureInBothDF in both DFs
gdfRigthBeforeFiltering = gdfRigthDict[k]
#spatial index the data
gdfRigthBeforeFiltering.sindex
#filter the data
gdfRigthAfterFiltering = sjoin(
gdfRigthBeforeFiltering,
gdf_convexhull,
how="inner", #not left or rigth!
op="intersects",
)
gdfRigthAfterFiltering.drop("index_right", axis=1, inplace=True)
#update the rigth dictionary with the filtered data
gdfRigthDict[k] = gdfRigthAfterFiltering
import geopandas as gpd
from geopandas.tools import sjoin
for k, v in gdfLeftDict.items():
#create convexhull for the left geodfs
geometryLeft = v.geometry
gdfConvexhull = gpd.GeoDataFrame(geometry=geometryLeft)
gdfConvexhull = gdfConvexhull.set_crs('epsg:XXXX')
convexhull = gdfConvexhull.unary_union.convex_hull
df_convexhull = pd.DataFrame({'FeatureInLeftDF':k, 'geometry':[convexhull]})
gdf_convexhull = gpd.GeoDataFrame(df_convexhull, geometry='geometry')
gdf_convexhull = gdf_convexhull.set_crs('epsg:XXXX')
gdf_convexhull.sindex
#select the rigth dataframe for the current featrue/chunk
gdfRigthBeforeFiltering = gdfRigthDict[k]
#spatial index the data
gdfRigthBeforeFiltering.sindex
#filter the data
gdfRigthAfterFiltering = sjoin(
gdfRigthBeforeFiltering,
gdf_convexhull,
how="inner", #not left or rigth!
op="intersects",
)
gdfRigthAfterFiltering.drop("index_right", axis=1, inplace=True)
#update the rigth dictionary with the filtered data
gdfRigthDict[k] = gdfRigthAfterFiltering
Data Preparation. When doing spatial operations between two geopandas dataframes, you can't just split the two and do multiprocessing, because then you'd just be trying to spatially connect certain chunks together. One can speed this up by creating chunks according to specific geographic regionssubregions, hopefully you have such as political boundariesa feature. You could do something likeFirst create a dictionary which splits your data by such a feature. So a key is the label of this: feature and the value contains the dataframe which has for the certain feature only the key value.
import geopandaspandas as gpd
from geopandas.tools import sjoinpd
# create#create 3unique chunkslist of spatialy filteredfeature gdfswhich accordingis toin stateboth boundariesgeodataframes
uniqueFeatureInLeftDF = gdfLeft.FeatureInLeftDF.unique()
#read in#create a filedata youframe wantdictionary to multiprocessstore lateryour ondata frames
gdfToFiltergdfLeftDict = gpd{elem : pd.read_fileDataFrame('path to) gdffor whichelem youin wantuniqueFeatureInLeftDF to}
for multiprocesskey laterin on'gdfLeftDict.keys():
#read in a file with boundaries thatgdfLeftDict[key] suits= yourgdfLeft[:][gdfLeft.FeatureInLeftDF== datakey]
gdfWithPoliticalBoundary
Do the above code again for the gdf you want to be joined, however in this case the value do not have to vary, since they will be filtered later on:
gdfRigthDict = gpd{elem : pd.read_fileDataFrame('path) tofor someelem politicalin boundaryuniqueFeatureInLeftDF shp,}
for gpkp,key gjson'in gdfRigthDict.keys()
:
#choose the regions with which yougdfRigthDict[key] want= togdfRigth
Now the data can be filtered by creating a convexhull for each unique value of the feature which splitted the left dataframe. Then this convexhull is used to reduce the right dataframe to rows which intersect the corresponding convexhull. (Concavhull would be better but at the moment geopandas has not such a built in function).
import splitgeopandas youras data,gpd
from yougeopandas.tools needimport tosjoin
for knowk, yourv datain wellgdfLeftDict.items():
for this step!
politicalBoundary_list =#create [['State9'],convexhull ['State2',for 'State5'],the ['State3']]left
geodfs
#empty list to store chunks
chunksLeft=geometryLeft []=
v.geometry
# filter the gdfToFilter bygdfConvexhull the= boundariesgpd.GeoDataFrame(geometry=geometryLeft)
from the list
for boundarygdfConvexhull in= politicalBoundary_listgdfConvexhull.set_crs('epsg:XXXX')
convexhull = gdfConvexhull.unary_union.convex_hull
#filterdf_convexhull the= regionspd.DataFrame({'FeatureInLeftDF':k, you'geometry':[convexhull]})
want to use forgdf_convexhull filtering= gpd.GeoDataFrame(df_convexhull, geometry='geometry')
gdfWithPoliticalBoundary_to_joingdf_convexhull = gdfWithPoliticalBoundary[gdfWithPoliticalBoundary.BOUNDARYgdf_convexhull.isinset_crs(boundary'epsg:XXXX')]
gdf_convexhull.sindex
#speed#select upthe spatialrigth joindataframe byfor indexingthe ancurrent r-treeuniqueFeatureInBothDF in both DFs
gdfToFilter.sindexgdfRigthBeforeFiltering = gdfRigthDict[k]
gdfWithPoliticalBoundary_to_join#spatial index the data
gdfRigthBeforeFiltering.sindex
gdfFiltered#filter the data
gdfRigthAfterFiltering = sjoin(
gdfToFiltergdfRigthBeforeFiltering,
gdfWithPoliticalBoundary_to_joingdf_convexhull,
how="inner", #not left or rigth!
op="intersects",
)
gdfFilteredgdfRigthAfterFiltering.drop("index_right", axis=1, inplace=True)
#store#update the rigth dictionary with the filtered gdfsdata
chunksLeft.append(gdfFiltered)gdfRigthDict[k] = gdfRigthAfterFiltering
You need to apply the above code to the second GeoDataFrames you want to multiply the function with later, and in this case store them in a list named chunksRigth. InIn general, in order to speed up a join, filter your dataframes first! So if date is also a criteria, you could also filter your dataframes by date before applying spatial operations.
def multiprocessSpatialJoin(gdfLeft, gdfRigth):
gdf_LeftJoin = sjoin(
gdfLeft,
gdfRigth,
how="left",
op="intersects",
)
gdf_LeftJoin.drop("index_right", axis=1, inplace=True)
return gdf_LeftJoin
import multiprocessing as mp
from pythonScripts.multiprocessFunctions import multiprocessSpatialJoin
if __name__ == '__main__':
#5=number of cores used
p = mp.Pool(5)
#starmap allows to insert two variables, the order and length of the two lists must be the same
#you want to join the two gdfs of the same region
results = p.starmap(multiprocessSpatialJoin, zip(chunksLeftlist(gdf_pointsDict.values()), chunksRigthlist(gdf_linesDict.values())))
#stop running
p.close()
#join the results
p.join()
#store the joined results if necessary can be concatet
gdf_spatial_joins_list = [x for x in results]
Data Preparation. When doing spatial operations between two geopandas dataframes, you can't just split the two and do multiprocessing, because then you'd just be trying to spatially connect certain chunks together. One can speed this up by creating chunks according to specific geographic regions, such as political boundaries. You could do something like this:
import geopandas as gpd
from geopandas.tools import sjoin
# create 3 chunks of spatialy filtered gdfs according to state boundaries
#read in a file you want to multiprocess later on
gdfToFilter = gpd.read_file('path to gdf which you want to multiprocess later on')
#read in a file with boundaries that suits your data
gdfWithPoliticalBoundary = gpd.read_file('path to some political boundary shp, gpkp, gjson')
#choose the regions with which you want to split your data, you need to know your data well for this step!
politicalBoundary_list = [['State9'], ['State2', 'State5'], ['State3']]
#empty list to store chunks
chunksLeft= []
# filter the gdfToFilter by the boundaries from the list
for boundary in politicalBoundary_list:
#filter the regions you want to use for filtering
gdfWithPoliticalBoundary_to_join = gdfWithPoliticalBoundary[gdfWithPoliticalBoundary.BOUNDARY.isin(boundary)]
#speed up spatial join by indexing an r-tree
gdfToFilter.sindex
gdfWithPoliticalBoundary_to_join.sindex
gdfFiltered = sjoin(
gdfToFilter,
gdfWithPoliticalBoundary_to_join,
how="inner",
op="intersects",
)
gdfFiltered.drop("index_right", axis=1, inplace=True)
#store the filtered gdfs
chunksLeft.append(gdfFiltered)
You need to apply the above code to the second GeoDataFrames you want to multiply the function with later, and in this case store them in a list named chunksRigth. In general, in order to speed up a join, filter your dataframes first! So if date is also a criteria, you could also filter your dataframes by date before applying spatial operations.
def multiprocessSpatialJoin(gdfLeft, gdfRigth):
gdf_LeftJoin = sjoin(
gdfLeft,
gdfRigth,
how="left",
op="intersects",
)
gdf_LeftJoin.drop("index_right", axis=1, inplace=True)
return gdf_LeftJoin
import multiprocessing as mp
from pythonScripts.multiprocessFunctions import multiprocessSpatialJoin
if __name__ == '__main__':
#5=number of cores used
p = mp.Pool(5)
#starmap allows to insert two variables, the order and length of the two lists must be the same
#you want to join the two gdfs of the same region
results = p.starmap(multiprocessSpatialJoin, zip(chunksLeft, chunksRigth))
#stop running
p.close()
#join the results
p.join()
#store the joined results if necessary can be concatet
gdf_spatial_joins_list = [x for x in results]
Data Preparation. When doing spatial operations between two geopandas dataframes, you can't just split the two and do multiprocessing, because then you'd just be trying to spatially connect certain chunks together. One can speed this up by creating chunks according to specific geographic subregions, hopefully you have such a feature. First create a dictionary which splits your data by such a feature. So a key is the label of this feature and the value contains the dataframe which has for the certain feature only the key value.
import pandas as pd
#create unique list of feature which is in both geodataframes
uniqueFeatureInLeftDF = gdfLeft.FeatureInLeftDF.unique()
#create a data frame dictionary to store your data frames
gdfLeftDict = {elem : pd.DataFrame() for elem in uniqueFeatureInLeftDF }
for key in gdfLeftDict.keys():
gdfLeftDict[key] = gdfLeft[:][gdfLeft.FeatureInLeftDF== key]
Do the above code again for the gdf you want to be joined, however in this case the value do not have to vary, since they will be filtered later on:
gdfRigthDict = {elem : pd.DataFrame() for elem in uniqueFeatureInLeftDF }
for key in gdfRigthDict.keys():
gdfRigthDict[key] = gdfRigth
Now the data can be filtered by creating a convexhull for each unique value of the feature which splitted the left dataframe. Then this convexhull is used to reduce the right dataframe to rows which intersect the corresponding convexhull. (Concavhull would be better but at the moment geopandas has not such a built in function).
import geopandas as gpd
from geopandas.tools import sjoin
for k, v in gdfLeftDict.items():
#create convexhull for the left geodfs
geometryLeft = v.geometry
gdfConvexhull = gpd.GeoDataFrame(geometry=geometryLeft)
gdfConvexhull = gdfConvexhull.set_crs('epsg:XXXX')
convexhull = gdfConvexhull.unary_union.convex_hull
df_convexhull = pd.DataFrame({'FeatureInLeftDF':k, 'geometry':[convexhull]})
gdf_convexhull = gpd.GeoDataFrame(df_convexhull, geometry='geometry')
gdf_convexhull = gdf_convexhull.set_crs('epsg:XXXX')
gdf_convexhull.sindex
#select the rigth dataframe for the current uniqueFeatureInBothDF in both DFs
gdfRigthBeforeFiltering = gdfRigthDict[k]
#spatial index the data
gdfRigthBeforeFiltering.sindex
#filter the data
gdfRigthAfterFiltering = sjoin(
gdfRigthBeforeFiltering,
gdf_convexhull,
how="inner", #not left or rigth!
op="intersects",
)
gdfRigthAfterFiltering.drop("index_right", axis=1, inplace=True)
#update the rigth dictionary with the filtered data
gdfRigthDict[k] = gdfRigthAfterFiltering
In general, in order to speed up a join, filter your dataframes first! So if date is also a criteria, you could also filter your dataframes by date before applying spatial operations.
def multiprocessSpatialJoin(gdfLeft, gdfRigth):
gdf_LeftJoin = sjoin(
gdfLeft,
gdfRigth,
how="left",
op="intersects",
)
gdf_LeftJoin.drop("index_right", axis=1, inplace=True)
return gdf_LeftJoin
import multiprocessing as mp
from pythonScripts.multiprocessFunctions import multiprocessSpatialJoin
if __name__ == '__main__':
#5=number of cores used
p = mp.Pool(5)
#starmap allows to insert two variables, the order and length of the two lists must be the same
results = p.starmap(multiprocessSpatialJoin, zip(list(gdf_pointsDict.values()), list(gdf_linesDict.values())))
#stop running
p.close()
#join the results
p.join()
#store the joined results if necessary can be concatet
gdf_spatial_joins_list = [x for x in results]
import geopandas as gpd
from geopandas.tools import sjoin
# create 3 chunks of spatialy filtered gdfs according to state boundaries
#read in a file you want to multiprocess later on
gdfToFilter = gpd.read_file('path to gdf which you want to multiprocess later on')
#read in a file with boundaries that suits your data
gdfWithPoliticalBoundary = gpd.read_file('path to some political boundary shp, gpkp, gjson')
#choose the regions with which you want to split your data, you need to know your data well for this step!
politicalBoundary_list = [['State9'], ['State2', 'State5'], ['State3']]
#empty list to store chunks
chunksLeft= []
# filter the gdfToFilter by the boundaries from the list
for boundary in politicalBoundary_list:
#filter the regions you want to use for filtering
gdfWithPoliticalBoundary_to_join = gdfWithPoliticalBoundary[gdfWithPoliticalBoundary.BOUNDARY.isin(boundary)]
#speed up spatial join by indexing an r-tree
gdfToFilter.sindex
gdfWithPoliticalBoundary_to_join.sindex
gdfFiltered = sjoin(
gdfToFilter,
gdfWithPoliticalBoundary_to_join,
how="inner",
op="intersects",
)
gdfFiltered.drop("index_right", axis=1, inplace=True)
#store the filtered gdfs
chunksLeft.append(gdfFiltered)
import geopandas as gpd
from geopandas.tools import sjoin
# create 3 chunks of spatialy filtered gdfs according to state boundaries
#read in a file you want to multiprocess later on
gdfToFilter = gpd.read_file('path to gdf which you want to multiprocess later on')
#read in a file with boundaries that suits your data
gdfWithPoliticalBoundary = gpd.read_file('path to some political boundary shp, gpkp, gjson')
#choose the regions with which you want to split your data, you need to know your data well for this step!
politicalBoundary_list = [['State9'], ['State2', 'State5'], ['State3']]
#empty list to store chunks
chunksLeft= []
# filter the gdfToFilter by the boundaries from the list
for boundary in politicalBoundary_list:
#filter the regions you want to use for filtering
gdfWithPoliticalBoundary_to_join = gdfWithPoliticalBoundary[gdfWithPoliticalBoundary.BOUNDARY.isin(boundary)]
#speed up spatial join
gdfToFilter.sindex
gdfWithPoliticalBoundary_to_join.sindex
gdfFiltered = sjoin(
gdfToFilter,
gdfWithPoliticalBoundary_to_join,
how="inner",
op="intersects",
)
gdfFiltered.drop("index_right", axis=1, inplace=True)
#store the filtered gdfs
chunksLeft.append(gdfFiltered)
import geopandas as gpd
from geopandas.tools import sjoin
# create 3 chunks of spatialy filtered gdfs according to state boundaries
#read in a file you want to multiprocess later on
gdfToFilter = gpd.read_file('path to gdf which you want to multiprocess later on')
#read in a file with boundaries that suits your data
gdfWithPoliticalBoundary = gpd.read_file('path to some political boundary shp, gpkp, gjson')
#choose the regions with which you want to split your data, you need to know your data well for this step!
politicalBoundary_list = [['State9'], ['State2', 'State5'], ['State3']]
#empty list to store chunks
chunksLeft= []
# filter the gdfToFilter by the boundaries from the list
for boundary in politicalBoundary_list:
#filter the regions you want to use for filtering
gdfWithPoliticalBoundary_to_join = gdfWithPoliticalBoundary[gdfWithPoliticalBoundary.BOUNDARY.isin(boundary)]
#speed up spatial join by indexing an r-tree
gdfToFilter.sindex
gdfWithPoliticalBoundary_to_join.sindex
gdfFiltered = sjoin(
gdfToFilter,
gdfWithPoliticalBoundary_to_join,
how="inner",
op="intersects",
)
gdfFiltered.drop("index_right", axis=1, inplace=True)
#store the filtered gdfs
chunksLeft.append(gdfFiltered)