Make OD Cost Matrix Layer (Network Analyst)

Summary

Makes an origin–destination (OD) cost matrix network analysis layer and sets its analysis properties. An OD cost matrix analysis layer is useful for representing a matrix of costs going from a set of origin locations to a set of destination locations.

Usage

  • After creating the analysis layer with this tool, you can add network analysis objects to it using the Add Locations tool, solve the analysis using the Solve tool, and save the results on disk using the Save To Layer File tool.

  • When using this tool in geoprocessing models, if the model is run as a tool, the output network analysis layer must be made a model parameter; otherwise, the output layer is not added to the contents of the map.

Parameters

LabelExplanationData Type
Input Analysis Network

The network dataset on which the OD cost matrix analysis will be performed.

Network Dataset Layer
Output Layer Name

Name of the OD cost matrix network analysis layer to create.

String
Impedance Attribute

The cost attribute that will be used as impedance in the analysis.

String
Default Cutoff
(Optional)

Default impedance value at which to cut off searching for destinations for a given origin. If the accumulated impedance becomes higher than the cutoff value, the traversal stops. The default can be overridden by specifying the cutoff value on the origins.

Double
Default Number of Destinations to Find
(Optional)

Default number of destinations to find for each origin. The default can be overridden by specifying a value for the TargetDestinationCount property on the origins.

Long
Accumulators
(Optional)

A list of cost attributes to be accumulated during analysis. These accumulation attributes are for reference only; the solver only uses the cost attribute specified by the Impedance Attribute parameter to calculate the route.

For each cost attribute that is accumulated, a Total_[Impedance] property is added to the routes that are output by the solver.

String
U-Turn Policy
(Optional)

Specifies the U-turn policy that will be used at junctions. Allowing U-turns implies that the solver can turn around at a junction and double back on the same street. Given that junctions represent street intersections and dead ends, different vehicles may be able to turn around at some junctions but not at others—it depends on whether the junction represents an intersection or a dead end. To accommodate this, the U-turn policy parameter is implicitly specified by the number of edges that connect to the junction, which is known as junction valency. The acceptable values for this parameter are listed below; each is followed by a description of its meaning in terms of junction valency.

  • ALLOW_UTURNSU-turns are permitted at junctions with any number of connected edges. This is the default value.
  • NO_UTURNSU-turns are prohibited at all junctions, regardless of junction valency. However, U-turns are still permitted at network locations even when this option is specified, but you can set the individual network location's CurbApproach property to prohibit U-turns there as well.
  • ALLOW_DEAD_ENDS_ONLYU-turns are prohibited at all junctions, except those that have only one adjacent edge (a dead end).
  • ALLOW_DEAD_ENDS_AND_INTERSECTIONS_ONLYU-turns are prohibited at junctions where exactly two adjacent edges meet but are permitted at intersections (junctions with three or more adjacent edges) and dead ends (junctions with exactly one adjacent edge). Often, networks have extraneous junctions in the middle of road segments. This option prevents vehicles from making U-turns at these locations.

If you need a more precisely defined U-turn policy, consider adding a global turn delay evaluator to a network cost attribute or adjusting its settings if one exists, and pay particular attention to the configuration of reverse turns. You can also set the CurbApproach property of your network locations.

String
Restrictions
(Optional)

A list of restriction attributes that will be applied during the analysis.

String
Use Hierarchy in Analysis
(Optional)
  • Checked—The hierarchy attribute will be used for the analysis. Using a hierarchy results in the solver preferring higher-order edges to lower-order edges. Hierarchical solves are faster, and they can be used to simulate the preference of a driver who chooses to travel on freeways rather than local roads when possible—even if that means a longer trip. This option is active only if the input network dataset has a hierarchy attribute.
  • Unchecked—The hierarchy attribute will not be used for the analysis, and the result will be an exact route for the network dataset.

The parameter is inactive if no hierarchy attribute is defined on the network dataset used to perform the analysis.

Boolean
Hierarchy Rank Settings
(Optional)

Legacy:

Prior to version 10, this parameter allowed you to change the hierarchy ranges for the analysis from the default hierarchy ranges established in the network dataset. At version 10, this parameter is no longer supported. To change the hierarchy ranges for the analysis, update the default hierarchy ranges in the network dataset.

