Closed GeeFernando closed 10 months ago
ReadMe.pdf I just found this article (page 24) which mentions some methods around swapping layers. But these methods aren't documented in the API reference - https://developers.arcgis.com/python/api-reference/
You need to do a delete_from_definition
, then add_to_definition
to add the new source dataset.
from __future__ import annotations
from arcgis.gis import GIS, Item
from arcgis.features import FeatureLayer, FeatureLayerCollection, Table
import concurrent.futures
def swap_view(
view: FeatureLayerCollection,
index: int,
new_source: FeatureLayer | Table,
future: bool = False,
) -> dict | concurrent.futures.Future:
"""
Swaps the Data Source Layer with a different parent layer.
================== ====================================================================
**Parameter** **Description**
------------------ --------------------------------------------------------------------
view Required FeatureLayerCollection. The view feature layer collection
to update.
------------------ --------------------------------------------------------------------
index Required int. The index of the layer on the view to replace.
------------------ --------------------------------------------------------------------
new_source Requred FeatureLayer or Table. The layer to replace the existing
source with.
------------------ --------------------------------------------------------------------
future Optional Bool. When True, a Future object will be returned else a
JSON object.
================== ====================================================================
"""
keys: list[str] = [
'currentVersion',
'id',
'name',
'type',
'displayField',
'description',
'copyrightText',
'defaultVisibility',
'editingInfo',
'isDataVersioned',
'hasContingentValuesDefinition',
'supportsAppend',
'supportsCalculate',
'supportsASyncCalculate',
'supportsTruncate',
'supportsAttachmentsByUploadId',
'supportsAttachmentsResizing',
'supportsRollbackOnFailureParameter',
'supportsStatistics',
'supportsExceedsLimitStatistics',
'supportsAdvancedQueries',
'supportsValidateSql',
'supportsCoordinatesQuantization',
'supportsLayerOverrides',
'supportsTilesAndBasicQueriesMode',
'supportsFieldDescriptionProperty',
'supportsQuantizationEditMode',
'supportsApplyEditsWithGlobalIds',
'supportsMultiScaleGeometry',
'supportsReturningQueryGeometry',
'hasGeometryProperties',
'geometryProperties',
'advancedQueryCapabilities',
'advancedQueryAnalyticCapabilities',
'advancedEditingCapabilities',
'infoInEstimates',
'useStandardizedQueries',
'geometryType',
'minScale',
'maxScale',
'extent',
'drawingInfo',
'allowGeometryUpdates',
'hasAttachments',
'htmlPopupType',
'hasMetadata',
'hasM',
'hasZ',
'objectIdField',
'uniqueIdField',
'globalIdField',
'typeIdField',
'dateFieldsTimeReference',
'preferredTimeReference',
'types',
'templates',
'supportedQueryFormats',
'supportedAppendFormats',
'supportedExportFormats',
'supportedSpatialRelationships',
'supportedContingentValuesFormats',
'supportedSyncDataOptions',
'hasStaticData',
'maxRecordCount',
'standardMaxRecordCount',
'standardMaxRecordCountNoGeometry',
'tileMaxRecordCount',
'maxRecordCountFactor',
'capabilities',
'url',
'adminLayerInfo',
]
if isinstance(new_source, FeatureLayer):
flc_lyr_info: FeatureLayer = view.layers[index]
elif isinstance(new_source, Table):
flc_lyr_info: Table = view.tables[index]
props: dict = {
key: new_source.properties[key]
for key in keys
if key in new_source.properties
}
if new_source._con.token:
props['url'] = new_source.url + f"?token={new_source._con.token}"
else:
props['url'] = new_source.url
if (
"viewLayerDefinition"
in flc_lyr_info.manager.properties['adminLayerInfo']
):
props['adminLayerInfo'] = {}
props['adminLayerInfo'][
'viewLayerDefinition'
] = flc_lyr_info.manager.properties['adminLayerInfo'][
'viewLayerDefinition'
]
props['adminLayerInfo']['viewLayerDefinition'][
'sourceServiceName'
] = new_source.manager.properties['name']
props['adminLayerInfo']['viewLayerDefinition'].pop("sourceId", None)
if isinstance(new_source, FeatureLayer):
delete_json: dict = {"layers": [{"id": index}], "tables": []}
add_json: dict = {"layers": [props]}
elif isinstance(new_source, Table):
delete_json: dict = {"layers": [], "tables": [{"id": index}]}
add_json: dict = {"tables": [props]}
view.manager.delete_from_definition(delete_json)
if future:
return view.manager.add_to_definition(add_json, future=True)
else:
return view.manager.add_to_definition(add_json, future=False)
gis = GIS(
profile='your_online_profile'
)
# Get the Item View
#
source_item: Item = gis.content.get("ITEM ID")
# Obtain the FeatureLayerCollection from the Item (from the view Item)
#
source_view: FeatureLayerCollection = FeatureLayerCollection.fromitem(
source_item
)
# Get the Replace Item
#
replace_item: Item = gis.content.get("ITEM ID")
# Get the FeatureLayer/Table to update
#
replace_layer: FeatureLayer = FeatureLayer.fromitem(replace_item)
# Swap the View to the New Source (replace_layer object)
#
swap_view(view=source_view, new_source=replace_layer, index=0)
Thanks so much for this @achapkowski 🤩
Has anyone figured out how to make this work when the new source FLC and the target view have multiple layers?
Swap the source of a hosted layer view using the ArcGIS API for Python Do you know whether it is possible to swap the source of a hosted layer view using the ArcGIS API for Python? This can be done using AGOL - https://www.esri.com/arcgis-blog/products/arcgis-online/data-management/swapping-layers-a-great-way-to-build-and-maintain-your-feature-layer/. But I was wondering if the same could be done using the ArcGIS API for Python.
Additional context Currently, I have a Python script that appends around 250,000 features to an ArcGIS Online feature layer. This script runs every day, but the append process can take anywhere from a couple of seconds to 10 minutes. However, during the appending process, the dashboard becomes unusable. If I could perform a layer swap, it would solve my issue 🤗 I'm just wondering whether you could achieve this using the ArcGIS API for Python 🤔