diff --git a/html/santa_cruz_precincts.py.html b/html/santa_cruz_precincts.py.html new file mode 100644 index 0000000..cb4da04 --- /dev/null +++ b/html/santa_cruz_precincts.py.html @@ -0,0 +1,741 @@ + +
+1 # ---------------------------------------------------------------------- +2 # santa_cruz_precincts.py +3 # Christopher Prendergast +4 # 2024/06/01 +5 # ---------------------------------------------------------------------- +6 # +7 import arcpy +8 import sys +9 from typing import List +10 from pathlib import Path +11 +12 global g_proj_dir +13 global g_in_gdb +14 global g_temp_gdb +15 global g_out_gdb +16 +17 +18 def full_path(root_dir: str, basename: str) -> str: +19 """ +20 Convert basename to a full path given the root directory or +21 geo-database path. +22 +23 :param str root_dir: The root directory or file geo-database +24 path. +25 :param str basename: The basename of a geo-database or feature +26 class. +27 :return str: The root and basename joined as a path. +28 """ +29 return str(Path(root_dir, basename)) +30 +31 +32 def setup_env(proj_dir_str: str, in_gdb_str: str, temp_gdb_str: str, +33 out_gdb_str: str) -> None: +34 """ +35 Set up the geo-database environment. Assign values to global +36 variables g_in_gdb and g_out_gdb. +37 +38 :param str proj_dir_str: The project directory. +39 :param str in_gdb_str: The basename of the input geo-database +40 within the project directory. +41 :param str temp_gdb_str: The full path of the temporary +42 geo-database. +43 :param str out_gdb_str: The basename of the output geo-database +44 within the project directory. +45 :return NoneType: None +46 """ +47 # +48 # Allow overwriting outputs. +49 # Note: overwriting doesn't work if the layer is open in ArcGIS Pro +50 # due to lock. Closing ArgGIS Pro releases the lock and the outputs +51 # can be overwritten. See: +52 # https://community.esri.com/t5/python-questions/arcpy-env-overwriteoutput-true-fails/m-p/411113#M32410 +53 # +54 arcpy.env.overwriteOutput = True +55 # +56 # Check the project directory exists. +57 # +58 global g_proj_dir +59 g_proj_dir = str(Path(proj_dir_str)) +60 assert Path(g_proj_dir).is_dir(), \ +61 f"Can't find the project directory {g_proj_dir}" +62 print("...project directory:", g_proj_dir) +63 # +64 # Assign global variables for the input and output geo-databases. +65 # +66 global g_in_gdb +67 g_in_gdb = full_path(proj_dir_str, in_gdb_str) +68 global g_temp_gdb +69 g_temp_gdb = temp_gdb_str +70 global g_out_gdb +71 g_out_gdb = full_path(proj_dir_str, out_gdb_str) +72 # +73 # Check the input and output geo-databases exist. +74 # +75 assert arcpy.Exists(g_in_gdb), \ +76 f"Can't find input geo-database: {g_in_gdb}" +77 assert arcpy.Exists(g_temp_gdb), \ +78 f"Can't find temporary geo-database: {g_temp_gdb}" +79 assert arcpy.Exists(g_out_gdb), \ +80 f"Can't find output geo-database: {g_out_gdb}" +81 print("...input geo-database:", g_in_gdb) +82 print("...temporary geo-database:", g_temp_gdb) +83 print("...output geo-database:", g_out_gdb) +84 +85 +86 def load_shapefile(shape_file: str, out_gdb: str) -> str: +87 """ +88 Load a shapefile into feature class with the same name in the +89 specified geodatabase. +90 +91 :param str shape_file: The file path to the shapefile. +92 :param str out_gdb: The path to the geo-database. +93 :return str: The geo-database path to the feature class +94 created. +95 """ +96 +97 print("...load_shapefile, shape_file", shape_file) +98 print("...load_shapefile, out_gdb:", out_gdb) +99 +100 assert arcpy.Exists(shape_file), \ +101 f"Can't find input shape_file: {shape_file}" +102 assert arcpy.Exists(out_gdb), \ +103 f"Can't find input out_gdb: {out_gdb}" +104 +105 try: +106 result: arcpy.Result = ( +107 arcpy.conversion.FeatureClassToGeodatabase( +108 Input_Features=[shape_file], +109 Output_Geodatabase=out_gdb +110 )) +111 except arcpy.ExecuteError: +112 # +113 # Handle geo-processing specific errors. +114 # +115 print("...load_shapefile, arcpy error executing " +116 "geo-processing tool.") +117 print(arcpy.GetMessages(2)) +118 sys.exit(101) +119 except: +120 # +121 # Handle any other type of error. +122 # +123 e = sys.exc_info()[1] +124 print(e.args[0]) +125 sys.exit(201) +126 +127 print(result.getMessages()) +128 # +129 # Unpack first element of result object as return value. +130 # +131 ret_val = result.getOutput(0) +132 # +133 # This tool ony returns the path to the gdb not the feature class. +134 # So, construct path to feature class here. +135 # +136 ret_val = full_path(ret_val, str(Path(shape_file).stem)) +137 +138 print("...load_shapefile,", arcpy.management.GetCount(ret_val), +139 "precincts loaded from shapefile.") +140 print("...load_shapefile, ret_val:", ret_val) +141 assert arcpy.Exists(ret_val), f"Can't find feature class: {ret_val}" +142 return ret_val +143 +144 +145 def load_table(dbf_file: str, out_gdb: str): +146 """ +147 Load a dbf file into a table with the same name in the specified +148 geo-database. +149 +150 :param str dbf_file: The file path to the dbf file. +151 :param str out_gdb: The path to the geo-database. +152 :return str: The geo-database path to the table created. +153 """ +154 +155 print("...load_table, dbf_file", dbf_file) +156 print("...load_table, out_gdb:", out_gdb) +157 +158 assert arcpy.Exists(dbf_file), \ +159 f"Can't find input dbf_file: {dbf_file}" +160 assert arcpy.Exists(out_gdb), f"Can't find input out_gdb: {out_gdb}" +161 +162 try: +163 result: arcpy.Result = arcpy.conversion.TableToGeodatabase( +164 Input_Table=[dbf_file], +165 Output_Geodatabase=out_gdb) +166 except arcpy.ExecuteError: +167 # +168 # Handle geo-processing specific errors. +169 # +170 print("...load_table, arcpy error executing " +171 "geo-processing tool.") +172 print(arcpy.GetMessages(2)) +173 sys.exit(102) +174 except: +175 # +176 # Handle any other type of error. +177 # +178 e = sys.exc_info()[1] +179 print(e.args[0]) +180 sys.exit(202) +181 +182 print(result.getMessages()) +183 # +184 # Unpack first element of result object as return value. +185 # +186 ret_val = result.getOutput(0) +187 # +188 # This tool ony returns the path to the gdb not the feature class. +189 # So, construct path to feature class here. +190 # +191 ret_val = full_path(ret_val, str(Path(dbf_file).stem)) +192 print("...load_table,", arcpy.management.GetCount(ret_val), +193 "cross_reference records loaded from dbf file.") +194 print("...load_table, ret_val:", ret_val) +195 assert arcpy.Exists(ret_val), f"Can't find feature class: {ret_val}" +196 return ret_val +197 +198 +199 def create_table(out_path: str, out_name: str) -> str: +200 """ +201 Create a new empty table in the specified geo-database. +202 +203 :param str out_path: The path to the geo-database +204 :param str out_name: The name of the table to create. +205 :return str: The geo-database path to the table created. +206 """ +207 +208 print("...create_table, out_path", out_path) +209 print("...create_table, out_name:", out_name) +210 +211 assert arcpy.Exists(out_path), \ +212 f"Can't find input out_path: {out_path}" +213 +214 try: +215 result: arcpy.Result = arcpy.management.CreateTable( +216 out_path=out_path, +217 out_name=out_name +218 ) +219 except arcpy.ExecuteError: +220 # +221 # Handle geo-processing specific errors. +222 # +223 print("...create_table, arcpy error executing " +224 "geo-processing tool.") +225 print(arcpy.GetMessages(2)) +226 sys.exit(103) +227 except: +228 # +229 # Handle any other type of error. +230 # +231 e = sys.exc_info()[1] +232 print(e.args[0]) +233 sys.exit(203) +234 +235 print(result.getMessages()) +236 # +237 # Unpack first element of result object as return value. +238 # +239 ret_val = result.getOutput(0) +240 print("...create_table, ret_val:", ret_val) +241 assert arcpy.Exists(ret_val), f"Can't find feature class: {ret_val}" +242 return ret_val +243 +244 +245 def add_fields(in_table: str, +246 field_description: List[List[str]]) -> str: +247 """ +248 Add fields to a table in the geo-database. +249 +250 :param str in_table: The geo-database path to the table. +251 :param str field_description: Specification of fields to add. +252 :return str: The geo-database path to the table. +253 """ +254 +255 print("...add_fields, in_table", in_table) +256 print("...add_fields, field_description:", field_description) +257 +258 assert arcpy.Exists(in_table), \ +259 f"Can't find input in_table: {in_table}" +260 +261 try: +262 result: arcpy.Result = arcpy.management.AddFields( +263 in_table=in_table, +264 field_description=field_description) +265 except arcpy.ExecuteError: +266 # +267 # Handle geo-processing specific errors. +268 # +269 print("...add_fields, arcpy error executing " +270 "geo-processing tool.") +271 print(arcpy.GetMessages(2)) +272 sys.exit(104) +273 except: +274 # +275 # Handle any other type of error. +276 # +277 e = sys.exc_info()[1] +278 print(e.args[0]) +279 sys.exit(204) +280 +281 print(result.getMessages()) +282 # +283 # Unpack first element of result object as return value. +284 # +285 ret_val = result.getOutput(0) +286 print("...add_fields, ret_val:", ret_val) +287 assert arcpy.Exists(ret_val), f"Can't find feature class: {ret_val}" +288 return ret_val +289 +290 +291 def join_by_field(in_data: str, in_field: str, join_table: str, +292 join_field: str, fields: List[str], +293 index_join_fields="NEW_INDEXES") -> str: +294 """ +295 Join two feature classes/tables based on a common key and transfer +296 the specified fields to one of the tables. +297 +298 :param str in_data: The geo-database path to the 1st table. +299 :param str in_field: The join field in the 1st table. +300 :param str join_table: The geo-database path to the 2nd table. +301 :param str str join_field: The join field in the 2nd table. +302 :param list fields: The list of fields to transfer. +303 :param str index_join_fields: Whether to create new indexes. +304 :return str: The geo-database path to the resulting +305 table. +306 """ +307 +308 print("...join_field, in_data", in_data) +309 print("...join_field, in_field:", in_field) +310 print("...join_field, join_table:", join_table) +311 print("...join_field, fields:", fields) +312 print("...join_field, index_join_fields:", index_join_fields) +313 +314 assert arcpy.Exists(in_data), f"Can't find input in_data: {in_data}" +315 assert arcpy.Exists(join_table), \ +316 f"Can't find input in_table: {join_table}" +317 +318 try: +319 result: arcpy.Result = arcpy.management.JoinField( +320 in_data=in_data, +321 in_field=in_field, +322 join_table=join_table, +323 join_field=join_field, +324 fields=fields, +325 index_join_fields=index_join_fields +326 ) +327 except arcpy.ExecuteError: +328 # +329 # Handle geo-processing specific errors. +330 # +331 print("...join_by_field, arcpy error executing " +332 "geo-processing tool.") +333 print(arcpy.GetMessages(2)) +334 sys.exit(105) +335 except: +336 # +337 # Handle any other type of error. +338 # +339 e = sys.exc_info()[1] +340 print(e.args[0]) +341 sys.exit(205) +342 +343 print(result.getMessages()) +344 # +345 # Unpack first element of result object as return value. +346 # +347 ret_val = result.getOutput(0) +348 print("...join_field,", arcpy.management.GetCount(ret_val), +349 "records after join.") +350 print("...join_field, ret_val:", ret_val) +351 assert arcpy.Exists(ret_val), f"Can't find feature class: {ret_val}" +352 return ret_val +353 +354 +355 def dissolve(in_features: str, out_feature_class: str, +356 dissolve_field: str) -> str: +357 """ +358 Dissolve the polygons in a feature class based on a shared value in +359 :a field. +360 +361 :param str in_features: The path to the input feature class. +362 :param str out_feature_class: The path to the output feature class. +363 :param str dissolve_field: The field to dissolve on. +364 :return str: The path to the output feature class. +365 """ +366 +367 print("...dissolve, in_features", in_features) +368 print("...dissolve, out_feature_class:", out_feature_class) +369 print("...dissolve, dissolve_field:", dissolve_field) +370 +371 assert arcpy.Exists(in_features), \ +372 f"Can't find input in_features: {in_features}" +373 +374 try: +375 result: arcpy.Result = arcpy.analysis.PairwiseDissolve( +376 in_features=in_features, +377 out_feature_class=out_feature_class, +378 dissolve_field=[dissolve_field] +379 ) +380 except arcpy.ExecuteError: +381 # +382 # Handle geo-processing specific errors. +383 # +384 print("...dissolve, arcpy error executing " +385 "geo-processing tool.") +386 print(arcpy.GetMessages(2)) +387 sys.exit(106) +388 except: +389 # +390 # Handle any other type of error. +391 # +392 e = sys.exc_info()[1] +393 print(e.args[0]) +394 sys.exit(206) +395 +396 print(result.getMessages()) +397 # +398 # Unpack first element of result object as return value. +399 # +400 ret_val = result.getOutput(0) +401 print("...dissolve,", arcpy.management.GetCount(ret_val), +402 "records after dissolve.") +403 print("...dissolve, ret_val:", ret_val) +404 assert arcpy.Exists(ret_val), f"Can't find feature class: {ret_val}" +405 return ret_val +406 +407 +408 def explode_xref(xref_table: str, xref_explode_table: str) -> str: +409 """ +410 Explode any regular precincts for each voting precinct in +411 the cross-reference table into multiple separate rows in a new +412 table. Note that the key and value in the exploded results table is +413 swapped from the input cross-reference table. The key in the output +414 table is the regular precinct and there can be only one voting +415 precinct for each regular precinct in the output. Each voting +416 precinct can appear in multiple rows in the output. +417 +418 :param str xref_table: The path to the cross-reference table. +419 :param str xref_explode_table: The path to the exploded table. +420 :return str: The path to the exploded table. +421 """ +422 +423 print("...explode_xref, xref_table", xref_table) +424 print("...explode_xref, xref_explode_table:", xref_explode_table) +425 +426 assert arcpy.Exists(xref_table), \ +427 f"Can't find input xref_table: {xref_table}" +428 assert arcpy.Exists(xref_explode_table), \ +429 f"Can't find input xref_explode_table: {xref_explode_table}" +430 +431 # +432 # Iterate over the cross-reference table and unpack multiple regular +433 # precincts dictionary entries. The dictionary key is the regular +434 # precinct and the value is the associated voting precinct. +435 # +436 precincts_1to1 = {} +437 try: +438 with (arcpy.da.SearchCursor( +439 xref_table, ["VotePrec", "_Precincts"]) as search_cur): +440 for voting_precinct, regular_precincts_str in search_cur: +441 # +442 # Unpack the regular precincts into individual items and +443 # add voting precinct to a dictionary with regular +444 # precinct as the key. Note: using a set here just in +445 # case there are any duplicate regular precincts in the +446 # same cross-reference row. +447 # +448 regular_precincts_set = \ +449 set(regular_precincts_str.split()) +450 for regular_precinct in regular_precincts_set: +451 precincts_1to1[regular_precinct] = \ +452 voting_precinct +453 except arcpy.ExecuteError: +454 # +455 # Handle geo-processing specific errors. +456 # +457 print("...explode_xref, arcpy error executing " +458 "geo-processing tool.") +459 print("...explode_xref, error in SearchCursor") +460 print(arcpy.GetMessages(2)) +461 sys.exit(107) +462 except: +463 # +464 # Handle any other type of error. +465 # +466 e = sys.exc_info()[1] +467 print(e.args[0]) +468 sys.exit(207) +469 # +470 # Insert the contents of the dictionary into a table so that we can +471 # use geo-processing tools to join to this table. +472 # +473 try: +474 with ( +475 arcpy.da.InsertCursor( +476 xref_explode_table, +477 ["Precinct", "VotePrec"]) as insert_cur): +478 for regular_precinct, voting_precinct \ +479 in precincts_1to1.items(): +480 insert_cur.insertRow( +481 [regular_precinct, +482 precincts_1to1[voting_precinct] +483 ] +484 ) +485 except arcpy.ExecuteError: +486 # +487 # Handle geo-processing specific errors. +488 # +489 print("...explode_xref, arcpy error executing " +490 "geo-processing tool.") +491 print("...explode_xref, error in InsertCursor") +492 print(arcpy.GetMessages(2)) +493 sys.exit(108) +494 except: +495 # +496 # Handle any other type of error. +497 # +498 e = sys.exc_info()[1] +499 print(e.args[0]) +500 sys.exit(208) +501 ret_val = xref_explode_table +502 print("...explode_xref, ret_val:", ret_val) +503 print("...explode_xref,", arcpy.management.GetCount(ret_val), +504 "regular precincts have a voting precinct assigned.") +505 assert arcpy.Exists(ret_val), f"Can't find feature class: {ret_val}" +506 return ret_val +507 +508 +509 def update_precincts(precincts_fc: str) -> str: +510 """ +511 Update the precincts feature class so that regular precincts that +512 don't appear in the cross-reference table have their voting precinct +513 set to the same value as their regular precinct. This is necessary +514 to avoid all these precincts being dissolved into a single polygon +515 because the share the same null value for voting precinct. +516 +517 :param str precincts_fc: The path to the precincts feature class. +518 :return str: The path to the precincts feature class. +519 """ +520 +521 print("...update_precincts, precincts_fc", precincts_fc) +522 +523 assert arcpy.Exists(precincts_fc), \ +524 f"Can't find input precincts_fc: {precincts_fc}" +525 +526 try: +527 with arcpy.da.UpdateCursor( +528 precincts_fc, ["Precinct", "VotePrec"], +529 where_clause='"VotePrec" is null') as update_cur: +530 update_count = 0 +531 for row in update_cur: +532 precinct, voting_precinct = row +533 if voting_precinct is None: +534 row[1] = precinct +535 update_cur.updateRow(row) +536 update_count += 1 +537 print("...update_precincts,", update_count, "rows updated.") +538 except arcpy.ExecuteError: +539 # +540 # Handle geo-processing specific errors. +541 # +542 print("...update_precincts, arcpy error executing " +543 "geo-processing tool.") +544 print("...update_precincts, error in UpdateCursor") +545 print(arcpy.GetMessages(2)) +546 sys.exit(109) +547 except: +548 # +549 # Handle any other type of error. +550 # +551 e = sys.exc_info()[1] +552 print(e.args[0]) +553 sys.exit(209) +554 +555 ret_val = precincts_fc +556 print("...update_precincts, ret_val:", ret_val) +557 print( +558 "...update_precincts,", +559 arcpy.management.GetCount(ret_val), +560 "regular precincts with a voting precinct assigned after update." +561 ) +562 assert arcpy.Exists(ret_val), f"Can't find feature class: {ret_val}" +563 return ret_val +564 +565 +566 def run_tools() -> None: +567 """ +568 Run the geo-processing tools to buffer and join the various feature +569 classes. +570 +571 :return NoneType: None +572 """ +573 # +574 # Load precincts from shapefile. +575 # +576 precincts_shp_file = str( +577 Path( +578 g_proj_dir, +579 "Precincts", +580 "Precincts.shp" +581 ) +582 ) +583 precincts = load_shapefile(precincts_shp_file, g_temp_gdb) +584 # +585 # Load cross-reference table from dbf file. +586 # +587 xref_dbf_file = str( +588 Path( +589 g_proj_dir, +590 "Precincts", +591 "Precinct_Cross_Reference.dbf" +592 ) +593 ) +594 xref = load_table(xref_dbf_file, g_temp_gdb) +595 # +596 # Create a table to hold exploded cross-references. +597 # +598 xref_explode = create_table(g_temp_gdb, "xref_explode") +599 fields_to_add = [ +600 ["Precinct", "TEXT", "", "255", "", ""], +601 ["VotePrec", "TEXT", "", "255", "", ""] +602 ] +603 xref_explode = add_fields(xref_explode, fields_to_add) +604 # +605 # Explode the cross-references. +606 # +607 xref_explode = explode_xref(xref, xref_explode) +608 # +609 # Join the exploded cross-references to the precincts. +610 # +611 precincts = join_by_field( +612 precincts, "Precinct", xref_explode, "Precinct", +613 ["VotePrec"]) +614 # +615 # Update precincts with no voting precinct. +616 # +617 update_precincts(precincts) +618 # +619 # Dissolve the precincts to get the voting precincts. +620 # +621 voting_precincts = full_path(g_out_gdb, "voting_precincts") +622 voting_precincts = dissolve( +623 precincts, voting_precincts, "VotePrec") +624 print(arcpy.management.GetCount(voting_precincts), +625 "voting precincts created.") +626 print(voting_precincts) +627 +628 +629 if __name__ == '__main__': +630 # +631 # Define locations of geodatabases. +632 # +633 my_proj_dir = r"C:\ArcGIS_local_projects\CodeChallenge3" +634 my_in_gdb = "CodeChallenge3.gdb" +635 # +636 # Intermediate results are written to the temporary geo-database. +637 # To speed processing and avoid writing intermediate results to +638 # disk this is set to "memory". +639 # If you need to keep these results, change this to the full path of +640 # a file geodatabase as follows: +641 # my_temp_gdb = full_path(my_proj_dir, "CodeChallenge3.gdb") +642 # +643 my_temp_gdb = "memory" +644 my_out_gdb = "CodeChallenge3.gdb" +645 setup_env(my_proj_dir, my_in_gdb, my_temp_gdb, my_out_gdb) +646 # +647 # Run the main process. +648 # +649 run_tools() +650 +651 # ---------------------------------------------------------------------- +652 # Sample Output +653 # ---------------------------------------------------------------------- +654 # "C:\Program Files\ArcGIS\Pro\bin\Python\envs\arcgispro-py3\python.exe" C:\PythonPro\Ex11\challenge3_v1.py +655 # ...project directory: C:\ArcGIS_local_projects\CodeChallenge3 +656 # ...input geo-database: C:\ArcGIS_local_projects\CodeChallenge3\CodeChallenge3.gdb +657 # ...temporary geo-database: memory +658 # ...output geo_database: C:\ArcGIS_local_projects\CodeChallenge3\CodeChallenge3.gdb +659 # ...load_shapefile, shape_file C:\ArcGIS_local_projects\CodeChallenge3\Precincts\Precincts.shp +660 # ...load_shapefile, out_gdb: memory +661 # C:\ArcGIS_local_projects\CodeChallenge3\Precincts\Precincts.shp Successfully converted: memory\Precincts +662 # Start Time: Wednesday, May 15, 2024 4:15:29 PM +663 # C:\ArcGIS_local_projects\CodeChallenge3\Precincts\Precincts.shp Successfully converted: memory\Precincts +664 # Succeeded at Wednesday, May 15, 2024 4:15:31 PM (Elapsed Time: 1.22 seconds) +665 # ...load_shapefile, 720 precincts loaded from shapefile. +666 # ...load_shapefile, ret_val: memory\Precincts +667 # ...load_table, dbf_file C:\ArcGIS_local_projects\CodeChallenge3\Precincts\Precinct_Cross_Reference.dbf +668 # ...load_table, out_gdb: memory +669 # Converted C:\ArcGIS_local_projects\CodeChallenge3\Precincts\Precinct_Cross_Reference.dbf to memory\Precinct_Cross_Reference successfully. +670 # Start Time: Wednesday, May 15, 2024 4:15:31 PM +671 # Converted C:\ArcGIS_local_projects\CodeChallenge3\Precincts\Precinct_Cross_Reference.dbf to memory\Precinct_Cross_Reference successfully. +672 # Succeeded at Wednesday, May 15, 2024 4:15:31 PM (Elapsed Time: 0.62 seconds) +673 # ...load_table, 138 cross_reference records loaded from dbf file. +674 # ...load_table, ret_val: memory\Precinct_Cross_Reference +675 # ...create_table, out_path memory +676 # ...create_table, out_name: xref_explode +677 # Start Time: Wednesday, May 15, 2024 4:15:31 PM +678 # Succeeded at Wednesday, May 15, 2024 4:15:31 PM (Elapsed Time: 0.01 seconds) +679 # ...create_table, ret_val: memory\xref_explode +680 # ...add_fields, in_table memory\xref_explode +681 # ...add_fields, field_description: [['Precinct', 'TEXT', '', '255', '', ''], ['VotePrec', 'TEXT', '', '255', '', '']] +682 # Start Time: Wednesday, May 15, 2024 4:15:31 PM +683 # Adding Precinct to xref_explode... +684 # Adding VotePrec to xref_explode... +685 # Succeeded at Wednesday, May 15, 2024 4:15:31 PM (Elapsed Time: 0.01 seconds) +686 # ...add_fields, ret_val: memory\xref_explode +687 # ...explode_xref, xref_table memory\Precinct_Cross_Reference +688 # ...explode_xref, xref_explode_table: memory\xref_explode +689 # ...explode_xref, ret_val: memory\xref_explode +690 # ...explode_xref, 561 regular precincts have a voting precinct assigned. +691 # ...join_field, in_data memory\Precincts +692 # ...join_field, in_field: Precinct +693 # ...join_field, join_table: memory\xref_explode +694 # ...join_field, fields: ['VotePrec'] +695 # ...join_field, index_join_fields: NEW_INDEXES +696 # Start Time: Wednesday, May 15, 2024 4:15:31 PM +697 # Succeeded at Wednesday, May 15, 2024 4:15:32 PM (Elapsed Time: 0.10 seconds) +698 # ...join_field, 720 records after join. +699 # ...join_field, ret_val: memory\Precincts +700 # ...update_precincts, precincts_fc memory\Precincts +701 # ...update_precincts, 159 rows updated. +702 # ...update_precincts, ret_val: memory\Precincts +703 # ...update_precincts, 720 regular precincts with a voting precinct assigned after update. +704 # ...dissolve, in_features memory\Precincts +705 # ...dissolve, out_feature_class: C:\ArcGIS_local_projects\CodeChallenge3\CodeChallenge3.gdb\voting_precincts +706 # ...dissolve, dissolve_field: VotePrec +707 # Start Time: Wednesday, May 15, 2024 4:15:32 PM +708 # Sorting Attributes... +709 # Dissolving... +710 # Succeeded at Wednesday, May 15, 2024 4:15:33 PM (Elapsed Time: 0.91 seconds) +711 # ...dissolve, 297 records after dissolve. +712 # ...dissolve, ret_val: C:\ArcGIS_local_projects\CodeChallenge3\CodeChallenge3.gdb\voting_precincts +713 # 297 voting precincts created. +714 # C:\ArcGIS_local_projects\CodeChallenge3\CodeChallenge3.gdb\voting_precincts +715 # +716 # Process finished with exit code 0 +717 # ---------------------------------------------------------------------- +718+ + \ No newline at end of file