Python Script: Create a rectangle using coordinates, width and height atributes from DBF

18333
19
Jump to solution
01-11-2017 09:01 AM
TimGattinger
New Contributor II

Dear Xander,

I wonder if it is possible to take width and length of the rectangle from a dbf table.. I have 24 rows with different length and width values, and hence I want to create 24 rectangles with different sizes according to width and length from the dbf table.

Best,

Tim

0 Kudos
1 Solution

Accepted Solutions
XanderBakker
Esri Esteemed Contributor

Yes, Blake Terhune  was completely right! Those were errors indeed. Find below the corrected (and tested) code:

import arcpy

def main():
    import os

    arcpy.env.overwriteOutput = True

    # input dbf file, edit this !!!
    tbl = r'D:\Xander\GeoNet\DBF2Rectangles\testdata.dbf'

    # edit these field names !!!
    fld_oid_in = 'OID@'
    fld_X = 'X'
    fld_Y = 'Y'
    fld_width = 'Width'
    fld_height = 'Height'
    fld_oid_out = 'OID_DBF'

    # output feature class
    fc_out = r'D:\Xander\GeoNet\DBF2Rectangles\test.gdb\rectangles' # edit this !!!

    # define a spatial reference, edit this !!!
    sr = arcpy.SpatialReference(3857)  # example for WGS_1984_Web_Mercator_Auxiliary_Sphere

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

    # add field OID DBF
    AddField(fc_out, fld_oid_out, "LONG", None)

    # insert cursor to store the results
    flds_out = ('SHAPE@', fld_oid_out)
    with arcpy.da.InsertCursor(fc_out, flds_out) as curs_out:

        # loop over dbf file
        flds = (fld_oid_in, fld_X, fld_Y, fld_width, fld_height)
        with arcpy.da.SearchCursor(tbl, flds) as curs:
            for row in curs:
                oid = row[0]
                x = row[1]
                y = row[2]
                w = row[3]
                h = row[4]
                polygon = createRectangle(x, y, w, h, sr)
                curs_out.insertRow((polygon, oid, ))


def AddField(fc, fld_name, fld_type, fld_length):
    if len(arcpy.ListFields(fc, fld_name)) == 0:
        arcpy.AddField_management(fc, fld_name, fld_type, None, None, fld_length)


def createRectangle(x, y, w, h, sr):
    xmin = float(x) - float(w) / 2.0
    xmax = float(x) + float(w) / 2.0
    ymin = float(y) - float(h) / 2.0
    ymax = float(y) + float(h) / 2.0
    lst_pnts = []
    lst_pnts.append(arcpy.Point(xmin, ymin))
    lst_pnts.append(arcpy.Point(xmin, ymax))
    lst_pnts.append(arcpy.Point(xmax, ymax))
    lst_pnts.append(arcpy.Point(xmax, ymin))
    lst_pnts.append(lst_pnts[0])
    return arcpy.Polygon(arcpy.Array(lst_pnts), sr)


if __name__ == '__main__':
    main()

And the result for some random data:

View solution in original post

19 Replies
XanderBakker
Esri Esteemed Contributor

Question branched from this thread: https://community.esri.com/thread/84853 by xander_bakker

0 Kudos
XanderBakker
Esri Esteemed Contributor

Hi Tim Gattinger , I branched your question to a new thread.

Yes it is possible to adapt the script to read width and height attributes from attributes in a DBF. What was not clear to me is if that DBF is a stand alone table or not. In case it is look at the example below.

This will take a DBF (specified on row 7) with the attributes defined on lines 11 to 14 and create a new output featureclass (defined at line 18) that will hold the polygons of the rectangles by reading XY attributes (is this the case?) and the width and height defined in attributes. Important is to specify a relevant (projected) coordinate system on line 21 in which X, Y, width and height are expressed:

import arcpy

def main():
    import os

    # input dbf file, edit this !!!
    tbl = r'D:\Folder\SubFolder\NameOfYour.dbf'

    # edit these field names !!!
    fld_oid_in = 'OID@'
    fld_X = 'X'
    fld_Y = 'Y'
    fld_width = 'Width'
    fld_height = 'Height'
    fld_oid_out = 'OID_DBF'

    # output feature class
    fc_out = r'D:\Folder\SubFolder\NameOfWorkspace.gdb\rectangles' # edit this !!!

    # define a spatial reference, edit this !!!
    sr = arcpy.SpatialReference(3857)  # example for WGS_1984_Web_Mercator_Auxiliary_Sphere

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

    # add field OID DBF
    AddField(fc_out, fld_oid_out, "LONG", None)

    # insert cursor to store the results
    flds_out = ('SHAPE@', fld_oid_out)
    with arcpy.da.InsertCursor(fc_out, flds_out) as curs_out:

        # loop over dbf file
        flds = (fld_oid, fld_X, fld_Y, fld_width, fld_height)
        with arcpy.da.SearchCursor(fc, flds) as curs:
            for row in curs:
                oid = row[0]
                x = row[1]
                y = row[2]
                w = row[3]
                h = row[4]
                polygon = createRectangle(x, y, w, h, sr)
                curs_out.insertRow((polygon, oid, ))


