1

I am trying to copy a selection of features from a shapefile to a separate shapefile, but I am stuck with trying to set the attributes of the separate shapefile to be the same as that of the original shapefile. I first thought about creating a list of attributes with the ' Name', 'Type', 'Width' and 'Precision' of each attribute and than use that list to define the attributes of the new shapefile. But I am unsure how to go about doing this?

My code so far is just constructing a list of existing attributes and creating a new shapefile:

attributes = []
for i in range(layerDef.GetFieldCount()):
    fieldName = layerDef.GetFieldDefn(i).GetName()
    fieldTypeCode = layerDef.GetFieldDefn(i).GetType()
    fieldType = layerDef.GetFieldDefn(i).GetFieldTypeName(fieldTypeCode)
    fieldWidth = layerDef.GetFieldDefn(i).GetWidth()
    GetPrecision = layerDef.GetFieldDefn(i).GetPrecision()
    attributesList = fieldName, fieldType, fieldWidth, GetPrecision
    attributes.append(attributesList)

newShapefile = driver.CreateDataSource("BuildingsFilter.shp")
srs = osr.SpatialReference()
srs.ImportFromWkt(DataSrsWkt)
newLayer = newShapefile.CreateLayer("BuildingsFilter, srs, geom_type = layer.GetLayerDefn().GetGeomType())
8

1) With ogr, see Fast tip: Filtering features using OGR Python for example

from osgeo import ogr
from os import remove
in_file= "shapefileA.shp"
out_file = "shapefileB.shp"
in_ds = ogr.Open( in_file )
in_lyr = in_ds.GetLayerByIndex(0)
if exists(out_file):
    remove(out_file)
driver_name = "ESRI Shapefile"
drv = ogr.GetDriverByName( driver_name )
out_ds = drv.CreateDataSource( out_file )
proj = in_lyr.GetSpatialRef()
out_lyr = out_ds.CreateLayer(out_file.split(".")[0],proj, ogr.wkbPoint )
# copy the schema of the original shapefile to the destination shapefile
lyr_def = in_lyr.GetLayerDefn ()
for i in range(lyr_def.GetFieldCount()):
    out_lyr.CreateField ( lyr_def.GetFieldDefn(i) )

##Writing the features
for feat in selection:
    out_lyr.CreateFeature(feat)

2) But it is much easier with Fiona (another OGR binding, all is Python dictionaries, many examples in GIS SE)

with fiona.open(in_file) as input:
    # The output has the same schema
    output_schema = input.schema.copy()
    # write a new shapefile
    with fiona.open(out_file , 'w', 'ESRI Shapefile',output_schema, crs=input.crs) as output:
        for elem in selection: 
             output.write(elem)
             # or output.write({'properties': elem['properties'],'geometry': elem['geometry']})

3) And with GeoPandas (Fiona + pandas)

import geopandas as gpd
input = gpd.read_file(in_file)
# show 4 first shapefile rows
input.head(4)
   Type  dip  dip_direct                  geometry
0    N   47         181  POINT (256690.6459337267 96921.05796609906)
1    R   60         175  POINT (256597.9054505839 97529.26299508238)
2    N   35         184  POINT (243734.4769253579 97348.09553964049)
3    N   35         198  POINT (244092.4983253977 97736.31151558728)
# select rows by values
selection = input.loc[input['dip'] > 60]
selection.head(4)
     Type  dip  dip_direct                                     geometry
11    R   70         146  POINT (247583.3848651695 95987.67605138522)
47    N   70         115    POINT (254177.4866783266 92510.493128259)
52    N   70         340  POINT (255987.0044773231 93405.54662835856)
53    N   70         348  POINT (256084.0584713098 93213.59539580709)

# save the resulting shapefile
selection.to_file(out_file) 
  • I used your first method and it worked, thank you. I will look into Fiona as well. – Tins Feb 28 '17 at 14:04
4

fiona is queen of this task (docs here).

import fiona

with fiona.open('input.shp') as source:
    source_schema = source.schema
    source_driver = source.driver
    source_crs = source.crs
    print(source_schema) # attribute fields & geometry def as dict
    print(source_driver) # "ESRI Shapefile"
    print(source_crs) # coordinate system

    with fiona.open('output.shp', 'w',
                    driver=source_driver,
                    crs=source_crs,
                    schema=source_schema) as shpout:
        for feature in source:
            # if feature should be written:
            shpout.write(feature)
  • Thank you for the reply, I applied the option without Fiona and it worked, but I'll have a look at Fiona regardless. – Tins Feb 28 '17 at 14:05

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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