Using the ArcGIS API for Python to create a view from a Hosted Feature Layer and to define a view definition

2106
14
02-11-2019 03:23 PM
EarlMedina1
Occasional Contributor III
10 14 2,106

Let's say you have a Hosted Feature Layer named worldEQ which contains data on Earthquakes that have occurred throughout the world for the last 50 years:

earthquakes

You wish to create a view named worldEQView from this Hosted Feature Layer. To do that, you could use the following snippet:

from arcgis import GIS
from arcgis.features import FeatureLayerCollection
gis = GIS("https://www.arcgis.com", "username","password")

# Search for Source Hosted Feature Layer
source_search = gis.content.search("world_earthquakes")[0]
source_flc = FeatureLayerCollection.fromitem(source_search)

# Create View from Source Hosted Feature Layer
new_view = source_flc.manager.create_view(name="worldEQView")‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

This works out great and your view is created:

viewresult

Let's suppose you next want to use the view to show only earthquakes that occurred before the year 1988. Reviewing the Data tab of the view's Item Details, you see that you can filter by a column year_:

tbl

When you set a View Definition, that definition is defined at the service level. If you quickly set a test definition in the ArcGIS Online/Portal for ArcGIS user interface and take a look at the view service's Service Definition, you'll see the property that needs to be updated is viewDefinitionQuery:

Click on 'View' in the View's Item Details page

servurl

Next, click on the Layer:

layerrest

Click on 'JSON'

jsonrest

Scroll all the way to the bottom to see the 'viewDefinitionQuery' property:

defrest
Note: changing the value of viewDefinitionQuery also updates the related definitionQuery property

To update the viewDefinitionQuery property with the ArcGIS API for Python, you do the following:

# Search for newly created View
view_search = gis.content.search("worldEQView")[0]
view_flc = FeatureLayerCollection.fromitem(view_search)

# The viewDefinitionQuery property appears under layers
view_layer = view_flc.layers[0]

# Define a SQL query to filter out events past 1988
view_def = {"viewDefinitionQuery" : "year_ < 1988"}

# Update the definition to include the view definition query
view_layer.manager.update_definition(view_def)‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

You should be able to see this update reflected after refreshing the view Item Details page > Visualization

def

Altogether, the script to create a View from the Hosted Feature Layer and then to set a View Definition is:

from arcgis import GIS
from arcgis.features import FeatureLayerCollection
gis = GIS("https://www.arcgis.com", "username","password")

# Search for Source Hosted Feature Layer
source_search = gis.content.search("world_earthquakes")[0]
source_flc = FeatureLayerCollection.fromitem(source_search)

# Create View from Source Hosted Feature Layer
new_view = source_flc.manager.create_view(name="worldEQView")

# Search for newly created View
view_search = gis.content.search("worldEQView")[0]
view_flc = FeatureLayerCollection.fromitem(view_search)

# The viewDefinitionQuery property appears under layers
view_layer = view_flc.layers[0]

# Define a SQL query to filter out events past 1988
view_def = {"viewDefinitionQuery" : "year_ < 1988"}

# Update the definition to include the view definition query
view_layer.manager.update_definition(view_def)‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

This can be generalized into a standalone script like this one:

import sys
from arcgis import GIS
from arcgis.features import FeatureLayerCollection

def search_layer(conn,layer_name):
search_results = conn.content.search(layer_name, item_type="Feature Layer")
proper_index = [i for i, s in enumerate(search_results)
if '"' + layer_name + '"' in str(s)]
found_item = search_results[proper_index[0]]
flc = FeatureLayerCollection.fromitem(found_item)
return flc

def create_view(conn, source_flc, view_name, layer_index, view_def):
new_view = source_flc.manager.create_view(name=view_name)
# Search for newly created View
view_flc = search_layer(conn, view_name)
# The viewDefinitionQuery property appears under layers
view_layer = view_flc.layers[layer_index]
# Update the definition to include the view definition query
view_layer.manager.update_definition(view_def)
print("View created")

def main():
conn = GIS("https://www.arcgis.com",
"username", "password")
# Index of the Layer to be filtered
layer_index = 0
# Define a SQL query to filter out events past 1988
view_def = {"viewDefinitionQuery" : "year_ < 1988"}
# Search for target Hosted Feature Layer
source_flc = search_layer(conn, "world_earthquakes")
# Create View from Hosted Feature Layer
create_view(conn, source_flc, "worldEQView", layer_index, view_def)

if __name__ == '__main__':
sys.exit(main())‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

If you need to define an area of interest, this would be approached like so:

view_def = {"viewLayerDefinition":{"filter":   
{"operator":"esriSpatialRelIntersects","value":
{"geometryType":"esriGeometryEnvelope","geometry":
{"xmin":4485937.7074932605,"ymin":1543545.165101517,
"xmax":9417043.276225261,"ymax":6239836.182941515,
"spatialReference":{"wkid":102100,"latestWkid":3857}}}}}}
view_layer.manager.update_definition(update_dict)
14 Comments
RichardLi3
New Contributor II

Thanks  Earl Medina.

BTW, does the last step ( refreshing the view Item Details page > Visualization) has to be done manually? API should be able to do it. What is it?

EarlMedina1
Occasional Contributor III

Hey Richard,

You don't really have to do that step.  It's just included for illustrative purposes.

-Earl

RichardLi3
New Contributor II

Thanks Earl.

New to API, here is another question:

What if I want to update the view's Filter in Item Detail > Visualization >Filter as the same definitionQuery? Does API update_definition support doing so?

Thanks,

Richard 


EarlMedina1
Occasional Contributor III

Hi Richard,

I'm afraid I don't quite understand your question. Can you explain further?

RichardLi3
New Contributor II

Hi Earl,

I'm trying to use API to create featurelayer views for each city based on a province feature layer, for example set the view's "viewDefinitionQuery" as " AOIname = 'Toronto' " using following code. 

# Define a SQL query to filter

update_dict = {"viewDefinitionQuery" : "AOIname = 'Toronto'"}
# Update the definition to include the view definition query
service_layer.manager.update_definition(update_dict)
Ideally, the new_created view should have a spatial extent as the city's boundary. However, After running above code, if you check the item detail > Visualization > Filter (as in following picture), you will found that the Filter in Visualization is empty. To make viewer extent zoom to city's boundary, you have to MANUALLY create a same definition query like AOIname = 'Toronto' , then click "Apply Filter and ZoomTo" .

I just want to know, does API support to set this spatial extent "Filter" definition query?  It is a similar function like "Recalculate Feature Class Extent" tool in ArcGIS Pro.
 
Thanks,
Richard
EarlMedina1
Occasional Contributor III

Hi Richard,

I'm pretty sure what you're asking about is described in Egge-Jan Pollé‌ 's post here: https://community.esri.com/people/EPolle_TensingInternational/blog/2019/03/27/create-view-from-hoste...

For a more general explanation of how to accomplish this see this post: https://community.esri.com/thread/230204-arcgis-api-for-python-set-an-area-of-interest-on-a-hosted-f...

Kind regards,

Earl

RichardLi3
New Contributor II

Thanks Earl. 

Egge-JanPollé1
MVP Regular Contributor

Hi Richard,

Yes, Earl Medina‌ is right: I had exactly the same challenge as you have. I had the geometry of - in my case 12 - provinces and I wanted to create 12 views using the provincial boundaries as 'Area of Interest'.

Please let us know whether you managed to create the views for Toronto and the other cities using the script in my blog: 

https://community.esri.com/people/EPolle_TensingInternational/blog/2019/03/27/create-view-from-hoste... 

Cheers,

Egge-Jan

RichardLi3
New Contributor II

Read your article then, it works for my case.

Thanks Egge-Jan.

Richard

Egge-JanPollé1
MVP Regular Contributor

You might consider to 'like' the blog post 🙂

RaúlJiménez_Ortega
Esri Contributor

Thanks Earl Medina for this awesome post .

I'm trying to accomplish what you have explained here but directly through the REST API, I posted a question last Thursday (Join Features and save result as Layer view through the REST API) but I didn't get any response yet ;(.

Could you help me with it? Or would it be better to talk to someone from Shannon Kalisky‌'s team?

Best regards!,

Raul

Hung_ChunWang
New Contributor

Hi, Earl Medina

Thanks for sharing the info. 

Just wondering do you happen to know what would be the way if l would like to overwrite layers via Python for those that have view layer created.

I have developed the code that can successfully overwrite layers without view layer and trying to figure out how to solve the issue mentioned above.

Thanks

Careinvest
New Contributor

Thanks, can you please advise how to use the Python API to create a view from a "Table (hosted, view)"?

I want to create a view like you do but the type property of my source is 'Feature Service' (it shows as Table (hosted, view) in the portal) and I get a KeyError: 'spatialReference'. 

I have therefore changed the code to 

from arcgis.features import Table

#and

source_table = Table.fromitem(source)

#and

view = source_table.manager.create_view(name='Test_view')

However, this returns 

AttributeError: 'FeatureLayerManager' object has no attribute 'create_view'

Can you please advise how to use the Python API to create a view from a "Table (hosted, view)"?

MehdiPira1
Esri Contributor

Nice one @EarlMedina1 !