Purpose

Fishnets are useful for a variety of projects and fields including conservation where it can be used to assign a reference code for unnamed sites and identify sites with a geographically unique name. The current fishnet tool in ArcGIS does not include a function to label each cell with a unique code. A tool available for labeling cells is the Grid Index Features tool but it only assigns cells in one format, A1 to A# in the first row, B1 to B# in the second row, AA1 to AA# in the 27th row, and so on. It does not use a format that pads numbers with zeros to maintain a cosnistent 3 or 5 character format, such as AA000 or A00.

Demand

I’m not the only person that has this problem. Many others want to label fishnets too. For example:

https://gis.stackexchange.com/questions/155022/controlling-label-attributes-of-grid-fishnet-index-using-arcgis-for-desktop-and

https://gis.stackexchange.com/questions/337055/add-excel-style-row-number-and-column-name-attributes-to-a-grid-index-in-arcgis

https://gis.stackexchange.com/questions/255512/automatically-name-rectangles-by-spatial-order-or-position-to-each-other

https://gis.stackexchange.com/questions/180688/insert-sequential-row-and-column-values-automatically-into-a-fishnet-dataset?rq=1

Description of Tool Output

Here I present a tool that can populate cells with a unique code in the format of A0, A00, A000, AA0, AA00, and AA000. The alphabet part of the assigned code starts with A (or AA) and goes up to Z (or ZZ) and the numeric part starts with 0 (or 00 or 000) and goes up to 9 (or 99 or 999). An example of the output is given in Figure 1. With a format of AA000, the first A is assigned to the first 26 columns, but each of those 26 columns has a unique alphabet (A to Z) for the second placeholder. Whereas the first 0 (first numerical placeholder) is assigned to the first 100 rows, the second 0 is assigned to the first 10 columns, and within the first 10 columns, each row has a unique number (0 to 9) for the third numerical placeholder. This format can have 676 000 unique cell codes.

If this is something you want to create for your fishnet, the code for the 5 segments of the tool are as follows.

Code for Reference Code Tool

Beginning with the adding a field that has a unique number for the rest of the tool to be based on, the field is called “IDNum”.

IDNum = arcpy.ValidateFieldName("IDNum")
arcpy.DeleteField_management(outputFishnet, ["IDNum"])
arcpy.AddField_management(outputFishnet, "IDNum", "LONG")
with arcpy.da.UpdateCursor(outputFishnet, ["IDNum"]) as cursor:
    ID_Num = 0
    for row in cursor:
        row[0] = ID_Num
        cursor.updateRow(row)
        ID_Num += 1

alpha = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z']
num = ['9', '8', '7', '6', '5', '4', '3', '2', '1', '0']

There are 5 main sections for producing the codes, 2 for naming columns (Alpha1, Alpha2), and 3 for naming rows (Num1, Num2, Num3).

Alpha1:

if columnNum >= 1:
    arcpy.AddField_management(outputFishnet, "Alpha1", "TEXT", 1)
    with arcpy.da.UpdateCursor(outputFishnet, ["Alpha1", "IDNum"]) as cursor:
        for row in cursor:
            x, y, z, counter = 0, 0, 0, 0
            while counter < numOfCols:
                while x < numOfRows:
                    if row[1] == numOfCols*x + y:
                        row[0] = alpha[z]
                        cursor.updateRow(row)
                    x += 1
                x = 0
                y += 1
                if y == numOfCols:
                    y, z = 0, 0
                z += 1
                if z == 26:
                    z = 0
                counter += 1

Alpha2:

if columnNum >= 2:
    arcpy.AddField_management(outputFishnet, "Alpha2", "TEXT", 1)
    with arcpy.da.UpdateCursor(outputFishnet, ["Alpha2", "IDNum"]) as cursor:
        w, x, y, z, counter, counter2 = 0, 0, 0, 0, 0, 0
        for row in cursor:
            if row[1] >= 25*x + y + numOfCols*w and row[1] <= 25*(x+1) + y + numOfCols*w:
                row[0] = alpha[z]
                cursor.updateRow(row)
            counter += 1
            counter2 += 1
            if counter == 25:
                x += 1
            if counter == 26:
                counter = 0
                y += 1
                z += 1
            if counter2%numOfCols == 0:
                w += 1
                x, y, z, counter = 0, 0, 0, 0

Num1:

if rowNum >= 1:
    arcpy.AddField_management(outputFishnet, "Num1", "TEXT", 1)
    with arcpy.da.UpdateCursor(outputFishnet, ["Num1", "IDNum"]) as cursor:
        for row in cursor:
            x, y, z = 1, 0, 0
            if numOfRows % 10 != 0:
                z = 10 - numOfRows%10
            if numOfRows % 10 == 0:
                z = 0
            while x <= numOfRows:
                if row[1] <= numOfCols*x - 1 and row[1] >= numOfCols*y:
                    row[0] = num[z]
                    cursor.updateRow(row)
                x += 1
                y += 1
                z += 1
                if z == 10:
                    z = 0

Num2:

if rowNum >= 2:
    arcpy.AddField_management(outputFishnet, "Num2", "TEXT", 1)
    with arcpy.da.UpdateCursor(outputFishnet, ["Num2", "Num1", "IDNum", "Alpha1", "Alpha2"]) as cursor:
        a = numOfRows
        if a >= 100:
            while a > 100:
                a -= 100
            a = int(math.ceil(a / 10.0)) * 10
        if a % 10 != 0:
            z = 10 - (a % 10)
        if a % 10 == 0:
            z = 10 - (a // 10)
        for row in cursor:
            if row[1] == '9' and row[3] == 'A' and row[4] == 'A':
                z += 1
                if z == 10:
                    z = 0
                row[0] = num[z]
            if row[1] != '9':
                row[0] = num[z]
            if row[1] == '9':
                row[0] = num[z]
            cursor.updateRow(row)

Num3:

if rowNum >= 3:
    arcpy.AddField_management(outputFishnet, "Num3", "TEXT", 1)
    with arcpy.da.UpdateCursor(outputFishnet, ["Num3", "Num2", "Num1", "Alpha1", "Alpha2"]) as cursor:
        a = numOfRows
        if row[1] == '9':
            a = a / 100 - 1
            z = 10 - a
        if row[1] != '9':
            a = a // 100
            z = 9 - a
        for row in cursor:
            if row[2] == '9' and row[1] == '9' and row[3] == 'A' and row[4] == 'A':
                z += 1
                if z == 10:
                    z = 0
                row[0] = num[z]
            else:
                row[0] = num[z]
            cursor.updateRow(row)

ArcGIS Tool

The tool is illustrated in the photo below.

Conclusion

I used this tool to create 7 fishnets populated with reference codes and it looks like the picture below (location is Georgian Bay, Lake Huron, Canada). See the first image for the zoomed in version of the bottom right fishnet.

I hope that this code can be of use to you, as it has made my work a lot more efficient. Note that the tool ran for nearly 4 hours one time (biggest fishnet in the middle), so do not give up if it takes what seems to be forever. Feel free to ask me any questions or if you would like me to send the tool over. Also, please message me if you know an easier to write the code as this was my first ArcGIS Python tool!