0

I am new to python programming. I am trying to create a script that can update attributes in a base shapefile based on a .csv file when changes are made to the .csv file. I also want the script to create new point features from the .csv file if they do not already exist in the shapefile.

Does anyone have a similar script already?

Here is what I have so far:

import arcpy, os, sys
arcpy.env.overwriteOutput = True    
outFC = r"c:\Users\abneyr\Documents\Spatial_Data\Test.shp"          
inputFile = r"c:\Users\abneyr\Documents\Python_Class\Study_Excel.csv"   
coordsys = r"c:\Users\abneyr\Documents\Python_Class\lab08data\lab08\ShapeFiles\WGS_1984.prj"    

arcpy.env.workspace = os.path.dirname(outFC)    
featClass = os.path.basename(outFC)              
if arcpy.Exists(featClass):                     
    arcpy.Delete_management(featClass)

arcpy.CreateFeatureclass_management(arcpy.env.workspace, featClass, "MULTIPOINT", "", "", "", coordsys) 
fileRead = open(inputFile, 'r')
headerLine = fileRead.readline()
firstValue = headerLine.split(",")  
nameIndex = firstValue.index("Name")    
lines = fileRead.readlines()    
fileRead.close()    

boxDictionary = {}  
with arcpy.da.SearchCursor(featClass, "*") as seCursor:
    for line in lines:
        Value = line.split(",")
        key = Value[nameIndex]
        if key in seCursor:
            continue

        with arcpy.da.InsertCursor(featClass, "SHAPE@") as isCursor:
            if key not in boxDictionary:
                boxDictionary[key] = arcpy.Array()
                print("Add {0} into the record".format(key))
                if "Latitude" in line:
                    continue

                xCoord = float(Value[1])
                yCoord = float(Value[0])
                boxDictionary[key].add(arcpy.Point(xCoord, yCoord))
                print("Add {0} into the shapefile".format(key))
            isCursor.insertRow([arcpy.Multipoint(boxDictionary[key])])
  • The problem is you need to respond to an edit of the CSV, that would be an event interface.. while you can create an event layer from an XY table responding to a filesystem event is a little more tricky. Are you fluent in C#, VB.net or C++? Have a read of stackoverflow.com/questions/931093/… for C++ and docs.microsoft.com/en-us/dotnet/api/… for VB.net and C# and possibly stackoverflow.com/questions/182197/… for python. – Michael Stimson Dec 7 '18 at 2:42
  • Welcome to GIS SE. Please edit your question to include a single, focused question as well as any code you may have written (including where you are stuck). – Aaron Dec 7 '18 at 4:30
  • I added the code – UncleSam191 Dec 7 '18 at 4:40
  • What happens when you run the code that you have presented? – PolyGeo Dec 7 '18 at 4:59
  • It adds points to the shapefile, but it is adding duplicates of points when the script is ran more than once. I need to put some sort of check before the insert cursor that prevents this from happening, but I am unsure of how to do this. I was attempting to do this with the search cursor, but that did not work for me. – UncleSam191 Dec 7 '18 at 5:42
0

When working with arcpy cursors it's often easier to just grab all the records and work with the data using basic Python functions. If you're nesting cursors it could be a sign you're doing things the hard way.

So for your example we'll get all the records and put them in a dictionary, keyed by "NAME", where the value is a list of the CSV values.

Instead of using a search cursor to try to see if the name is already in the shapefile, we'll just grab all the names one time and throw them in a list. This lets you do easy-to-read stuff like if name in names:.

Then when we want to insert records, we can use dict.iteritems to get the CSV record's name, values, plus looping all in one line. If that name isn't in the list, insert it. Note: I don't have Arc anymore so I wrote this example from memory and some of the arcpy-specific code might not be right.

We also use with foo as bar: context managers so we don't have to worry about closing things.

The basic idea is:

# Get all of the records and put them in a dictionary
# the key is name, the value is a list of records
with open(inputFile, 'r') as csv:
    headerLine = fileRead.readline()
    header = headerLine.split(",")  
    nameIndex = header.index("Name")    
    points = {}
    for line in fileRead.readlines():
        values = line.split(",")
        points[values[nameIndex]] = values

# Use a search cursor to grab all the names that are in the shapefile 
# We'll do this once so we can do a fast lookup in memory
# instead of fumbling around with cursors
with arcpy.da.SearchCursor(featClass, "NAME") as seCursor:
    names = []
    for row in seCursor:
        names.append(row[0])

# Set up an insert cursor
# We'll add a row from the CSV records when we can't find the name
# in the list of names
with arcpy.da.InsertCursor(featClass, "SHAPE@", "NAME") as isCursor:
    for name, values in points.iteritems():
        if name not in names:
            print("Add {0} into the record".format(name))
            xCoord = float(values[1])
            yCoord = float(values[0])
            geom = arcpy.Multipoint([[xCoord, yCoord]]])
            isCursor.insertRow([geom, name])

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.