Filter plans and/or projects

Download the sample

This sample demonstrates how to search and filter the data available in the urban database of an urban model. The sample covers three different search examples:

  • Find the public projects with a start date set to summer 2019 (using a Hardeeville model).
  • Find the global IDs of all public projects and plans created by a user (using a Hardeeville model).
  • Fetch all publicly available urban models using variables and pagination.

The first two instances work with a Hardeeville example city, which was created specifically for the sample code. The urbanModelId is "8d199b9a69664aac9b2c3a69573600a6".

Import relevant libraries and the Urban API schema stored as a Python module. See the Get Started section to get instructions on how to export the schema to a Python module.

       
1
2
3
4
5
6
7
from sgqlc.operation import Operation
from sgqlc.endpoint.http import HTTPEndpoint
from sgqlc.types import Variable
import sgqlc.types
from urban_api_schema import urban_api_schema as schema

from datetime import date, datetime

Find the public projects with a start date set to summer 2019 (using a Hardeeville model)

Implement a helper function that returns the season of a given date.

             
1
2
3
4
5
6
7
8
9
10
11
12
13
Y = 2000 # dummy leap year to allow input X-02-29 (leap day)
seasons = [('winter', (date(Y,  1,  1),  date(Y,  3, 20))),
           ('spring', (date(Y,  3, 21),  date(Y,  6, 20))),
           ('summer', (date(Y,  6, 21),  date(Y,  9, 22))),
           ('autumn', (date(Y,  9, 23),  date(Y, 12, 20))),
           ('winter', (date(Y, 12, 21),  date(Y, 12, 31)))]

def get_season(my_time):
    if isinstance(my_time, datetime):
        my_time = my_time.date()
    my_time = my_time.replace(year=Y)
    return next(season for season, (start, end) in seasons
                if start <= my_time <= end)

Provide the endpoint_url and urban_model_id variables.

   
1
2
3
endpoint_url = 'https://urban-api.arcgis.com/graphql'
endpoint = HTTPEndpoint(endpoint_url)
urban_model_id = "8d199b9a69664aac9b2c3a69573600a6"

Create an Operation instance of schema.Query type, which allows you to generate and interpret GraphQL queries. In the next step, ask for specific fields on selected objects. More specifically, select a few project attributes stored in the urban database of the urban model with the identifier specified in the urban_model_id argument.

Intermediate results can be stored in a variable, such as for projects and attributes, and reused later.

               
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# initialize the query
op = Operation(schema.Query)

# set the body of the query
projects = op.urban_model(urban_model_id=urban_model_id).urban_database.projects(
    # complex argument types, such as paging are passed as JSON objects
    paging={'limit':100}
)
attributes = projects.attributes()

# select relevant return fields
attributes.event_name()
attributes.global_id()
attributes.start_date()
attributes.description()

Call the endpoint to retrieve all projects in the urban model. The return_projects variable stores the output of the query in JSON format.

    
1
2
3
4
return_projects = endpoint(op)
errors = return_projects.get('errors')
if errors:
    print(errors)

To parse the returned JSON data into more convenient native objects, add the query operation to the results variable. Loop through the returned projects and find the relevant ones with a start date set to summer 2019.

              
1
2
3
4
5
6
7
8
9
10
11
12
13
14
obj = op + return_projects

# loop through the projects
for project in obj.urban_model.urban_database.projects:
    start_date_timestamp = project.attributes.start_date
    start_date_dt_object = datetime.fromtimestamp(start_date_timestamp/1000)

    # find and return projects with a start date set to summer 2019
    if (get_season(start_date_dt_object)=='summer') and (start_date_dt_object.year==2019):
        print("Start date: {}, \t Global ID: {}, \t Project name: {}"
              .format(start_date_dt_object.strftime('%Y-%m-%d'),
                      project.attributes.global_id,
                      project.attributes.event_name)
             )

The output should look something like this:

    
1
2
3
4
Start date: 2019-07-19,      Global ID: ce68ea4c-7ade-464f-ba59-616d0212e958,    Project name: DLP Fire Warehouse
Start date: 2019-07-26,      Global ID: def80619-f087-4436-b9f9-92fc4bc01b34,    Project name: Hearthstone Lakes Phase 3
Start date: 2019-08-01,      Global ID: d30bf160-5081-45a6-a915-20a010deb1dd,    Project name: Latitude Phase 3B
Start date: 2019-08-28,      Global ID: d451e5c6-0a2a-4443-8f24-c9a31e22bc1c,    Project name: Ramirez Landscaping

Find the global IDs of all public projects and plans created by a user (using a Hardeeville model)

Get the global IDs of all the plans and projects created by a given user.

