Updating the extent of a WebMap using the ArcGIS API for Python

749
6
Jump to solution
01-10-2024 06:16 AM
Labels (2)
Clubdebambos
Occasional Contributor III

I have switched from the Map Viewer Classic to the new Map Viewer. The code below to update the WebMap extent used to work on the Classic but fails to work on the new Map Viewer. Is anyone else having this issue? Has anyone successfully updated the WebMap extent using the ArcGIS API for Python with the new Map Viewer?

 

from arcgis.gis import GIS

## Access AGOL
agol = GIS("home")

## Access the WebMap Item
wm_item = agol.content.get("WM_ITEM_ID")

## the new extent
xmin = -12
ymin = 50
xmax = -2
ymax = 58

item_properties = {'extent':'{0},{1},{2},{3}'.format(xmin, ymin, xmax, ymax)}

## update the WebMap Item
wm_item.update(item_properties)

 

The code runs without error but the WebMap extent when the WebMap is opened remains unchanged.

Additional Information: it updates the JSON but doesnt affect the WebMap extent when opening the viewer.

~ learn.finaldraftmapping.com
0 Kudos
2 Solutions

Accepted Solutions
PeterKnoop
MVP Regular Contributor

The solution for New Map Viewer Set Default Extent put me on the right track when I ran into this same issue. 

With the new Map Viewer also comes a new way of defining the initial or home view of your web map, the viewpoint.  So now you need to set the viewpoint parameter in the item's data, rather than its extent in  item_properties.

In your example, you can use get_data to view your item's current viewpoint, e.g., 

wm_item.get_data()

{
'operationalLayers': [],
'baseMap': {
'baseMapLayers': [{
'id': 'World_Hillshade_3805',
'opacity': 1,
'title': 'World Hillshade',
'url': 'https://services.arcgisonline.com/arcgis/rest/services/Elevation/World_Hillshade/MapServer',
'visibility': True,
'layerType': 'ArcGISTiledMapServiceLayer'
},
{
'id': 'VectorTile_2333',
'opacity': 1,
'title': 'World Topographic Map',
'visibility': True,
'layerType': 'VectorTileLayer',
'styleUrl': 'https://cdn.arcgis.com/sharing/rest/content/items/7dc6cea0b1764a1f9af2e679f642f0f5/resources/styles/root.json'
}],
'title': 'Topographic'
},
'authoringApp': 'ArcGISMapViewer',
'authoringAppVersion': '2023.2',
'initialState': {
'viewpoint': {
'targetGeometry': {
'spatialReference': {
'latestWkid': 3857,
'wkid': 102100
},
'xmin': -9363110.186797503,
'ymin': 5143763.742527973,
'xmax': -9274213.922901962,
'ymax': 5258113.536842443
}
}
},
'spatialReference': {
'latestWkid': 3857,
'wkid': 102100
},
'timeZone': 'system',
'version': '2.29'
}




You can store the item's data in a dictionary, then modify the targetGeometry, e.g.,

data_dict = wm_item.get_data()
data_dict['initialState']['viewpoint']['targetGeometry']['xmin'] = -11363110.186797503
data_dict['initialState']['viewpoint']['targetGeometry']['ymin'] = 5143763.742527973
data_dict['initialState']['viewpoint']['targetGeometry']['xmax'] = -11274213.922901962
data_dict['initialState']['viewpoint']['targetGeometry']['ymax'] = 5258113.536842443

Then use update to save your new viewpoint, updating the item's data, rather than its item_properties, e.g., 

web_map_item.update(
data = data_dict
)

You might still want to set the extent property for the web map, as it is supposedly still used in searching/filtering items by location. I usually set both the viewpoint and extent now.

 

 

View solution in original post

Clubdebambos
Occasional Contributor III

Thanks @PeterKnoop  I can confirm this works when updating the initialState property, just to add, I'm taking coordinates from WGS84 and applying to the extent so there is a conversion required to project to 3857 as per below.

 

