How to generate grid with offset and assign values to the cells of a the grid?

3018
28
Jump to solution
06-23-2018 08:04 PM
HushamMohamed
Occasional Contributor

I have to generate thousands of cells as a grid, and then I have to assign  values to the cells, so far I know the a fishnet tool can generate the grid but how can I manage to create the offset.  May some one have better Idea.


The details of the grid are as illustrated in the attached diagram.
I have 5 Rows and 6 column,    after the 3rd column  the grid should start with B, other numbering should be the same as A.

0 Kudos
28 Replies
HushamMohamed
Occasional Contributor

You are absolutely correct,  I mean labeling,  and almost exactly right correct in your all other assumptions.

Thank you

0 Kudos
XanderBakker
Esri Esteemed Contributor

You could try this:

def main():
    import arcpy
    import os

    # settings
    fc_out = r'C:\GeoNet\RectangleBlocks\data.gdb\result04'
    fld_lbl = r'RectangleID'
    sr = arcpy.SpatialReference(2276)  # NAD_1983_StatePlane_Texas_North_Central_FIPS_4202_Feet?

    x_start = 2523853.5  # lower left
    y_start = 7124354.1  # lower left
    rect_width = 10.0
    rect_height = 5.0
    num_blocks_h = 6
    num_blocks_v = 5
    num_rect_in_block_h = 4
    num_rect_in_block_v = 8
    spacing_h = 3.0
    spacing_v = 3.0

    # create output featureclass
    arcpy.env.overwriteOutput = True
    fc_ws, fc_name = os.path.split(fc_out)
    arcpy.CreateFeatureclass_management(fc_ws, fc_name, "POLYGON", None, None, None, sr)

    # add field
    arcpy.AddField_management(fc_out, fld_lbl, "TEXT", None, None, 10)

    # insert cursor
    flds = ("SHAPE@", fld_lbl)
    cnt = 0
    with arcpy.da.InsertCursor(fc_out, flds) as curs:

        # loop through blocks
        for block_h in range(num_blocks_h):
            for block_v in range(num_blocks_v):
                # loop through rectangles
                for rect_h in range(num_rect_in_block_h):
                    for rect_v in range(num_rect_in_block_v):
                        x_min = x_start + block_h * spacing_h + block_h * num_rect_in_block_h * rect_width + rect_h * rect_width
                        y_min = y_start + block_v * spacing_v + block_v * num_rect_in_block_v * rect_height + rect_v * rect_height
                        x_max = x_min + rect_width
                        y_max = y_min + rect_height
                        rectangle = CreateRactangle(x_min, y_min, x_max, y_max, sr)
                        label = GetLabel(block_h, block_v, rect_h, rect_v)
                        cnt += 1
                        if cnt % 50 == 0:
                            print("Processing rectangle: {}".format(cnt))
                        curs.insertRow((rectangle, label, ))

    print("Finished processing {} rectangles".format(cnt))


def CreateRactangle(x_min, y_min, x_max, y_max, sr):
    coords = [[x_min, y_min], [x_min, y_max], [x_max, y_max],
              [x_max, y_min], [x_min, y_min]]
    return arcpy.Polygon(arcpy.Array([arcpy.Point(*coord) for coord in coords]), sr)

def GetLabel(block_h, block_v, rect_h, rect_v):

    even = rect_h % 2 == 0
    if rect_v < 4:
        # lower
        if even:
            part3 = rect_v + 1
        else:
            part3 = rect_v + 5

        quad_row = 1 + 12 * block_v
        if rect_h <2:
            quad_col = block_h * 2
        else:
            # lower right
            quad_col = 1 + block_h * 2
    else:
        if even:
            part3 = rect_v - 3
        else:
            part3 = rect_v + 1
        quad_row = 7 + 12 * block_v
        if rect_h <2:
            quad_col = block_h * 2
        else:
            # lower right
            quad_col = 1 + block_h * 2
    part2 = quad_row + quad_col

    if block_h < 3:
        part1 = "A"
    else:
        part1 = "B"
        part2 = part2 - 6


    return "{}-{}-{}".format(part1, part2, part3)

if __name__ == '__main__':
    main()

Which results in:

HushamMohamed
Occasional Contributor

Xander

This script saved my day a couple of times

one line of your script I had never used before.

    return "{}-{}-{}".format(part1, part2, part3)

format  is it a method  to concatenate string elements.

"Thank you" does not even begin to express the gratitude I have for this help. 

0 Kudos
DanPatterson_Retired
MVP Emeritus
HushamMohamed
Occasional Contributor

