Managing offline map areas

Introduction

With ArcGIS you can take your web maps and layers offline to reliably work with your GIS data in disconnected scenarios when connectivity is intermittent or unavailable.

To learn about the concepts, steps, data requirements and applications that support taking a map offline, refer to the appropriate documentation pages:

Once web maps have been prepared, certain applications in the ArcGIS Platform and the ArcGIS Runtime SDKs allow you to build applications that can utitlize these maps while remaining disconnected. These workflows all make use of offline map areas, which a web map owner can define in one of two ways:

  • ahead of the time field workers will download these areas for offline use, known as preplanned map areas
  • at the time field workers actually need to download them for use, known as on-demand map areas

Note: Only a web map owner can create offline map areas. See Create and manage offline areas for details.

Making map areas ahead of time is the recommended workflow because the map author can ensure accuracy of the offline content and packaging of offline contents occurs only once. Packaged content can be used by mutliple workers to increase performance. This guide describes how to use the ArcGIS API for Python to create preplanned offline map areas for use in custom ArcGIS Runtime SDK apps or Esri applications such as ArcGIS Field Maps.

Let's get started with the API to demonstrate preparing areas ahead of time.

Creating offline map areas

With ArcGIS API for Python, you can conveniently manage offline areas from a WebMap object. The offline_areas property accesses the OfflineMapAreaManager object with which you can administer all aspects of offline map area management, from creating, to listing to updating. Let's take a look:

from arcgis.gis import GIS
from arcgis.mapping import WebMap
gis = GIS(profile="your_online_admin_profile")

Let's use a hydrology web map depicting the Middle Little Missouri River Sub Basin from the National Hydrology Dataset in the state of North Dakota in the United Sates.

wm_item = gis.content.get("6d7330a7f3f5438ebcbc6fe23f8abcc8")
wm_item
Middle Little Missouri Sub Basin Wetlands and Riparian Areas
Map of the National Wetlands Inventory wetlands and riparian areas data for the Middle Little Missouri Sub-Basin.Web Map by online_admin_user
Last Modified: July 31, 2023
0 comments, 193 views
wm_obj = WebMap(wm_item)

You can create offline areas for a specified extent, a specific polygon, or a bookmark. You can additionally specify any layers that you need to ignore, a destination folder to store these packages and a minimum and maximum scale to which the packages need to be cached. Let's examine a couple examples:

Creating offline areas with Bookmarks

The web map depicts wetlands data from subwatersheds within the Little Missouri River basin area of North Dakota. We've created bookmarks in the web map for areas surrounding three subwatersheds:

for bookmark in wm_obj.definition.bookmarks:
    print(bookmark.name)
Lower Garner Creek
Merrifield Creek
Bear Creek

We'll create an offline area for the bookmark called Lower Garner Creek. We'll also limit the data extracted into the offline map area package to specific layers in the web map. We'll include a subwatershed boundaries layer and a wetlands layer designating features we want our field workers to update. Let's first look at the list of layers from our web map so we know how to create a list of layers for the ignore_layers argument. We'll import the FeatureLayer class to examine some properties of each layer in the web map:

from arcgis.features import FeatureLayer

for wmlyr in wm_obj.layers:
    flyr = FeatureLayer(wmlyr['url'], gis)
    print(f"{flyr.properties.id:<3}{flyr.properties.name}\n{' '*2}{wmlyr.url}")
0  Non_Populated_GNIS_Places
  https://services7.arcgis.com/JEwYeAy2cc8qOe3o/arcgis/rest/services/Middle_Little_Missouri_SubBasin_Wetlands_and_Riparian_Areas/FeatureServer/0
1  Populated_GNIS_Place_Names
  https://services7.arcgis.com/JEwYeAy2cc8qOe3o/arcgis/rest/services/Middle_Little_Missouri_SubBasin_Wetlands_and_Riparian_Areas/FeatureServer/1
2  Middle Little Missouri Wetlands
  https://services7.arcgis.com/JEwYeAy2cc8qOe3o/arcgis/rest/services/Middle_Little_Missouri_SubBasin_Wetlands_and_Riparian_Areas/FeatureServer/2
3  Middle Little Missouri Riparian Areas
  https://services7.arcgis.com/JEwYeAy2cc8qOe3o/arcgis/rest/services/Middle_Little_Missouri_SubBasin_Wetlands_and_Riparian_Areas/FeatureServer/3
