<jupyter_start><jupyter_text>Setup<jupyter_code>import arcpy
import arcgis
import pandas as pd
import os
gis = arcgis.gis.GIS(url="https://ndirt.maps.arcgis.com", username="ANieto_ndirt")
bridge_item = gis.content.search("DCVAMD_NBI_Bridges", item_type="feature service")[0]
bridge_item
deficient_bridge_item = gis.content.search("DCVAMD_CBSA_DeficientBridges", item_type="feature service")[0]
deficient_bridge_item
analyzed_bridges_item = gis.content.search("Bridges_Analyzed", item_type="feature service")[0]
analyzed_bridges_item
analyzed_bridges_lyr = analyzed_bridges_item.layers[0]
analyzed_bridges_lyr
analyzed_bridges_item.layers[0].query("1=1")
analyzed_bridges_top_ranked = analyzed_bridges_item.layers[0].query("cbsa_rank = 1")
analyzed_bridges_top_ranked_df = analyzed_bridges_top_ranked.df
analyzed_bridges_top_ranked_df
commute_df = pd.DataFrame.from_csv(r"D:\5_Data\Transportation\Transit\commute_table.csv")
tract_polys = gis.content.search("DCVAMD_CBSA_Tracts_Polygons", item_type="feature service")[0]
tract_points = gis.content.search("DCVAMD_CBSA_Tracts_Centroids", item_type="feature service")[1]
tract_polys
tract_points
route_items = gis.content.search("Test Routes", item_type="feature service")
origin_dest_points = route_items[0]
normal_route = route_items[2]
impaired_route = route_items[1]
normal_route
impaired_route
import time

def animate_layer_addition_to_map(map_widget, list_of_items, zoom_level, basemap='gray-vector'):
    # The map widget
    m = map_widget
    m.basemap = basemap
    
    # 1. Parse the find-routes analysis results
    # Extract the output data from the analysis results
    # Store the output points and lines in pandas dataframes
    lines_df = result.output_routes.df
    lines_fset = arcgis.features.FeatureSet.from_dataframe(lines_df)
    
    # 2. Define the map symbology
    # Allocation lines
    allocation_line_symbol_1 = {'type': 'esriSLS', 'style': 'esriSLSSolid',
                                'color': [255,255,255,153], 'width': 0.7}

    allocation_line_symbol_2 = {'type': 'esriSLS', 'style': 'esriSLSSolid',
                                'color': [0,255,197,39], 'width': 3}

    allocation_line_symbol_3 = {'type': 'esriSLS', 'style': 'esriSLSSolid',
                                'color': [0,197,255,39], 'width': 5}
    
    allocation_line_symbol_4 = {'type': 'esriSLS', 'style': 'esriSLSSolid',
                                'color': [0,92,230,39], 'width': 7}
    
    time.sleep(1.5)
    m.draw(shape=result.output_routes, symbol=allocation_line_symbol_4)
    m.draw(shape=result.output_routes, symbol=allocation_line_symbol_2)
    m.draw(shape=result.output_routes, symbol=allocation_line_symbol_1)
    
    m.add_layer(stops_layer)
    
    m.zoom = zoom_level<jupyter_output><empty_output><jupyter_text>Spatial Analysis Methodology 1. Ask questions: Formulate hypotheses and spatialquestions. 2. Explore the data: Examine the data quality,completeness, and measurement limitations (scaleand resolution) to determine the level of analysis andinterpretation that can be supported. 3. Analyze and model: Break the problem down intosolvable components that can be modeled. Quantifyand evaluate the spatial questions. 4. Interpret the results: Evaluate and analyze the resultsin the context of the question posed, data limitations,accuracy, and other implications. 5. Repeat as necessary: Spatial analysis is a continuousand iterative process that often leads to furtherquestions and refinements. 6. Present the results: The best information andanalysis becomes increasingly valuable when it can beeffectively presented and shared with a larger audience. 7. Make a decision: Spatial analysis and GIS are used to support the decision-making process. A successful spatial analysis process often leads to the understanding necessary to drive decisions and action.  1. Ask Questions  What would be the impact to commuters if a structurally deficient bridge is impaired?  2. Explore Data  Exploring Bridge Data  Bridges in the DC Area (CBSA)<jupyter_code>bridges_map = gis.map('Fairfax County', zoomlevel=8)