Network Analyst Hierarchy Settings
Output Path Shape
(Optional)
  • NO_LINESNo shape will be generated for the output routes. This is useful when you have a large number of origins and destinations and are interested only in the OD cost matrix table (and not the output line shapes).
  • STRAIGHT_LINESThe output route shape will be a single straight line between each of the origin-destination pairs.

Regardless of the output shape type specified, the best route is always determined by the network impedance, not Euclidean distance. This means that only the route shapes are different, not the underlying traversal of the network.

String
Start Time
(Optional)

Indicates the departure time from origins.

If you have chosen a traffic-based impedance attribute, the solution will be generated given dynamic traffic conditions at the time of day specified here. A date and time can be specified as 5/14/2012 10:30 AM.

Instead of using a particular date, a day of the week can be specified using the following dates.

  • Today—12/30/1899
  • Sunday—12/31/1899
  • Monday—1/1/1900
  • Tuesday—1/2/1900
  • Wednesday—1/3/1900
  • Thursday—1/4/1900
  • Friday—1/5/1900
  • Saturday—1/6/1900
For example, to specify that travel should begin at 5:00 PM on Tuesday, specify the parameter value as 1/2/1900 5:00 PM.

Date

Derived Output

LabelExplanationData Type
Network Analyst Layer

The newly created network analysis layer.

Network Analyst Layer

arcpy.management.MakeODCostMatrixLayer(in_network_dataset, out_network_analysis_layer, impedance_attribute, {default_cutoff}, {default_number_destinations_to_find}, {accumulate_attribute_name}, {UTurn_policy}, {restriction_attribute_name}, {hierarchy}, {hierarchy_settings}, {output_path_shape}, {time_of_day})
NameExplanationData Type
in_network_dataset

The network dataset on which the OD cost matrix analysis will be performed.

Network Dataset Layer
out_network_analysis_layer

Name of the OD cost matrix network analysis layer to create.

String
impedance_attribute

The cost attribute that will be used as impedance in the analysis.

String
default_cutoff
(Optional)

Default impedance value at which to cut off searching for destinations for a given origin. If the accumulated impedance becomes higher than the cutoff value, the traversal stops. The default can be overridden by specifying the cutoff value on the origins.

Double
default_number_destinations_to_find
(Optional)

Default number of destinations to find for each origin. The default can be overridden by specifying a value for the TargetDestinationCount property on the origins.

Long
accumulate_attribute_name
[accumulate_attribute_name,...]
(Optional)

A list of cost attributes to be accumulated during analysis. These accumulation attributes are for reference only; the solver only uses the cost attribute specified by the Impedance Attribute parameter to calculate the route.

For each cost attribute that is accumulated, a Total_[Impedance] property is added to the routes that are output by the solver.

String
UTurn_policy
(Optional)

Specifies the U-turn policy that will be used at junctions. Allowing U-turns implies that the solver can turn around at a junction and double back on the same street. Given that junctions represent street intersections and dead ends, different vehicles may be able to turn around at some junctions but not at others—it depends on whether the junction represents an intersection or a dead end. To accommodate this, the U-turn policy parameter is implicitly specified by the number of edges that connect to the junction, which is known as junction valency. The acceptable values for this parameter are listed below; each is followed by a description of its meaning in terms of junction valency.

  • ALLOW_UTURNSU-turns are permitted at junctions with any number of connected edges. This is the default value.
  • NO_UTURNSU-turns are prohibited at all junctions, regardless of junction valency. However, U-turns are still permitted at network locations even when this option is specified, but you can set the individual network location's CurbApproach property to prohibit U-turns there as well.
  • ALLOW_DEAD_ENDS_ONLYU-turns are prohibited at all junctions, except those that have only one adjacent edge (a dead end).
  • ALLOW_DEAD_ENDS_AND_INTERSECTIONS_ONLYU-turns are prohibited at junctions where exactly two adjacent edges meet but are permitted at intersections (junctions with three or more adjacent edges) and dead ends (junctions with exactly one adjacent edge). Often, networks have extraneous junctions in the middle of road segments. This option prevents vehicles from making U-turns at these locations.

