Comparison with ArcPy#

This notebook compares the usage of footbridge with arcpy.

[1]:
import os
import arcpy
import footbridge as ft
from timer import Timer

timer = Timer()

# large dataset of US National Highway System roads, one feature class
# https://hepgis-usdot.hub.arcgis.com/datasets/dce9f09392eb474c8ad8e6a78416279b_0
gdb_path = os.path.abspath("NHS.gdb")

arcpy.env.overwriteOutput = True

Load feature class into memory#

ArcPy#

[2]:
timer.start()
# ------------
arcpy.env.workspace = gdb_path
arcpy_fcs = arcpy.ListFeatureClasses()
fc_name = arcpy_fcs[0]
fc_path = os.path.join(gdb_path, fc_name)
arcpy_fc = os.path.join("memory", fc_name)
arcpy.conversion.ExportFeatures(fc_path, arcpy_fc)
# -----------
timer.stop()
18.6794 seconds

footbridge#

[3]:
timer.start()
# ------------
ft_fc = ft.GeoDatabase(gdb_path)[0]
# -----------
timer.stop()
13.8833 seconds

Fewer lines

More pythonic

Faster runtime

Overall

ArcPy

footbridge

Count rows#

ArcPy#

[4]:
timer.start()
# ------------
count_result = arcpy.management.GetCount(arcpy_fc)
row_count = count_result[0]
# -----------
timer.stop()
f"{row_count} rows"
0.1106 seconds
[4]:
'491781 rows'

footbridge#

[5]:
timer.start()
# ------------
row_count = len(ft_fc)
# -----------
timer.stop()
f"{row_count} rows"
0.001 seconds
[5]:
'491781 rows'

Fewer lines

More pythonic

Faster runtime

Overall

ArcPy

footbridge

Filter rows#

ArcPy#

[6]:
timer.start()
# ------------
arcpy_fc_filtered = os.path.join("memory", fc_name + "_filtered")
arcpy.conversion.ExportFeatures(
    arcpy_fc, arcpy_fc_filtered, where_clause="ROUTEID = '50'"
)
# -----------
timer.stop()
f"{arcpy.management.GetCount(arcpy_fc_filtered)[0]} rows"
0.1153 seconds
[6]:
'24 rows'

footbridge#

[7]:
timer.start()
# ------------
ft_fc_filtered = ft_fc.select_rows("ROUTEID == '50'")
# -----------
timer.stop()
f"{len(ft_fc_filtered)} rows"
0.0385 seconds
[7]:
'24 rows'

Fewer lines

More pythonic

Faster runtime

Overall

ArcPy

footbridge

Get the last row#

ArcPy#

[8]:
timer.start()
# ------------
with arcpy.da.SearchCursor(arcpy_fc, field_names=["*"]) as s_cursor:
    for row in s_cursor:
        this_row = row
# -----------
timer.stop()
this_row
2.3388 seconds
[8]:
(491781,
 (-16685208.940766193, 8677951.279447716),
 '2025.03.27',
 2022.0,
 2.0,
 20.0,
 '2281321F013',
 0.0,
 0.354,
 ' ',
 ' ',
 ' ',
 ' ',
 4.0,
 1.0,
 ' ',
 ' ',
 ' ',
 0.0,
 ' ',
 3.0,
 4.0,
 1.0,
 0.0,
 0.0,
 2305.0,
 1744.0,
 0.0,
 0.0,
 0.0,
 None,
 0.354,
 datetime.datetime(2025, 3, 5, 0, 0),
 'Add: STRAHNET Connector',
 'AK_HPMS_FULL_2022')

footbridge#

