Location-allocation

Location-allocation example

Figure :

The best location for a new fast-food restaurant that can serve additional customers. The location-allocation service can allocate demand to existing locations (the restaurant location shown with the black filled circle) and can help you find one or more new locations (the restaurant location shown with a star) that can maximize the number of customers that can walk to your restaurant.

What is location-allocation?

Location-allocation is the process of finding a set of facilities that will best serve demand from surrounding areas. As the name suggests, location-allocation is a two-fold problem that simultaneously locates facilities and allocates demand points to the facilities.

You can use location-allocation to build applications that answer questions such as:

  • Given a set of existing fire stations, which site for a new fire station would provide the best response times for the community?
  • If a retail company has to downsize, which stores should it close to maximize the overall demand?
  • Where should a factory be built to minimize the distance to distribution centers?

How location-allocation works

The typical workflow for location-allocation analysis is to define:

  1. One or more locations that serve as facilities.
  2. One or more locations that represent demand for the services offered at the facilities.
  3. The type of travel for the analysis.
  4. The objective of the location-allocation analysis such as maximize the attendance or minimize the travel time.
  5. Number of facilities the service should choose.
  6. Call the service to find the best locations for the facilities and allocate demand to the chosen facilities.

URL requests

You can perform location allocation by making an HTTPS request to the location-allocation service submitJob operation or by using client APIs. Specify one or more facilities, demand points, the location-allocation problem type, and additional parameters to refine the operation. Some of the most common parameters are described below.

Location-allocation only supports job requests.

Request limits

LimitJob
Maximum number of facilities:1,000
Maximum number of facilities to find:100
Maximum number of demand points:10,000
Maximum transaction time:60 minutes
Maximum number of point barriers:250
Maximum number of street features intersected by polyline barriers:500
Maximum number of street features intersected by polygon barriers:2,000
Maximum straight-line distance for the walking travel mode:

(If the straight-line distance between any incidents or facilities is greater than this limit, the analysis will fail when the walking restriction is used.)
27 miles (43.45 kilometers)
Force hierarchy beyond a straight-line distance of:

(If the straight-line distance between any origin or destination is greater than the limit shown here, the analysis uses hierarchy, even if the travel mode defines not to use hierarchy.)
50 miles (80.46 kilometers)
Maximum snap tolerance:

(If the distance between an input point and its nearest traversable street is greater than the distance specified here, the point is excluded from the analysis.)
12.42 miles (20 kilometers)

URL

 
https://logistics.arcgis.com/arcgis/rest/services/World/LocationAllocation/GPServer/SolveLocationAllocation/submitJob?<parameters>

Key parameters

NameDescriptionExamples
facilitiesOne or more locations that serve as facilities.facilities={"features":[{"geometry":{"x":-117.195696,"y":34.056503}}]}
demand_pointsOne or more locations that represent demand for the services offered at the facilities.demand_points={"features":[{"geometry":{"x":-117.190774,"y":34.057301}},{"geometry":{"x":-117.199781,"y":34.06047}}]}
travel_modeThe mode of transportation such as driving a car or a truck or walking.travelMode=JSON Object
problem_typeThe objective of the location-allocation analysisproblem_type=Maximize Attendance
number_of_facilities_to_findNumber of facilities the service should choosenumber_of_facilities_to_find=2

Additional parameters: Set additional constraints when performing location-allocation such as default_measurement_cutoff to limit the travel time or travel distance between a facility and a demand point, ortravel_direction to indicate if travel occurs from facility to demand points or vice versa.

Examples

Job: Find new restaurant location

In this example, the best location for a new fast-food restaurant is found to serve additional customers. A restaurant already exists in the downtown central business district that is popular with employees who work at the nearby offices. You want to expand your business by opening one more branch that can cater to more employees from nearby office buildings.