bridges_map.basemap = 'gray-vector'
display(bridges_map)
bridges_map.add_layer(bridge_item)
bridges_sdf = arcgis.features.SpatialDataFrame.from_layer(bridge_item.layers[0]); bridges_sdf.head()
print([col for col in bridges_sdf.columns])<jupyter_output><empty_output><jupyter_text>National Bridge Inventory (NBI) Schema: https://www.fhwa.dot.gov/bridge/mtguide.pdf  Structurally Deficient Bridges in the DC Area (CBSA)<jupyter_code>deficient_bridges_map = gis.map('Fairfax County', zoomlevel=8)
deficient_bridges_map.basemap = 'gray-vector'
display(deficient_bridges_map)
deficient_bridges_map.add_layer(deficient_bridge_item)<jupyter_output><empty_output><jupyter_text>Exploring Commuting Data  Map of all DC CBSA Tracts<jupyter_code>tracts_map = gis.map('Arlington, VA', zoomlevel=9)
tracts_map.basemap = 'streets-night-vector'
tracts_map.add_layer(tract_points)
display(tracts_map)<jupyter_output><empty_output><jupyter_text>Table of Commuting Patterns by Tract Census Journey to Work Data: https://www.census.gov/topics/employment/commuting.html<jupyter_code>commute_df = pd.DataFrame.from_csv(r"D:\5_Data\Transportation\Transit\commute_table.csv")
commute_df<jupyter_output><empty_output><jupyter_text>3. Analyze and model:  Analysis Question: What would be the impact to commuters if a structurally deficient bridge is impaired?<jupyter_code>exploration_map = gis.map('Arlington, VA', zoomlevel=9)
exploration_map.basemap = 'streets-night-vector'
exploration_map.add_layer(tract_points)
display(exploration_map)
exploration_map.add_layer(deficient_bridge_item)<jupyter_output><empty_output><jupyter_text>Let's explore an example commute...<jupyter_code>m2 = gis.map('Washington Navy Yard', zoomlevel=12)
m2.basemap = 'gray-vector'
display(m2)
m2.add_layer(origin_dest_points)
m2.add_layer(normal_route)
m2.add_layer(deficient_bridge_item)
m2.add_layer(impaired_route)<jupyter_output><empty_output><jupyter_text>Prototype Analysis Workflow    Automated Workflow Steps:  1. Set Environment and Retrieve Bridge and Commute Pattern Data<jupyter_code># Set workspace
processing_workspace = r"D:\ANieto_SolutionEngineer\Projects\FedGIS\ArcGISAPIforPython_Workspace\bridge_processing"
workspace_gdb = r"D:\ANieto_SolutionEngineer\Projects\FedGIS\ArcGISAPIforPython_Workspace\BridgeCriticality_Arcpy_Workspace.gdb"
# workspace_gdb = "C:\\Users\\albe9057\\Documents\\ANieto_SolutionEngineering\\Projects\\FedGIS\\FedGIS_2018\\Plenary_ArcGISAPIforPython\\Work\\Bridge_Criticality_Analysis\\BridgeCriticality_Arcpy_Workspace.gdb"

# Set Arcpy environment
arcpy.env.workspace = workspace_gdb
arcpy.env.overwriteOutput = True

# Set reference to origins
origin_tracts = r"D:\ANieto_SolutionEngineer\Projects\FedGIS\ArcGISAPIforPython_Workspace\BridgeCriticality_Arcpy_Workspace.gdb\DCVAMD_CBSA_Tracts_Centroids"
# origin_tracts = "C:\\Users\\albe9057\\Documents\\ANieto_SolutionEngineering\\Projects\\FedGIS\\FedGIS_2018\\Plenary_ArcGISAPIforPython\\Work\\Bridge_Criticality_Analysis\\Bridge_Criticality_Analysis.gdb\\DCVAMD_CBSA_Tracts_Centroids"
origins_id_field = "ID"
origins_name_field = "NAME"

# Set reference to destinations
dest_tracts = r"D:\ANieto_SolutionEngineer\Projects\FedGIS\ArcGISAPIforPython_Workspace\BridgeCriticality_Arcpy_Workspace.gdb\DCVAMD_CBSA_Tracts_Centroids"
# dest_tracts = "C:\\Users\\albe9057\\Documents\\ANieto_SolutionEngineering\\Projects\\FedGIS\\FedGIS_2018\\Plenary_ArcGISAPIforPython\\Work\\Bridge_Criticality_Analysis\\Bridge_Criticality_Analysis.gdb\\DCVAMD_CBSA_Tracts_Centroids"
dest_id_field = "ID"
dest_name_field = "NAME"