[9]:
timer.start()
# ------------
this_row = ft_fc[-1]
# -----------
timer.stop()
this_row
0.0039 seconds
[9]:
VERSION YEAR STFIPS CTFIPS ROUTEID BEGINPOINT ENDPOINT SIGN1 SIGNT1 SIGNN1 ... AADT_COM AADT_SINGL FUT_AADT FUT_YEAR MILES UPDATE_DAT NHS_ACTION FILE_NAME SHAPE_Length geometry
ObjectID
491780 2025.03.27 2022.0 2.0 20.0 2281321F013 0.0 0.354 ... 0.0 0.0 0.0 NaT 0.354 2025-03-05 00:00:00+00:00 Add: STRAHNET Connector AK_HPMS_FULL_2022 1176.089478 MULTILINESTRING ((-16685133.238 8677491.246, -16685113.534 8677517.377, -16685110.974 8677534.721, -16685108.636 8677551.14, -16685105.964 8677567.558, -16685103.181 8677583.977, -16685100.398 8677600.396, -16685097.504 8677616.584, -16685094.721 8677633.003, -16685091.938 8677649.422, -16685089.155 8677665.841, -16685086.372 8677682.029, -16685083.478 8677698.679, -16685080.695 8677714.867, -16685077.801 8677731.286, -16685075.018 8677747.937, -16685072.123 8677764.125, -16685069.34 8677780.544, -16685066.446 8677796.964, -16685063.552 8677813.383, -16685060.658 8677829.803, -16685057.763 8677846.222, -16685054.98 8677862.642, -16685052.197 8677879.292, -16685049.748 8677895.712, -16685047.856 8677912.363, -16685046.743 8677929.245, -16685046.743 8677945.896, -16685047.744 8677962.778, -16685050.194 8677979.429, -16685053.756 8677995.849, -16685058.654 8678012.038, -16685064.665 8678027.764, -16685071.901 8678043.027, -16685080.361 8678057.597, -16685089.935 8678071.473, -16685100.51 8678084.656, -16685111.865 8678097.144, -16685123.998 8678108.707, -16685137.023 8678119.346, -16685151.049 8678128.828, -16685165.632 8678137.385, -16685180.66 8678144.554, -16685196.245 8678150.799, -16685212.386 8678155.655, -16685228.75 8678159.355, -16685245.337 8678161.899, -16685262.035 8678163.056, -16685278.955 8678163.287, -16685295.542 8678162.593, -16685312.24 8678160.974, -16685328.938 8678158.893, -16685345.302 8678156.118, -16685361.666 8678152.88, -16685377.918 8678149.179, -16685394.171 8678145.248, -16685410.312 8678141.085, -16685457.289 8678123.74, -16685473.43 8678118.883, -16685489.349 8678114.258, -16685505.379 8678109.401, -16685521.52 8678104.776, -16685537.662 8678100.613, -16685554.026 8678097.144, -16685570.501 8678094.369, -16685587.421 8678093.212, -16685604.231 8678093.675, -16685621.93 8678081.88))

1 rows × 35 columns

Fewer lines

More pythonic

Faster runtime

Overall

ArcPy

footbridge

Get a row at an index#

[10]:
row_index = 400000

ArcPy#

[11]:
timer.start()
# ------------
with arcpy.da.SearchCursor(arcpy_fc, field_names=["*"]) as s_cursor:
    for idx, row in enumerate(s_cursor):
        if idx == row_index:
            this_row = row
            break
# -----------
timer.stop()
this_row
2.0408 seconds
[11]:
(400001,
 (-8541104.104770636, 4903934.337197111),
 '2025.03.27',
 2020.0,
 42.0,
 43.0,
 '1 22 0322 - 4031',
 4.862,
 4.973,
 'U322',
 'U',
 '322',
 '28th Division Hwy',
 7.0,
 1.0,
 ' ',
 ' ',
 ' ',
 0.0,
 'P',
 2.0,
 2.0,
 4.0,
 0.0,
 1.0,
 37081.0,
 37283.0,
 553.0,
 593.0,
 0.0,
 None,
 0.109283,
 None,
 ' ',
 'PA_NHS_2021')

footbridge#

[12]:
timer.start()
# ------------
this_row = ft_fc[row_index]
# -----------
timer.stop()
this_row
0.001 seconds
[12]:
VERSION YEAR STFIPS CTFIPS ROUTEID BEGINPOINT ENDPOINT SIGN1 SIGNT1 SIGNN1 ... AADT_COM AADT_SINGL FUT_AADT FUT_YEAR MILES UPDATE_DAT NHS_ACTION FILE_NAME SHAPE_Length geometry
ObjectID
400000 2025.03.27 2020.0 42.0 43.0 1 22 0322 - 4031 4.862 4.973 U322 U 322 ... 553.0 593.0 0.0 NaT 0.109283 NaT PA_NHS_2021 230.148704 MULTILINESTRING ((-8541219.173 4903933.712, -8541021.692 4903935.025, -8540989.076 4903933.274))

1 rows × 35 columns

Fewer lines

More pythonic

Faster runtime

Overall

ArcPy

footbridge

Get a column#

[13]:
column_name = "MILES"

ArcPy#

[14]:
timer.start()
# ------------
fc_field_mapping = arcpy.FieldMappings()
fc_field_mapping.addTable(arcpy_fc)
mapping_index = fc_field_mapping.findFieldMapIndex(column_name)
field_map = fc_field_mapping.getFieldMap(mapping_index)

new_field_mapping = arcpy.FieldMappings()
new_field_mapping.addFieldMap(field_map)