To solve this problem using the location-allocation service, you need to provide the appropriate inputs to the service that are described below:

  • The office buildings are the demand_points. They have a field called Weight that represents the number of people working in those buildings and so can be your potential customers.

  • The existing and prospective locations for the restaurants are the facilities. As you still want to run the existing restaurant, the FacilityType value for this location is 1 so that the location-allocation service will always include this facility in the final solution. You have identified four other potential locations where you can start a new branch of your restaurant. The FacilityType on these four locations is 0 so that the location-allocation service will select the best from these four in addition to the existing location.

  • The customers are walking to your restaurant. So you set the travel_mode as walking time.

  • Location-allocation service supports various problem types that have different goals. Picking the correct problem type is important to get expected results. In this scenario, you want to chose the new location such that it can attract maximum number of customers that are closest to new location so that they don't have to walk a lot to reach your restaurant from their offices. So you need to select the Maximize Attendance problem type as it is designed to achieve this goal.

  • You need to find one new restaurant location in addition to the existing location. So you set the number_of_facilities_to_find as 2. The location-allocation service will first allocate the customers to the existing restaurant and then allocate the remaining customers to the best location out of the four candidates that you have selected.

  • The travel_direction is set as Demand To Facility since the customers will be visiting the restaurant from their offices.

APIs

ArcGIS Python API
                                                                                                                                                                                                                                                                                                     
"""
Find the best location for a new branch of a fast food restaurant to serve additional customers.
"""

import datetime
import arcgis
import pandas as pd


def print_result(result):
    """Print useful information from the result."""
    pd.set_option("display.max_rows", None)
    pd.set_option("display.max_colwidth", None)

    output_facilities = result.output_facilities.sdf[["Name", "FacilityType", "DemandCount", "DemandWeight"]]
    print("\n-- Chosen Facilities -- \n")
    print(output_facilities[output_facilities["FacilityType"].isin([1, 3])].to_string(index=False))

    output_allocation = result.output_allocation_lines.sdf
    print("\n-- Output Allocation -- \n")
    print(output_allocation[["Name", "Weight", "Total_Minutes"]].to_string(index=False))