# Set reference to bridges
bridges_fc = "C:\\Users\\albe9057\\Documents\\ANieto_SolutionEngineering\\Projects\\FedGIS\\FedGIS_2018\\Plenary_ArcGISAPIforPython\\Work\\Bridge_Criticality_Analysis\\Bridge_Criticality_Analysis.gdb\\DCVAMD_CBSA_DeficientBridges"
polybarrier_bridges_fc = "C:\\Users\\albe9057\\Documents\\ANieto_SolutionEngineering\\Projects\\FedGIS\\FedGIS_2018\\Plenary_ArcGISAPIforPython\\Work\\Bridge_Criticality_Analysis\\Bridge_Criticality_Analysis.gdb\\DCVAMD_CBSA_DeficientBridges_Polybarriers"
polybarriers_id_field = "OBJECTID"

# Set reference to the network dataset
network_dataset = "C:\\ArcGIS\\Business Analyst\\US_2015\\Data\\Streets Data\\NAVTEQ_2014_Q3_NA.gdb\\Routing\\Routing_ND"

# Set reference to commute table
commute_table = "C:\\Users\\albe9057\\Documents\\ANieto_SolutionEngineering\\Projects\\FedGIS\\FedGIS_2018\\Plenary_ArcGISAPIforPython\\Work\\Bridge_Criticality_Analysis\\Bridge_Criticality_Analysis.gdb\\ctpp_journey_to_work"

