I need to be able to progammatically create Hosted Feaure Layer Views of a number of services which we collaborate to ArcGIS Online. This is to provide a community view of data we hold at Council level. I have found an excellent Python script - https://community.esri.com/t5/gis-life-blog/create-view-from-hosted-feature-layer-and-define/ba-p/89... - which I have managed to hack to use our own data. This works perfectly when the source item consists of a single layer. However I am completely failing to make it work when the source layer for the view is a sublayer.
For example I want to create a community view of the Places theme of our Local Plan Policy areas - https://ren.maps.arcgis.com/home/item.html?id=805b7050bcfd4154a6a15f533eae7a52
https://services2.arcgis.com/fq3IIWzrdf1xBoPI/arcgis/rest/services/LDP_ADOPTED_2021/FeatureServer/6
using our Community Council boundaries - ItemID 0382e3a4a2e944858426ddde271211f0
e.g. places = gis.content.get('0382e3a4a2e944858426ddde271211f0').layers[1].query()
I just don't seem to be able to find a way to make this work. Any help gratefully received.
Solved! Go to Solution.
Hi @SeanCulpan
You need to use the view_layers parameter for the creat_view() method and supply a list of feature layers to add to the view, in this case there is one layer to add.
## create the view, the view will contain one layer
new_view = flc.manager.create_view(
name = "NAME_OF_NEW_VIEW",
## select the layer based on its id
view_layers = [flc.layers[6]]
)Here's the full script that works for me.
from arcgis.gis import GIS
from arcgis.features import FeatureLayerCollection
## access agol
agol = GIS("home")
## access the feature service item that contains the layers
fs_item = agol.content.get("FS_ITEM_ID")
## create a FeatureLayerCololection object from the feature service item
flc = FeatureLayerCollection.fromitem(fs_item)
## get the feature that represents the polygon to apply as a geometry filter
aoi_record = agol.content.get("ANOTHER_FS_ITEM_ID").layers[0].query(where="COUNTY='GALWAY'")
## get the srs of the aoi
srs = aoi_record.spatial_reference
## get the geometry of the aoi polygon
view_geom = aoi_record.features[0].geometry.get('rings')
## create the view, the view will contain one layer
new_view = flc.manager.create_view(
name = "NAME_OF_NEW_VIEW",
## select the layer based on its id
view_layers = [flc.layers[6]]
)
## access that layer
lyr = new_view.layers[0]
## create a dictionary to define the geometry filter with the aoi
update_dict = {
"viewLayerDefinition" : {
"filter" : {
"operator" : "esriSpatialRelContains",
"value" : {
"geometryType" : "esriGeometryPolygon",
"geometry" : {
"rings": view_geom,
"spatialReference":srs
}
}
}
}
}
## update the view to apply the geometry filter
print(lyr.manager.update_definition(update_dict))I hope I got the workflow you were looking for correct.
Hi @SeanCulpan
You need to use the view_layers parameter for the creat_view() method and supply a list of feature layers to add to the view, in this case there is one layer to add.
## create the view, the view will contain one layer
new_view = flc.manager.create_view(
name = "NAME_OF_NEW_VIEW",
## select the layer based on its id
view_layers = [flc.layers[6]]
)Here's the full script that works for me.
from arcgis.gis import GIS
from arcgis.features import FeatureLayerCollection
## access agol
agol = GIS("home")
## access the feature service item that contains the layers
fs_item = agol.content.get("FS_ITEM_ID")
## create a FeatureLayerCololection object from the feature service item
flc = FeatureLayerCollection.fromitem(fs_item)
## get the feature that represents the polygon to apply as a geometry filter
aoi_record = agol.content.get("ANOTHER_FS_ITEM_ID").layers[0].query(where="COUNTY='GALWAY'")
## get the srs of the aoi
srs = aoi_record.spatial_reference
## get the geometry of the aoi polygon
view_geom = aoi_record.features[0].geometry.get('rings')
## create the view, the view will contain one layer
new_view = flc.manager.create_view(
name = "NAME_OF_NEW_VIEW",
## select the layer based on its id
view_layers = [flc.layers[6]]
)
## access that layer
lyr = new_view.layers[0]
## create a dictionary to define the geometry filter with the aoi
update_dict = {
"viewLayerDefinition" : {
"filter" : {
"operator" : "esriSpatialRelContains",
"value" : {
"geometryType" : "esriGeometryPolygon",
"geometry" : {
"rings": view_geom,
"spatialReference":srs
}
}
}
}
}
## update the view to apply the geometry filter
print(lyr.manager.update_definition(update_dict))I hope I got the workflow you were looking for correct.
Thank you. I was missing the list of layers in the create_view method. Got my Notebook working as expected now.
This is a very useful post.
Ignore the below. I figured it out.Does anyone have any guidance for doing this but using multiple sublayers? For example, our source layer contains 4 sublayers and we want to create views that contain 3 out of the 4 sublayers (id's 1-3). This will also require setting different visible fields as the fields are not the same across the 3 sublayers, and ViewDefinitionQuery statements for each of the 3 sublayers.
Many thanks.
This and other posts were somewhat helpful in my pursuits to create a number of hosted feature layer view items. But, I needed to apply the query to many layers, and to apply an attribute filter instead of an AOI. This isn't the best code, but perhaps it will help someone else out. It also sets the Title of the View item.
import arcpy
import os
import sys # may not be needed here, the below is extracted from a larger code base
import shutil # may not be needed here, the below is extracted from a larger code base
from time import strftime
from arcgis.features import FeatureLayerCollection
from arcgis.gis import GIS
today = strftime("%Y%m%d")
def next_section(): # this is more relevant when output to a log file
print("###############################################################")
try:
########################### START ###############################
next_section()
print("Starting up. Running for "+today)
next_section()
########## !!!! REVIEW AND SET BEOFRE RUN !!!! ##########
## works on one HFL at a time, creating views for 8 regions, where layer IDs start with 0 and increment uniformly
parent_hfl_id = "3af...26"
layers_count = 12
service_name_base = "LRS_Cadastral_Reconcile_Interest"
item_title_base ="LRS Cadastral Reconcile Interest-Tracts"
gis = GIS("pro") # make sure Pro is signed in and set to correct active portal
fs_item = gis.content.get(parent_hfl_id)
flc = FeatureLayerCollection.fromitem(fs_item)
for fwsregion in range(1,9): # creates views for 1 through 8
fwsregion = str(fwsregion)
view_name=service_name_base+"_Region_"+fwsregion # no spaces or special chars
try:
view = flc.manager.create_view(name=view_name) # creates view
view_list = gis.content.search(view_name) # gets the new view item
view_item = view_list[0] # and just the new item, from returned list
view_item.update(item_properties={'title':item_title_base+" - Region "+fwsregion}) # set title on the view (can set other properties, too)
print("View created:",view_name)
defquery_dict = {
"viewDefinitionQuery" : "FWSREGION = '"+fwsregion+"'"
} # SQL query to apply to layers
for layer_id in range(0,layers_count): # apply to all layers (consistent in this application)
lyr = view.layers[layer_id]
lyr.manager.update_definition(defquery_dict)
print("Filter applied to",layer_id+1,"layers")
except:
print("Failed to create",view_name,"Check that it doesn't already exist!")
next_section()
############################## END ###############################
print("Completed.")
########################### ERRORS ###############################
except Exception as e: # may want to use traceback, revisit later
print("Error: "+ str(e))
#################################################################