def main():
    """Program execution logic."""
    # inputs
    facilities = {
        "features": [
            {
                "attributes": {
                    "Name": "Existing Location",
                    "FacilityType": 1
                },
                "geometry": {
                    "x": -122.333906,
                    "y": 47.609152
                }
            },
            {
                "attributes": {
                    "Name": "Candidate 1",
                    "FacilityType": 0
                },
                "geometry": {
                    "x": -122.333585,
                    "y": 47.604501
                }
            },
            {
                "attributes": {
                    "Name": "Candidate 2",
                    "FacilityType": 0
                },
                "geometry": {
                    "x": -122.334550,
                    "y": 47.605557
                }
            },
            {
                "attributes": {
                    "Name": "Candidate 3",
                    "FacilityType": 0
                },
                "geometry": {
                    "x": -122.337753,
                    "y": 47.609442
                }
            },
            {
                "attributes": {
                    "Name": "Candidate 4",
                    "FacilityType": 0
                },
                "geometry": {
                    "x": -122.335319,
                    "y": 47.607317
                }
            }
        ]
    }
    demand_points = {
        "features": [
            {
                "attributes": {
                    "Name": "Colman Building",
                    "Weight": 1573
                },
                "geometry": {
                    "x": -122.335583,
                    "y": 47.603495
                }
            },
            {
                "attributes": {
                    "Name": "Norton Parking Garage",
                    "Weight": 1262
                },
                "geometry": {
                    "x": -122.33482,
                    "y": 47.603745
                }
            },
            {
                "attributes": {
                    "Name": "DocuSign Tower",
                    "Weight": 2385
                },
                "geometry": {
                    "x": -122.334151,
                    "y": 47.605060
                }
            },
            {
                "attributes": {
                    "Name": "Fourth and Madison Building",
                    "Weight": 1096
                },
                "geometry": {
                    "x": -122.333227,
                    "y": 47.605493
                }
            },
            {
                "attributes": {
                    "Name": "Safeco Plaza",
                    "Weight": 3618
                },
                "geometry": {
                    "x": -122.333899,
                    "y": 47.606190
                }
            },
            {
                "attributes": {
                    "Name": "1201 Third Avenue",
                    "Weight": 1782
                },
                "geometry": {
                    "x": -122.336163,
                    "y": 47.607204
                }
            },
            {
                "attributes": {
                    "Name": "Puget Sound Plaza",
                    "Weight": 2165
                },
                "geometry": {
                    "x": -122.335796,
                    "y": 47.608602
                }
            },
            {
                "attributes": {
                    "Name": "Rainier Square",
                    "Weight": 1316
                },
                "geometry": {
                    "x": -122.334881,
                    "y": 47.609021
                }
            },
            {
                "attributes": {
                    "Name": "Century Square",
                    "Weight": 1974
                },
                "geometry": {
                    "x": -122.337503,
                    "y": 47.610273
                }
            },
            {
                "attributes": {
                    "Name": "Miken Building",
                    "Weight": 3920
                },
                "geometry": {
                    "x": -122.336516,
                    "y": 47.609510
                }
            },
            {
                "attributes": {
                    "Name": "Westlake Park",
                    "Weight": 2467
                },
                "geometry": {
                    "x": -122.336353,
                    "y": 47.6110466
                }
            },
            {
                "attributes": {
                    "Name": "U.S. Bank Centre",
                    "Weight": 3997
                },
                "geometry": {
                    "x": -122.334571,
                    "y": 47.610492
                }
            },
            {
                "attributes": {
                    "Name": "Westlake Center",
                    "Weight": 2440
                },
                "geometry": {
                    "x": -122.337406,
                    "y": 47.611980
                }
            },
            {
                "attributes": {
                    "Name": "Nordstrom Flagship Store",
                    "Weight": 2438
                },
                "geometry": {
                    "x": -122.336295,
                    "y": 47.6123047
                }
            },
            {
                "attributes": {
                    "Name": "Columbia Center",
                    "Weight": 5400
                },
                "geometry": {
                    "x": -122.330746,
                    "y": 47.604502
                }
            },
            {
                "attributes": {
                    "Name": "800 Fifth Avenue",
                    "Weight": 3697
                },
                "geometry": {
                    "x": -122.330228,
                    "y": 47.605698
                }
            },
            {
                "attributes": {
                    "Name": "Seattle Municipal Tower",
                    "Weight": 2025
                },
                "geometry": {
                    "x": -122.329605,
                    "y": 47.605143
                }
            },
            {
                "attributes": {
                    "Name": "Washington State Convention Center",
                    "Weight": 1076
                },
                "geometry": {
                    "x": -122.331520,
                    "y": 47.611664
                }
            }
        ]
    }


    # Connect to the location-allocation service
    api_key = "YOUR-API-KEY"
    arcgis.GIS("https://www.arcgis.com", api_key=api_key)

    # Get the walking time travel mode defined for the portal. Fail if the travel mode is not found.
    walking_time_travel_mode = ""
    for feature in arcgis.network.analysis.get_travel_modes().supported_travel_modes.features:
        attributes = feature.attributes
        if attributes["AltName"] == "Walking Time":
            walking_time_travel_mode = attributes["TravelMode"]
            break
    assert walking_time_travel_mode, "Walking Time travel mode not found"

    # Call the location-allocation service
    result = arcgis.network.analysis.solve_location_allocation(facilities=facilities,
                                                               demand_points=demand_points,
                                                               travel_mode=walking_time_travel_mode,
                                                               problem_type="Maximize Attendance",
                                                               number_of_facilities_to_find=2,
                                                               travel_direction="Demand to Facility",
                                                               )
    print_result(result)



if __name__ == "__main__":
    main()

REST API

Unlike Direct request type which allows you to make a request and get back all the results in the response, when working with a Job request type, you need to follow a three step workflow:

  1. Make the submitJob request with the appropriate request parameters to get a job id.
  2. Using the job id, check the job status to see if the job completed successfully.
  3. Use the job id to get one or more results.
