I am currently trying to edit a preset layout on ArcGIS Pro
The layout currently consists of a Legend, a Title and a Map.
I would like to create a Python Script, to export this layout individually for each layer to PNG.
For each export,
I would have already snapped a particular region of the map I require so no need for any changes.
The Legend - it will reflect the new layer being selected
The Title - it will have the name of the new layer
Thank you!
Solved! Go to Solution.
I am not sure why I am unable to see such granularity in terms of properties under Legend
Hmm, no idea, but you can also do it with Python (see line 22).
I would also like to know how I can specify which layers I would like to export, instead of all the layers on the map.
listLayers() has an optional string argument which lets you search for layer name patterns. You could mabe rig something up with listLayers("*Stats"), but the far easier and more expandable way is to add a second step that only keeps the layers with the names you specify. See lines 32 and 39.
from pathlib import Path
def export_layout_for_each_layer(layer_list, layout, save_folder):
save_folder = Path(save_folder)
# turn all layers off
for layer in layer_list:
layer.visible = False
# while there are still layers in the list
while layer_list:
# remove the first layer from the list and make it visible
layer = layer_list.pop(0)
layer.visible = True
# special treatment for group layers
if layer.isGroupLayer:
# recursively call this function on its sub layers (this exports all the sub layers on their own
export_layout_for_each_layer(layer.listLayers(), layout, save_folder)
# make the sub layers visible (so we can export the group layer) and remove the sub layers from the master layer list (because we already exported them)
for sub_layer in layer.listLayers():
layer_list.remove(sub_layer)
sub_layer.visible = True
# make sure the legend only shows active layers
layout.listElements("LEGEND_ELEMENT")[0].syncLayerVisibility = True
# set title and export, then make layer invisible
print(f"Exporting layout for {layer.name}")
layout.listElements("TEXT_ELEMENT")[0].text = layer.name
layout.exportToPDF(save_folder/f"{layer.name}.pdf")
layer.visible = False
# define your save location and export layerrs
save_folder = Path(arcpy.env.workspace).parent
export_layer_names = ["Money Stats" , "House Stats", "Car Stats", "Travel Stats"]
# get the elements you need
aprx = arcpy.mp.ArcGISProject("current")
layout = aprx.listLayouts("Layout")[0]
map_frame = layout.listElements('MAPFRAME_ELEMENT')[0]
all_layers = map_frame.map.listLayers()
export_layers = [layer for layer in all_layers if layer.name in export_layer_names]
# run it
export_layout_for_each_layer(export_layers, layout, save_folder)
from pathlib import Path
# define your save location
save_folder = Path(arcpy.env.workspace).parent # 'C:/Users/xxx/Documents/ArcGIS/Projects/Testing'
# get the elements you need
aprx = arcpy.mp.ArcGISProject("current")
layout = aprx.listLayouts("Layout")[0]
title = layout.listElements("TEXT_ELEMENT")[0]
map_frame = layout.listElements('MAPFRAME_ELEMENT')[0]
layers = map_frame.map.listLayers()
# turn off all layers
for layer in layers:
layer.visible = False
# loop over layers
save_folder = Path(save_folder)
for layer in layers:
print(f"Exporting layout for {layer.name}")
layer.visible = True
title.text = layer.name
layout.exportToPDF(save_folder/f"{layer.name}.pdf")
layer.visible = False
This assumes that you only have one text element (the title) and no group layers.
This also handles group layers, even nested ones:
from pathlib import Path
def export_layout_for_each_layer(layer_list, layout, save_folder):
save_folder = Path(save_folder)
# turn all layers off
for layer in layer_list:
layer.visible = False
# while there are still layers in the list
while layer_list:
# remove the first layer from the list and make it visible
layer = layer_list.pop(0)
layer.visible = True
# special treatment for group layers
if layer.isGroupLayer:
# recursively call this function on its sub layers (this exports all the sub layers on their own
export_layout_for_each_layer(layer.listLayers(), layout, save_folder)
# make the sub layers visible (so we can export the group layer) and remove the sub layers from the master layer list (because we already exported them)
for sub_layer in layer.listLayers():
layer_list.remove(sub_layer)
sub_layer.visible = True
# set title and export, then make layer invisible
print(f"Exporting layout for {layer.name}")
layout.listElements("TEXT_ELEMENT")[0].text = layer.name
layout.exportToPDF(save_folder/f"{layer.name}.pdf")
layer.visible = False
# define your save location
save_folder = Path(arcpy.env.workspace).parent
# get the elements you need
aprx = arcpy.mp.ArcGISProject("current")
layout = aprx.listLayouts("Layout")[0]
map_frame = layout.listElements('MAPFRAME_ELEMENT')[0]
layers = map_frame.map.listLayers()
# run it
export_layout_for_each_layer(layers, layout, save_folder)
Wow, Thanks Johannes! 🙂
This is getting closer to what I would like. I also have a legend in the layout I would like to change according to the layer as well. How will I be able to do this?
Do you have a link to this documentation for editing and exporting layouts specifically as well?
Thank you for your assistance on this!
I also have a legend in the layout I would like to change according to the layer as well. How will I be able to do this?
Make sure that your legend synchronizes with visible layers:
Do you have a link to this documentation for editing and exporting layouts specifically as well?
You can manipulate layouts with the arcpy.mp (mapping) module: Introduction to arcpy.mp—ArcGIS Pro | Documentation
In the link's table of contents, expand the "Classes" tab to see the documentation for all classes of that module. Here, I used Layout, MapFrame, Map, Layer, and TextElement.
Hi Johannes,
Thank you for helping me with this. I am not sure why I am unable to see such granularity in terms of properties under Legend. It stops at the General Tab and does not have the "Synchronize with map" option.
I would also like to know how I can specify which layers I would like to export, instead of all the layers on the map. I created a list and passed it through the map_frame.map.listlayers() but it does not seem to work.
For example, I have 4 group layers ["Money Stats" , "House Stats", "Car Stats", "Travel Stats"], and I only want to iterate through the layers under these group layers and export.
Cheers
sahus
I am not sure why I am unable to see such granularity in terms of properties under Legend
Hmm, no idea, but you can also do it with Python (see line 22).
I would also like to know how I can specify which layers I would like to export, instead of all the layers on the map.
listLayers() has an optional string argument which lets you search for layer name patterns. You could mabe rig something up with listLayers("*Stats"), but the far easier and more expandable way is to add a second step that only keeps the layers with the names you specify. See lines 32 and 39.
from pathlib import Path
def export_layout_for_each_layer(layer_list, layout, save_folder):
save_folder = Path(save_folder)
# turn all layers off
for layer in layer_list:
layer.visible = False
# while there are still layers in the list
while layer_list:
# remove the first layer from the list and make it visible
layer = layer_list.pop(0)
layer.visible = True
# special treatment for group layers
if layer.isGroupLayer:
# recursively call this function on its sub layers (this exports all the sub layers on their own
export_layout_for_each_layer(layer.listLayers(), layout, save_folder)
# make the sub layers visible (so we can export the group layer) and remove the sub layers from the master layer list (because we already exported them)
for sub_layer in layer.listLayers():
layer_list.remove(sub_layer)
sub_layer.visible = True
# make sure the legend only shows active layers
layout.listElements("LEGEND_ELEMENT")[0].syncLayerVisibility = True
# set title and export, then make layer invisible
print(f"Exporting layout for {layer.name}")
layout.listElements("TEXT_ELEMENT")[0].text = layer.name
layout.exportToPDF(save_folder/f"{layer.name}.pdf")
layer.visible = False
# define your save location and export layerrs
save_folder = Path(arcpy.env.workspace).parent
export_layer_names = ["Money Stats" , "House Stats", "Car Stats", "Travel Stats"]
# get the elements you need
aprx = arcpy.mp.ArcGISProject("current")
layout = aprx.listLayouts("Layout")[0]
map_frame = layout.listElements('MAPFRAME_ELEMENT')[0]
all_layers = map_frame.map.listLayers()
export_layers = [layer for layer in all_layers if layer.name in export_layer_names]
# run it
export_layout_for_each_layer(export_layers, layout, save_folder)
Hi Johannes,
Thank you for your help! The code makes sense, but it throws me a ValueError. I think the ".remove" function causes the issue.
I tried using pop as well.
Do let me know if you have workarounds for this! Really appreciate your help thus far!! 🙂
Thank you
sahus
Yeah, I didn't test before posting...
It tries to remove sublayers from the list, but they aren't in the list because you removed them in line 39 above.
Just let it fail silently:
try:
layer_list.remove(sub_layer)
except ValueError:
pass # sub_layer not in layer_list
Hi Johannes,
It worked great, thank you for your help! Really appreciate the clarifications and direction!
Cheers
Sahus