4  Theodore_Roosevelt_National_Park
  https://services7.arcgis.com/JEwYeAy2cc8qOe3o/arcgis/rest/services/Middle_Little_Missouri_SubBasin_Wetlands_and_Riparian_Areas/FeatureServer/4
5  Sub_Watershed Boundaries
  https://services7.arcgis.com/JEwYeAy2cc8qOe3o/arcgis/rest/services/Middle_Little_Missouri_SubBasin_Wetlands_and_Riparian_Areas/FeatureServer/5
6  Middle_Little_Missouri_Subbasin
  https://services7.arcgis.com/JEwYeAy2cc8qOe3o/arcgis/rest/services/Middle_Little_Missouri_SubBasin_Wetlands_and_Riparian_Areas/FeatureServer/6

We only want to include layer 2, and layer 5. So let's use a list comprehension to create a list of the urls for the feature layers we want to ignore:

flyrs_to_ignore = [fl["url"] for fl in wm_obj.layers if not fl["url"][-1] in ["2", "5"]]
flyrs_to_ignore
['https://services7.arcgis.com/JEwYeAy2cc8qOe3o/arcgis/rest/services/Middle_Little_Missouri_SubBasin_Wetlands_and_Riparian_Areas/FeatureServer/0',
 'https://services7.arcgis.com/JEwYeAy2cc8qOe3o/arcgis/rest/services/Middle_Little_Missouri_SubBasin_Wetlands_and_Riparian_Areas/FeatureServer/1',
 'https://services7.arcgis.com/JEwYeAy2cc8qOe3o/arcgis/rest/services/Middle_Little_Missouri_SubBasin_Wetlands_and_Riparian_Areas/FeatureServer/3',
 'https://services7.arcgis.com/JEwYeAy2cc8qOe3o/arcgis/rest/services/Middle_Little_Missouri_SubBasin_Wetlands_and_Riparian_Areas/FeatureServer/4',
 'https://services7.arcgis.com/JEwYeAy2cc8qOe3o/arcgis/rest/services/Middle_Little_Missouri_SubBasin_Wetlands_and_Riparian_Areas/FeatureServer/6']

We'll also set the farthest scale users will zoom out to view layers in the package with the min_scale argument. In addition, we'll use the item_properties parameter to specify properties for the resulting Map Area item. We'll specify the title, description, and tags for the item that gets created.

This operation can take a while as the server is packaging the contents of the web map for offline use. To view the status, you can optionally turn on the verbosity using the env module as shown below:

from arcgis import env
env.verbose = True

Note: You must own the web map or be an organization administrator to run this operation.

offline_item_properties = {"title": "Offline area for Lower Garner Creek Subwatershed",
                          "tags": ["Python", "automation", "hydrology", "wetlands"],
                          "snippet": "Area created for updating wetlands and riparian areas."}

lower_garner_offline_item = wm_obj.offline_areas.create(area = wm_obj.definition.bookmarks[0].name,
                                                        item_properties = offline_item_properties,
                                                        min_scale = 210000,
                                                        max_scale = 0,
                                                        ignore_layers= flyrs_to_ignore,
                                                        folder="Wetlands_Inventory")

We can now use the list() method on the web map object to examine the resulting item:

wm_obj.offline_areas.list()
[<Item title:"Offline area for Lower Garner Creek Subwatershed" type:Map Area owner:online_admin_user>]

Notice the type attribute of the item is Map Area.

Create offline areas with an Extent

We can also use an extent object to create an offline map area. An extent defines a bounding box by specifying coordinate pairs for both the lower-left and upper-right corners. You can define an extent yourself with coordinates that lie within the entire extent of the web map, or use existing features within web map layers to define an extent.

We can define a smaller area within the bounds of our data using latitude and longitude coordinates for an area we know is within our overall extent. For this dataset, we know we are in southwestern North Dakota, so we'll define an extent covering a subarea of a subwatershed named Middlefield Creek within the basin.

When using an extent for the area argument the format needs to be a list of 2 coordinate pairs:

extentcoordinates = [[_x minimum, y minimum], [x maximum, y maximum]]

mfield_sub_extent = [[-103.56, 46.76], [-103.50, 46.80]]
offline_item_properties = {"title": "Offline area for mid-section of Merrifield Creek Subwatershed",
                          "tags": ["Python", "automation", "hydrology", "wetlands"],
                          "snippet": "Area created for updating wetlands and riparian areas in Little Missouri River basin."}