# Set reference to impedance values needed for odcm
impedance_value=99999
impedance_attribute="Minutes"
accumulate_attributes = ["Minutes", "Miles"]<jupyter_output><empty_output><jupyter_text>2. Perform Bridge Commuting Impacts Analysis  Option 1: Python API ODCM via WebGIS<jupyter_code>arcgis.network.analysis.generate_origin_destination_cost_matrix?<jupyter_output><empty_output><jupyter_text>Option 2: Custom ODCM via ArcPy   Custom ODCM Helper Function<jupyter_code>def create_odcm(gdb,
                origins_fc,
                origins_id_field,
                origins_name_field,
                destinations_fc,
                destinations_id_field,
                destinations_name_field,
                odcm_name,
                network_dataset,
                impedance_value,
                impedance_attribute,
                impedance_attribute_field_name="Dij",
                use_lines=False,
                out_na_layer_name="Origins2Destinations",
                validate_inputs=False,
                method_message="\t\tcreate_odcm: ",
                output_origin_id_field_name='origin_id',
                output_origin_name_field_name='origin_name',
                output_dest_id_field_name='destination_id',
                output_dest_name_field_name='destination_name',
                logger_object=None):
    """
    create_odcm: Creates an origin-destination cost matrix with additional output handling
    """

    # Set standardized method messaging title

    general_utils.log_print("{0}Initializing Origin-Destination Cost Matrix process...".format(method_message),
                            "INFO",
                            logger_object)

    # Establish workspace parameters
    workspace = gdb
    arcpy.env.workspace = workspace
    arcpy.env.overwriteOutput = True

    # Determine which version of arcgis desktop is being used
    DesktopVersion = ArcGISVersionChecker()[2]

    lines_param = "STRAIGHT_LINES" if use_lines else "NO_LINES"
    general_utils.log_print("DEVNOTE: lines_param={0}".format(lines_param), "DEBUG", logger_object)

    general_utils.log_print("{0}Acquiring Network Analyst extension...".format(method_message), "DEBUG", logger_object)
    # Acquire Network Analyst extension
    if arcpy.CheckExtension("Network") != "Available":
        # Raise a custom exception
        ##            raise LicenseError
        general_utils.log_print("{0}ERROR: A Network Analyst License is required in order to create the ODCM; the ODCM will not be produced. Please consult with the GIS Developer if a license is expected to be available...".format(method_message),
                                "ERROR",
                                logger_object)
        raise ValueError("Unable to acquire a network analyst license!")

    elif arcpy.CheckExtension("Network") == "Available":
        arcpy.CheckOutExtension("Network")

        if validate_inputs:
            # Perform verification of origins and destinations feature classes
            general_utils.log_print("{0}Acquiring Origins...".format(method_message), "DEBUG", logger_object)
            if arcpy.Exists(origins_fc):
                pass
            else:
                general_utils.log_print("Unable to run create_odcm with provided origins!", "ERROR", logger_object)
                raise ValueError("Unable to run create_odcm with provided origins!")
            print("{0}Acquiring Destinations...".format(method_message))
            if arcpy.Exists(destinations_fc):
                pass
            else:
                general_utils.log_print("Unable to run create_odcm with provided destinations!", "ERROR", logger_object)
                raise ValueError("Unable to run create_odcm with provided destinations!")

        general_utils.log_print("{0}Establishing Network Analyst Layer...".format(method_message), "DEBUG", logger_object)
        outlayerfile = out_na_layer_name + ".lyr"

        general_utils.log_print("{0}The established impedance attribute is: {1}".format(method_message, str(impedance_attribute)), "DEBUG", logger_object)
        # Create variable that refers to the Impedance Attribute Field from the default ODCM Table
        impedance_attribute_field = "Total_" + impedance_attribute

        general_utils.log_print("{0}Establishing Destination Search Distance Cut-Off...".format(method_message), "DEBUG", logger_object)
        # Import user parameter 'Impedance Cutoff'

        general_utils.log_print("{0}Impedance Cutoff: {1}".format(method_message, str(impedance_value)), "DEBUG", logger_object)
        # Create the Composite Origin-Destination Cost Matrix Network Analysis Layer.

        general_utils.log_print("{0}Creating Origin-Destination Cost Matrix...".format(method_message), "DEBUG", logger_object)
        out_na_layer = arcpy.MakeODCostMatrixLayer_na(network_dataset,
                                                      out_na_layer_name,
                                                      impedance_attribute,
                                                      impedance_value, "", "", "", "",
                                                      "USE_HIERARCHY", "",
                                                      lines_param).getOutput(0)

        # Acquire the SubLayers from the Composite Origin-Destination Cost Matrix Network Analysis Layer
        general_utils.log_print("{0}Acquiring Composite Network Analysis SubLayers...".format(method_message), "DEBUG", logger_object)
        sublayer_names = arcpy.na.GetNAClassNames(out_na_layer)
        # Acquire the Origin's SubLayer
        general_utils.log_print("{0}Acquiring Origins SubLayer...".format(method_message), "DEBUG", logger_object)
        origins_layername = sublayer_names["Origins"]
        # Create a Field Map object to Map the 'CovLogic_Centroid' IDs to the Origins field of the Origin-Destination Cost Matrix
        origins_fieldmap = arcpy.na.NAClassFieldMappings(out_na_layer, origins_layername)
        origins_fieldmap["Name"].mappedFieldName = origins_id_field
        # Load the Origins into the Composite Network Analysis Layer.
        general_utils.log_print("{0}Loading Origins into Composite Network Analysis Layer...".format(method_message), "DEBUG", logger_object)
        arcpy.na.AddLocations(out_na_layer, origins_layername, origins_fc, origins_fieldmap)
        # Acquire the Destinations SubLayer.
        general_utils.log_print("{0}Acquiring Destinations SubLayer...".format(method_message), "DEBUG", logger_object)
        destinations_layername = sublayer_names["Destinations"]
        # Create a Field Map object to map the 'proForma' DIDs to the Destinations field of the Origin-Destination Cost Matrix.
        destinations_fieldmap = arcpy.na.NAClassFieldMappings(out_na_layer, destinations_layername)
        destinations_fieldmap["Name"].mappedFieldName = destinations_id_field
        # Load the Destinations into the Composite Network Analysis Layer.
        general_utils.log_print("{0}Loading Destinations into Composite Network Analysis Layer...".format(method_message), "DEBUG", logger_object)
        arcpy.na.AddLocations(out_na_layer, destinations_layername, destinations_fc, destinations_fieldmap)
        # Solve the Network
        general_utils.log_print("{0}Solving Network 'Origins2Destinations' Origin-Destination Cost Matrix...".format(method_message), "DEBUG", logger_object)
        arcpy.na.Solve(out_na_layer)
        # Verify if the directory, C:\Temp exists on the client system
        if not os.path.exists(r"C:\Temp"):
            # IF the directory, C:\Temp does not exist, create it
            os.makedirs(r"C:\Temp")
        # Set the Workspace to C:\Temp
        general_utils.log_print("{0}Resetting Workspace to C:\Temp...".format(method_message), "DEBUG", logger_object)
        arcpy.env.workspace = r"C:\Temp"
        # Extract the 'in_memory' result layer and save it as a Layer File in the workspace.
        general_utils.log_print("{0}Extracting Result Layer from memory...".format(method_message), "DEBUG", logger_object)
        arcpy.SaveToLayerFile_management(out_na_layer, outlayerfile, "RELATIVE")
        # Establish a reference to the Result Layer
        general_utils.log_print("{0}Acquiring Result Layer...".format(method_message), "DEBUG", logger_object)
        ResultLayer = arcpy.mapping.Layer(r"C:\Temp\{0}.lyr".format(out_na_layer_name))
        # Reset the Workspace to the workspace
        general_utils.log_print("{0}Resetting Workspace to {1}...".format(method_message, str(workspace)), "DEBUG", logger_object)
        arcpy.env.workspace = workspace
        # Establish a reference to a standard ESRI Map Template
        general_utils.log_print("{0}Acquiring ESRI Template MXD...".format(method_message), "DEBUG", logger_object)
        TempMXD = arcpy.mapping.MapDocument(r"C:\Program Files (x86)\ArcGIS\\{0}\\MapTemplates\Traditional Layouts\LetterPortrait.mxd".format(str(DesktopVersion)))
        # Establish a reference to the DataFrame within the ESRI Map Template
        general_utils.log_print("{0}Acquiring ESRI Template MXD DataFrame...".format(method_message), "DEBUG", logger_object)
        TempDF = arcpy.mapping.ListDataFrames(TempMXD)[0]
        # Add the 'ResultLayer' to the DataFrame in the 'TempMXD'
        general_utils.log_print("{0}Adding Result Layer to ESRI Template MXD...".format(method_message), "DEBUG", logger_object)
        arcpy.mapping.AddLayer(TempDF, ResultLayer)
        # Create a container and dynamically populate it with the layer in the Dataframe named 'Lines'
        lines_lyr = arcpy.mapping.ListLayers(TempMXD, "Lines", TempDF)
        if len(lines_lyr) > 1:
            raise ValueError("Multiple OD Cost Matrices populated in Template MXD. Cannot identify correct OD Cost Matrix.")
        elif len(lines_lyr) < 1:
            raise ValueError("OD Cost Matrix was not populated in Template MXD. Unable to extract result.")
        else:
            for lyr in lines_lyr:
                # Export the table associated with the 'Lines' layer to a new table in the Workspace
                general_utils.log_print("{0}Extracting Retail Node Sites Origin-Destination Cost Matrix...".format(method_message), "DEBUG", logger_object)
                arcpy.TableToTable_conversion(lyr, workspace, "ODCM_{0}".format(str(odcm_name)))
                # Remove the layer from the TempMXD's DataFrame
                general_utils.log_print("{0}Removing Result Layer from ESRI Template MXD...".format(method_message), "DEBUG", logger_object)
                arcpy.mapping.RemoveLayer(TempDF, lyr)
                # Delete the 'ResultLayer' file from disk
                if not use_lines:
                    general_utils.log_print("{0}Deleting Result Layer from disk...".format(method_message), "DEBUG", logger_object)
                    arcpy.Delete_management(r"C:\Temp\{0}.lyr".format(out_na_layer_name))
        # Establish a reference to the ProForma Sites Origin-Destination Cost Matrix
        general_utils.log_print("{0}Acquiring Origin-Destination Cost Matrix...".format(method_message), "DEBUG", logger_object)
        odcm = "{0}\\ODCM_{1}".format(workspace, str(odcm_name))
        # Display a message to the user that the Origin-Destination Cost Matrix generation process completed
        general_utils.log_print("{0}Origin-Destination Cost Matrix data loading process complete.".format(method_message), "DEBUG", logger_object)

        """ [SP] Hydrate Origin-Destination Cost Matrix"""
        # Delete any unnecessary fields ('DestinationID', 'OriginID', 'DestinationRank') from the current odcm
        general_utils.log_print(
            "{0}Performing ODCM preparation and preliminary calculations...".format(method_message), "DEBUG", logger_object)
        general_utils.log_print(
            "{0}Deleting fields 'DestinationID' | 'OriginID' from ODCM...".format(method_message), "DEBUG", logger_object)
        arcpy.DeleteField_management(odcm, ["DestinationID", "OriginID"])

        # Create a new fields for origin and destinations in the 'ODCM' table

        # Add id field for origin ids
        general_utils.log_print("{0}Creating new field '{1}'...".format(method_message, output_origin_id_field_name), "DEBUG", logger_object)
        arcpy.AddField_management(odcm, output_origin_id_field_name, "TEXT", "", "", 20, output_origin_id_field_name,
                                  "NULLABLE",
                                  "REQUIRED")
        # Add name field for origins
        general_utils.log_print("{0}Creating new field '{1}'...".format(method_message, output_origin_name_field_name), "DEBUG", logger_object)
        arcpy.AddField_management(odcm, output_origin_name_field_name, "TEXT", "", "", 100,
                                  output_origin_name_field_name,
                                  "NULLABLE", "REQUIRED")

        # Destinations fields
        # Add id field for destinations
        general_utils.log_print("{0}Creating new field '{1}'...".format(method_message, output_dest_id_field_name), "DEBUG", logger_object)
        arcpy.AddField_management(odcm, output_dest_id_field_name, "TEXT", "", "", 20,
                                  output_dest_id_field_name,
                                  "NULLABLE", "REQUIRED")
        # Add name field for destinations
        general_utils.log_print("{0}Creating new field '{1}'...".format(method_message, output_dest_name_field_name), "DEBUG", logger_object)
        arcpy.AddField_management(odcm, output_dest_name_field_name, "TEXT", "", "", 100,
                                  output_dest_name_field_name,
                                  "NULLABLE", "REQUIRED")

        # Calculate the 'OriginID' and 'DestinationID' fields in the 'ODCM' table,
        # populating the field with the components from the default 'Name' field in the odcm table
        general_utils.log_print("{0}Calculating '{1}', '{2}' fields...".format(method_message,
                                                             output_origin_id_field_name,
                                                             output_dest_id_field_name), "DEBUG", logger_object)
        with arcpy.da.UpdateCursor(odcm, ['Name', output_origin_id_field_name, output_dest_id_field_name]) as cursor:
            for row in cursor:
                string = row[0]
                origin_id = string.split(' - ')[0]
                dest_id = string.split(' - ')[1]
                row[1] = origin_id
                row[2] = dest_id
                cursor.updateRow(row)

        # Create a new field 'Dij' in the 'ODCM' table
        general_utils.log_print("{0}Creating new field '{1}'...".format(method_message, impedance_attribute_field_name), "DEBUG", logger_object)
        arcpy.AddField_management(odcm,
                                  impedance_attribute_field_name,
                                  "DOUBLE", 15, 5, "",
                                  impedance_attribute_field_name, "NULLABLE",
                                  "REQUIRED")
        # Calculate the 'Dij' field in the 'ODCM' table
        general_utils.log_print("{0}Calculating '{1}' field...".format(method_message, impedance_attribute_field_name), "DEBUG", logger_object)
        arcpy.CalculateField_management(odcm,
                                        impedance_attribute_field_name,
                                        "!" + impedance_attribute_field + "!",
                                        "PYTHON")
        # Round the values held in the 'Dij' field in the 'ODCM' table to the nearest 5 significant digits
        arcpy.CalculateField_management(odcm,
                                        impedance_attribute_field_name,
                                        "round(!{0}!, 5)".format(impedance_attribute_field_name),
                                        "PYTHON")
        # Delete the default impedence attribute field from the 'ODCM' table
        general_utils.log_print("{0}Removing default impedance attribute field...".format(method_message), "DEBUG", logger_object)
        arcpy.DeleteField_management(odcm, str(impedance_attribute_field))

        general_utils.log_print("{0}Operation complete. Go Gators.".format(method_message), "DEBUG", logger_object)

        arcpy.CheckInExtension("Network")
        return odcm<jupyter_output><empty_output><jupyter_text>Run ODCM for Nominal Commute<jupyter_code>if os.path.isfile("nominal_odcm.csv"):
    print("Found nominal ODCM. Using processed data...")
    nominal_odcm_df = pd.DataFrame.from_csv("nominal_odcm.csv")
    
