Optimised version of projecting coordinates on the fly

Last week I posted about creating a csv file containing coordinates projected on the fly. Seeing as I had to update the files as the projection information changed, I decided I might as well optimise my code. I managed to halve the amount of code and not write anything temporary to disk as the final output I want is non-spatial anyway.

'''
Created on 22 Sep 2014

@author: Cindy Williams

Project coordinates on the fly and write to csv
'''

import arcpy
import csv
import os

arcpy.env.overwriteOutput = True

fld = r"C:\Some\Arb\Folder"
sr_cape = arcpy.SpatialReference(r"C:\Some\Arb\Folder\cape17.prj")
sr_mines = arcpy.SpatialReference(r"C:\Some\Arb\Folder\Schwarzeck17_mines.prj")
fields = ["Field3", "SHAPE@XY"]
x_constant = 89
y_constant = 2000018

# Specify topdown=True so that it does not process the created csvs
for root, dirnames, filenames in os.walk(fld, topdown=True):
    for f in filenames:
        if f.endswith(".csv"):
            print "Processing " + f
            cur_csv = os.path.join(root, f)
            lyr = "XY_Layer"
            # Create XY Layer in the original CS
            arcpy.management.MakeXYEventLayer(cur_csv, "Field1", "Field2", lyr, sr_cape)
            print "\tCreated XY Event Layer"
            # Output csv filename created from splitting current csv filename
            final_csv = os.path.join(fld, "Schwarzeck17_" + f.rpartition(" ")[2])
            with open(final_csv, 'wb') as csvfile:
                csvwriter = csv.writer(csvfile)
                # Use a cursor to project the coordinates to the new CS
                with arcpy.da.SearchCursor(lyr, fields, "#", sr_mines) as cursor:
                    for row in cursor:
                        # Apply the constant and write to csv
                        csvwriter.writerow([row[1][0] - x_constant, row[1][1] - y_constant, row[0]])
            print "Processed " + final_csv
            # Clean up
            arcpy.management.Delete(lyr)
print "Script complete."

Project coordinates on the fly using Update Cursor

A colleague in our Namibian office recently asked me to project some points for him. Easy enough, except it was in a xyz file and it was a million points and the file was huge and their internet is not great (which is saying something, as our internet is abysmal). After splitting the file into 10 separate csv files and emailing them (I know, I know), I gave one file to another colleague who is a projections ninja (silently beats them into submission? I don’t know).

Once she had figured out the multiple issues (there are always multiple issues – “Can you quickly project this arb file for me” invariably turns into a full day escapade), it was time to automate the process for all the csvs. To Python!

'''
Created on 17 Sep 2014

@author: Cindy Williams

Process csv and project coordinates on the fly
Output new csv file
'''
import arcpy
import csv
import os

arcpy.env.overwriteOutput = True

in_fld = r"C:\Some\Arb\Folder"
out_fld = os.path.join(in_fld, "constant")
end_fld = os.path.join(in_fld, "schwarzeck")
gdb = r"C:\Some\Arb\Folder\working.gdb"
sr_nam = arcpy.SpatialReference(r"C:\Some\Arb\Folder\Schwarzeck17.prj")
sr_cape = arcpy.SpatialReference(r"C:\Some\Arb\Folder\cape17.prj")
lyr = "XY_Layer"
excl = ["constant", "schwarzeck"]

def checkPath(p):
    if not os.path.exists(p):
        os.mkdir(p)
        return "Created path " + p
    else:
        return "Path exists: " + p
    
print checkPath(out_fld)
print checkPath(end_fld)

for root, dirs, filenames in os.walk(in_fld, topdown=True):
    dirs[:] = [d for d in dirs if d not in excl] # Prune directories in-place
    for f in filenames:
        if f.endswith(".csv"):
            cur_csv = os.path.join(root, f)
            new_csv = os.path.join(out_fld, "CapeConstant_" + str(f.split(") ")[1]))
            
            # Read in the values and add the constant 
            with open(cur_csv, 'rb') as infile:
                with open(new_csv, 'wb') as outfile:
                    csvreader = csv.reader(infile)
                    csvwriter = csv.writer(outfile)
                    csvwriter.writerow(["y", "x", "z"])
                    for row in csvreader:
                        csvwriter.writerow([row[0], float(row[1]) - 2000000], row[2])
            print "Finished processing " + f

for root, dirs, filenames in os.walk(out_fld):
    for f in filenames:
        cur_xy = os.path.join(root, f)
        end_csv = os.path.join(end_fld, "Schwarzeck17_" + f.split("_")[1])
        ftr = os.path.join(gdb, f[:-4])
        # Create temporary points layer from coordinates in the csv
        arcpy.management.MakeXYEventLayer(cur_xy, "y", "x", lyr, sr_cape)
        print "Created XY Layer for " + f
        # Copy temp layer to disk
        arcpy.management.CopyFeatures(lyr, ftr)
        print "Created feature class"
        # Project on the fly and write new coordinates to csv
        with open(end_csv, 'wb') as csvfile:
            csvwriter = csv.writer(csvfile)
            with arcpy.da.UpdateCursor(ftr, ["SHAPE@XY", "z"], "#", sr_nam) as cursor:
                for row in cursor:
                    csvwriter.writerow([row[0][0], row[0][1], row[1]])
        print "Processed " + end_csv