arcpy_fc_col = os.path.join("memory", fc_name + "_col")
result = arcpy.conversion.ExportFeatures(
    arcpy_fc, arcpy_fc_col, field_mapping=new_field_mapping
)
# -----------
timer.stop()
[field.name for field in arcpy.ListFields(arcpy_fc_col)]
3.1782 seconds
[14]:
['OBJECTID', 'Shape', 'MILES']

footbridge#

[15]:
timer.start()
# ------------
ft_fc_col = ft_fc.select_columns(column_name)
# -----------
timer.stop()
ft_fc_col.list_fields()
0.0474 seconds
[15]:
['ObjectID', 'MILES', 'geometry']

Fewer lines

More pythonic

Faster runtime

Overall

ArcPy

footbridge

Field calculator#

ArcPy#

[16]:
timer.start()
# ------------
arcpy.management.CalculateField(arcpy_fc, "KILOMETERS", "!MILES! * 1.60934", "PYTHON3")
# -----------
timer.stop()
[field.name for field in arcpy.ListFields(arcpy_fc)]
10.6854 seconds
[16]:
['OBJECTID',
 'Shape',
 'VERSION',
 'YEAR',
 'STFIPS',
 'CTFIPS',
 'ROUTEID',
 'BEGINPOINT',
 'ENDPOINT',
 'SIGN1',
 'SIGNT1',
 'SIGNN1',
 'LNAME',
 'NHS',
 'STATUS',
 'FACID',
 'CONNID',
 'CONNDES',
 'CONNMILES',
 'ACLASS',
 'FCLASS',
 'FACILITYT',
 'THROUGH_LA',
 'SPEED_LIMI',
 'OWNERSHIP',
 'URBANCODE',
 'AADT',
 'AADT_COM',
 'AADT_SINGL',
 'FUT_AADT',
 'FUT_YEAR',
 'MILES',
 'UPDATE_DAT',
 'NHS_ACTION',
 'FILE_NAME',
 'KILOMETERS']

footbridge#

[17]:
timer.start()
# ------------
ft_fc.calculate("KILOMETERS", "MILES * 1.60934")
# -----------
timer.stop()
ft_fc.list_fields()
0.0597 seconds
[17]:
['ObjectID',
 'VERSION',
 'YEAR',
 'STFIPS',
 'CTFIPS',
 'ROUTEID',
 'BEGINPOINT',
 'ENDPOINT',
 'SIGN1',
 'SIGNT1',
 'SIGNN1',
 'LNAME',
 'NHS',
 'STATUS',
 'FACID',
 'CONNID',
 'CONNDES',
 'CONNMILES',
 'ACLASS',
 'FCLASS',
 'FACILITYT',
 'THROUGH_LA',
 'SPEED_LIMI',
 'OWNERSHIP',
 'URBANCODE',
 'AADT',
 'AADT_COM',
 'AADT_SINGL',
 'FUT_AADT',
 'FUT_YEAR',
 'MILES',
 'UPDATE_DAT',
 'NHS_ACTION',
 'FILE_NAME',
 'SHAPE_Length',
 'KILOMETERS',
 'geometry']

Fewer lines

More pythonic

Faster runtime

Overall

ArcPy

footbridge

Buffer#

ArcPy#

[18]:
timer.start()
# ------------
arcpy_fc_buffered = os.path.join("memory", fc_name + "_buffered")
arcpy.analysis.PairwiseBuffer(arcpy_fc_filtered, arcpy_fc_buffered, "10 Miles")
# -----------
timer.stop()
0.1783 seconds

footbridge#

[19]:
timer.start()
# ------------
buffered = ft_fc_filtered.gdf.buffer(10 * 1609.344)  # geometry units are meters
ft_fc_buffered = ft.FeatureClass(buffered)
# -----------
timer.stop()
< 10 ms

Fewer lines

More pythonic

Faster runtime

Overall

ArcPy

footbridge

Copy feature class to new geodatabase#

[20]:
out_folder = os.path.abspath(".")
gdb_name = "test.gdb"
out_gdb = os.path.join(out_folder, gdb_name)
out_fc = os.path.join(out_gdb, fc_name)

ArcPy#

[21]:
timer.start()
# ------------
arcpy.management.CreateFileGDB(out_folder, gdb_name)
arcpy.conversion.ExportFeatures(arcpy_fc, out_fc)
# -----------
timer.stop()
16.5243 seconds

footbridge#

[22]:
timer.start()
# ------------
ft_fc.save(out_gdb, fc_name, overwrite=True)
# -----------
timer.stop()
18.4099 seconds

Fewer lines

More pythonic

Faster runtime

Overall

ArcPy

footbridge

Summary#

ArcPy

footbridge

Load feature class

Count rows

Filter rows

Get the last row

Get a row at an index

Get a column

Field calculator

Buffer

Copy to new GDB