Skip To Content

Make OD Cost Matrix Analysis Layer

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. The layer can be created using a local network dataset or a service hosted online or in a portal.

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.

  • In ArcGIS Pro, network analysis layers store their data on disk in file geodatabase feature classes. When creating a new network analysis layer in a project, the layer's data will be created in a new feature dataset in the Current Workspace environment. When creating a new network analysis layer in a Python script, you must first explicitly set the workspace environment to a file geodatabase where you want the layer's data to be stored, using arcpy.env.workspace = "<path to file gdb>". When the layer is created, a new feature dataset containing the appropriate sublayer feature classes will be added to this file geodatabase.

Syntax

MakeODCostMatrixAnalysisLayer_na (network_data_source, {layer_name}, {travel_mode}, {cutoff}, {number_of_destinations_to_find}, {time_of_day}, {time_zone}, {line_shape}, {accumulate_attributes})
ParameterExplanationData Type
network_data_source

The network dataset or service on which the network analysis will be performed. Use the portal URL for a service.

Network Dataset Layer;String
layer_name
(Optional)

Name of the network analysis layer to create.

String
travel_mode
(Optional)

Name of the travel mode to use in the analysis. The travel mode represents a collection of network settings, such as travel restrictions and U-turn policies, that determine how a pedestrian, car, truck, or other medium of transportation moves through the network. Travel modes are defined on your network data source.

An arcpy.na.TravelMode object and a string containing the valid JSON representation of a travel mode can also be used as input to the parameter.

String
cutoff
(Optional)

The impedance value at which to stop searching for destinations for a given origin. This value will be in the units of the impedance attribute used by your chosen travel mode. No destinations beyond this limit will be found. This cutoff value can be overridden on a per-origin basis by specifying individual cutoff values in the origins sublayer. By default, no cutoff is used for the analysis.

Double
number_of_destinations_to_find
(Optional)

The number of destinations to find per origin. This default can be overridden by specifying an individual value for the TargetDestinationCount property in the origins sublayer. By default, no limit is used, and all destinations are found.

Long
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 p.m. on Tuesday, specify the parameter value as 1/2/1900 5:00 PM.

Date
time_zone
(Optional)

Specifies the time zone of the Time of Day parameter.

  • LOCAL_TIME_AT_LOCATIONSThe Time of Day parameter refers to the time zone in which the origins are located. This is the default.
  • UTCThe Time of Day parameter refers to Coordinated Universal Time (UTC). Choose this option if you want to calculate your OD cost matrix for a specific time, such as now, but aren't certain in which time zone the origins will be located.
String
line_shape
(Optional)
  • NO_LINESNo shape will be generated for the output origin-destination route pair. This is useful when you have a large number of origins and destinations and are interested only in the impedance costs in the OD cost matrix table, not in visualizing your OD cost matrix in a map.
  • STRAIGHT_LINESThe output route shape will be a single straight line between each of the origin-destination pairs. This is the default.

No matter which output shape type is chosen, the best route is always determined by the network impedance, never Euclidean distance. This means only the route shapes are different, not the underlying traversal of the network.

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

List of cost attributes to be accumulated during analysis. These accumulated attributes are purely for reference; the solver only uses the cost attribute used by your designated travel mode when solving your analysis.

For each cost attribute that is accumulated, a Total_[Impedance] property is populated in the network analysis output features.

This parameter is not available if the network data source is a service.

String

Code sample

MakeODCostMatrixAnalysisLayer example 1 (Python window)

Execute the tool using only the required parameters.

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

Execute the tool using all parameters.

network = "C:/Data/Paris.gdb/Transportation/ParisMultimodal_ND"
arcpy.na.MakeODCostMatrixAnalysisLayer(network, "DrivetimeCosts", 
                                "Driving Time", 10, 20, "1/1/1900 9:00 AM",
                                "UTC", "NO_LINES", ["Meters", "DriveTime"])
MakeODCostMatrixAnalysisLayer example 3 (workflow)

The following stand-alone Python script demonstrates how the MakeODCostMatrixAnalysisLayer 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: MakeODCostMatrixAnalysisLayer_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:
    #Check out Network Analyst license if available. Fail if the Network Analyst license is not available.
    if arcpy.CheckExtension("network") == "Available":
        arcpy.CheckOutExtension("network")
    else:
        raise arcpy.ExecuteError("Network Analyst Extension license is not available.")
    
    #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"
    travel_mode = "Driving Time"
    search_tolerance = "1000 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.
    result_object = arcpy.na.MakeODCostMatrixAnalysisLayer(network, layer_name,
                                                travel_mode, 10)

    #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))
MakeODCostMatrixAnalysisLayer 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: MakeODCostMatrixAnalysisLayer_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:
    #Check out Network Analyst license if available. Fail if the Network Analyst license is not available.
    if arcpy.CheckExtension("network") == "Available":
        arcpy.CheckOutExtension("network")
    else:
        raise arcpy.ExecuteError("Network Analyst Extension license is not available.")
    
    #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"
    #User settings for driving
    travel_mode = "Driving Time"
    #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.MakeODCostMatrixAnalysisLayer(network, layer_name,
                    travel_mode,
                    number_of_destinations_to_find=num_hospitals_to_find,
                    time_of_day=start_time, line_shape=out_lines, 
                    accumulate_attributes=accumulate_attributes)

    #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, "")

    #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, "")

    #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, impedance attribute, and other
    #accumulated costs) from the output Lines to a copy of the input census
    #tracts feature class using the Tract_ID field
    # Determine the impedance attribute
    solver_props = arcpy.na.GetSolverProperties(layer_object)
    impedance = solver_props.impedance
    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))
MakeODCostMatrixAnalysisLayer example 5 (stand-alone script)

The following stand-alone Python script demonstrates how to create a modified version of a travel mode from the network dataset and use this travel mode when creating a new OD Cost Matrix layer.

import json

network = r"C:/Data/SanFrancisco.gdb/Transportation/Streets_ND"
# Get all travel modes from the network dataset
travel_modes = arcpy.na.GetTravelModes(network)
# Get the Driving Distance travel mode
dd_travel_mode = travel_modes["Driving Distance"]
# Make a json representation of the travel mode
travel_mode_json = json.loads(str(dd_travel_mode))
# Modify the userHierarchy property to turn hierarchy off, and update the name
travel_mode_json["useHierarchy"] = False
travel_mode_json["name"] = "Driving Distance without Hierarchy"
# Create a new travel mode object from the modified json
new_travel_mode_object = arcpy.na.TravelMode(json.dumps(travel_mode_json))
# Use the new travel mode object to MakeODCostMatrixAnalysisLayer
# We could also pass in the json directly without first converting it to an object
arcpy.na.MakeODCostMatrixAnalysisLayer(network, "OD Without Hierarchy", new_travel_mode_object)

Environments

Licensing information

  • ArcGIS Desktop Basic: Yes
  • ArcGIS Desktop Standard: Yes
  • ArcGIS Desktop Advanced: Yes