1. Submit job2. Check job status3. Get results (output_facilities)3. Get results (output_allocation_lines)
cURLHTTP
         
curl https://logistics.arcgis.com/arcgis/rest/services/World/LocationAllocation/GPServer/SolveLocationAllocation/submitJob? \
-d "f=json" \
-d "token=YOUR-API-KEY" \
-d "facilities={'features':[{'attributes':{'Name':'Existing Location','FacilityType':1},'geometry':{'x':-122.333906,'y':47.609152}},{'attributes':{'Name':'Candidate 1','FacilityType':0},'geometry':{'x':-122.333585,'y':47.604501}},{'attributes':{'Name':'Candidate 2','FacilityType':0},'geometry':{'x':-122.334550,'y':47.605557}},{'attributes':{'Name':'Candidate 3','FacilityType':0},'geometry':{'x':-122.337753,'y':47.609442}},{'attributes':{'Name':'Candidate 4','FacilityType':0},'geometry':{'x':-122.335319,'y':47.607317}}]}" \
-d "demand_points={'features':[{'attributes':{'Name':'Colman Building','Weight':1573},'geometry':{'x':-122.335583,'y':47.603495}},{'attributes':{'Name':'Norton Parking Garage','Weight':1262},'geometry':{'x':-122.33482,'y':47.603745}},{'attributes':{'Name':'DocuSign Tower','Weight':2385},'geometry':{'x':-122.334151,'y':47.605060}},{'attributes':{'Name':'Fourth and Madison Building','Weight':1096},'geometry':{'x':-122.333227,'y':47.605493}},{'attributes':{'Name':'Safeco Plaza','Weight':3618},'geometry':{'x':-122.333899,'y':47.606190}},{'attributes':{'Name':'1201 Third Avenue','Weight':1782},'geometry':{'x':-122.336163,'y':47.607204}},{'attributes':{'Name':'Puget Sound Plaza','Weight':2165},'geometry':{'x':-122.335796,'y':47.608602}},{'attributes':{'Name':'Rainier Square','Weight':1316},'geometry':{'x':-122.334881,'y':47.609021}},{'attributes':{'Name':'Century Square','Weight':1974},'geometry':{'x':-122.337503,'y':47.610273}},{'attributes':{'Name':'Miken Building','Weight':3920},'geometry':{'x':-122.336516,'y':47.609510}},{'attributes':{'Name':'Westlake Park','Weight':2467},'geometry':{'x':-122.336353,'y':47.6110466}},{'attributes':{'Name':'U.S. Bank Centre','Weight':3997},'geometry':{'x':-122.334571,'y':47.610492}},{'attributes':{'Name':'Westlake Center','Weight':2440},'geometry':{'x':-122.337406,'y':47.611980}},{'attributes':{'Name':'Nordstrom Flagship Store','Weight':2438},'geometry':{'x':-122.336295,'y':47.6123047}},{'attributes':{'Name':'Columbia Center','Weight':5400},'geometry':{'x':-122.330746,'y':47.604502}},{'attributes':{'Name':'800 Fifth Avenue','Weight':3697},'geometry':{'x':-122.330228,'y':47.605698}},{'attributes':{'Name':'Seattle Municipal Tower','Weight':2025},'geometry':{'x':-122.329605,'y':47.605143}},{'attributes':{'Name':'Washington State Convention Center','Weight':1076},'geometry':{'x':-122.331520,'y':47.611664}}]}" \
-d "travel_mode={'attributeParameterValues':[{'attributeName':'Avoid Private Roads','parameterName':'Restriction Usage','value':'AVOID_MEDIUM'},{'attributeName':'Walking','parameterName':'Restriction Usage','value':'PROHIBITED'},{'attributeName':'Preferred for Pedestrians','parameterName':'Restriction Usage','value':'PREFER_LOW'},{'attributeName':'WalkTime','parameterName':'Walking Speed (km/h)','value':5},{'attributeName':'Avoid Roads Unsuitable for Pedestrians','parameterName':'Restriction Usage','value':'AVOID_HIGH'}],'description':'Follows paths and roads that allow pedestrian traffic and finds solutions that optimize travel time. The walking speed is set to 5 kilometers per hour.','distanceAttributeName':'Kilometers','id':'caFAgoThrvUpkFBW','impedanceAttributeName':'WalkTime','name':'Walking Time','restrictionAttributeNames':['Avoid Private Roads','Avoid Roads Unsuitable for Pedestrians','Preferred for Pedestrians','Walking'],'simplificationTolerance':2,'simplificationToleranceUnits':'esriMeters','timeAttributeName':'WalkTime','type':'WALK','useHierarchy':false,'uturnAtJunctions':'esriNFSBAllowBacktrack'}"
-d "problem_type=Maximize Attendance" \
-d "number_of_facilities_to_find=2" \
-d "travel_direction=Demand to Facility"
Response (JSON)
    
