Filter layer inside webmap

1125
9
Jump to solution
09-03-2018 06:53 AM
Highlighted
New Contributor II

Hi all,

Is there a posibility to filter an operational layer inside a webmap (similar to what definition query does in ArcMap) and after to save the webmap with the new updates?

I`m at the step where I iterate through my layers from my map but I cannot find the solution to apply a filter/definition query to them.

Thanks,

Ionut

Reply
0 Kudos
1 Solution

Accepted Solutions
Highlighted
Esri Contributor

Thanks for looking at that a bit more, The code I had on there was for applying the filter to the featurelayer.

Below is another code block for how you can access a web map isolate a layer in a webmap and change the filter.

To test the code below:

  1. create a basic webmap in your organization titled TimeZoneRegions
  2. Add the following featurelayer to the map  Layer: World Regions (ID: 2) 
  3. Save the map

The one Dependency of the code below is the WorldTimeZones - World Regions operational layer in the webmap needs to have a filter set already.

There is a block of code below that will check to see if a Layerdefinition exists on the operational layer before it gets applied:

if 'layerDefinition' in tZoneLyr:

Code:

from arcgis.gis import GIS
import copy
from json import dumps
from json import JSONDecoder
from arcgis.mapping import WebMap


#Connect to the Organization
gis = GIS("https://www.arcgis.com", "<UserName>", "<passW>")


#Search for the webmap
webmapPub = gis.content.search("title:TimeZoneRegions",item_type = "Web Map")


#Use a list comprehension to find the right one you are updating
timeZoneWebMap = [wmap for wmap in webmapPub if wmap.title == 'TimeZoneRegions'][0]


#Get the webmap json
pubMapJson = timeZoneWebMap.get_data(try_json=True)


# Filter Expression to apply to layer
lyrFilter = "REGION = '{0}'".format("Antarctica")


#Make a deepcopy of the json to modify
fldMapJsonCopy = copy.deepcopy(pubMapJson)


#List comprehension to find the one layer you need to modify by title
#Here you could loop on all layers to modify the filter too.
lyrT = [l for l in pubMapJson['operationalLayers'] if l['title']== 'WorldTimeZones - World Regions']



if len(lyrT) >0:
    tZoneLyr = lyrT[0]
    if 'layerDefinition' in tZoneLyr:
       z = [[x, y] for x, y in enumerate(pubMapJson['operationalLayers']) if y['title'] == 'WorldTimeZones - World Regions'][0]
       fldMapJsonCopy['operationalLayers'][z[0]]['layerDefinition']['definitionExpression'] = lyrFilter



#Save the changes to the Webmap
timeZoneWebMap.update(item_properties={'text':dumps(fldMapJsonCopy)})

View solution in original post

9 Replies
Highlighted
Esri Contributor

Hi Ionut,

Take a look at the following post, the question is similar, although it was in regards to a single layer.

https://community.esri.com/thread/206220-how-to-add-a-filter-to-an-arcgis-online-item-using-the-pyth... 

Thanks, 

Jeff

Highlighted
New Contributor II

Hi Jeff,

Thanks for the quick feedback! 

I tried the solution you provided but for some reason, the get_data() method returns None..

I`d also like to point out that in the solution you provided, the item is obtained by searching the content and retrieving the Feature Layer; in my case, I have an operational layer in a web map; not sure if it`s the same thing.

As I can see, the sql expression is mounted on definitionExpression on the object, but in my case I cannot find this property on the layer object from my webmap.

Thanks,

Ionut

Reply
0 Kudos
Highlighted
New Contributor II

UPDATE:

You were right, I`ve used your solution to get a workflow.

I`ve managed to iterate through layers in the webmap, and for each one, I`ve replace it with the same, just that I applied the definitionExpression on it; something like this:

for layer in webMapLayers:
   layerTitle = layer.title

   srcResults = adminGIS.content.search(layerTitle)
   featCollection = srcResults[0]

   sql = "sql filter"

   webMapItem.remove_layer(layer)
   webMapItem.add_layer(featCollection)
   webMapItem.layers[0]['layerDefinition']['definitionExpression'] = sql

   webMapItem.update()

Thanks again,

Ionut

Reply
0 Kudos
Highlighted
Esri Contributor

Thanks for looking at that a bit more, The code I had on there was for applying the filter to the featurelayer.

Below is another code block for how you can access a web map isolate a layer in a webmap and change the filter.

To test the code below:

  1. create a basic webmap in your organization titled TimeZoneRegions
  2. Add the following featurelayer to the map  Layer: World Regions (ID: 2) 
  3. Save the map

The one Dependency of the code below is the WorldTimeZones - World Regions operational layer in the webmap needs to have a filter set already.