Thank you, for the Useful Link

0 Kudos
XanderBakker
Esri Esteemed Contributor

In short the line:

    return "{}-{}-{}".format(part1, part2, part3)

... will take a string "{}-{}-{}" and will replace each "{}" by a parameters specified in the format. A very easy and powerful feature of Python. I recommend that you read the documentation provided by the links in Dan_Patterson 's comment.

HushamMohamed
Occasional Contributor

Thanks,  Dan Patterson 's comment very useful

0 Kudos
HushamMohamed
Occasional Contributor

I am playing around this script,  I am not quite well understanding the second part (creating the label - starting from

GetLabel function). If you could put some comments on this parts,
def GetLabel(block_h, block_v, rect_h, rect_v):

    even = rect_h % 2 == 0
    if rect_v < 4:
        # lower
        if even:
            part3 = rect_v + 1
        else:
            part3 = rect_v + 5

        quad_row = 1 + 12 * block_v
        if rect_h <2:
            quad_col = block_h * 2
        else:
            # lower right
            quad_col = 1 + block_h * 2
    else:
        if even:
            part3 = rect_v - 3
        else:
            part3 = rect_v + 1
        quad_row = 7 + 12 * block_v
        if rect_h <2:
            quad_col = block_h * 2
        else:
            # lower right
            quad_col = 1 + block_h * 2
    part2 = quad_row + quad_col

    if block_h < 3:
        part1 = "C"
    else:
        part1 = "D"
        part2 = part2 - 6


    return "{}-{}-{}".format(part1, part2, part3)‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍




 


I am trying to modify this part so the label goes straight through C only without D section and without the offset,

Thank You

0 Kudos
XanderBakker
Esri Esteemed Contributor

See below the snippet with some comments:

def GetLabel(block_h, block_v, rect_h, rect_v):
    # 4 parameters necessary:
     # - block_h = block number horizontally
    # - block_v = block number vertically
    # - rect_h  = rectangle number horizontally
    # - rect_v  = rectangle number vertically       

     # determine if the rectangle number horizontally is even or uneven
    even = rect_h % 2 == 0
     
     # devide the block vertically in two halves
    if rect_v < 4:
        # lower 4 rectangle lines inside a block
        if even:
              # determine the 3rd part of the label
               # values 0 + 1 to 3 + 1 -> (1 - 4)
            part3 = rect_v + 1
        else:
              # values 0 + 5 to 3 + 5 -> (5 - 8)
            part3 = rect_v + 5

          # determine the quadrant of the block (in rows)
          # for instance the second block (=1 when starting to count at 0) vertically 
          # will result in 1 + 12 * 1 = 13 (which is where the lower left starts 
          # see "A-13-1"
        quad_row = 1 + 12 * block_v
          
          # determine the quadrant of the block (in cols)
        if rect_h <2:
              # left part of block
            quad_col = block_h * 2
        else:
            # right part of block
            quad_col = 1 + block_h * 2
    else:
         # do the same for the upper 4 rectangle lines inside a block
        if even:
            part3 = rect_v - 3
        else:
            part3 = rect_v + 1
        quad_row = 7 + 12 * block_v
        if rect_h <2:
            quad_col = block_h * 2
        else:
            # lower right
            quad_col = 1 + block_h * 2

    # part 2 of the label is the result of adding quad_row and quad_col
     part2 = quad_row + quad_col

    if block_h < 3:
         # for first 3 blocks horizontally, assign an "A"
        part1 = "A"
    else:
         # otherwise assign a "B" and correct part 2 of the label
        part1 = "B"
        part2 = part2 - 6

    # construct the label combing the 3 parts
    return "{}-{}-{}".format(part1, part2, part3)

Ï'm a little confused about your comment to go straight to "C without "D". "D" would only occur when there are more than 9 blocks horizontally. Does that happen? I assume to include the "C" you would have to replace the else on line 54 with an elif block_h < 6 and add the else on line 58 assigning "C" to part 1 and probably applying some corrections to part2 (run it and see what the value should be). 

HushamMohamed
Occasional Contributor

Thank you Xander,

I am still did not get it,  now my scenario is changed I am only have one section now, and no spacing

    x_start = 2523853.5  # lower left
    y_start = 7124354.1  # lower left
    rect_width = 10.0
    rect_height = 5.0
    num_blocks_h = 7
    num_blocks_v = 7
    num_rect_in_block_h = 4
    num_rect_in_block_v = 8
    spacing_h = 0.0
    spacing_v = 0.0

 and here is the complete code, but I have some logic errors, see the Red in the Results (Repeating row no)