else:

    # Run nominal ODCM using tracts to tracts
    nominal_odcm = create_odcm(gdb=workspace_gdb,
                               origins_fc=origin_tracts,
                               origins_id_field=origins_id_field,
                               origins_name_field=origins_name_field,
                               destinations_fc=dest_tracts,
                               destinations_id_field=dest_id_field,
                               destinations_name_field=dest_name_field,
                               odcm_name="nominal_baseline",
                               network_dataset=network_dataset,
                               impedance_value=impedance_value,
                               impedance_attribute=impedance_attribute,
                               accumulate_attribute_name=accumulate_attributes,
                               polybarrier_fc=None,
                               polybarrier_id_field=None,
                               polybarrier_name_field=None,
                               impedance_attribute_field_name="Dij",
                               use_lines=False,
                               out_na_layer_name="Origins2Destinations",
                               validate_inputs=False,
                               method_message="create_odcm: ",
                               output_origin_id_field_name='origin_id',
                               output_origin_name_field_name='origin_name',
                               output_dest_id_field_name='destination_id',
                               output_dest_name_field_name='destination_name',
                               logger_object=None)

    # Convert the odcm gis table to a pandas dataframe
    print("Calculating ID Fields...")
    nominal_odcm_df = convert_gis_table_to_pddataframe(nominal_odcm)
    nominal_odcm_df['OriginID'] = nominal_odcm_df.apply(lambda row: get_origin_id_from_odid(row['Name']), axis=1)
    nominal_odcm_df['DestinationID'] = nominal_odcm_df.apply(lambda row: get_dest_id_from_odid(row['Name']), axis=1)
    nominal_odcm_df.to_csv("nominal_odcm.csv")