merrifield_offline_item = wm_obj.offline_areas.create(area = mfield_sub_extent,
                                                        item_properties = offline_item_properties,
                                                        min_scale = 210000,
                                                        max_scale = 0,
                                                        ignore_layers= flyrs_to_ignore,
                                                        folder="Wetlands_Inventory")

Using the same list() method as above, we can now see that we have two Map Area items for this web map.

print(wm_obj.offline_areas.list())
[<Item title:"Offline area for mid-section of Merrifield Creek Subwatershed" type:Map Area owner:online_admin_user>, <Item title:"Offline area for Lower Garner Creek Subwatershed" type:Map Area owner:online_admin_user>]

Create offline areas from a specific polygon

We can also create an offline map area using an instance of a polygon geometry to define the geographic area. We can extract a polygon from one of our layers.

from arcgis.geometry import Polygon

subwatershed_lyr = FeatureLayer(wm_obj.layers[5]["url"], gis)
bear_ck = subwatershed_lyr.query(where="name = 'Bear Creek'").features[0]
bear_ck_poly = Polygon(bear_ck.geometry)
bear_ck_poly
offline_item_properties = {"title": "Offline area for Bear Creek Subwatershed",
                          "tags": ["Python", "automation", "hydrology", "wetlands"],
                          "snippet": "Area created for updating wetlands and riparian areas in Bear Creek subwatershed in the Little Missouri River basin."}

merrifield_offline_item = wm_obj.offline_areas.create(area = bear_ck_poly,
                                                        item_properties = offline_item_properties,
                                                        min_scale = 210000,
                                                        max_scale = 0,
                                                        ignore_layers= flys_to_ignore,
                                                        folder="Wetlands_Inventory")
wm_obj.offline_areas.list()
[<Item title:"Offline area for mid-section of Merrifield Creek Subwatershed" type:Map Area owner:online_admin_user>,
 <Item title:"Offline area for Bear Creek Subwatershed" type:Map Area owner:online_admin_user>,
 <Item title:"Offline area for Lower Garner Creek Subwatershed" type:Map Area owner:online_admin_user>]

We've used three different ways of specifying a geographic area to create offline mapping ares for our web map. Now it's time to inspect the Map Area items to get some additional information. As we saw earlier, the create() method results in items with a type attribute of Map Area. We can loop through our list to see this:

for oma_item in wm_obj.offline_areas.list():
    print(f"{oma_item.title:65}{oma_item.type}")
Offline area for mid-section of Merrifield Creek Subwatershed    Map Area
Offline area for Bear Creek Subwatershed                         Map Area
Offline area for Lower Garner Creek Subwatershed                 Map Area

Inspecting offline packages created for a map area

When you create an offline map area, the data for the specified extent is bundled into one or many packages for downloading depending upon the types of layers in the web map. Feature Layers are packaged into mobile geodatabases, while tile layers and vector tile layers are bundled into tile packages and vector tile packages, respectively. See the Create and manager offline map areas documentation for details.

The packages created for a Map Area item share a relationship with the item. The relationship type is an Area2Package relation with a forward direction. See the Relationship types documentation for a comprehensive list of possible relations between items. Any item has the related_items() method from which you can retrieve the items that participate in the specific relationship type:

for oma_item in wm_obj.offline_areas.list():
    print(f"{oma_item.title} shares the `Area2Package` relationship with: \n{'-' * 50}")
    for rel_item in oma_item.related_items('Area2Package', 'forward'):
        print(f"{' '*2}{rel_item.title:55}\n{' '*4}{rel_item.type}")
    print("\n")
Offline area for mid-section of Merrifield Creek Subwatershed shares the `Area2Package` relationship with: 
--------------------------------------------------
  Middle_Little_Missouri_SubBasin_Wetlands_and_Riparian_Areas-380a6e66592d41219f5efeb076b9286e
    SQLite Geodatabase


Offline area for Bear Creek Subwatershed shares the `Area2Package` relationship with: 
--------------------------------------------------
  VectorTileServe-77514eec74ac400a98a6026440a4e7f6       
    Vector Tile Package
  Middle_Little_Missouri_SubBasin_Wetlands_and_Riparian_Areas-2cd25cf0ca7b4267904f4dc831bd6a71
    SQLite Geodatabase


Offline area for Lower Garner Creek Subwatershed shares the `Area2Package` relationship with: 
--------------------------------------------------
  Middle_Little_Missouri_SubBasin_Wetlands_and_Riparian_Areas-f04e141cf75842b0821664b4e8ab6233
    SQLite Geodatabase
  VectorTileServe-a971522fa2ec43a08b76565b146fdbe4       
    Vector Tile Package