If you need a more precisely defined U-turn policy, consider adding a global turn delay evaluator to a network cost attribute or adjusting its settings if one exists, and pay particular attention to the configuration of reverse turns. You can also set the CurbApproach property of your network locations.

String
restriction_attribute_name
[restriction_attribute_name,...]
(Optional)

A list of restriction attributes that will be applied during the analysis.

String
hierarchy
(Optional)
  • USE_HIERARCHYThe hierarchy attribute will be used for the analysis. Using a hierarchy results in the solver preferring higher-order edges to lower-order edges. Hierarchical solves are faster, and they can be used to simulate the preference of a driver who chooses to travel on freeways rather than local roads when possible—even if that means a longer trip. This option is valid only if the input network dataset has a hierarchy attribute.
  • NO_HIERARCHYThe hierarchy attribute will not be used for the analysis, and the result will be an exact route for the network dataset.

The parameter is not used if no hierarchy attribute is defined on the network dataset used to perform the analysis.

Boolean
hierarchy_settings
(Optional)

Legacy:

Prior to version 10, this parameter allowed you to change the hierarchy ranges for the analysis from the default hierarchy ranges established in the network dataset. At version 10, this parameter is no longer supported and should be specified as an empty string. To change the hierarchy ranges for the analysis, update the default hierarchy ranges in the network dataset.

Network Analyst Hierarchy Settings
output_path_shape
(Optional)
  • NO_LINESNo shape will be generated for the output routes. This is useful when you have a large number of origins and destinations and are interested only in the OD cost matrix table (and not the output line shapes).
  • STRAIGHT_LINESThe output route shape will be a single straight line between each of the origin-destination pairs.

Regardless of the output shape type specified, the best route is always determined by the network impedance, not Euclidean distance. This means that only the route shapes are different, not the underlying traversal of the network.

String
time_of_day
(Optional)

Indicates the departure time from origins.

If you have chosen a traffic-based impedance attribute, the solution will be generated given dynamic traffic conditions at the time of day specified here. A date and time can be specified as 5/14/2012 10:30 AM.

Instead of using a particular date, a day of the week can be specified using the following dates.

  • Today—12/30/1899
  • Sunday—12/31/1899
  • Monday—1/1/1900
  • Tuesday—1/2/1900
  • Wednesday—1/3/1900
  • Thursday—1/4/1900
  • Friday—1/5/1900
  • Saturday—1/6/1900
For example, to specify that travel should begin at 5:00 PM on Tuesday, specify the parameter value as 1/2/1900 5:00 PM.

Date

Derived Output

NameExplanationData Type
output_layer

The newly created network analysis layer.

Network Analyst Layer

Code sample

MakeODCostMatrixLayer example 1 (Python window)

Run the tool using only the required parameters.

network = "C:/Data/Paris.gdb/Transportation/ParisMultimodal_ND"
arcpy.na.MakeODCostMatrixLayer(network, "DrivetimeCosts", "DriveTime")
MakeODCostMatrixLayer example 2 (Python window)

Run the tool using all parameters.

network = "C:/Data/Paris.gdb/Transportation/ParisMultimodal_ND"
arcpy.na.MakeODCostMatrixLayer(network, "DrivetimeCosts", "DriveTime", 10, 20,
                                ["Meters", "DriveTime"], "NO_UTURNS",
                                ["Oneway"], "USE_HIERARCHY", "", "NO_LINES")
MakeODCostMatrixLayer example 3 (workflow)

The following stand-alone Python script demonstrates how the MakeODCostMatrixLayer tool can be used to create an origin-destination cost matrix for delivery of goods from the warehouses to all stores within a 10-minute drive time.

# Name: MakeODCostMatrixLayer_Workflow.py
# Description: Create an origin-destination cost matrix for delivery of goods
#              from the warehouses to all stores within a 10-minute drive time
#              and save the results to a layer file on disk. Such a matrix can
#              be used as an input for logistics, delivery and routing analyses.
# Requirements: Network Analyst Extension

#Import system modules
import arcpy
from arcpy import env
import os