nominal_odcm_df.head()<jupyter_output><empty_output><jupyter_text>Run Bridge Iteration: For each Bridge, Run ODCM with Bridge Feature as a Network Barrier<jupyter_code># Set iteration: Structurally Deficient Bridges in DC Metropolitan Region from NBI data

# Build list of buffered bridges
bridges_list = [row[0] for row in arcpy.da.SearchCursor(polybarrier_bridges_fc, polybarriers_id_field)]

# Make bridges processing directory
bridge_dir_path = r"D:\ANieto_SolutionEngineer\Projects\FedGIS\ArcGISAPIforPython_Workspace\bridge_processing"

if not os.path.isdir(bridge_dir_path):
    os.mkdir(bridge_dir_path)
    brigde_dir = bridge_dir_path
else:
    bridge_dir = bridge_dir_path

os.chdir(bridge_dir)

# For each bridge
for bridge in bridges_list:
    
    print("\nChecking bridge {0} of {1}...".format(str(bridge), str(len(bridges_list))))
    if os.path.isfile("impacted_commuters_odcm_{0}.csv".format(str(bridge))):
        print("Found bridge. Using processed data...")
        impacted_commuters_df = pd.DataFrame.from_csv("impacted_commuters_odcm_{0}.csv".format(str(bridge)))

    else:

        print("\nProcessing bridge {0} of {1}...".format(str(bridge), str(len(bridges_list))))
        # Set where clause
        bridge_sql = "{0} = {1}".format(arcpy.AddFieldDelimiters(polybarrier_bridges_fc, polybarriers_id_field), bridge)

        # Export feature to act as a single polyline barrier
        polybarrier_bridge_fc = arcpy.Select_analysis(polybarrier_bridges_fc, "{0}/Bridge_{1}".format(workspace_gdb, str(bridge)), bridge_sql)

        # Run impaired ODCM using tracts to tracts, using a bridge feature as a polygon barrier
        impaired_odcm = create_odcm(gdb=workspace_gdb,
                                origins_fc=origin_tracts,
                                origins_id_field=origins_id_field,
                                origins_name_field=origins_name_field,
                                destinations_fc=dest_tracts,
                                destinations_id_field=dest_id_field,
                                destinations_name_field=dest_name_field,
                                odcm_name="impaired_test",
                                network_dataset=network_dataset,
                                impedance_value=impedance_value,
                                impedance_attribute=impedance_attribute,
                                accumulate_attribute_name=accumulate_attributes,
                                polybarrier_fc=polybarrier_bridge_fc,
                                polybarrier_id_field=polybarriers_id_field,
                                polybarrier_name_field="ITEM6A",
                                impedance_attribute_field_name="Dij",
                                use_lines=False,
                                out_na_layer_name="Origins2Destinations",
                                validate_inputs=False,
                                method_message="create_odcm: ",
                                output_origin_id_field_name='origin_id',
                                output_origin_name_field_name='origin_name',
                                output_dest_id_field_name='destination_id',
                                output_dest_name_field_name='destination_name',
                                logger_object=None)

        # Convert the odcm gis table to a pandas dataframe
        impaired_odcm_csv = gis_table_to_csv(impaired_odcm, bridge_dir, "impaired_odcm_{0}.csv".format(str(bridge)))
        impaired_odcm_df = pd.DataFrame.from_csv(impaired_odcm_csv)
        
