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 |
✅ |
✅ |