{
  "jobId": "j64631b4afe854912bfe914d2400af60d",
  "jobStatus": "esriJobSubmitted"
}
Request
cURLHTTP
   
curl https://logistics.arcgis.com/arcgis/rest/services/World/LocationAllocation/GPServer/SolveLocationAllocation/jobs/j64631b4afe854912bfe914d2400af60d? \
-d "f=json" \
-d "token=YOUR-API-KEY"
Response (JSON)
                                             
{
  "jobId": "j64631b4afe854912bfe914d2400af60d",
  "jobStatus": "esriJobSucceeded",
  "results": {
    "Solve_Succeeded": {
      "paramUrl": "results/Solve_Succeeded"
    },
    "Output_Allocation_Lines": {
      "paramUrl": "results/Output_Allocation_Lines"
    },
    "Output_Facilities": {
      "paramUrl": "results/Output_Facilities"
    },
    "Output_Demand_Points": {
      "paramUrl": "results/Output_Demand_Points"
    },
    "Output_Network_Analysis_Layer": {
      "paramUrl": "results/Output_Network_Analysis_Layer"
    },
    "Output_Result_File": {
      "paramUrl": "results/Output_Result_File"
    }
  },
  "inputs": {
    "Facilities": {
      "paramUrl": "inputs/Facilities"
    },
    "Demand_Points": {
      "paramUrl": "inputs/Demand_Points"
    },
    "Problem_Type": {
      "paramUrl": "inputs/Problem_Type"
    },
    "Number_of_Facilities_to_Find": {
      "paramUrl": "inputs/Number_of_Facilities_to_Find"
    },
    "Travel_Direction": {
      "paramUrl": "inputs/Travel_Direction"
    },
    "Travel_Mode": {
      "paramUrl": "inputs/Travel_Mode"
    }
  },
  "messages": []
}
Request
cURLHTTP
   
curl https://logistics.arcgis.com/arcgis/rest/services/World/LocationAllocation/GPServer/SolveLocationAllocation/jobs/j64631b4afe854912bfe914d2400af60d/results/Output_Facilities? \
-d "f=json" \
-d "token=YOUR-API-KEY"
Response (JSON)
                                            
{
  "paramName": "Output_Facilities",
  "dataType": "GPFeatureRecordSetLayer",
  "value": {
    "geometryType": "esriGeometryPoint",
    "spatialReference": {
      "wkid": 4326,
      "latestWkid": 4326
    },
    "fields": [
      // one or more field definitions
    ],
    "features": [
      {
        "attributes": {
          "Name": "Existing Location",
          "FacilityType": 1,
          "DemandCount": 10,
          "DemandWeight": 23491.08198335598
          // more field values
        },
        "geometry": {
          "x": -122.33390599999996,
          "y": 47.609152000000051
        }
      },
      {
        "attributes": {
          "Name": "Candidate 1",
          "FacilityType": 3,
          "DemandCount": 8,
          "DemandWeight": 20987.984012529399
          // more field values
        },
        "geometry": {
          "x": -122.33358499999997,
          "y": 47.604501000000027
        }
      }
      // more output facilities
    ],
    "exceededTransferLimit": false
  }
}
Request
cURLHTTP
   