The endpoint_url and the urban_model_id variables are the same as in the first example. Create a new instance of Operation and select relevant objects and fields.

                       
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# initialize the query
op = Operation(schema.Query)

# set the body of the query
urban_database = op.urban_model(urban_model_id=urban_model_id).urban_database()

# add projects to the query
projects = urban_database.projects(paging={'limit':100})
project_attributes = projects.attributes()

# select relevant return fields considering projects
project_attributes.event_name()
project_attributes.global_id()
project_attributes.owner_name()

# add plans to the query
plans = urban_database.plans(paging={'limit': 100})
plan_attributes = plans.attributes()

# select relevant return fields considering plans
plan_attributes.event_name()
plan_attributes.global_id()
plan_attributes.owner_name()

Call the endpoint to retrieve all plans and projects in the urban model.

    
1
2
3
4
plans_projects = endpoint(op)
errors = plans_projects.get('errors')
if errors:
    print(errors)

To parse the returned JSON data into more convenient native objects, add the query operation to the results variable. Provide the ArcGIS account username of the user, which you want to use to filter the plans and projects. Loop through the returned plans and projects and find the ones created by the provided user.

               
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
obj = op + plans_projects

user_filter = "urban_till_dev"

# go through returned projects
print('Global IDs of projects created by {} \n'.format(user_filter))
for project in obj.urban_model.urban_database.projects:
    if project.attributes.owner_name==user_filter:
        print(project.attributes.global_id)

# go through returned plans
print('\nGlobal IDs of plans created by {} \n'.format(user_filter))
for plan in obj.urban_model.urban_database.plans:
    if plan.attributes.owner_name==user_filter:
        print(plan.attributes.global_id)

The output should look something like this:

           
1
2
3
4
5
6
7
8
9
10
11
Global IDs of projects created by urban_till_dev

48c52224-1dd1-4055-a342-b334695f340f
c3b18289-7012-4ef4-a4dc-2b2e39cb4e3e
def80619-f087-4436-b9f9-92fc4bc01b34
ce68ea4c-7ade-464f-ba59-616d0212e958
d451e5c6-0a2a-4443-8f24-c9a31e22bc1c

Global IDs of plans created by urban_till_dev

a09f01e4-9cb9-4d03-a983-6335ad4828a6

Fetch all publicly available urban models using variables and pagination

It is possible that the number of publicly available urban models exceeds the maximum number of objects which can be retrieved in a single API call. If you want to fetch more objects than defined by the maximum limits, you must use pagination. You are going to implement it in this example.

Urban API provides offset-based pagination, in which a client requests a page based on an absolute index in the list (offset) and the maximum number of elements to return (limit).

Create a new instance of Operation and set two arguments (variables), limit and offset. The variables must be named and have a defined type. Next, select relevant objects and return fields for the query operation.

         
1
2
3
4
5
6
7
8
9
op = Operation(schema.Query, limit=int, offset=int)

# set the body of the query
urban_models = op.urban_models(limit=Variable('limit'), offset=Variable('offset'))

# select relevant return fields
urban_models.title()
urban_models.access()
urban_models.owner()

Create a list to store all relevant models and initialize var_limit and var_offset variables. Set the var_limit to 100 to fetch the data in batches of 100 objects. The value of the var_offset variable is going to change in the while loop until all data is retrieved. Note, that the code snippet below invoke multiple API calls.

                   
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
all_models = []
var_limit = 100
var_offset = 0

while True:
    json_data = endpoint(op, variables={'limit':var_limit, 'offset': var_offset})
    errors = json_data.get('errors')
    if errors:
        print(errors)

    obj = op + json_data

    if len(obj.urban_models)==0:
        break
    else:
        for urban_model in obj.urban_models:
            all_models.append(urban_model)

    var_offset+=100

The urban models are stored in the all_models variable. You can get the total number of the retrieved models from the length of the list. Print all the retrieved urban models.

     
1
2
3
4
5
print('There are {} publicly available urban models.'
      .format(len(all_models)))

for model in all_models:
    print(model)

The output should look something like this:

       
1
2
3
4
5
6
7
There are 345 publicly available urban models.
UrbanModel(title=Sample Urban Project, access=public, owner=EsriTrainingSvc)
UrbanModel(title=River Forest Urban Model, access=public, owner=devlavigne)
UrbanModel(title=Fullerton, access=public, owner=Learn_ArcGIS)
UrbanModel(title=Modelo Curso ArcGIS Urban 2.0, access=public, owner=ricardocuberos_esriven)
UrbanModel(title=Housing Analysis with ArcGIS Urban, access=public, owner=bsims_hlplanning)
...

Your browser is no longer supported. Please upgrade your browser for the best experience. See our browser deprecation post for more details.