#         impaired_odcm_df = convert_gis_table_to_pddataframe(impaired_odcm)
        impaired_odcm_df['OriginID'] = impaired_odcm_df.apply(lambda row: get_origin_id_from_odid(row['Name']), axis=1)
        impaired_odcm_df['DestinationID'] = impaired_odcm_df.apply(lambda row: get_dest_id_from_odid(row['Name']), axis=1)
        impaired_odcm_df.to_csv("impaired_odcm_{0}.csv".format(str(bridge)))

        # Join nominal and impaired ODCM dataframes
        nom_imp_odcm_df = pd.merge(nominal_odcm_df, impaired_odcm_df, how="left", on="Name")

        # Join nominal+impaired ODCM dataframe to commute dataframe (inner join; remove anything not common)
        commute_impacts_df = pd.merge(commute_df, nom_imp_odcm_df, how="inner", left_on="ORIGIN_DESTINATION_ID", right_on="Name")
        commute_impacts_df.to_csv("commute_impacts_odcm_{0}.csv".format(str(bridge)))

        # Identify deltas in impedance
        commute_impacts_df['minutes_diff'] = commute_impacts_df['Total_Minutes_x'] - commute_impacts_df['Total_Minutes_y']
        commute_impacts_df['miles_diff'] = commute_impacts_df['Total_Miles_x'] - commute_impacts_df['Total_Miles_y']
        impacted_commuters_df = commute_impacts_df.loc[commute_impacts_df['minutes_diff'] > 0]
        impacted_commuters_df.to_csv("impacted_commuters_odcm_{0}.csv".format(str(bridge)))

    # Calculate count and impedance sum in deltas
    routes_impacted = impacted_commuters_df.shape[0]
    commuters_impacted = commuters_impacted = impacted_commuters_df['EST'].sum()
    total_additional_minutes = impacted_commuters_df['minutes_diff'].sum()
    total_additional_miles = impacted_commuters_df['miles_diff'].sum()

    bridges_df.loc[bridge, "routes_impacted"] = routes_impacted
    bridges_df.loc[bridge, "commuters_impacted"] = commuters_impacted
    bridges_df.loc[bridge, "total_additional_minutes"] = total_additional_minutes
    bridges_df.loc[bridge, "total_additional_miles"] = total_additional_miles
    
    
