How can I assign grid values to the squares of a fishnet grid?

9762
15
Jump to solution
06-09-2015 06:02 AM
RyanGardner-Cook
New Contributor III

Hello,

I am working with a fishnet grid that I created but cannot figure out how to populate the attribute table of the shapefile with the corresponding grid designation. 

The details of the grid are as follows:
The X of the grid originally started with A and ended with AX. We have since had to broaden it both east and west to include YE through ZZ, then A through CT (so 146 columns in the grid). The Y of the grid is 1 through 147.  Each grid square is 5x5 meters.

There must be something I am missing in order to assign grid values to each square.  I have played around a bit with attribute assist, and editing a grid template for Make Grids and Graticules Layer (both of which are new to me).  I have also started playing around with creating rows and columns of polygons named according to the grid and named accordingly and spatially joining them with the grid squares...  I haven't quite been able to figure it out with any of these, and I figure there must be a simpler way, right?

Cheers,

Ryan

Tags (3)
1 Solution

Accepted Solutions
XanderBakker
Esri Esteemed Contributor

And to give an example:

Was created using this code:

import arcpy

def main():
    # the fishnet featureclass
    fc = r"C:\Forum\FishIndex\test.gdb\indexgrid01"

    # fields to will be updated (should exist)
    fld_row = "row"
    fld_col = "col"
    fld_idx = "GridIndex"

    # extent (all lower left of fishnet polygons)
    xmin = 150000
    ymin = 450000
    xmax = 150725
    ymax = 450730
    width = 5
    height = 5

    # update features
    flds = ("SHAPE@", fld_row, fld_col, fld_idx)
    with arcpy.da.UpdateCursor(fc, flds) as curs:
        for row in curs:
            ext = row[0].extent
            rownum = getRowNumber(ext.YMin, ymax, height)
            colnum = getColNumber(ext.XMin, xmin, width)
            idxnum = getIndex(colnum, rownum)
            row[1] = rownum
            row[2] = colnum
            row[3] = idxnum
            curs.updateRow(row)

def getRowNumber(yi, ymax, height):
    return int((ymax - yi) / height + 1)

def getColNumber(xi, xmin, width):
    return int((xi - xmin) / width + 1)

def getIndex(col, row):
    col = correctCol(col)
    # http://stackoverflow.com/questions/19153462/python-get-excel-style-column-names-from-column-number
    LETTERS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
    result = []
    while col:
        col, rem = divmod(col-1, 26)
        result[:0] = LETTERS[rem]
    return ''.join(result) + str(row)

def correctCol(col):
    # YE through ZZ, then A through CT
    YE, ZZ = 655, 702
    if col <= (ZZ - YE + 1):
        return col + YE -1
    else:
        return col - (ZZ - YE + 1)
    return col

if __name__ == '__main__':
    main()

View solution in original post

15 Replies
WesMiller
Regular Contributor III

You could recreate the grid with Create Grid Index tool ArcGIS Desktop

Or you could assign use arcpy.Sort_management to spatially sort the grid you have and use the new object IDs to populate your IDs

RyanGardner-Cook
New Contributor III

The index tool wasn't doing it for me.  Had Xander's script not worked, do you have any recommendations for how I should have automatically populated my IDs after sorting the grid?  Do the columns and rows separately and then concat?  Thanks!

0 Kudos
WesMiller
Regular Contributor III

The Sort_managment tool would have sorted your tiles spatially, see below.

0     1     2     3     4     5

6     7     8     9     10     11

12     13     14     15     16

Your table would have been in a spatially logical order. Use the line below in your ArcMap python window and change "YourGridHere" with your fishnnet grid to see how it works

arcpy.Sort_management("YourGridHere","in_memory\\YourGridUL","Shape","UL")

XanderBakker
Esri Esteemed Contributor

If it has to be the YE to ZZ and A to CT and the Create Grid Index as Wes Miller suggests, does not produce what you want, I suppose it would be possible to create a python script that will assign the grid values automatically.

0 Kudos
XanderBakker
Esri Esteemed Contributor

And to give an example:

Was created using this code:

import arcpy