try:
    #Set environment settings
    output_dir = "C:/Data"
    #The NA layer's data will be saved to the workspace specified here
    env.workspace = os.path.join(output_dir, "Output.gdb")
    env.overwriteOutput = True

    #Set local variables
    input_gdb = "C:/Data/Paris.gdb"
    network = os.path.join(input_gdb, "Transportation", "ParisMultimodal_ND")
    layer_name = "WarehouseToStoreDrivetimeMatrix"
    impedance = "DriveTime"
    search_tolerance = "1000 Meters"
    accumulate_attributes = ["Meters"]
    origins = os.path.join(input_gdb, "Analysis", "Warehouses")
    destinations = os.path.join(input_gdb, "Analysis", "Stores")
    output_layer_file = os.path.join(output_dir, layer_name + ".lyrx")

    #Create a new OD Cost matrix layer. We wish to find all stores within a 10
    #minute cutoff. Apart from finding the drive time to the stores, we also
    #want to find the total distance, so we will accumulate the "Meters"
    #impedance attribute.
    result_object = arcpy.na.MakeODCostMatrixLayer(network, layer_name,
                                                impedance, 10, "",
                                                accumulate_attributes)

    #Get the layer object from the result object. The OD cost matrix layer can
    #now be referenced using the layer object.
    layer_object = result_object.getOutput(0)

    #Get the names of all the sublayers within the OD cost matrix layer.
    sublayer_names = arcpy.na.GetNAClassNames(layer_object)
    #Stores the layer names that we will use later
    origins_layer_name = sublayer_names["Origins"]
    destinations_layer_name = sublayer_names["Destinations"]

    #Load the warehouse locations as origins using a default field mappings and
    #a search tolerance of 1000 Meters.
    arcpy.na.AddLocations(layer_object, origins_layer_name, origins, "",
                          search_tolerance)

    #Load the store locations as destinations and map the NOM field from stores
    #features as Name property using field mappings
    field_mappings = arcpy.na.NAClassFieldMappings(layer_object,
                                                        destinations_layer_name)
    field_mappings["Name"].mappedFieldName = "NOM"
    arcpy.na.AddLocations(layer_object, destinations_layer_name, destinations,
                          field_mappings, search_tolerance)

    #Solve the OD cost matrix layer
    arcpy.na.Solve(layer_object)

    #Save the solved OD cost matrix layer as a layer file on disk
    layer_object.saveACopy(output_layer_file)

    print("Script completed successfully")

except Exception as e:
    # If an error occurred, print line number and error message
    import traceback, sys
    tb = sys.exc_info()[2]
    print("An error occurred on line %i" % tb.tb_lineno)
    print(str(e))
MakeODCostMatrixLayer example 4 (workflow)

The following stand-alone Python script demonstrates how to access sublayers, join input and output layers, and transfer field values from input origins and destinations to the output Lines layer.

# Name: MakeODCostMatrixLayer_Workflow2.py
# Description: Find the travel time to the closest hospital from each census
#               tract and join the travel time and hospital name to the input
#               tracts.
# Requirements: Network Analyst Extension

#Import system modules
import arcpy
from arcpy import env
import datetime
import os