print("Complete.")
bridges_df.to_csv(r"C:\Users\albe9057\Documents\GitHub\ArcGISPythonAPI_Projects\Presentation\FedGIS2018\bridges_processed.csv")<jupyter_output><empty_output><jupyter_text>Calculate "Impact Rank" for bridges for entire study area (CBSA) and for each county<jupyter_code># Stack rank all bridges based on criticality score
bridges_df['cbsa_rank'] = bridges_df['total_additional_miles'].rank(ascending=False); bridges_df
# Group-by for county rankings
bridges_df['county_rank'] = bridges_df.groupby('ITEM3')['total_additional_miles'].rank(ascending=False); bridges_df<jupyter_output><empty_output><jupyter_text>3. Publish Outputs to WebGIS<jupyter_code># Publish outputs
bridges_df.to_csv(r"C:\Users\albe9057\Documents\GitHub\ArcGISPythonAPI_Projects\Presentation\FedGIS2018\bridges_analyzed.csv")
# bridges_processed_csv = r"C:\Users\albe9057\Documents\GitHub\ArcGISPythonAPI_Projects\Presentation\FedGIS2018\bridges_processed.csv"
bridges_analyzed_csv = r"C:\Users\albe9057\Documents\GitHub\ArcGISPythonAPI_Projects\Presentation\FedGIS2018\bridges_analyzed.csv"
# Publish csv item
bridges_analyzed_csv_item = gis.content.add({}, bridges_analyzed_csv)
# Convert csv item to hosted layer in ArcGIS Online
bridges_analyzed_lyr = bridges_analyzed_csv_item.publish()<jupyter_output><empty_output><jupyter_text>The ArcGIS API for Python let us document, design, prototype, and run our workflow helped us get to an analysis that can now be deployed.   4. Interpret Results<jupyter_code>display(analyzed_bridges_item)<jupyter_output><empty_output><jupyter_text>Map of Analyzed Bridges<jupyter_code>analyzed_bridges_map = gis.map('Fairfax County', zoomlevel=8)
analyzed_bridges_map.basemap = 'gray-vector'
display(analyzed_bridges_map)
analyzed_bridges_map.add_layer(analyzed_bridges_item)<jupyter_output><empty_output><jupyter_text>Map of Most Critical Bridge, with nominal commutes, and alternative commutes<jupyter_code>most_critical_bridge_map = gis.map('Fairfax County', zoomlevel=8)
most_critical_bridge_map.basemap = 'gray-vector'
display(most_critical_bridge_map)<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.09144686080073157, 'fraction_numerical': 0.008801760352070413, 'mean_word_length': 3.2900576192227535, 'pattern_counts': {'":': 2, '<': 70, '<?xml version=': 0, '>': 71, 'https://': 3, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 35, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '17', 'dir': 'jupyter-structured-clean-dedup', 'id': '41849', 'license': 'Apache-2.0', 'n_tokens_mistral': 10813, 'n_tokens_neox': 10189, 'n_words': 1994, 'path': 'talks/uc2018/AnalysisAndDataScience/FindingCriticalBridges.ipynb', 'repo_name': 'nitz21/arcpy', 'size': '34993'}