-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcreate_new_webmap.py
More file actions
398 lines (313 loc) · 13.2 KB
/
create_new_webmap.py
File metadata and controls
398 lines (313 loc) · 13.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
"""
Module for creating new web maps, adding feature layers to them,
and creating popups for desired map layers
"""
# import modules
from arcgis.gis import GIS
from arcgis.mapping import WebMap
# create connection to ArcGIS Enterprise/Portal
PORTAL_CONNECTION = GIS("portal_url", "username", "password")
def create_new_webmap(project_name, layer_names, *args):
"""
creates a web map, adds feature layers to web map,
and defines properties for layers and the web map
Args:
project_name (str): name of project
layer_names (list): list of layer names to be added to web map
Raises:
TypeError: if project name is not type of string
TypeError: if layer names is not type of list
TypeError: if layer name is not type of string
"""
if not isinstance(project_name, str):
raise TypeError('expected project name to be type of str')
if not isinstance(layer_names, list):
raise TypeError('expected layer names to be type of list')
for layer_name in layer_names:
if not isinstance(layer_name, str):
raise TypeError('expected layer name to be type of str')
# get feature layers collection and update its properties
feature_layers = get_feature_layers_collection(project_name)
feature_layers_properties = get_properties_from_project(
project_name=project_name,
content_type='Feature Layer',
project_additional_info=list(args)
)
feature_layers.update(item_properties=feature_layers_properties)
protect_share_item(feature_layers)
# create a new web map
new_web_map = WebMap()
print('creating a new web map')
# add feature layers to the web map
for feature_layer in feature_layers.layers:
new_web_map.add_layer(layer=feature_layer)
print('adding', feature_layers.title, 'to web map')
# define properties for the web map
web_map_properties = get_properties_from_project(
project_name=project_name,
content_type='WebMap',
project_additional_info=list(args)
)
# create popups for map layers
create_popups(
web_map=new_web_map,
project_name=project_name,
layer_names=layer_names
)
# save the web map
new_web_map.save(item_properties=web_map_properties)
print('saving web map in portal')
def get_portal_item(portal_connection, item_name, item_type):
"""
gets portal items, including feature layers collections,
map image layers, and vector tile packages
in ArcGIS Enterprise/Portal
Args:
portal_connection
item_name (str): name of an item
item_type (str): type of an item
Returns:
portal_item (arcgis.gis.Item): any item of feature, map image, and tile layer
Raises:
KeyError: if the specified search item is not found
KeyError: if the specified portal item is not found
"""
search_item = portal_connection.content.search(
query='title:{} AND owner:{}'.format(item_name, portal_connection.users.me.username),
item_type=item_type
)
if not search_item:
raise KeyError('unable to find {}'.format(item_name))
item = search_item[0]
item_id = item.id
portal_item = portal_connection.content.get(item_id)
if not portal_item:
raise KeyError("unable to find an item with id of '{}'".format(item_id))
return portal_item
def get_feature_layers_collection(project_name):
"""
gets feature layers collection of a project
in ArcGIS Enterprise/Portal
Args:
project_name (str): project name
Returns:
feature_layer_collection or feature service (arcgis.gis.Item)
"""
feature_layers_collection = get_portal_item(
portal_connection=PORTAL_CONNECTION,
item_name="{}_Map".format(project_name),
item_type="Feature Layer"
)
return feature_layers_collection
def get_properties_from_project(project_name, content_type, project_additional_info):
"""
gets properties of a project
and applies them for portal contents
Args:
project_name (str): name of project
content_type (str): type of portal item
project_additional_info (list): list of additional information of a project
"""
title_not_used = {'title'}
item_title = "{}_{}".format(project_name, content_type)
access_information = "Data Center"
license_info = 'All rights reserved.'
item_tags = [project_name] + project_additional_info
item_snippet = ('This is a {} of {} project.').format(content_type, project_name)
font_properties = '''<font color='#8b0000' size='4'><font style='font-family: inherit;'>'''
item_description = (
'This is a {} of {} project.').format(content_type, project_name)
properties = {
"title": item_title,
"snippet": item_snippet,
"description": font_properties + item_description,
"tags": item_tags,
"accessInformation": access_information,
"licenseInfo": font_properties + license_info
}
if content_type != 'WebMap':
item_properties = {key: properties[key] for key in properties if key not in title_not_used}
else:
item_properties = properties
return item_properties
def protect_share_item(portal_item):
"""
uses Python API methods to protect a portal item
from deletion and shares it in organization
Args:
portal_item (arcgis.gis.item)
"""
# protect portal item from deletion
portal_item.protect(enable=True)
print('protecting portal item of', portal_item.title, 'from deletion')
# share portal item in the organization
portal_item.share('org')
print('sharing', portal_item.title, 'in organization')
def create_popups(web_map, project_name, layer_names):
"""
creates popups for web map operational layers
Args:
web_map (arcgis.gis.Item)
project_name (str): name of project
layer_names (list): list of layer names to have popups
"""
if layer_names:
for layer_name in layer_names:
# popup
feature_layer_popup(
map_service_name='{}_{}'.format(project_name, 'Map'),
map_service_type='Feature Layer',
web_map=web_map,
layer_name=layer_name
)
else:
print('No popup was defined for layers')
def feature_layer_popup(map_service_name, map_service_type, web_map, layer_name):
"""
includes all steps to create and customize
popups for both registered and hosted feature layers in a web map
Args:
map_service_name (str): name of feature layers on the portal
map_service_type (str): type of feature layers on the portal
web_map (ArcGIS item): created web map
layer_name (str): name of each layer in a service
"""
# get operational layer of a web map
operational_layer = get_webmap_operational_layers(
web_map=web_map,
layer_name=layer_name
)
# get feature layer from feature layer collection
target_layer = get_feature_layer_from_feature_service(
map_service_name=map_service_name,
map_service_type=map_service_type,
layer_name=layer_name
)
# set popup info for the operational layer based on the type of services
# hosted feature layer
if operational_layer['popupInfo']:
operational_layer_popup = operational_layer['popupInfo']
# registered feature layer
else:
# set popup info
operational_layer.update(popupInfo=target_layer['popupInfo'])
operational_layer_popup = operational_layer['popupInfo']
# set title for popup
operational_layer_popup['title'] = layer_name
# set description for popup
layer_popup_description = customize_popup_description(
operational_layer=operational_layer,
map_service_type=map_service_type
)
operational_layer_popup['description'] = layer_popup_description
# set decimal places and digit separators for numeric fields
for field in operational_layer_popup['fieldInfos']:
for fld in target_layer.properties.fields:
# double
if field['fieldName'] == fld.name and fld.type == "esriFieldTypeDouble":
field.update({"format": {"places": 2, "digitSeparator": False}})
# integer
elif field['fieldName'] == fld.name and fld.type == "esriFieldTypeInteger":
field.update({"format": {"places": 0, "digitSeparator": False}})
print('customizing popup for', operational_layer['title'])
def customize_popup_description(operational_layer, map_service_type):
"""
creates description for popups of layers by using
an HTML format for font and fields information
Args:
operational_layer (dict): operational layer in a web map
map_service_type (str): type of map service
Returns:
layer_popup_description (str): customized description for popup
"""
layer_popup_description = '''<font color='#dc143c' face='Arial' size='2'>'''
if map_service_type == 'Feature Layer':
operational_layer_popup = operational_layer['popupInfo']
for field in operational_layer_popup['fieldInfos']:
# registered feature layers
if any(letter.isupper() for letter in field['fieldName']) \
and not field['fieldName'] in NO_POPUP_FIELDS:
field_name = split_uppercase(field['fieldName'])
field_popup = '<b> %s :</b> {%s} <br /><br />' % (field_name, field['fieldName'])
layer_popup_description += field_popup
# hosted feature layers
elif any(letter.isupper() for letter in field['label']) \
and not field['label'] in NO_POPUP_FIELDS:
label = split_uppercase(field['label'])
field_popup = '<b> %s :</b> {%s} <br /><br />' % (label, field['label'])
layer_popup_description += field_popup
print('customizing popup description for', operational_layer['title'])
return layer_popup_description
def get_feature_layer_from_feature_service(map_service_name, map_service_type, layer_name):
"""
gets a feature layer in feature layer collection
Args:
map_service_name (str): name of feature layers on the portal
map_service_type (str): type of feature layers on the portal
layer_name (str): name of each layer in a service
"""
# access a feature service and gets its data
feature_layers = get_portal_item(
portal_connection=PORTAL_CONNECTION,
item_name=map_service_name,
item_type=map_service_type
)
feature_layer_data = feature_layers.get_data()
# get index of a feature layer
layer_index = get_feature_layer_index(feature_layers, layer_name)
if not feature_layer_data:
# get target layer in hosted feature service
target_layer = feature_layers.layers[layer_index]
else:
# get target layer in registered feature service
target_layer = feature_layer_data['layers'][layer_index]
return target_layer
def get_feature_layer_index(feature_layer_collection, layer_name):
"""
gets index of layers in a feature layer collection
Args:
feature_layer_collection (arcgis.gis.item): published feature layers
layer_name (str): name of desired layer
Returns:
layer_index (int): index of a layer in a feature layer collection
"""
for index, url in zip(range(len(feature_layer_collection.layers)),
feature_layer_collection.layers):
if layer_name in feature_layer_collection.layers[index].properties.name:
layer_index = index
print('index of feature layer',
feature_layer_collection.layers[layer_index].properties.name, 'with url of',
url, 'is', layer_index)
return layer_index
def get_webmap_operational_layers(web_map, layer_name):
"""
gets operational layers of a web map
Args:
web map (arcgis item)
layer_name (str): name of a layer
Returns:
operational_layer (dict): operational layer of web map, map property
"""
web_map_definition = web_map.definition
for layer in web_map_definition['operationalLayers']:
if layer_name in layer['title']:
operational_layer = layer
return operational_layer
def split_uppercase(word):
"""
splits strings that have uppercase
Args:
word (str): a word to be splitted
"""
final_word = ''
for i in word:
final_word += ' %s' % i if i.isupper() else i
return final_word.strip()
# list of fields that are not shown in popups of layers
NO_POPUP_FIELDS = [
'OBJECTID', 'ORIG_FID', 'ORIG_FID_1', 'Shape.STArea()',
'Shape.STLength()', 'Shape__Area', 'Shape__lenght', 'Shape'
]
if __name__ == "__main__":
create_new_webmap("project_name", ['layer_one', 'layer_two'])
print('End!')