There is a block of code below that will check to see if a Layerdefinition exists on the operational layer before it gets applied:

if 'layerDefinition' in tZoneLyr:

Code:

from arcgis.gis import GIS
import copy
from json import dumps
from json import JSONDecoder
from arcgis.mapping import WebMap


#Connect to the Organization
gis = GIS("https://www.arcgis.com", "<UserName>", "<passW>")


#Search for the webmap
webmapPub = gis.content.search("title:TimeZoneRegions",item_type = "Web Map")


#Use a list comprehension to find the right one you are updating
timeZoneWebMap = [wmap for wmap in webmapPub if wmap.title == 'TimeZoneRegions'][0]


#Get the webmap json
pubMapJson = timeZoneWebMap.get_data(try_json=True)


# Filter Expression to apply to layer
lyrFilter = "REGION = '{0}'".format("Antarctica")


#Make a deepcopy of the json to modify
fldMapJsonCopy = copy.deepcopy(pubMapJson)


#List comprehension to find the one layer you need to modify by title
#Here you could loop on all layers to modify the filter too.
lyrT = [l for l in pubMapJson['operationalLayers'] if l['title']== 'WorldTimeZones - World Regions']



if len(lyrT) >0:
    tZoneLyr = lyrT[0]
    if 'layerDefinition' in tZoneLyr:
       z = [[x, y] for x, y in enumerate(pubMapJson['operationalLayers']) if y['title'] == 'WorldTimeZones - World Regions'][0]
       fldMapJsonCopy['operationalLayers'][z[0]]['layerDefinition']['definitionExpression'] = lyrFilter



#Save the changes to the Webmap
timeZoneWebMap.update(item_properties={'text':dumps(fldMapJsonCopy)})

View solution in original post

Highlighted
New Contributor II

Hi Jeff,

That`s sweet! Thanks a lot!

Although, what if get_data() method on my layer returns None?

Because that`s what happened to me and I had replace the original layer with itself but with a filter applied...

Again, thanks a lot for your feedback!

Best,

Ionut

Reply
0 Kudos
Highlighted
New Contributor II

EDIT: Just needed to use the data correctly.

SOLUTION : webMapItem.layers[len(webMapItem.layers) - 1]['layerDefinition']['drawingInfo'] = json.loads(str(simbol)) 

where simbol is actualy the json data for symbology for the layer.

Hi Jeff,

In the same way 'definitionExpression' is set above, I`m trying to do with 'drawingInfo' property on the layer, but when I`m setting the info, I`m getting "Object of type 'PropertyMap' is not JSON serializable".

Basically, I`m iterating every layer in the webmap, remove each one, and after add it again, set the 'layerDefinition''definitionExpression' to filter the data and after I`m trying to also set the intial symbol, but somehow it`s not working...

Any idea??

Thanks,

Ionut

Highlighted
Regular Contributor

Jeff Bigos

I'm looking to implement something nearly identical to this: modifying a filter to a feature layer within a web map and saving a new copy. I'm struggling to find what arguments (proper documentation) are expected for

fldMapJsonCopy['operationalLayers'][z[0]]['layerDefinition']['definitionExpression'] = lyrFilter

I've looked at your other example here and have tried to piece things together but I'm not having any luck. I don't fully understand what the enumeration process here is and don't think i need it.

from arcgis.gis import GIS
from arcgis.mapping import WebMap
import json, copy
gis = GIS("https://my/portal", "UseMe", "L1f3izGr@nd!")

webMapSearch = gis.content.search("title: NortheastFieldData2",item_type = "Web Map")
pubMapJson = webMapTest.get_data(try_json=True)
layerMod = [l for l in pubMapJson['operationalLayers'] if l ['title']=='NortheastCruisePoints']
lyrFilter = "LVI_CODE = '{0}'".format("7532")
fieldMapCopy = copy.deepcopy(pubMapJson)
fieldMapCopy['operationalLayers'][layerMod]['layerDefinition']['definitionExpression']=lyrFilter

Error:

---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-37-aec78b329a7c> in <module>
----> 1 fieldMapCopy['operationalLayers'][layerMod]['layerDefinition']['definitionExpression'] = lyrFilter

TypeError: list indices must be integers or slices, not list
Reply
0 Kudos
Highlighted
Occasional Contributor

I am late in replying, but the error is indicating the data you have is a list not a dictionary.  Check out if what you are getting is what you are expecting. 

I also notice that the index 'layerMod' of the 'operationalLayers' variable seems to be erroneous.

Highlighted
Regular Contributor

I just can't find any reliable documentation about this. I have had a ticket open with tech support that's older than a month now.

Reply
0 Kudos