from arcgis.gis import GIS
from arcgis.geometry import project
from arcgis.mapping import WebMap

## Access AGOL
agol = GIS("home")

## Access the WebMap Item
wm_item = agol.content.get("WM_ITEM_ID")

## Create a WebMap object from WebMp Item
webmap = WebMap(wm_item)

## I would get these as the bbox of a geometry
xmin = -12
ymin = 50
xmax = -2
ymax = 58

## project from 4326 to 3857
result = project(geometries=[{"x": xmin, "y" : ymin}, {"x" : xmax, "y" : ymax}], in_sr=4326, out_sr=3857)

## get the 3857 bbox coords
v_ymin = result[0]["y"]
v_ymax = result[1]["y"]
v_xmin = result[0]["x"]
v_xmax = result[1]["x"]

## apply to the initialState property in webmap.definition
## NOTE: initialState only seems to appear as a property after saving the webmap manually
webmap.definition['initialState']['viewpoint']['targetGeometry']['xmin'] = v_xmin
webmap.definition['initialState']['viewpoint']['targetGeometry']['ymin'] = v_ymin
webmap.definition['initialState']['viewpoint']['targetGeometry']['xmax'] = v_xmax
webmap.definition['initialState']['viewpoint']['targetGeometry']['ymax'] = v_ymax

## update the webmap properties
item_properties = {"text":webmap.definition}
wm_item.update(item_properties=item_properties)

 

~ learn.finaldraftmapping.com

View solution in original post

0 Kudos
6 Replies
PeterKnoop
MVP Regular Contributor

The solution for New Map Viewer Set Default Extent put me on the right track when I ran into this same issue. 

With the new Map Viewer also comes a new way of defining the initial or home view of your web map, the viewpoint.  So now you need to set the viewpoint parameter in the item's data, rather than its extent in  item_properties.

In your example, you can use get_data to view your item's current viewpoint, e.g., 

wm_item.get_data()

{
'operationalLayers': [],
'baseMap': {
'baseMapLayers': [{
'id': 'World_Hillshade_3805',
'opacity': 1,
'title': 'World Hillshade',
'url': 'https://services.arcgisonline.com/arcgis/rest/services/Elevation/World_Hillshade/MapServer',
'visibility': True,
'layerType': 'ArcGISTiledMapServiceLayer'
},
{
'id': 'VectorTile_2333',
'opacity': 1,
'title': 'World Topographic Map',
'visibility': True,
'layerType': 'VectorTileLayer',
'styleUrl': 'https://cdn.arcgis.com/sharing/rest/content/items/7dc6cea0b1764a1f9af2e679f642f0f5/resources/styles/root.json'
}],
'title': 'Topographic'
},
'authoringApp': 'ArcGISMapViewer',
'authoringAppVersion': '2023.2',
'initialState': {
'viewpoint': {
'targetGeometry': {
'spatialReference': {
'latestWkid': 3857,
'wkid': 102100
},
'xmin': -9363110.186797503,
'ymin': 5143763.742527973,
'xmax': -9274213.922901962,
'ymax': 5258113.536842443
}
}
},
'spatialReference': {
'latestWkid': 3857,
'wkid': 102100
},
'timeZone': 'system',
'version': '2.29'
}




You can store the item's data in a dictionary, then modify the targetGeometry, e.g.,

data_dict = wm_item.get_data()
data_dict['initialState']['viewpoint']['targetGeometry']['xmin'] = -11363110.186797503
data_dict['initialState']['viewpoint']['targetGeometry']['ymin'] = 5143763.742527973
data_dict['initialState']['viewpoint']['targetGeometry']['xmax'] = -11274213.922901962
data_dict['initialState']['viewpoint']['targetGeometry']['ymax'] = 5258113.536842443

Then use update to save your new viewpoint, updating the item's data, rather than its item_properties, e.g., 

web_map_item.update(
data = data_dict
)