def AddField(fc, fld_name, fld_type, fld_length):
    if len(arcpy.ListFields(fc, fld_name)) == 0:
        arcpy.AddField_management(fc, fld_name, fld_type, None, None, fld_length)


def createRectangle(x, y, w, h, sr):
    xmin = float(x) - float(w) / 2.0
    xmax = float(x) + float(w) / 2.0
    ymin = float(y) - float(h) / 2.0
    ymax = float(y) + float(h) / 2.0
    lst_pnts = []
    lst_pnts.append(arcpy.Point(xmin, ymin))
    lst_pnts.append(arcpy.Point(xmin, ymax))
    lst_pnts.append(arcpy.Point(xmax, ymax))
    lst_pnts.append(arcpy.Point(xmax, ymin))
    lst_pnts.append(lst_pnts[0])
    return arcpy.Polygon(arcpy.Array(lst_pnts), sr)


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

Oops, just noticed I made an mistake on line 43 - 44. It should be replaced by:

                polygon = createRectangle(x, y, w, h, sr)

New: just updated code in post above...

0 Kudos
JoshuaBixby
MVP Esteemed Contributor

Can you update your original code as well (maybe you did and I am missing the obvious)?

0 Kudos
TimGattinger
New Contributor II

Thanks, it looks great I'll try the code as soon as possible.. I just didnt understand where the X,Y coordinates come from...I created center points from an underlying shapefile, can I e.g. take the coordiunates form these points and just add them to the dbf and go on with the script you just wrote?

So..in your code are the X,Y coordinates meant to be the starting point for each rectangle, or sth like that?

Best, Tim

0 Kudos
TimGattinger
New Contributor II

After the adaptions I made, it still says 'global name 'fc' not defined'..do you have an idea?! Im quite new to the programming stuff btw..

0 Kudos
BlakeTerhune
MVP Regular Contributor

In line 36 of Xander's code where the SearchCursor is created, I think fc should be changed to tbl. However, it also looks like fld_oid is undefined on line 35; maybe should be fld_oid_in?

XanderBakker
Esri Esteemed Contributor

Very valid comments Blake Terhune  (+1)... will generate a dummy table with some random data and test the code, to see what needs to be changed.

0 Kudos
XanderBakker
Esri Esteemed Contributor

Yes, Blake Terhune  was completely right! Those were errors indeed. Find below the corrected (and tested) code:

import arcpy

def main():
    import os

    arcpy.env.overwriteOutput = True

    # input dbf file, edit this !!!
    tbl = r'D:\Xander\GeoNet\DBF2Rectangles\testdata.dbf'

    # edit these field names !!!
    fld_oid_in = 'OID@'
    fld_X = 'X'
    fld_Y = 'Y'
    fld_width = 'Width'
    fld_height = 'Height'
    fld_oid_out = 'OID_DBF'

    # output feature class
    fc_out = r'D:\Xander\GeoNet\DBF2Rectangles\test.gdb\rectangles' # edit this !!!

    # define a spatial reference, edit this !!!
    sr = arcpy.SpatialReference(3857)  # example for WGS_1984_Web_Mercator_Auxiliary_Sphere

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

    # add field OID DBF
    AddField(fc_out, fld_oid_out, "LONG", None)

    # insert cursor to store the results
    flds_out = ('SHAPE@', fld_oid_out)
    with arcpy.da.InsertCursor(fc_out, flds_out) as curs_out:

        # loop over dbf file
        flds = (fld_oid_in, fld_X, fld_Y, fld_width, fld_height)
        with arcpy.da.SearchCursor(tbl, flds) as curs:
            for row in curs:
                oid = row[0]
                x = row[1]
                y = row[2]
                w = row[3]
                h = row[4]
                polygon = createRectangle(x, y, w, h, sr)
                curs_out.insertRow((polygon, oid, ))


def AddField(fc, fld_name, fld_type, fld_length):
    if len(arcpy.ListFields(fc, fld_name)) == 0:
        arcpy.AddField_management(fc, fld_name, fld_type, None, None, fld_length)


def createRectangle(x, y, w, h, sr):
    xmin = float(x) - float(w) / 2.0
    xmax = float(x) + float(w) / 2.0
    ymin = float(y) - float(h) / 2.0
    ymax = float(y) + float(h) / 2.0
    lst_pnts = []
    lst_pnts.append(arcpy.Point(xmin, ymin))
    lst_pnts.append(arcpy.Point(xmin, ymax))
    lst_pnts.append(arcpy.Point(xmax, ymax))
    lst_pnts.append(arcpy.Point(xmax, ymin))
    lst_pnts.append(lst_pnts[0])
    return arcpy.Polygon(arcpy.Array(lst_pnts), sr)


if __name__ == '__main__':
    main()

And the result for some random data: