[GIS] Length of intersections from a linestring and a grid shapefile by using Python GeoPandas & QGIS

geopandasintersectionlinepolygonpython

I am using Python GeoPandas and I have two shapefiles. One of them is a grid file containing equal polygons. The other shapefile is a linestring file with several lines and its Attributes.

The idea is to do a multiplication with the intersection length of each individual line within a grid cell and finally sum up all multiplication results which belong to this certain grid cell. Each row is one grid cell in the grid shapefile. I need the length of each intersection which is inside a grid cell. So there might be only one grid cell, but multiple intersections within this certain grid cell.

This simple multiplication should be like this:

df['new_column_result']= line['intersection_length_inside _cell_i']*line['factor_x']

And afterwards use this multiplication to calculate the sum of all df['new_column_result'] that are in the cell.

Additionally, the grid cells which are not touching any lines at all should be removed and the two shapefiles should be merged as an output. This part I managed to do by using the sjoin function of GeoPandas, but I am not sure if it is suitable for my goals. Sadly at the moment I get the same grid cell (with the same grid cell ID) multiple times. I guess it is produced for each "intersection_length_inside _cell_i".

For joining this two dataframes(or shapefiles) I use:

intersections = geopandas.sjoin(gridshapefile, lineshapefile, how="inner", op='intersects')

enter image description here

Best Answer

Here is one way to do it (the simplified way ) :

let's suppose that in each shapefile you have a unique column called index, if you don't you can create it by reindexing the DataFrame

 lines.reset_index(inplace = True)
 grids.reset_index(inplace = True)

1 - first apply a spatial join between both of your shapefiles, with operation within to avoid extreme cases when a line only touches the border of a grid

sjoin = geopandas.sjoin(lines, grids, how='inner', op='within')

2- then for each grid get a list of lines geometries that are within it:

grids['lines_within_geoms'] = grids['index'].apply(lambda x: sjoin[sjoin['index_right'] == x]['geometry'].tolist())

3- same for the column factor_x

grids['lines_within_factors'] = grids['index'].apply(lambda x: sjoin[sjoin['index_right'] == x]['factor_x'].tolist())

4 - and at last combine shapely's intersection with length to get the final result

grids['result'] = None

for index, row in grids.iterrows():
    sum_intersections = 0

    for i in range(len(row['lines_within_geoms'])):
        sum_intersections += row['geometry'].intersection(row['lines_within_geoms'][i]).length * row['lines_within_factors'][i]

    grids.loc[index, 'result'] = sum_intersections

grids.drop(['lines_within_geoms', 'lines_within_factors'], axis = 1, inplace = True)
Related Question