Copying descriptions from feature layers to map image layers with ArcGIS Python API?

627
9
01-28-2020 04:29 AM
PhillipGiraud
New Contributor II

Hi

I am wondering if there is a way to copy descriptions from feature layers to map image layers using the Python API?

I know when publishing feature layers there is a corresponding map image layer that is published, but I cannot see a way to link the two together, any ideas?

Our users tend to fill out the description information for one layer but not the other so it would be good to put a process in place that will automatically copy this information over.

0 Kudos
9 Replies
AnttiKajanus
New Contributor III

Feature Service metadata (service level, not item level) can be updated by using 'update_definition' as mentioned in Service definitions | ArcGIS for Developers 

I would assume that there is similar method for the map image layer. Maybe it's this arcgis.mapping module — arcgis 1.7.0 documentation where you should pass the description through service definition parameter. 

I don't have any map image layers on hand so I cannot test the theory.

0 Kudos
PhillipGiraud
New Contributor II

Thank you for your reply.

It is more the linking between feature layers and map image layers which are published together on the Portal.

I have a description in the feature layer, but wish to copy this over to the map image layer that was published at the same time, but I cannot find any relationship between the two (I have included screenshots below of what I mean).

0 Kudos
AnttiKajanus
New Contributor III

I don't think there is way to link item descriptions by default so it will require some code for it. 

How are you publishing the services? If you use a python tool for the publishing, then it would be easy thing to update the description (or any item level metadata) from a single configuration. If your customers are manually creating services, then you would need to either to have script running on timer or manually run it every now and then to update the values.  Something along this way

from arcgis.gis import GIS
import getpass

password = getpass.getpass("Enter password: ")

gis = GIS('org', 'me', password)
print("Connected to: {}\nConnected as: {}".format(
gis.properties.urlKey + "." + gis.properties.customBaseUrl,
gis.users.me.username))

search_result = gis.content.search(
query="title:Liikenneväylät Helsinki",
item_type="Feature Layer")
search_result

#[<Item title:"Liikenneväylät Helsinki (Read-only)" type:Feature Layer Collection owner:xxx>,
# <Item title:"Liikenneväylät Helsinki" type:Feature Layer Collection owner:xxxx>,
# <Item title:"Liikenneväylät Helsinki (Edit)" type:Feature Layer Collection owner:xxx>]

# Copy from master service to the view
copy_from_item = search_result[1]
print(copy_from_item.description)

# Take the item that is being updated
copy_to_item = search_result[0]
print(copy_to_item.description)

#Added!
#None

# Define which values are updated
item_properties = {
'description' : copy_from_item.description
}

copy_to_item.update(item_properties=item_properties)
print(copy_to_item.description)

#Added!‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

Hope it helps.

0 Kudos
PhillipGiraud
New Contributor II

Thanks very much for replying Antti.

This would certainly work if the layer names are identical, but I am not sure if that is a foolproof way of associating the layers together (and you can find that the feature layer title could be changed to a different name than that of the map image layer and vice versa).

My thinking was obtaining the URL path for each service, replacing 'FeatureServer' with 'MapServer' and seeing if an associated MapServer is running, if so change the description.

But, this I think would only be working with the service, not the actual items in the Portal?

0 Kudos
AnttiKajanus
New Contributor III

Yeah, it's not. Some of it really depends how the services are published but if the process is not really coordinated then it limits options. If you have a control over the publishing process you use could for example relatedItems (with type service2service) concept to map the services if you want to have a link between them or you could just copy the item metadata as part of the publishing process. If you don't have control then you cannot really assume that they would publish the Map Image Layer with the same name as the Feature Service either. It might be rarer for sure but could be done. 

If you assume that the name of the service is the same, you could go through all the layers in your organization and check url from the item properties and map the corresponding items together. Yeah, its a bit crude solution but should work if the assumption is correct.

search_result = gis.content.search(
query="title:\"Liikenneväylät Helsinki\" AND (type: \"Map Service\" OR type:\"Feature Service\" OR type:\"Image Service\")")

for item in search_result:
if (item.title == "Liikenneväylät Helsinki"):
print(item.title + " : " + item.url)

# Liikenneväylät Helsinki : https://services1.arcgis.com/ut5Ig3pyAO7DhCxU/arcgis/rest/services/Liikenneväylät_Helsinki/FeatureServer
# Liikenneväylät Helsinki : https://services1.arcgis.com/ut5Ig3pyAO7DhCxU/arcgis/rest/services/Liikenneväylät_Helsinki/MapServer
‍‍‍‍‍‍‍‍‍

Are the services published as hosted services in ArcGIS Online or is Enterprise/Server involved? Are the services actually using the same data or are the services totally different with duplicated data?

edit: added link to the relatedItems documentation

0 Kudos
PhillipGiraud
New Contributor II

The data is published using ArcGIS Pro / ArcMap and the share as web layer option.

The services are using the same data and are being published via Enterprise/Server.

0 Kudos
AnttiKajanus
New Contributor III

I see. I think that then you can assume that the service names are the same and you could use the url trick to match them. Unfortunately AGOL doesn't seem to support query based on the url so you need to query all layers and then handle the pairing in code.

This kind of approach seems to work but since I do quite a few queries here, it's a bit slow if you have a lot of services. 

feature_services_result = gis.content.search(
query="type:\"Feature Service\" AND owner:{}".format(me), max_items=1000)

for feature_service_item in feature_services_result:
url_root = feature_service_item.url.rsplit('/', 1)[0]
if feature_service_item.type == 'Feature Service':
map_services_result = gis.content.search(
query="type:\"Map Service\" AND owner:{}".format(me), max_items=1000)
if len(map_services_result) > 0:
for map_service_item in map_services_result:
if url_root in map_service_item.url:
print("Match found:")
print("Feature Service: {}".format(feature_service_item.url))
print("Map Service: {}".format(map_service_item.url))
item_properties = {
'description' : feature_service_item.description
}
print("Updating metadata for item {}".format(map_service_item.id))
update_result = map_service_item.update(item_properties=item_properties)
if (update_result):
print("Update completed for the item")
else:
print("Update failed for the item")

# Match found:
# Feature Service: https://services1.arcgis.com/ut5Ig3pyAO7DhCxU/arcgis/rest/services/Liikenneväylät_Helsinki/FeatureServer
# Map Service: https://services1.arcgis.com/ut5Ig3pyAO7DhCxU/arcgis/rest/services/Liikenneväylät_Helsinki/MapServer
# Updating metadata for item 40eb38d75cac4bc6afe18681ecdb49f2
# Update completed for the item
PhillipGiraud
New Contributor II

That's brilliant Antti thank you, exactly what I was thinking but yes agree that it may take a while to complete as it has to loop through all services.

Thanks for being so helpful.

0 Kudos
AnttiKajanus
New Contributor III

Happy to help! It's good training for me to get more used to the API and it's capabilities and limitations.