1

I'm working on a Python script that strips the GPS info from images and uses that info to create a shapefile from that info. Right now I have all the file names as keys to tuples of decimal degrees coordinates. This dictionary prints out like this:

{'IMG_2840.jpg': (39.08861111111111, 114.80472222222222), 'IMG_2823.jpg': (38.61611111111111, 119.88777777777777), 'IMG_2912.jpg': (41.97861111111111, 106.25500000000001), 'IMG_2859.jpg': (39.742777777777775, 112.19694444444444), 'IMG_2813.jpg': (39.200833333333335, 119.79416666666665), 'IMG_2790.jpg': (41.82111111111111, 121.72472222222221), 'IMG_2753.jpg': (41.72027777777778, 124.32249999999999), 'IMG_2916.jpg': (41.01388888888889, 105.97611111111111), 'IMG_2750.jpg': (42.50833333333333, 125.72888888888889)}

How would I take this dictionary and turn it into a shapefile so that the names of the files are the names of the points?

I would prefer an open source way such as shapely or ogr/gdal.

Here's the code that generated this list. It does not really deal with spatial data at all.

filelist = os.listdir(Path)
for f in filelist:
    if f.endswith(".jpg"):
        with open(Path + "/" + f, 'r') as I:
            print(I)
            img = Image.open(Path + "/" + f)
            exif = {ExifTags.TAGS[k]: v for k, v in img._getexif().items() if k in ExifTags.TAGS}
            print(exif)
            meta = exif['GPSInfo'][2]
            meta = [x[0] for x in meta]
            d = meta[0]
            m = meta[1]
            s = meta[2]
            NCDict[os.path.basename(I.name)] = dms_to_dd(d=d,m=m,s=s)
            # Ncoords = {I:dms_to_dd(d=d, m=m, s=s)}
            # print(Ncoords)
            meta2 = exif['GPSInfo'][4]
            meta2 = [b[0] for b in meta2]
            d = meta2[0]
            m = meta2[1]
            s = meta2[2]
            WCDict[os.path.basename(I.name)] = dms_to_dd(d=d,m=m,s=s)
print NCDict
print WCDict

# writing xy coords to new file
corddict=[NCDict,WCDict]
finalCoord = {}
for k in NCDict.iterkeys():
    finalCoord[k] = tuple(finalCoord[k] for finalCoord in corddict)
print(finalCoord)
2

2 Answers 2

3

You don't need ArcPy here, simply use the geospatial pure Python modules as GeoPandas, Fiona, Shapely, pyshp (shapefile) or osgeo.ogr

# the resulting dictionary
dicto = {'IMG_2840.jpg': (39.08861111111111, 114.80472222222222), 'IMG_2823.jpg': (38.61611111111111, 119.88777777777777), 'IMG_2912.jpg': (41.97861111111111, 106.25500000000001), 'IMG_2859.jpg': (39.742777777777775, 112.19694444444444), 'IMG_2813.jpg': (39.200833333333335, 119.79416666666665), 'IMG_2790.jpg': (41.82111111111111, 121.72472222222221), 'IMG_2753.jpg': (41.72027777777778, 124.32249999999999), 'IMG_2916.jpg': (41.01388888888889, 105.97611111111111), 'IMG_2750.jpg': (42.50833333333333, 125.72888888888889)}

With GeoPandas

# convert to a GeoDataFrame
import geopandas as gpd
result = gpd.GeoDataFrame.from_dict(dicto, orient='index').reset_index() 
# rename the columns
result.columns = ['name','x','y']
print(result.head(3))
       name          x           y
0  IMG_2840.jpg  39.088611  114.804722
1  IMG_2823.jpg  38.616111  119.887778
2  IMG_2912.jpg  41.978611  106.255000
# create a shapely geometry column
from shapely.geometry import Point
result['geometry'] = result.apply(lambda row: Point(row.x, row.y), axis=1)
# print first row as control
print(result.head(1))
       name          x           y                             geometry
0  IMG_2840.jpg  39.088611  114.804722  POINT (39.08861111111111 114.8047222222222)
result.crs = "4326"
# save resulting shapefile
result.to_file("result.shp")

With Fiona:

import fiona
from shapely.geometry import mapping
from fiona.crs import from_epsg
# define the schema of the resulting shapefile
schema={'geometry': 'Point', 'properties': {'name':'str:10'}}
# create and save the resulting shapefile
with fiona.open('result2.shp', 'w',crs=from_epsg(4326),driver='ESRI Shapefile', schema=schema) as output:
   for key, value in dicto.items():
       point = Point(value[0],value[1])
       prop = prop = {'name':key}
       output.write({'geometry':mapping(point),'properties': prop})

With pyshp (without shapely)

import shapefile
w = shapefile.Writer(shapefile.POINT)
w.field('name', 'C')
for key, value in dicto.items():
   w.record(key) 
   w.point(value[0],value[1])
w.save("result3.shp")

enter image description here

1
  • Thanks! This is exactly what I was looking for! Commented May 1, 2019 at 22:06
0

From an arcpy perspective it's fairly easy to add to the end of your code:

# Create a point feature class
arcpy.CreateFeatureclass_management('c:\\your\\output\\path','OutputPoints.shp','POINT',spatial_reference=arcpy.SpatialReference(4326)) # assuming WGS84 geographic

# open an insert cursor on the output shapefile
with arcpy.da.InsertCursor(os.path.join('c:\\your\\output\\path','OutputPoints.shp'),'SHAPE@XY') as ICur:
    # loop through the dictionary
    for k in NCDict.iterkeys():
        # insert the point into the shapefile
        ICur.insertRow(NCDict[k])

This shows how to create a feature class (shapefile), start an insert cursor and insert new rows. Your dictionary contains tuples already which are suitable to be inserted directly when using the SHAPE@XY geometry type, see the examples in writing geometries.

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.