def main():
    import arcpy
    import os

    # settings
    fc_out = r'C:\HH\ce\cemeterypy.gdb\result05'
    fld_lbl = r'RectangleID'
    sr = arcpy.SpatialReference(2276)  # NAD_1983_StatePlane_Texas_North_Central_FIPS_4202_Feet?

    x_start = 2523853.5  # lower left
    y_start = 7124354.1  # lower left
    rect_width = 10.0
    rect_height = 5.0
    num_blocks_h = 7
    num_blocks_v = 7
    num_rect_in_block_h = 4
    num_rect_in_block_v = 8
    spacing_h = 0.0
    spacing_v = 0.0

    # create output featureclass
    arcpy.env.overwriteOutput = True
    fc_ws, fc_name = os.path.split(fc_out)
    arcpy.CreateFeatureclass_management(fc_ws, fc_name, "POLYGON", None, None, None, sr)

    # add field
    arcpy.AddField_management(fc_out, fld_lbl, "TEXT", None, None, 10)

    # insert cursor
    flds = ("SHAPE@", fld_lbl)
    cnt = 0
    with arcpy.da.InsertCursor(fc_out, flds) as curs:

        # loop through blocks
        for block_h in range(num_blocks_h):
            for block_v in range(num_blocks_v):
                # loop through rectangles
                for rect_h in range(num_rect_in_block_h):
                    for rect_v in range(num_rect_in_block_v):
                        x_min = x_start + block_h * spacing_h + block_h * num_rect_in_block_h * rect_width + rect_h * rect_width
                        y_min = y_start + block_v * spacing_v + block_v * num_rect_in_block_v * rect_height + rect_v * rect_height
                        x_max = x_min + rect_width
                        y_max = y_min + rect_height
                        rectangle = CreateRactangle(x_min, y_min, x_max, y_max, sr)
                        label = GetLabel(block_h, block_v, rect_h, rect_v)
                        cnt += 1
                        if cnt % 50 == 0:
                            print("Processing rectangle: {}".format(cnt))
                        curs.insertRow((rectangle, label, ))

    print("Finished processing {} rectangles".format(cnt))


def CreateRactangle(x_min, y_min, x_max, y_max, sr):
    coords = [[x_min, y_min], [x_min, y_max], [x_max, y_max],
              [x_max, y_min], [x_min, y_min]]
    return arcpy.Polygon(arcpy.Array([arcpy.Point(*coord) for coord in coords]), sr)

def GetLabel(block_h, block_v, rect_h, rect_v):
    # 4 parameters necessary:
     # - block_h = block number horizontally
    # - block_v = block number vertically
    # - rect_h  = rectangle number horizontally
    # - rect_v  = rectangle number vertically

     # determine if the rectangle number horizontally is even or uneven
    even = rect_h % 2 == 0

     # devide the block vertically in two halves
    if rect_v < 4:
        # lower 4 rectangle lines inside a block
        if even:
              # determine the 3rd part of the label
               # values 0 + 1 to 3 + 1 -> (1 - 4)
            part3 = rect_v + 1
        else:
              # values 0 + 5 to 3 + 5 -> (5 - 8)
            part3 = rect_v + 5

          # determine the quadrant of the block (in rows)
          # for instance the second block (=1 when starting to count at 0) vertically
          # will result in 1 + 12 * 1 = 13 (which is where the lower left starts
          # see "A-13-1"
        quad_row = 1 + 14 * block_v

          # determine the quadrant of the block (in cols)
        if rect_h <2:
              # left part of block
            quad_col = block_h * 2
        else:
            # right part of block
            quad_col = 1 + block_h * 2
    else:
         # do the same for the upper 4 rectangle lines inside a block
        if even:
            part3 = rect_v - 3
        else:
            part3 = rect_v + 1
        quad_row = 15 + 14 * block_v
        if rect_h <2:
            quad_col = block_h * 2
        else:
            # lower right
            quad_col = 1 + block_h * 2

    # part 2 of the label is the result of adding quad_row and quad_col
    part2 = quad_row +  quad_col

    if block_h < 7:
         # for first 3 blocks horizontally, assign an "A"
        part1 = "A"
    else:
         # otherwise assign a "B" and correct part 2 of the label
        part1 = "B"
        part2 = part2 - 7

    # construct the label combing the 3 parts
    return "{}-{}-{}".format(part1, part2, part3)
if __name__ == '__main__':
    main()

Result

Thank  you

0 Kudos