0

The following script was written with the goal of taking a raster file, importing into a ArcGIS database and creating several deliverables from it. All aspects of the script/tool are working except for the handling if the output file name exists. I don't want to overwrite as it could lead to problems if others are using this script. The solution I came up with was to append a '_i' to the output file name if the output path exists, with i=1 initially but i+=1 as long as the path exists until it reaches a file name that doesn't exist.

The problem seems to be when I use the functions GDBFCinc() (for items in a geodatabase that don't require an extension) or 'fileinc()' (for items that do require an extension) the script seems to ignore them. However, when I use their contents, i.e. not calling the function, but copying the contents and manually putting the variable in each spot, the output file increments correctly. As such I think I am calling the function wrong or in someway have defined it improperly. This is an early foray into using functions/modules so clearing up what I am doing wrong will help in the long run.

import arcpy, sys, os, fnmatch
from arcpy.sa import *
from datetime import datetime

#These functions had been in separate module, however, for trouble shooting purposes brought here. 
def GDBFCinc(n):
    '''Uses arcpy to check if a file path already exists and increments a numerical suffix until it does not. Works on Geodatbases.'''
    if not arcpy.Exists(n):
        pass
    else:
        i=1
        n = "{}_{}".format(n,i)
        while arcpy.Exists(n):
            i+=1
            n = "{}_{}".format(n,i)

def fileinc(n):
    '''Checks if a file path already exists and increments a numerical suffix before the file extension until it does not.'''
    if not os.path.exists(n):
        pass
    else:
        filename, file_extension = os.path.splitext(n)
        i=1
        n = "{}_{}{}".format(filename,i,file_extension)
        while arcpy.Exists(n):
            i+=1
            n = "{}_{}{}".format(filename,i,file_extension)

#This code is intended to go through each region and:
#1.Take the .ASC bathy surface dictated by user input and import it into the MBES Geodatabase with the client desired name and user dictated suffix
#2.Clip it to the regional polygon and create bilinear pyramids for that grid.
#3.Output that clipped file to ASC grid to the client data folder.
#4.Create 4 seperate hillshades and bilinear pyramids for those hillshades
#5.Create Aspect and Slope Grids and bilinear pyramids for those grids.
#6.Calculate Focal Statistics.
#7.Calculate 20m and 100m Contours.

#Set tool input parameters.
#Input Grid, File path,.
MBESRawPath = arcpy.GetParameterAsText(0)
#Region input, string.
region = arcpy.GetParameterAsText(1)
#Leg input, String
leg = arcpy.GetParameterAsText(2)
#User dicated Suffix, string.
SUF = arcpy.GetParameterAsText(3)
#Polygon for Clip, File Path.
poly = arcpy.GetParameterAsText(4)

#File Location Dictionary to be called based on region input value. Used for both root directory and clip polygon if no user input.
Rootdict = {"TG_Root":"D:\\J18350-TGS-WestAfrica\\Client\\GIS\\Geodatabases\\The-Gambia\\" , "TG_Poly":"A:\\J18350-TGS-WestAfrica_Leg_3\\Client\\GIS\\Shapefiles\\RegionalClippingBoundaries\\TG_ClippingPolygon.shp" , "GB_Root" : "D:\\J18350-TGS-WestAfrica\\Client\\GIS\\Geodatabases\\Guinea_Bissau\\", "GB_Poly" : "A:\\J18350-TGS-WestAfrica_Leg_2\\Client\\GIS\\Shapefiles\\RegionalClippingBoundaries\\GB_ClippingPolygon.shp", "AGC_Root" : "D:\\J18350-TGS-WestAfrica\\Client\\GIS\\Geodatabases\\AGC\\", "AGC_Poly" : "A:\\J18350-TGS-WestAfrica_Leg_2\\Client\\GIS\\Shapefiles\\RegionalClippingBoundaries\\AGC_ClippingPolygon.shp", "SN_Root": "D:\\J18350-TGS-WestAfrica\\Client\\GIS\\Geodatabases\\Senegal-North\\", "SN_Poly": "A:\\J18350-TGS-WestAfrica_Leg_2\\Client\\GIS\\Shapefiles\\RegionalClippingBoundaries\\SN_ClippingPolygon.shp", "SS_Root" :"D:\\J18350-TGS-WestAfrica\\Client\\GIS\\Geodatabases\\Senegal-South\\", "SS_Poly" : "A:\\J18350-TGS-WestAfrica_Leg_2\\Client\\GIS\\Shapefiles\\RegionalClippingBoundaries\\SS_ClippingPolygon.shp"}
root = Rootdict[region + '_Root']

#Setup for user input suffix. Uses user input, prepending a '_', if user input = date then output current date, if no user input, = ""(blank).
date_object = datetime.now()
if SUF != "":
    Suffix = "_" + SUF
elif SUF == "date":
    Suffix = "_" + date_object
else:
    Suffix = ""

#Set up for user input poly. Uses user input file path or defaults to regional polygon if no user input.
if poly != "":
    clippoly = poly
else:
    clippoly = Rootdict[region + "_Poly"]

#Get the file name from the input path and parse it so the 'infile' variable = the file name with no extension .
T = ""
infilepath = os.path.split(MBESRawPath)
tmp = infilepath[-1].split(".")
infile = tmp[0]

#Create variables for various file paths.
MBESGDBPath = root + region + "_MBES_Bathymetry_Mosaics.gdb\\"
MBESOUTPATH =  "A:\\J18350-TGS-WestAfrica_Leg_" + leg + "\\Client\\Data\\MBES_Processed\\Bathymetry\\" + region + "\\"
MBESOUTFILENAME = MBESOUTPATH + "Mosaic_EM302_Bathymetry_15m" + Suffix + ".asc"
AspectFile = MBESGDBPath + "Mosaic_EM302_Aspect_15m" + Suffix
SlopeFile = MBESGDBPath + "Mosaic_EM302_Slope_15m" + Suffix
GDBFileName = MBESGDBPath + T + infile

#Check if file name begins with a number, if so the output file in the geodatabase will begin with T (ArcGIS quirk) and that needs to be reflected when referencing it.
numbers = "0123456789"
if infile[0] in numbers:
    T = "T"
else:
    T = ""


#Import user input raster to geodatabase
arcpy.RasterToGeodatabase_conversion(MBESRawPath, MBESGDBPath)

#Get Poly extents from the raster itself for use in the clipping process.
extent = arcpy.Describe(clippoly)
rectangle = str(extent.extent)

#Make 'bathyfile' variable that uses the earlier constructed current regions database path plus the client desired file name.
bathyfile = MBESGDBPath + "Mosaic_EM302_Bathymetry_15m" + Suffix
#Use GDBFCinc to increment 'bathyfile' if path exists in geodatabase to avoid overwrite error.
GDBFCinc(bathyfile)

#Clip imported raster to the current regions polygon.
arcpy.Clip_management(GDBFileName, rectangle, bathyfile, clippoly, 255 , "ClippingGeometry")
arcpy.BuildPyramids_management(bathyfile,"-1", "NONE", "BILINEAR", "DEFAULT","","")

#Increment 'MBESOUTFILENAME' if path exists in output directory. 
fileinc(MBESOUTFILENAME)
arcpy.RasterToASCII_conversion(bathyfile, MBESOUTFILENAME)

#Create variables for the hillshade file names so the can be manipulated more easily
H1 = MBESGDBPath + "Mosaic_EM302_Hillshade_Az315_Alt25_15m" + Suffix
H2 = MBESGDBPath + "Mosaic_EM302_Hillshade_Az225_Alt25_15m" + Suffix
H3 = MBESGDBPath + "Mosaic_EM302_Hillshade_Az135_Alt25_15m" + Suffix
H4 = MBESGDBPath + "Mosaic_EM302_Hillshade_Az45_Alt25_15m" + Suffix

#Create 4 different hillshades per the clients request. Build pyramids for each hillshade
GDBFCinc(H1)
arcpy.HillShade_3d(bathyfile, H1 , 315,25)
arcpy.BuildPyramids_management(H1,"-1", "NONE", "BILINEAR", "DEFAULT","","")
GDBFCinc(H2)
arcpy.HillShade_3d(bathyfile, H2 , 225,25)
arcpy.BuildPyramids_management(H2,"-1", "NONE", "BILINEAR", "DEFAULT","","")
GDBFCinc(H3)
arcpy.HillShade_3d(bathyfile, H3, 135,25)
arcpy.BuildPyramids_management(H3,"-1", "NONE", "BILINEAR", "DEFAULT","","")
GDBFCinc(H4)
arcpy.HillShade_3d(bathyfile, H4 , 45,25)
arcpy.BuildPyramids_management(H4,"-1", "NONE", "BILINEAR", "DEFAULT","","")

#Create Aspect and pyramids
GDBFCinc(AspectFile)
arcpy.Aspect_3d(bathyfile, AspectFile)
arcpy.BuildPyramids_management(AspectFile, "-1", "NONE", "BILINEAR", "DEFAULT","","")

# Create Slope Surface and pyramids
GDBFCinc(SlopeFile)
arcpy.Slope_3d(bathyfile, SlopeFile )
arcpy.BuildPyramids_management(SlopeFile, "-1", "NONE", "BILINEAR", "DEFAULT","","")

#Create Focal Stat surface for generating contours
outFocalStat = FocalStatistics(bathyfile, NbrRectangle(20,20,"CELL"),"MEAN","DATA")
outFocalStat.save(MBESGDBPath + "BathyFocalStats_1" + Suffix)

#Create 20m and 100m Contours
arcpy.Contour_3d(MBESGDBPath + "BathyFocalStats_1", MBESGDBPath + "Mosaic_EM302_BathymetryContours_20m" + Suffix, 20)
arcpy.Contour_3d(MBESGDBPath + "BathyFocalStats_1", MBESGDBPath + "Mosaic_EM302_BathymetryContours_100m" + Suffix, 100)


print "Complete"

I have been working on the lack of return. This is what I have so far, Still not working properly (not incrementing when file exists).

def GDBFCinc(n):
    '''Uses arcpy to check if a file path already exists and increments a numerical suffix until it does not. Works on Geodatbases.'''
    if not arcpy.Exists(n):
        pass
    else:
        i=1
        n = "{}_{}".format(n,i)
        while arcpy.Exists(n):
            i+=1
            n = "{}_{}".format(n,i)
    return n
def fileinc(n):
    '''Checks if a file path already exists and increments a numerical suffix before the file extension until it does not.'''
    if not os.path.exists(n):
        pass
    else:
        filename, file_extension = os.path.splitext(n)
        i=1
        n = "{}_{}{}".format(filename,i,file_extension)
        while arcpy.Exists(n):
            i+=1
            n = "{}_{}{}".format(filename,i,file_extension)
    return n
3
  • You have posted to much code if the problem is only the functions. Start by not combining path using +, instead use os.path.join. Your function is not returning anything, so they will return None by default
    – BERA
    May 1, 2019 at 15:19
  • Main issue I see is no return value and related variable assignment. Will elaborate in answer.
    – SMiller
    May 1, 2019 at 15:19
  • Bera, apologies on too much code. I was unsure if something in the way i was calling the function or otherwise could be the problem. May 1, 2019 at 15:28

1 Answer 1

0

To transfer data outside of a function definition, you need to use return with a value (or global variables, which are not pythonic and not recommended in most cases). For more see here:

It looks like you are wanting to change the value of the variable H1 based on the output from GDBFCinc. To do that, add a return to GDBFCinc, and assign the result of GDBFCinc(H1) to a variable, such as H1.

e.g.

def GDBFCinc(n):
    '''Uses arcpy to check if a file path already exists and increments a numerical suffix until it does not. Works on Geodatbases.'''
    if not arcpy.Exists(n):
        pass
    else:
        i=1
        n = "{}_{}".format(n,i)
        while arcpy.Exists(n):
            i+=1
            n = "{}_{}".format(n,i)
    return n

and

H1 = GDBFCinc(H1)

Similarly, add a return to fileinc, although I don't see that function referenced in your code snippet so can't advise whether it's being called properly.

2
  • @smilller. Your input was valuable and the function is now being called. However, instead of replacing the "_1" at the end of the file name, it is appending the incremented suffix i.e. "_1_2_3...). I find this strange, because again, when I Implement the body of the function directly in the code it works ("_1" replaced with "_2"). Could you give some insight as to what I might be doing wrong or maybe set me down the right path to fixing this? May 4, 2019 at 14:29
  • You are saving n to check against the list of filenames, then returning n (name_2_3). Save the basename separately and increment the name to check based on the basename + _x.
    – SMiller
    May 5, 2019 at 12:29

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.