curl https://logistics.arcgis.com/arcgis/rest/services/World/LocationAllocation/GPServer/SolveLocationAllocation/jobs/j64631b4afe854912bfe914d2400af60d/results/Output_Allocation_Lines? \
-d "f=json" \
-d "token=YOUR-API-KEY"
Response (JSON)
                                                              
{
  "paramName": "Output_Allocation_Lines",
  "dataType": "GPFeatureRecordSetLayer",
  "value": {
    "geometryType": "esriGeometryPolyline",
    "spatialReference": {
      "wkid": 4326,
      "latestWkid": 4326
    },
    "fields": [
      // one or more field definitions
    ],
    "features": [
      {
        "attributes": {
          "Name": "1201 Third Avenue - Existing Location",
          "Weight": 1775.9506637889651,
          "Total_Minutes": 3.5401683400770021
          // more field values
        },
        "geometry": {
          "paths": [
            [
              [
                -122.33616299999994,
                47.607204000000081
              ],
              [
                -122.33390599999996,
                47.609152000000051
              ]
            ]
          ]
        }
      },
      {
        "attributes": {
          "Name": "Puget Sound Plaza - Existing Location",
          "Weight": 2159.2300778196532,
          "Total_Minutes": 2.7793033199226498
          // more field values
        },
        "geometry": {
          "paths": [
            [
              [
                -122.33579599999996,
                47.608602000000076
              ],
              [
                -122.33390599999996,
                47.609152000000051
              ]
            ]
          ]
        }
      }
      // more allocation lines
    ],
    "exceededTransferLimit": false
  }
}

Tutorials

Services

Routing service

Get turn-by-turn directions and solve advanced routing problems.

API support

RoutingFleet routingClosest facility routingService areasLocation-allocationTravel cost matrix
ArcGIS JS APIFully supportedAccess with geoprocessing taskFully supportedFully supportedAccess with geoprocessing taskAccess with geoprocessing task
ArcGIS Android APIFully supportedAccess with geoprocessing taskFully supportedFully supportedAccess with geoprocessing taskAccess with geoprocessing task
ArcGIS iOS APIFully supportedAccess with geoprocessing taskFully supportedFully supportedAccess with geoprocessing taskAccess with geoprocessing task
ArcGIS .Net APIFully supportedAccess with geoprocessing taskFully supportedFully supportedAccess with geoprocessing taskAccess with geoprocessing task
ArcGIS Qt APIFully supportedAccess with geoprocessing taskFully supportedFully supportedAccess with geoprocessing taskAccess with geoprocessing task
ArcGIS Java APIFully supportedAccess with geoprocessing taskFully supportedFully supportedAccess with geoprocessing taskAccess with geoprocessing task
ArcGIS Python APIFully supportedFully supportedFully supportedFully supportedFully supportedFully supported
Esri LeafletAccess via ArcGIS REST JSAccess via ArcGIS REST JSAccess via ArcGIS REST JSAccess via ArcGIS REST JSAccess via ArcGIS REST JSAccess via ArcGIS REST JS
MapBox GL JSAccess via ArcGIS REST JSAccess via ArcGIS REST JSAccess via ArcGIS REST JSAccess via ArcGIS REST JSAccess via ArcGIS REST JSAccess via ArcGIS REST JS
OpenLayersAccess via ArcGIS REST JSAccess via ArcGIS REST JSAccess via ArcGIS REST JSAccess via ArcGIS REST JSAccess via ArcGIS REST JSAccess via ArcGIS REST JS
ArcGIS REST JSFully supportedFully supportedFully supportedFully supportedFully supportedFully supported
Full supportPartial support (see notes)Not supported

Tools