try:
    #Set environment settings
    output_dir = "C:/Data"
    #The NA layer's data will be saved to the workspace specified here
    env.workspace = os.path.join(output_dir, "Output.gdb")
    env.overwriteOutput = True

    #Set inputs and outputs
    input_gdb = "C:/Data/SanFrancisco.gdb"
    network = os.path.join(input_gdb, "Transportation", "Streets_ND")
    origins = os.path.join(input_gdb, "Analysis", "TractCentroids")
    destinations = os.path.join(input_gdb, "Analysis", "Hospitals")
    output_features = "TractCentroids_withOD"

    #Define some OD cost matrix analysis settings
    layer_name = "HospitalsOD"
    #Optimize based on travel time
    impedance = "TravelTime"
    #Calculate the total distance, even though the analysis is optimizing time
    accumulate_attributes = ["Meters"]
    #Find only the closest hospital
    num_hospitals_to_find = 1
    #Set the time of day for the analysis to 6PM on a generic Monday.
    start_time = datetime.datetime(1900, 1, 1, 18, 0, 0)
    #Don't output line shapes (output Lines will still list travel times)
    out_lines = "NO_LINES"

    #Create a new OD cost matrix layer.
    result_object = arcpy.na.MakeODCostMatrixLayer(network, layer_name,
                    impedance,
                    default_number_destinations_to_find=num_hospitals_to_find,
                    accumulate_attribute_name=accumulate_attributes,
                    output_path_shape=out_lines, time_of_day=start_time)

    #Get the layer object from the result object. The OD layer can
    #now be referenced using the layer object.
    layer_object = result_object.getOutput(0)

    #Get the names of all the sublayers within the OD layer.
    sublayer_names = arcpy.na.GetNAClassNames(layer_object)
    #Store the layer names for later use
    origins_layer_name = sublayer_names["Origins"]
    destinations_layer_name = sublayer_names["Destinations"]

    #The input census tract data has a unique ID field that can be transferred
    #to the analysis layer. Add the field, and then use field mapping to
    #transfer the values.
    arcpy.na.AddFieldToAnalysisLayer(layer_object, origins_layer_name,
                                                        "Tract_ID", "TEXT")
    field_mappings = arcpy.na.NAClassFieldMappings(layer_object,
                                                            origins_layer_name)
    field_mappings["Tract_ID"].mappedFieldName = "ID"

    #Load the census tracts as origins.
    arcpy.na.AddLocations(layer_object, origins_layer_name, origins,
                            field_mappings, "",
                            exclude_restricted_elements = "EXCLUDE")

    #Map the input hospital NAME field to a new Hospital_Name field in
    #Destinations
    arcpy.na.AddFieldToAnalysisLayer(layer_object, destinations_layer_name,
                                                        "Hospital_Name", "TEXT")
    field_mappings = arcpy.na.NAClassFieldMappings(layer_object,
                                                        destinations_layer_name)
    field_mappings["Hospital_Name"].mappedFieldName = "NAME"

    #Load the hospitals as desinations.
    arcpy.na.AddLocations(layer_object, destinations_layer_name, destinations,
                            field_mappings, "",
                            exclude_restricted_elements = "EXCLUDE")

    #Solve the OD layer
    arcpy.na.Solve(layer_object)

    #Get sublayers
    #listLayers returns a list of sublayer layer objects contained in the NA
    #group layer, filtered by layer name used as a wildcard. Use the sublayer
    #name from GetNAClassNames as the wildcard string in case the sublayers
    #have non-default names.
    origins_sublayer = layer_object.listLayers(origins_layer_name)[0]
    destinations_sublayer = layer_object.listLayers(destinations_layer_name)[0]
    lines_sublayer = layer_object.listLayers(sublayer_names["ODLines"])[0]

    #Use the JoinField tool to transfer OD Cost Matrix information to the
    #output feature class
    #Transfer the tract ID from the input Origins to the output Lines
    arcpy.management.JoinField(lines_sublayer, "OriginID",
                                    origins_sublayer, "ObjectID", "Tract_ID")
    #Transfer the hospital name from the input Destinations to the output Lines
    arcpy.management.JoinField(lines_sublayer, "DestinationID",
                            destinations_sublayer, "ObjectID", "Hospital_Name")
    #Transfer fields of interest (hospital name, TravelTime cost, and other
    #accumulated costs) from the output Lines to a copy of the input census
    #tracts feature class using the Tract_ID field
    output_impedance_fieldname = "Total_" + impedance
    fields_to_transfer = ["Hospital_Name", output_impedance_fieldname]
    for field in accumulate_attributes:
        fields_to_transfer.append("Total_" + field)
    arcpy.management.CopyFeatures(origins, output_features)
    arcpy.management.JoinField(output_features, "ID",
                                lines_sublayer, "Tract_ID", fields_to_transfer)

    print("Script completed successfully")

except Exception as e:
    # If an error occurred, print line number and error message
    import traceback, sys
    tb = sys.exc_info()[2]
    print("An error occurred on line %i" % tb.tb_lineno)
    print(str(e))

Environments