2

I have a Linestrings' shapefile to which I added a column named "length". I want to set the length of each row (geometry) in that column. Here's my code :

import geopandas as gpd
from shapely.geometry import *
from shapely.ops import transform
from functools import partial
import pyproj

def addLengthField(shapefile, output):
shp = gpd.GeoDataFrame.from_file(shapefile)
shp['length'] = ''
shp.to_file(output)

addLengthField('./Shapefiles/curbs.shp', './Outputs/curbsWithLength.shp')

def setLengthValue(shapefile, output):
shp = gpd.GeoDataFrame.from_file(shapefile)
for index, row in shp.iterrows():
    geom = shape(row['geometry'])
   # since the result of geom.length is not in Meters, I wanted to make a transformation
    # Geometry transform partial function based on pyproj.transform
    project = partial(
        pyproj.transform,
        pyproj.Proj(init='EPSG:4152'),
        pyproj.Proj(init='EPSG:4152'))
    projectedCurbs = transform(project, geom)

    row['length'] = int(projectedCurbs.length)
    print row['length'] # length values are well displayed
    # Save the final output in another shapefile
shp.to_file(output)

setLengthValue('./Outputs/curbsWithLength.shp','.Outputs/finaloutput.shp')

When I run the script the printed values are well displayed but when I open the output shapefile in QGIS the length's column is empty! Any ideas on what could be wrong?

1 Answer 1

3

The problem is that you don't actually update the data frame column. Try printing the shp before the export and you will see that the length column is NaN.

There is no need to iterate the rows of data frame. It is more efficient to use the pandas.DataFrame.apply method. Here, we apply the calc_length function re-projecting lines and getting their length.

import geopandas as gpd
import shapely
from functools import partial
import pyproj

shapefile = r'C:\GIS\Temp\Roads.shp'
shp = gpd.GeoDataFrame.from_file(shapefile)

def calc_length(row):        
    project = partial(pyproj.transform,
                      pyproj.Proj(init='EPSG:26912'),
                      pyproj.Proj(init='EPSG:{}'.format(epsg_code)))

    shapely_geom = shapely.geometry.shape(row['geometry'])
    proj_line = shapely.ops.transform(project, shapely_geom) 
    return round(proj_line.length,2)

epsg_code = 3857
shp['LengWebMerc'] = shp.apply(calc_length,axis=1)

shp['LengSrc'] = shp['geometry'].length

print shp[['geometry','LengWebMerc','LengSrc']].head(5)
shp.to_file(r'C:\GIS\Temp\RoadsWithLengthCalc.shp')

Here I have calculated two new columns - one for the source coord system (can compare with the built-in column Shape_Leng) and one for WebMercator (3857).

                                            geometry  LengWebMerc  LengSrc
0  LINESTRING (298612.5652000001 4145761.7546, 29...      6328.80  5014.87
1  LINESTRING (298467.2676999997 4141110.3543, 29...      3148.88  2501.91
2  LINESTRING (300608.0926000001 4139778.65530000...      2867.44  2274.21
3  LINESTRING (300608.0926000001 4139778.65530000...        74.89    59.49
4  LINESTRING (300653.7907999996 4139740.57300000...         0.91     0.72
3
  • Thank you so much @Alex Tereshenkov for your answer! I didn't know that the apply method applies the function to each row. Thanks again
    – GeoSal
    Aug 7, 2016 at 11:49
  • Could you please take a look at my other question ? gis.stackexchange.com/questions/206066/…
    – GeoSal
    Aug 7, 2016 at 11:52
  • 1
    @Gisel, no problem at all! I know, pandas can be a bit confusing with the syntax and the logic of accessing rows. I posted an answer to your other question. Aug 8, 2016 at 8:09

Your Answer

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

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