def main():
    # the fishnet featureclass
    fc = r"C:\Forum\FishIndex\test.gdb\indexgrid01"

    # fields to will be updated (should exist)
    fld_row = "row"
    fld_col = "col"
    fld_idx = "GridIndex"

    # extent (all lower left of fishnet polygons)
    xmin = 150000
    ymin = 450000
    xmax = 150725
    ymax = 450730
    width = 5
    height = 5

    # update features
    flds = ("SHAPE@", fld_row, fld_col, fld_idx)
    with arcpy.da.UpdateCursor(fc, flds) as curs:
        for row in curs:
            ext = row[0].extent
            rownum = getRowNumber(ext.YMin, ymax, height)
            colnum = getColNumber(ext.XMin, xmin, width)
            idxnum = getIndex(colnum, rownum)
            row[1] = rownum
            row[2] = colnum
            row[3] = idxnum
            curs.updateRow(row)

def getRowNumber(yi, ymax, height):
    return int((ymax - yi) / height + 1)

def getColNumber(xi, xmin, width):
    return int((xi - xmin) / width + 1)

def getIndex(col, row):
    col = correctCol(col)
    # http://stackoverflow.com/questions/19153462/python-get-excel-style-column-names-from-column-number
    LETTERS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
    result = []
    while col:
        col, rem = divmod(col-1, 26)
        result[:0] = LETTERS[rem]
    return ''.join(result) + str(row)

def correctCol(col):
    # YE through ZZ, then A through CT
    YE, ZZ = 655, 702
    if col <= (ZZ - YE + 1):
        return col + YE -1
    else:
        return col - (ZZ - YE + 1)
    return col

if __name__ == '__main__':
    main()
XanderBakker
Esri Esteemed Contributor

and to add some explanation to the code:

  • line 5 holds a reference to the input feature class (fishnet)
  • lines 8 - 10, define the names of the field that are being updated (should already exist in the input fc)
  • lines 13 - 18, define the fishnet (the upper right corner is actually the lower left corner of the upper right polygon)
  • line 21, creates a tuple with the fields to be used in the cursor
  • line 22, defines the cursor (this is something that allows you to traverse the data and in this case update the data), very important to look into cursors and the data access (da) module
  • line 23, start looping through each record in the featureclass
  • line 24, read the extent property of the geometry
  • line 25, determine the row number based on the Ymin of the extent and the height of the grid
  • line 26, determine the column number based on the Xmin of the extent and the width of the grid
  • line 27, determine the grid index based on row and column numbers
  • lines 28 - 30, write the results to the row object
  • line 31, updates the record
  • lines 33 - 34, the function that calculates the row number
  • lines 36 - 37, the function that calculates the column number
  • lines 39 to 47, calls the function correctCol on line 49 to correct column number for your specific case and converts the column into an Excel like notation.
  • lines 49 - 56, changes the column number to create the value corresponding to YE-ZZ and A to CT column number values
RyanGardner-Cook
New Contributor III

Hi Xander,
I am hoping you can help clarify a couple things for me, please.

I am playing around with the script a bit, trying to make different grid schemes.  I am getting errors on lines 22 and 54.  Will the cursor be totally different if I am just doing an AA through GS grid?  I also cut down lines 49-56 to
# AA through GS
Return col
Is that correct?
Sorry to trouble you and thanks so much for your time and expertise!

0 Kudos
XanderBakker
Esri Esteemed Contributor

Hi Ryan Gardner-Cook ,

An error on line 22 (initializing the update cursor) normally occurs when:

  • the featureclass cannot be found, accessed or updated
  • the tuple of fields contains a field that does not exist

An error on line 54 is a bit strange, but this might be due to cutting down lines 49-56 or some indentation. it would help to see the entire error message to determine what is going on.

To simply create a grid that that starts a a single A and continue up to GS (?) would only require you to switch off the correction of the column number on line 40 or the original code. You can put a "#" sign before the line to comment the line and prevent it from executing, like you can see on line 41 where the source url is a comment.

0 Kudos
RyanGardner-Cook
New Contributor III

So the idea is to start with a double A (i.e. AA) through, in this case, GR.

Here is the error:

Runtime error

Traceback (most recent call last):

  File "<string>", line 54, in <module>

  File "<string>", line 22, in main

RuntimeError: cannot open 'C:\JVRP\Legio_Grid.shp'

I get the same error after switching off line 40.

I think part of the problem, at least, is the feature class location...  The data source says the database is in a location separate from the shapefile.

edit: Yeah, that was creating the error.  Now the issue is that the first square in the grid is A0, as opposed to AA1.

0 Kudos