You might still want to set the extent property for the web map, as it is supposedly still used in searching/filtering items by location. I usually set both the viewpoint and extent now.

 

 

Clubdebambos
Occasional Contributor III

Hi @PeterKnoop 

I am in the middle of testing this but I think I have found a bug. When you use the ArcGIS API for Python to create a WebMap there is no initialState property added. Even after using the API to add layers, reorder layers, and perform other tasks, the initialState property does not appear and only seems to be added when you open the WebMap in ArcGIS Online and save it. Only then does the initialState property get added. 

~ learn.finaldraftmapping.com
0 Kudos
Clubdebambos
Occasional Contributor III

I have submitted as a bug here: https://github.com/Esri/arcgis-python-api/issues/1742 

~ learn.finaldraftmapping.com
0 Kudos
Clubdebambos
Occasional Contributor III

Thanks @PeterKnoop  I can confirm this works when updating the initialState property, just to add, I'm taking coordinates from WGS84 and applying to the extent so there is a conversion required to project to 3857 as per below.

 

from arcgis.gis import GIS
from arcgis.geometry import project
from arcgis.mapping import WebMap

## Access AGOL
agol = GIS("home")

## Access the WebMap Item
wm_item = agol.content.get("WM_ITEM_ID")

## Create a WebMap object from WebMp Item
webmap = WebMap(wm_item)

## I would get these as the bbox of a geometry
xmin = -12
ymin = 50
xmax = -2
ymax = 58

## project from 4326 to 3857
result = project(geometries=[{"x": xmin, "y" : ymin}, {"x" : xmax, "y" : ymax}], in_sr=4326, out_sr=3857)

## get the 3857 bbox coords
v_ymin = result[0]["y"]
v_ymax = result[1]["y"]
v_xmin = result[0]["x"]
v_xmax = result[1]["x"]

## apply to the initialState property in webmap.definition
## NOTE: initialState only seems to appear as a property after saving the webmap manually
webmap.definition['initialState']['viewpoint']['targetGeometry']['xmin'] = v_xmin
webmap.definition['initialState']['viewpoint']['targetGeometry']['ymin'] = v_ymin
webmap.definition['initialState']['viewpoint']['targetGeometry']['xmax'] = v_xmax
webmap.definition['initialState']['viewpoint']['targetGeometry']['ymax'] = v_ymax

## update the webmap properties
item_properties = {"text":webmap.definition}
wm_item.update(item_properties=item_properties)

 

~ learn.finaldraftmapping.com
0 Kudos
PeterKnoop
MVP Regular Contributor

@Clubdebambos you probably have already figured this out... instead of projecting your coordinates to a different spatial reference, and then applying them, you could change the spatial reference in the definition. It just happened that the example I copied from was using 3857.

Instead could you perhaps specify a spatialReference of 4326, and use your coordinates directly?

webmap.definition['initialState']['viewpoint']['targetGeometry'] = {
'spatialReference': {
'latestWkid': 4326,
'wkid': 4326
},
'xmin': result[0]["x"],
'ymin': result[0]["y"],
'xmax': result[1]["x"],
'ymax': result[1]["y"]
}

Also, if the initialState parameter is missing from your newly created web map, perhaps you could programmatically add it and update the definition? (Or was the bug that you couldn't add it programmatically?)

webmap.definition['initialState'] = {
'viewpoint': {
'targetGeometry': {
'spatialReference': {
'latestWkid': <wkid>,
'wkid': <wkid>
},
'xmin': <xmin>,
'ymin': <ymin>,
'xmax': <xmax>,
'ymax': <ymax>
}
}
}

 

Clubdebambos
Occasional Contributor III

Hi @PeterKnoop,

Thanks for the additional info. I like to match what would happen if I did it manually, hence projecting to 3857. I find things are more likely to work and less likely to cause issues. I performed that exact workaround for adding earlier. I only recently moved to the new map viewer so going through everything with a fine tooth comb 😃 

~ learn.finaldraftmapping.com
0 Kudos