These items are meant for use in offline applications like ArcGIS Field Maps, ArcGIS Survey123, or ArcGIS Runtime SDK applicatons. If needed, you can call the download() method of the Map Area item to download the data to disk.

Updating offline areas

The layer data used to create the offline map areas may change, so keeping offline areas up to date is an important task. The update() method of the OfflineMapAreaManager class accomplishes this. The method accepts a list of Map Area items as input. If no items are specified in the items argument, all map area items for the web map get updated.

Below is an example of how the progress is relayed back to you when you turn on the verbosity in the env module.

from arcgis import env
env.verbose=True
# update all offline areas for the fire web map
wm_obj.offline_areas.update()
Submitted.
Executing...
Start Time: Wednesday, August 02, 2023 12:13:43 AM
Middle_Little_Missouri_SubBasin_Wetlands_and_Riparian_Areas/FeatureServer - Get Service Definition
Middle_Little_Missouri_SubBasin_Wetlands_and_Riparian_Areas/FeatureServer - Submit sync job
World_Basemap_v2/VectorTileServer - Submit export job
Middle_Little_Missouri_SubBasin_Wetlands_and_Riparian_Areas/FeatureServer - Get Service Definition
Middle_Little_Missouri_SubBasin_Wetlands_and_Riparian_Areas/FeatureServer - Submit sync job
Middle_Little_Missouri_SubBasin_Wetlands_and_Riparian_Areas/FeatureServer - Get Service Definition
Middle_Little_Missouri_SubBasin_Wetlands_and_Riparian_Areas/FeatureServer - Submit sync job
World_Basemap_v2/VectorTileServer - Submit export job
Middle_Little_Missouri_SubBasin_Wetlands_and_Riparian_Areas/FeatureServer - Add/Update package item
Middle_Little_Missouri_SubBasin_Wetlands_and_Riparian_Areas/FeatureServer - Add/Update package item
Middle_Little_Missouri_SubBasin_Wetlands_and_Riparian_Areas/FeatureServer - Add/Update package item
Middle_Little_Missouri_SubBasin_Wetlands_and_Riparian_Areas/FeatureServer - Processing complete
Middle_Little_Missouri_SubBasin_Wetlands_and_Riparian_Areas/FeatureServer - Processing complete
Middle_Little_Missouri_SubBasin_Wetlands_and_Riparian_Areas/FeatureServer - Processing complete
World_Basemap_v2/VectorTileServer - Add/Update package item
World_Basemap_v2/VectorTileServer - Add/Update package item
World_Basemap_v2/VectorTileServer - Processing complete
World_Basemap_v2/VectorTileServer - Processing complete
RefreshMapAreaPackage GP Job: j6122b0038a9d4f35bbdd726985b6d25c finished successfully.
[{'source': 'https://services7.arcgis.com/JEwYeAy2cc8qOe3o/arcgis/rest/services/Middle_Little_Missouri_SubBasin_Wetlands_and_Riparian_Areas/FeatureServer',
  'itemId': '36d7b8e5bfe74b37a07eaad00be4033d',
  'state': 'unchanged'},
 {'source': 'https://services7.arcgis.com/JEwYeAy2cc8qOe3o/arcgis/rest/services/Middle_Little_Missouri_SubBasin_Wetlands_and_Riparian_Areas/FeatureServer',
  'itemId': 'c74db213e5b94ce486d07f29fb240b80',
  'state': 'unchanged'},
 {'source': 'https://services7.arcgis.com/JEwYeAy2cc8qOe3o/arcgis/rest/services/Middle_Little_Missouri_SubBasin_Wetlands_and_Riparian_Areas/FeatureServer',
  'itemId': 'd6a380a85291455382e7eb52870420d4',
  'state': 'unchanged'},
 {'source': 'https://basemaps.arcgis.com/arcgis/rest/services/World_Basemap_v2/VectorTileServer',
  'itemId': '6ac731fed6c14a0aa516dc8dbe4b5b77',
  'state': 'updated'},
 {'source': 'https://basemaps.arcgis.com/arcgis/rest/services/World_Basemap_v2/VectorTileServer',
  'itemId': 'b458a7d78a7148f7b53beed1124ccfe0',
  'state': 'updated'}]

Now any field users are all set with the latest packages for use in a disconnected setting.

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